changed media retriever failure handling

This commit is contained in:
Thibault Deckers 2020-09-18 15:35:57 +09:00
parent 2fc15a126b
commit fe12767b4a
4 changed files with 116 additions and 107 deletions

View file

@ -199,27 +199,29 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
private Map<String, String> getVideoAllMetadataByMediaMetadataRetriever(String uri) { private Map<String, String> getVideoAllMetadataByMediaMetadataRetriever(String uri) {
Map<String, String> dirMap = new HashMap<>(); Map<String, String> dirMap = new HashMap<>();
MediaMetadataRetriever retriever = StorageUtils.openMetadataRetriever(context, Uri.parse(uri)); MediaMetadataRetriever retriever = StorageUtils.openMetadataRetriever(context, Uri.parse(uri));
try { if (retriever != null) {
for (Map.Entry<Integer, String> kv : VIDEO_MEDIA_METADATA_KEYS.entrySet()) { try {
Integer key = kv.getKey(); for (Map.Entry<Integer, String> kv : VIDEO_MEDIA_METADATA_KEYS.entrySet()) {
String value = retriever.extractMetadata(key); Integer key = kv.getKey();
if (value != null) { String value = retriever.extractMetadata(key);
switch (key) { if (value != null) {
case MediaMetadataRetriever.METADATA_KEY_BITRATE: switch (key) {
value = Formatter.formatFileSize(context, Long.parseLong(value)) + "/sec"; case MediaMetadataRetriever.METADATA_KEY_BITRATE:
break; value = Formatter.formatFileSize(context, Long.parseLong(value)) + "/sec";
case MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION: break;
value += "°"; case MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION:
break; value += "°";
break;
}
dirMap.put(kv.getValue(), value);
} }
dirMap.put(kv.getValue(), value);
} }
} catch (Exception e) {
Log.w(LOG_TAG, "failed to get video metadata by MediaMetadataRetriever for uri=" + uri, e);
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release();
} }
} catch (Exception e) {
Log.w(LOG_TAG, "failed to get video metadata by MediaMetadataRetriever for uri=" + uri, e);
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release();
} }
return dirMap; return dirMap;
} }
@ -317,45 +319,47 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
private Map<String, Object> getVideoCatalogMetadataByMediaMetadataRetriever(String uri) { private Map<String, Object> getVideoCatalogMetadataByMediaMetadataRetriever(String uri) {
Map<String, Object> metadataMap = new HashMap<>(); Map<String, Object> metadataMap = new HashMap<>();
MediaMetadataRetriever retriever = StorageUtils.openMetadataRetriever(context, Uri.parse(uri)); MediaMetadataRetriever retriever = StorageUtils.openMetadataRetriever(context, Uri.parse(uri));
try { if (retriever != null) {
String dateString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE); try {
String rotationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); String dateString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE);
String locationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION); String rotationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
String locationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION);
if (dateString != null) { if (dateString != null) {
long dateMillis = MetadataHelper.parseVideoMetadataDate(dateString); long dateMillis = MetadataHelper.parseVideoMetadataDate(dateString);
// 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) { if (dateMillis > 0) {
metadataMap.put(KEY_DATE_MILLIS, dateMillis); metadataMap.put(KEY_DATE_MILLIS, dateMillis);
}
} }
} if (rotationString != null) {
if (rotationString != null) { metadataMap.put(KEY_VIDEO_ROTATION, Integer.parseInt(rotationString));
metadataMap.put(KEY_VIDEO_ROTATION, Integer.parseInt(rotationString)); }
} if (locationString != null) {
if (locationString != null) { Matcher locationMatcher = VIDEO_LOCATION_PATTERN.matcher(locationString);
Matcher locationMatcher = VIDEO_LOCATION_PATTERN.matcher(locationString); if (locationMatcher.find() && locationMatcher.groupCount() >= 2) {
if (locationMatcher.find() && locationMatcher.groupCount() >= 2) { String latitudeString = locationMatcher.group(1);
String latitudeString = locationMatcher.group(1); String longitudeString = locationMatcher.group(2);
String longitudeString = locationMatcher.group(2); if (latitudeString != null && longitudeString != null) {
if (latitudeString != null && longitudeString != null) { try {
try { double latitude = Double.parseDouble(latitudeString);
double latitude = Double.parseDouble(latitudeString); double longitude = Double.parseDouble(longitudeString);
double longitude = Double.parseDouble(longitudeString); if (latitude != 0 && longitude != 0) {
if (latitude != 0 && longitude != 0) { metadataMap.put(KEY_LATITUDE, latitude);
metadataMap.put(KEY_LATITUDE, latitude); metadataMap.put(KEY_LONGITUDE, longitude);
metadataMap.put(KEY_LONGITUDE, longitude); }
} catch (NumberFormatException ex) {
// ignore
} }
} catch (NumberFormatException ex) {
// ignore
} }
} }
} }
} catch (Exception e) {
Log.w(LOG_TAG, "failed to get catalog metadata by MediaMetadataRetriever for uri=" + uri, e);
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release();
} }
} catch (Exception e) {
Log.w(LOG_TAG, "failed to get catalog metadata by MediaMetadataRetriever for uri=" + uri, e);
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release();
} }
return metadataMap; return metadataMap;
} }

View file

@ -25,25 +25,27 @@ class VideoThumbnailFetcher implements DataFetcher<InputStream> {
@Override @Override
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) { public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
MediaMetadataRetriever retriever = StorageUtils.openMetadataRetriever(model.getContext(), model.getUri()); MediaMetadataRetriever retriever = StorageUtils.openMetadataRetriever(model.getContext(), model.getUri());
try { if (retriever != null) {
byte[] picture = retriever.getEmbeddedPicture(); try {
if (picture != null) { byte[] picture = retriever.getEmbeddedPicture();
callback.onDataReady(new ByteArrayInputStream(picture)); if (picture != null) {
} else { callback.onDataReady(new ByteArrayInputStream(picture));
// not ideal: bitmap -> byte[] -> bitmap } else {
// but simple fallback and we cache result // not ideal: bitmap -> byte[] -> bitmap
ByteArrayOutputStream bos = new ByteArrayOutputStream(); // but simple fallback and we cache result
Bitmap bitmap = retriever.getFrameAtTime(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
if (bitmap != null) { Bitmap bitmap = retriever.getFrameAtTime();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); if (bitmap != null) {
bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);
}
callback.onDataReady(new ByteArrayInputStream(bos.toByteArray()));
} }
callback.onDataReady(new ByteArrayInputStream(bos.toByteArray())); } catch (Exception ex) {
callback.onLoadFailed(ex);
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release();
} }
} catch (Exception ex) {
callback.onLoadFailed(ex);
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release();
} }
} }

View file

@ -135,49 +135,51 @@ public class SourceImageEntry {
// finds: width, height, orientation/rotation, date, title, duration // finds: width, height, orientation/rotation, date, title, duration
private void fillByMediaMetadataRetriever(@NonNull Context context) { private void fillByMediaMetadataRetriever(@NonNull Context context) {
MediaMetadataRetriever retriever = StorageUtils.openMetadataRetriever(context, uri); MediaMetadataRetriever retriever = StorageUtils.openMetadataRetriever(context, uri);
try { if (retriever != null) {
String width = null, height = null, rotation = null, durationMillis = null; try {
if (isImage()) { String width = null, height = null, rotation = null, durationMillis = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (isImage()) {
width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT); width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH);
rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_ROTATION); height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT);
rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_ROTATION);
}
} else if (isVideo()) {
width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
durationMillis = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
}
if (width != null) {
this.width = Integer.parseInt(width);
}
if (height != null) {
this.height = Integer.parseInt(height);
}
if (rotation != null) {
this.orientationDegrees = Integer.parseInt(rotation);
}
if (durationMillis != null) {
this.durationMillis = Long.parseLong(durationMillis);
} }
} else if (isVideo()) {
width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
durationMillis = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
}
if (width != null) {
this.width = Integer.parseInt(width);
}
if (height != null) {
this.height = Integer.parseInt(height);
}
if (rotation != null) {
this.orientationDegrees = Integer.parseInt(rotation);
}
if (durationMillis != null) {
this.durationMillis = Long.parseLong(durationMillis);
}
String dateString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE); String dateString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE);
long dateMillis = MetadataHelper.parseVideoMetadataDate(dateString); long dateMillis = MetadataHelper.parseVideoMetadataDate(dateString);
// 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) { if (dateMillis > 0) {
this.sourceDateTakenMillis = dateMillis; this.sourceDateTakenMillis = dateMillis;
} }
String title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE); String title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
if (title != null) { if (title != null) {
this.title = title; this.title = title;
}
} catch (Exception e) {
// ignore
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release();
} }
} catch (Exception e) {
// ignore
} finally {
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
retriever.release();
} }
} }

View file

@ -460,7 +460,8 @@ public class StorageUtils {
} }
retriever.setDataSource(context, uri); retriever.setDataSource(context, uri);
} catch (Exception e) { } catch (Exception e) {
Log.e(LOG_TAG, "failed to open MediaMetadataRetriever for uri=" + uri, e); // unsupported format
return null;
} }
return retriever; return retriever;
} }