video: metadata fallback

This commit is contained in:
Thibault Deckers 2019-08-04 19:15:30 +09:00
parent a7f9163ec3
commit 67a5bd3f16
4 changed files with 81 additions and 4 deletions

View file

@ -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);
}
}

View file

@ -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<String, Map<String, String>> metadataMap = new HashMap<>();
Map<String, String> dirMap = new HashMap<>();
// unnamed fallback directory
metadataMap.put("", dirMap);
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(path);
for (Map.Entry<Integer, String> 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);
}
}
}

View file

@ -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<Integer, String> MEDIA_METADATA_KEYS = new HashMap<Integer, String>() {
{
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");
}
};
}

View file

@ -98,7 +98,7 @@ class InfoPageState extends State<InfoPage> {
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)),
),