#405 fixed editing metadata for some MP4 files
This commit is contained in:
parent
b268a5c117
commit
85ffd6843b
4 changed files with 142 additions and 24 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
109
pubspec.lock
109
pubspec.lock
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in a new issue