#405 fixed editing metadata for some MP4 files

This commit is contained in:
Thibault Deckers 2022-11-16 16:17:54 +01:00
parent b268a5c117
commit 85ffd6843b
4 changed files with 142 additions and 24 deletions

View file

@ -8,6 +8,10 @@ All notable changes to this project will be documented in this file.
- Accessibility: apply bold font system setting - Accessibility: apply bold font system setting
### Fixed
- reading metadata for some MP4 files
## <a id="v1.7.4"></a>[v1.7.4] - 2022-11-11 ## <a id="v1.7.4"></a>[v1.7.4] - 2022-11-11
### Added ### Added

View file

@ -124,6 +124,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
val metadataMap = HashMap<String, MutableMap<String, String>>() val metadataMap = HashMap<String, MutableMap<String, String>>()
var foundExif = false var foundExif = false
var foundXmp = false var foundXmp = false
var foundMp4Uuid = false
fun processXmp(xmpMeta: XMPMeta, dirMap: MutableMap<String, String>, allowMultiple: Boolean = false) { fun processXmp(xmpMeta: XMPMeta, dirMap: MutableMap<String, String>, allowMultiple: Boolean = false) {
if (foundXmp && !allowMultiple) return if (foundXmp && !allowMultiple) return
@ -209,11 +210,13 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
val metadata = Helper.safeRead(input) val metadata = Helper.safeRead(input)
foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 } foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 }
foundMp4Uuid = metadata.directories.any { it is Mp4UuidBoxDirectory && it.tagCount > 0 }
val dirByName = metadata.directories.filter { val dirByName = metadata.directories.filter {
(it.tagCount > 0 || it.errorCount > 0) (it.tagCount > 0 || it.errorCount > 0)
&& it !is FileTypeDirectory && it !is FileTypeDirectory
&& it !is AviDirectory && it !is AviDirectory
&& !(it is XmpDirectory && it.tagCount == 1 && it.containsTag(XmpDirectory.TAG_XMP_VALUE_COUNT))
}.groupBy { dir -> dir.name } }.groupBy { dir -> dir.name }
for (dirEntry in dirByName) { for (dirEntry in dirByName) {
@ -388,11 +391,13 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
} }
XMP.checkHeic(context, mimeType, uri, foundXmp, ::fallbackProcessXmp) XMP.checkHeic(context, mimeType, uri, foundXmp, ::fallbackProcessXmp)
if (isLargeMp4(mimeType, sizeBytes)) { // `metadata-extractor` may fail to get UUID boxes for some MP4 files,
XMP.checkMp4(context, mimeType, uri) { dirs -> // so we always check with `mp4parser`, even for smaller files
for (dir in dirs.filterIsInstance<XmpDirectory>()) { XMP.checkMp4(context, mimeType, uri) { dirs ->
fallbackProcessXmp(dir.xmpMeta) for (dir in dirs.filterIsInstance<XmpDirectory>()) {
} fallbackProcessXmp(dir.xmpMeta)
}
if (!foundMp4Uuid) {
for (dir in dirs.filterIsInstance<Mp4UuidBoxDirectory>()) { for (dir in dirs.filterIsInstance<Mp4UuidBoxDirectory>()) {
processMp4Uuid(dir) processMp4Uuid(dir)
} }
@ -491,6 +496,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
var flags = (metadataMap[KEY_FLAGS] ?: 0) as Int var flags = (metadataMap[KEY_FLAGS] ?: 0) as Int
var foundExif = false var foundExif = false
var foundXmp = false var foundXmp = false
var foundMp4Uuid = false
fun processXmp(xmpMeta: XMPMeta, allowMultiple: Boolean = false) { fun processXmp(xmpMeta: XMPMeta, allowMultiple: Boolean = false) {
if (foundXmp && !allowMultiple) return if (foundXmp && !allowMultiple) return
@ -543,6 +549,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input -> Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
val metadata = Helper.safeRead(input) val metadata = Helper.safeRead(input)
foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 } foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 }
foundMp4Uuid = metadata.directories.any { it is Mp4UuidBoxDirectory && it.tagCount > 0 }
// File type // File type
for (dir in metadata.getDirectoriesOfType(FileTypeDirectory::class.java)) { for (dir in metadata.getDirectoriesOfType(FileTypeDirectory::class.java)) {
@ -695,11 +702,13 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
} }
XMP.checkHeic(context, mimeType, uri, foundXmp, ::processXmp) XMP.checkHeic(context, mimeType, uri, foundXmp, ::processXmp)
if (isLargeMp4(mimeType, sizeBytes)) { // `metadata-extractor` may fail to get UUID boxes for some MP4 files,
XMP.checkMp4(context, mimeType, uri) { dirs -> // so we always check with `mp4parser`, even for smaller files
for (dir in dirs.filterIsInstance<XmpDirectory>()) { XMP.checkMp4(context, mimeType, uri) { dirs ->
processXmp(dir.xmpMeta) for (dir in dirs.filterIsInstance<XmpDirectory>()) {
} processXmp(dir.xmpMeta)
}
if (!foundMp4Uuid) {
for (dir in dirs.filterIsInstance<Mp4UuidBoxDirectory>()) { for (dir in dirs.filterIsInstance<Mp4UuidBoxDirectory>()) {
processMp4Uuid(dir) processMp4Uuid(dir)
} }
@ -941,11 +950,11 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
} }
XMP.checkHeic(context, mimeType, uri, foundXmp, ::processXmp) XMP.checkHeic(context, mimeType, uri, foundXmp, ::processXmp)
if (isLargeMp4(mimeType, sizeBytes)) { // `metadata-extractor` may fail to get UUID boxes for some MP4 files,
XMP.checkMp4(context, mimeType, uri) { dirs -> // so we always check with `mp4parser`, even for smaller files
for (dir in dirs.filterIsInstance<XmpDirectory>()) { XMP.checkMp4(context, mimeType, uri) { dirs ->
processXmp(dir.xmpMeta) for (dir in dirs.filterIsInstance<XmpDirectory>()) {
} processXmp(dir.xmpMeta)
} }
} }
@ -1026,11 +1035,11 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
} }
XMP.checkHeic(context, mimeType, uri, foundXmp, ::processXmp) XMP.checkHeic(context, mimeType, uri, foundXmp, ::processXmp)
if (isLargeMp4(mimeType, sizeBytes)) { // `metadata-extractor` may fail to get UUID boxes for some MP4 files,
XMP.checkMp4(context, mimeType, uri) { dirs -> // so we always check with `mp4parser`, even for smaller files
for (dir in dirs.filterIsInstance<XmpDirectory>()) { XMP.checkMp4(context, mimeType, uri) { dirs ->
processXmp(dir.xmpMeta) for (dir in dirs.filterIsInstance<XmpDirectory>()) {
} processXmp(dir.xmpMeta)
} }
} }

View file

@ -8,6 +8,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "47.0.0" version: "47.0.0"
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.8"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
@ -60,7 +67,7 @@ packages:
aves_report_platform: aves_report_platform:
dependency: "direct main" dependency: "direct main"
description: description:
path: "plugins/aves_report_console" path: "plugins/aves_report_crashlytics"
relative: true relative: true
source: path source: path
version: "0.0.1" version: "0.0.1"
@ -74,7 +81,7 @@ packages:
aves_services_platform: aves_services_platform:
dependency: "direct main" dependency: "direct main"
description: description:
path: "plugins/aves_services_none" path: "plugins/aves_services_google"
relative: true relative: true
source: path source: path
version: "0.0.1" version: "0.0.1"
@ -120,6 +127,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
cloud_firestore_platform_interface:
dependency: transitive
description:
name: cloud_firestore_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "5.8.5"
cloud_firestore_web:
dependency: transitive
description:
name: cloud_firestore_web
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.5"
collection: collection:
dependency: "direct main" dependency: "direct main"
description: description:
@ -264,6 +285,41 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "6.1.2" version: "6.1.2"
firebase_core:
dependency: transitive
description:
name: firebase_core
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.5.2"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
firebase_crashlytics:
dependency: transitive
description:
name: firebase_crashlytics
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.5"
firebase_crashlytics_platform_interface:
dependency: transitive
description:
name: firebase_crashlytics_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.6"
flex_color_picker: flex_color_picker:
dependency: "direct main" dependency: "direct main"
description: description:
@ -342,6 +398,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.6.13" version: "0.6.13"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
flutter_staggered_animations: flutter_staggered_animations:
dependency: "direct main" dependency: "direct main"
description: description:
@ -385,6 +448,41 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
google_api_availability:
dependency: transitive
description:
name: google_api_availability
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
google_maps_flutter:
dependency: transitive
description:
name: google_maps_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
google_maps_flutter_android:
dependency: transitive
description:
name: google_maps_flutter_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.3"
google_maps_flutter_ios:
dependency: transitive
description:
name: google_maps_flutter_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.12"
google_maps_flutter_platform_interface:
dependency: transitive
description:
name: google_maps_flutter_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.4"
highlight: highlight:
dependency: transitive dependency: transitive
description: description:
@ -947,6 +1045,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
streams_channel: streams_channel:
dependency: "direct main" dependency: "direct main"
description: description:

View file

@ -30,11 +30,11 @@ dependencies:
aves_report: aves_report:
path: plugins/aves_report path: plugins/aves_report
aves_report_platform: aves_report_platform:
path: plugins/aves_report_console path: plugins/aves_report_crashlytics
aves_services: aves_services:
path: plugins/aves_services path: plugins/aves_services
aves_services_platform: aves_services_platform:
path: plugins/aves_services_none path: plugins/aves_services_google
charts_flutter: charts_flutter:
collection: collection:
connectivity_plus: connectivity_plus: