From 67a5bd3f16b9957ca0d97416eeed8993e61937e9 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Sun, 4 Aug 2019 19:15:30 +0900 Subject: [PATCH] video: metadata fallback --- .../deckers/thibault/aves/MainActivity.java | 2 +- .../aves/channelhandlers/MetadataHandler.java | 50 +++++++++++++++++++ .../thibault/aves/utils/Constants.java | 31 +++++++++++- lib/widgets/fullscreen/info_page.dart | 2 +- 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/java/deckers/thibault/aves/MainActivity.java b/android/app/src/main/java/deckers/thibault/aves/MainActivity.java index f109c5fb1..13b2d9c7e 100644 --- a/android/app/src/main/java/deckers/thibault/aves/MainActivity.java +++ b/android/app/src/main/java/deckers/thibault/aves/MainActivity.java @@ -23,7 +23,7 @@ public class MainActivity extends FlutterActivity { FlutterView messenger = getFlutterView(); new MethodChannel(messenger, AppAdapterHandler.CHANNEL).setMethodCallHandler(new AppAdapterHandler(this)); new MethodChannel(messenger, ImageDecodeHandler.CHANNEL).setMethodCallHandler(new ImageDecodeHandler(this, mediaStoreStreamHandler)); - new MethodChannel(messenger, MetadataHandler.CHANNEL).setMethodCallHandler(new MetadataHandler()); + new MethodChannel(messenger, MetadataHandler.CHANNEL).setMethodCallHandler(new MetadataHandler(this)); new EventChannel(messenger, MediaStoreStreamHandler.CHANNEL).setStreamHandler(mediaStoreStreamHandler); } } diff --git a/android/app/src/main/java/deckers/thibault/aves/channelhandlers/MetadataHandler.java b/android/app/src/main/java/deckers/thibault/aves/channelhandlers/MetadataHandler.java index c45c77173..5273d43c8 100644 --- a/android/app/src/main/java/deckers/thibault/aves/channelhandlers/MetadataHandler.java +++ b/android/app/src/main/java/deckers/thibault/aves/channelhandlers/MetadataHandler.java @@ -1,5 +1,9 @@ package deckers.thibault.aves.channelhandlers; +import android.content.Context; +import android.media.MediaMetadataRetriever; +import android.text.format.Formatter; + import androidx.annotation.NonNull; import com.adobe.xmp.XMPException; @@ -7,6 +11,7 @@ import com.adobe.xmp.XMPIterator; import com.adobe.xmp.XMPMeta; import com.adobe.xmp.properties.XMPPropertyInfo; import com.drew.imaging.ImageMetadataReader; +import com.drew.imaging.ImageProcessingException; import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import com.drew.metadata.Tag; @@ -19,12 +24,19 @@ import java.io.InputStream; import java.util.HashMap; import java.util.Map; +import deckers.thibault.aves.utils.Constants; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; public class MetadataHandler implements MethodChannel.MethodCallHandler { public static final String CHANNEL = "deckers.thibault/aves/metadata"; + private Context context; + + public MetadataHandler(Context context) { + this.context = context; + } + @Override public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) { switch (call.method) { @@ -61,6 +73,8 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler { } } result.success(metadataMap); + } catch (ImageProcessingException e) { + result.error("getOverlayMetadata-imageprocessing", "failed to get metadata for path=" + path + " (" + e.getMessage() + ")", null); } catch (FileNotFoundException e) { result.error("getOverlayMetadata-filenotfound", "failed to get metadata for path=" + path + " (" + e.getMessage() + ")", null); } catch (Exception e) { @@ -103,10 +117,46 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler { } } result.success(metadataMap); + } catch (ImageProcessingException e) { + getAllVideoMetadataFallback(call, result); } catch (FileNotFoundException e) { result.error("getAllMetadata-filenotfound", "failed to get metadata for path=" + path + " (" + e.getMessage() + ")", null); } catch (Exception e) { result.error("getAllMetadata-exception", "failed to get metadata for path=" + path, e); } } + + private void getAllVideoMetadataFallback(MethodCall call, MethodChannel.Result result) { + String path = call.argument("path"); + + try { + Map> metadataMap = new HashMap<>(); + Map dirMap = new HashMap<>(); + // unnamed fallback directory + metadataMap.put("", dirMap); + + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(path); + for (Map.Entry kv : Constants.MEDIA_METADATA_KEYS.entrySet()) { + Integer key = kv.getKey(); + String value = retriever.extractMetadata(key); + if (value != null) { + switch (key) { + case MediaMetadataRetriever.METADATA_KEY_BITRATE: + value = Formatter.formatFileSize(context, Long.parseLong(value)) + "/sec"; + break; + case MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION: + value += "°"; + break; + } + dirMap.put(kv.getValue(), value); + } + } + retriever.release(); + + result.success(metadataMap); + } catch (Exception e) { + result.error("getAllVideoMetadataFallback-exception", "failed to get metadata for path=" + path, e); + } + } } \ No newline at end of file diff --git a/android/app/src/main/java/deckers/thibault/aves/utils/Constants.java b/android/app/src/main/java/deckers/thibault/aves/utils/Constants.java index 210809660..bfdddc09d 100644 --- a/android/app/src/main/java/deckers/thibault/aves/utils/Constants.java +++ b/android/app/src/main/java/deckers/thibault/aves/utils/Constants.java @@ -1,10 +1,37 @@ package deckers.thibault.aves.utils; +import android.media.MediaMetadataRetriever; + +import java.util.HashMap; +import java.util.Map; + public class Constants { // mime types public static final String MIME_VIDEO = "video"; - public static final String MIME_JPEG = "image/jpeg"; - public static final String MIME_PNG = "image/png"; public static final String MIME_GIF = "image/gif"; + + // video metadata keys, from android.media.MediaMetadataRetriever + + public static final Map MEDIA_METADATA_KEYS = new HashMap() { + { + put(MediaMetadataRetriever.METADATA_KEY_MIMETYPE, "MIME Type"); + put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS, "Number of Tracks"); + put(MediaMetadataRetriever.METADATA_KEY_HAS_AUDIO, "Has Audio"); + put(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "Has Video"); + put(MediaMetadataRetriever.METADATA_KEY_BITRATE, "Bitrate"); + put(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION, "Video Rotation"); + put(MediaMetadataRetriever.METADATA_KEY_DATE, "Date"); + put(MediaMetadataRetriever.METADATA_KEY_LOCATION, "Location"); + put(MediaMetadataRetriever.METADATA_KEY_YEAR, "Year"); + put(MediaMetadataRetriever.METADATA_KEY_ARTIST, "Artist"); + put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, "Album Artist"); + put(MediaMetadataRetriever.METADATA_KEY_ALBUM, "Album"); + put(MediaMetadataRetriever.METADATA_KEY_TITLE, "Title"); + put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, "Author"); + put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, "Composer"); + put(MediaMetadataRetriever.METADATA_KEY_WRITER, "Writer"); + put(MediaMetadataRetriever.METADATA_KEY_GENRE, "Genre"); + } + }; } diff --git a/lib/widgets/fullscreen/info_page.dart b/lib/widgets/fullscreen/info_page.dart index ecf7bf1bd..b762f2da6 100644 --- a/lib/widgets/fullscreen/info_page.dart +++ b/lib/widgets/fullscreen/info_page.dart @@ -98,7 +98,7 @@ class InfoPageState extends State { final directory = metadataMap[directoryName]; final tagKeys = directory.keys.toList()..sort(); return [ - Padding( + if (directoryName.isNotEmpty) Padding( padding: EdgeInsets.symmetric(vertical: 4.0), child: Text(directoryName, style: TextStyle(fontSize: 18)), ),