viewer: improved fetch for unknown content
This commit is contained in:
parent
8d798c6f08
commit
e011efe6a9
5 changed files with 84 additions and 27 deletions
|
@ -222,7 +222,7 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
||||||
|
|
||||||
if (dateString != null) {
|
if (dateString != null) {
|
||||||
long dateMillis = MetadataHelper.parseVideoMetadataDate(dateString);
|
long dateMillis = MetadataHelper.parseVideoMetadataDate(dateString);
|
||||||
// some videos 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("dateMillis", dateMillis);
|
metadataMap.put("dateMillis", dateMillis);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@ package deckers.thibault.aves.model.provider;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.media.MediaMetadataRetriever;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
import com.drew.imaging.ImageMetadataReader;
|
import com.drew.imaging.ImageMetadataReader;
|
||||||
import com.drew.imaging.ImageProcessingException;
|
import com.drew.imaging.ImageProcessingException;
|
||||||
|
@ -17,15 +19,66 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import deckers.thibault.aves.utils.Constants;
|
||||||
|
import deckers.thibault.aves.utils.MetadataHelper;
|
||||||
|
|
||||||
import static deckers.thibault.aves.utils.MetadataHelper.getOrientationDegreesForExifCode;
|
import static deckers.thibault.aves.utils.MetadataHelper.getOrientationDegreesForExifCode;
|
||||||
|
|
||||||
class UnknownContentImageProvider extends ImageProvider {
|
class UnknownContentImageProvider extends ImageProvider {
|
||||||
@Override
|
@Override
|
||||||
public void fetchSingle(final Activity activity, final Uri uri, final String mimeType, final ImageOpCallback callback) {
|
public void fetchSingle(final Activity activity, final Uri uri, final String mimeType, final ImageOpCallback callback) {
|
||||||
int width = 0, height = 0, orientationDegrees = 0;
|
int width = 0, height = 0;
|
||||||
Long sourceDateTakenMillis = null;
|
Integer orientationDegrees = null;
|
||||||
|
Long sourceDateTakenMillis = null, durationMillis = null;
|
||||||
|
String title = null;
|
||||||
|
|
||||||
// check metadata first
|
// check first metadata with MediaMetadataRetriever
|
||||||
|
|
||||||
|
try {
|
||||||
|
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||||
|
retriever.setDataSource(activity, uri);
|
||||||
|
|
||||||
|
title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
|
||||||
|
String dateString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE);
|
||||||
|
long dateMillis = MetadataHelper.parseVideoMetadataDate(dateString);
|
||||||
|
// some entries have an invalid default date (19040101T000000.000Z) that is before Epoch time
|
||||||
|
if (dateMillis > 0) {
|
||||||
|
sourceDateTakenMillis = dateMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
String widthString = null, heightString = null, rotationString = null, durationMillisString = null;
|
||||||
|
if (mimeType.startsWith(Constants.MIME_IMAGE)) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
widthString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH);
|
||||||
|
heightString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT);
|
||||||
|
rotationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_IMAGE_ROTATION);
|
||||||
|
}
|
||||||
|
} else if (mimeType.startsWith(Constants.MIME_VIDEO)) {
|
||||||
|
widthString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
|
||||||
|
heightString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
|
||||||
|
rotationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
|
||||||
|
durationMillisString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
|
||||||
|
}
|
||||||
|
if (widthString != null) {
|
||||||
|
width = Integer.parseInt(widthString);
|
||||||
|
}
|
||||||
|
if (heightString != null) {
|
||||||
|
height = Integer.parseInt(heightString);
|
||||||
|
}
|
||||||
|
if (rotationString != null) {
|
||||||
|
orientationDegrees = Integer.parseInt(rotationString);
|
||||||
|
}
|
||||||
|
if (durationMillisString != null) {
|
||||||
|
durationMillis = Long.parseLong(durationMillisString);
|
||||||
|
}
|
||||||
|
retriever.release();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback to metadata-extractor for known types
|
||||||
|
if (width <= 0 || height <= 0 || orientationDegrees == null || sourceDateTakenMillis == null) {
|
||||||
|
if (Constants.MIME_JPEG.equals(mimeType)) {
|
||||||
try (InputStream is = activity.getContentResolver().openInputStream(uri)) {
|
try (InputStream is = activity.getContentResolver().openInputStream(uri)) {
|
||||||
Metadata metadata = ImageMetadataReader.readMetadata(is);
|
Metadata metadata = ImageMetadataReader.readMetadata(is);
|
||||||
JpegDirectory jpegDir = metadata.getFirstDirectoryOfType(JpegDirectory.class);
|
JpegDirectory jpegDir = metadata.getFirstDirectoryOfType(JpegDirectory.class);
|
||||||
|
@ -49,6 +102,8 @@ class UnknownContentImageProvider extends ImageProvider {
|
||||||
} catch (IOException | ImageProcessingException | MetadataException e) {
|
} catch (IOException | ImageProcessingException | MetadataException e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fallback to decoding the image bounds
|
// fallback to decoding the image bounds
|
||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
|
@ -75,13 +130,13 @@ class UnknownContentImageProvider extends ImageProvider {
|
||||||
entry.put("mimeType", mimeType);
|
entry.put("mimeType", mimeType);
|
||||||
entry.put("width", width);
|
entry.put("width", width);
|
||||||
entry.put("height", height);
|
entry.put("height", height);
|
||||||
entry.put("orientationDegrees", orientationDegrees);
|
entry.put("orientationDegrees", orientationDegrees != null ? orientationDegrees : 0);
|
||||||
entry.put("sizeBytes", null);
|
entry.put("sizeBytes", null);
|
||||||
entry.put("title", null);
|
entry.put("title", title);
|
||||||
entry.put("dateModifiedSecs", null);
|
entry.put("dateModifiedSecs", null);
|
||||||
entry.put("sourceDateTakenMillis", sourceDateTakenMillis);
|
entry.put("sourceDateTakenMillis", sourceDateTakenMillis);
|
||||||
entry.put("bucketDisplayName", null);
|
entry.put("bucketDisplayName", null);
|
||||||
entry.put("durationMillis", null);
|
entry.put("durationMillis", durationMillis);
|
||||||
callback.onSuccess(entry);
|
callback.onSuccess(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,6 +244,8 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
|
||||||
if (entry == null || !entry.isVideo) return;
|
if (entry == null || !entry.isVideo) return;
|
||||||
|
|
||||||
final path = entry.path;
|
final path = entry.path;
|
||||||
|
if (path == null) return;
|
||||||
|
|
||||||
var controllerEntry = _videoControllers.firstWhere((kv) => kv.item1 == entry.path, orElse: () => null);
|
var controllerEntry = _videoControllers.firstWhere((kv) => kv.item1 == entry.path, orElse: () => null);
|
||||||
if (controllerEntry != null) {
|
if (controllerEntry != null) {
|
||||||
_videoControllers.remove(controllerEntry);
|
_videoControllers.remove(controllerEntry);
|
||||||
|
|
|
@ -28,7 +28,7 @@ class BasicSection extends StatelessWidget {
|
||||||
InfoRow('Resolution', resolutionText),
|
InfoRow('Resolution', resolutionText),
|
||||||
InfoRow('Size', entry.sizeBytes != null ? formatFilesize(entry.sizeBytes) : '?'),
|
InfoRow('Size', entry.sizeBytes != null ? formatFilesize(entry.sizeBytes) : '?'),
|
||||||
InfoRow('URI', entry.uri ?? '?'),
|
InfoRow('URI', entry.uri ?? '?'),
|
||||||
InfoRow('Path', entry.path ?? '?'),
|
if (entry.path != null) InfoRow('Path', entry.path),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ class _LocationSectionState extends State<LocationSection> {
|
||||||
child: SectionRow('Location'),
|
child: SectionRow('Location'),
|
||||||
),
|
),
|
||||||
ImageMap(
|
ImageMap(
|
||||||
markerId: entry.path,
|
markerId: entry.uri ?? entry.path,
|
||||||
latLng: LatLng(
|
latLng: LatLng(
|
||||||
entry.latLng.item1,
|
entry.latLng.item1,
|
||||||
entry.latLng.item2,
|
entry.latLng.item2,
|
||||||
|
|
Loading…
Reference in a new issue