info: improved media descriptions & minor fixes
This commit is contained in:
parent
123a4df495
commit
120f9cd4e4
2 changed files with 74 additions and 16 deletions
|
@ -7,7 +7,6 @@ import android.media.MediaMetadataRetriever
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.text.format.Formatter
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.exifinterface.media.ExifInterface
|
import androidx.exifinterface.media.ExifInterface
|
||||||
import com.adobe.internal.xmp.XMPException
|
import com.adobe.internal.xmp.XMPException
|
||||||
|
@ -28,6 +27,7 @@ import deckers.thibault.aves.utils.*
|
||||||
import deckers.thibault.aves.utils.ExifInterfaceHelper.describeAll
|
import deckers.thibault.aves.utils.ExifInterfaceHelper.describeAll
|
||||||
import deckers.thibault.aves.utils.ExifInterfaceHelper.getSafeDateMillis
|
import deckers.thibault.aves.utils.ExifInterfaceHelper.getSafeDateMillis
|
||||||
import deckers.thibault.aves.utils.ExifInterfaceHelper.getSafeInt
|
import deckers.thibault.aves.utils.ExifInterfaceHelper.getSafeInt
|
||||||
|
import deckers.thibault.aves.utils.MediaMetadataRetrieverHelper.getSafeDescription
|
||||||
import deckers.thibault.aves.utils.MediaMetadataRetrieverHelper.getSafeInt
|
import deckers.thibault.aves.utils.MediaMetadataRetrieverHelper.getSafeInt
|
||||||
import deckers.thibault.aves.utils.Metadata.getRotationDegreesForExifCode
|
import deckers.thibault.aves.utils.Metadata.getRotationDegreesForExifCode
|
||||||
import deckers.thibault.aves.utils.Metadata.isFlippedForExifCode
|
import deckers.thibault.aves.utils.Metadata.isFlippedForExifCode
|
||||||
|
@ -151,17 +151,7 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
||||||
val retriever = StorageUtils.openMetadataRetriever(context, uri) ?: return dirMap
|
val retriever = StorageUtils.openMetadataRetriever(context, uri) ?: return dirMap
|
||||||
try {
|
try {
|
||||||
for ((code, name) in MediaMetadataRetrieverHelper.allKeys) {
|
for ((code, name) in MediaMetadataRetrieverHelper.allKeys) {
|
||||||
val value = retriever.extractMetadata(code)
|
retriever.getSafeDescription(code, context) { dirMap[name] = it }
|
||||||
if (value != null) {
|
|
||||||
when (code) {
|
|
||||||
MediaMetadataRetriever.METADATA_KEY_BITRATE -> Formatter.formatFileSize(context, value.toLong()) + "/sec"
|
|
||||||
MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION -> "$value°"
|
|
||||||
MediaMetadataRetriever.METADATA_KEY_DURATION -> "$value ms"
|
|
||||||
MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT, MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH -> "$value pixels"
|
|
||||||
MediaMetadataRetriever.METADATA_KEY_LOCATION, MediaMetadataRetriever.METADATA_KEY_MIMETYPE -> null
|
|
||||||
else -> value
|
|
||||||
}?.let { dirMap[name] = it }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(LOG_TAG, "failed to get video metadata by MediaMetadataRetriever for uri=$uri", e)
|
Log.w(LOG_TAG, "failed to get video metadata by MediaMetadataRetriever for uri=$uri", e)
|
||||||
|
@ -333,7 +323,8 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
||||||
try {
|
try {
|
||||||
val latitude = latitudeString.toDoubleOrNull() ?: 0
|
val latitude = latitudeString.toDoubleOrNull() ?: 0
|
||||||
val longitude = longitudeString.toDoubleOrNull() ?: 0
|
val longitude = longitudeString.toDoubleOrNull() ?: 0
|
||||||
if (latitude != 0 && longitude != 0) {
|
// keep `0.0` as `0.0`, not `0`
|
||||||
|
if (latitude != 0.0 || longitude != 0.0) {
|
||||||
metadataMap[KEY_LATITUDE] = latitude
|
metadataMap[KEY_LATITUDE] = latitude
|
||||||
metadataMap[KEY_LONGITUDE] = longitude
|
metadataMap[KEY_LONGITUDE] = longitude
|
||||||
}
|
}
|
||||||
|
@ -379,7 +370,7 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
||||||
val num = it.numerator
|
val num = it.numerator
|
||||||
val denom = it.denominator
|
val denom = it.denominator
|
||||||
metadataMap[KEY_EXPOSURE_TIME] = when {
|
metadataMap[KEY_EXPOSURE_TIME] = when {
|
||||||
num > denom -> it.toSimpleString(true) + "″"
|
num >= denom -> it.toSimpleString(true) + "″"
|
||||||
num != 1L && num != 0L -> Rational(1, (denom / num.toDouble()).roundToLong()).toString()
|
num != 1L && num != 0L -> Rational(1, (denom / num.toDouble()).roundToLong()).toString()
|
||||||
else -> it.toString()
|
else -> it.toString()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
package deckers.thibault.aves.utils
|
package deckers.thibault.aves.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.media.MediaFormat
|
||||||
import android.media.MediaMetadataRetriever
|
import android.media.MediaMetadataRetriever
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.text.format.Formatter
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
object MediaMetadataRetrieverHelper {
|
object MediaMetadataRetrieverHelper {
|
||||||
@JvmField
|
@JvmField
|
||||||
|
@ -21,8 +26,8 @@ object MediaMetadataRetrieverHelper {
|
||||||
MediaMetadataRetriever.METADATA_KEY_DATE to "Date",
|
MediaMetadataRetriever.METADATA_KEY_DATE to "Date",
|
||||||
MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER to "Disc Number",
|
MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER to "Disc Number",
|
||||||
MediaMetadataRetriever.METADATA_KEY_DURATION to "Duration",
|
MediaMetadataRetriever.METADATA_KEY_DURATION to "Duration",
|
||||||
MediaMetadataRetriever.METADATA_KEY_EXIF_LENGTH to "EXIF Length",
|
MediaMetadataRetriever.METADATA_KEY_EXIF_LENGTH to "Exif Length",
|
||||||
MediaMetadataRetriever.METADATA_KEY_EXIF_OFFSET to "EXIF Offset",
|
MediaMetadataRetriever.METADATA_KEY_EXIF_OFFSET to "Exif Offset",
|
||||||
MediaMetadataRetriever.METADATA_KEY_GENRE to "Genre",
|
MediaMetadataRetriever.METADATA_KEY_GENRE to "Genre",
|
||||||
MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO to "Has Audio",
|
MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO to "Has Audio",
|
||||||
MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO to "Has Video",
|
MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO to "Has Video",
|
||||||
|
@ -49,6 +54,8 @@ object MediaMetadataRetrieverHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val durationFormat = SimpleDateFormat("HH:mm:ss.SSS", Locale.ROOT).apply { timeZone = TimeZone.getTimeZone("UTC") }
|
||||||
|
|
||||||
// extensions
|
// extensions
|
||||||
|
|
||||||
fun MediaMetadataRetriever.getSafeString(tag: Int, save: (value: String) -> Unit) {
|
fun MediaMetadataRetriever.getSafeString(tag: Int, save: (value: String) -> Unit) {
|
||||||
|
@ -72,4 +79,64 @@ object MediaMetadataRetrieverHelper {
|
||||||
// some entries have an invalid default date (19040101T000000.000Z) that is before Epoch time
|
// some entries have an invalid default date (19040101T000000.000Z) that is before Epoch time
|
||||||
if (dateMillis > 0) save(dateMillis)
|
if (dateMillis > 0) save(dateMillis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun MediaMetadataRetriever.getSafeDescription(tag: Int, context: Context, save: (value: String) -> Unit) {
|
||||||
|
val value = this.extractMetadata(tag)
|
||||||
|
if (value != null) {
|
||||||
|
when (tag) {
|
||||||
|
// format
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_IMAGE_ROTATION,
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION -> "$value°"
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT, MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH,
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT, MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH -> "$value pixels"
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_BITRATE -> {
|
||||||
|
val bitrate = value.toLongOrNull() ?: 0
|
||||||
|
if (bitrate > 0) Formatter.formatFileSize(context, bitrate) + "/sec" else null
|
||||||
|
}
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_CAPTURE_FRAMERATE -> {
|
||||||
|
val framerate = value.toDoubleOrNull() ?: 0.0
|
||||||
|
if (framerate > 0.0) "$framerate" else null
|
||||||
|
}
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_DURATION -> {
|
||||||
|
val dateMillis = value.toLongOrNull() ?: 0
|
||||||
|
if (dateMillis > 0) durationFormat.format(Date(dateMillis)) else null
|
||||||
|
}
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_COLOR_RANGE -> {
|
||||||
|
when (value.toIntOrNull()) {
|
||||||
|
MediaFormat.COLOR_RANGE_FULL -> "Full"
|
||||||
|
MediaFormat.COLOR_RANGE_LIMITED -> "Limited"
|
||||||
|
else -> value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_COLOR_STANDARD -> {
|
||||||
|
when (value.toIntOrNull()) {
|
||||||
|
MediaFormat.COLOR_STANDARD_BT709 -> "BT.709"
|
||||||
|
MediaFormat.COLOR_STANDARD_BT601_PAL -> "BT.601 625 (PAL)"
|
||||||
|
MediaFormat.COLOR_STANDARD_BT601_NTSC -> "BT.601 525 (NTSC)"
|
||||||
|
MediaFormat.COLOR_STANDARD_BT2020 -> "BT.2020"
|
||||||
|
else -> value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_COLOR_TRANSFER -> {
|
||||||
|
when (value.toIntOrNull()) {
|
||||||
|
MediaFormat.COLOR_TRANSFER_LINEAR -> "Linear"
|
||||||
|
MediaFormat.COLOR_TRANSFER_SDR_VIDEO -> "SMPTE 170M"
|
||||||
|
MediaFormat.COLOR_TRANSFER_ST2084 -> "SMPTE ST 2084"
|
||||||
|
MediaFormat.COLOR_TRANSFER_HLG -> "ARIB STD-B67 (HLG)"
|
||||||
|
else -> value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// hide `0` values
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_COMPILATION,
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_YEAR -> if (value != "0") value else null
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER -> if (value != "0/0") value else null
|
||||||
|
// hide
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_LOCATION,
|
||||||
|
MediaMetadataRetriever.METADATA_KEY_MIMETYPE -> null
|
||||||
|
// as is
|
||||||
|
else -> value
|
||||||
|
}?.let { save(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue