info: show picture embedded in videos
This commit is contained in:
parent
097a051b37
commit
652a5383ea
6 changed files with 54 additions and 10 deletions
|
@ -190,6 +190,9 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
|||
case "getContentResolverMetadata":
|
||||
new Thread(() -> getContentResolverMetadata(call, new MethodResultWrapper(result))).start();
|
||||
break;
|
||||
case "getEmbeddedPictures":
|
||||
new Thread(() -> getEmbeddedPictures(call, new MethodResultWrapper(result))).start();
|
||||
break;
|
||||
case "getExifThumbnails":
|
||||
new Thread(() -> getExifThumbnails(call, new MethodResultWrapper(result))).start();
|
||||
break;
|
||||
|
@ -415,7 +418,7 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
|||
metadataMap.put(KEY_LATITUDE, latitude);
|
||||
metadataMap.put(KEY_LONGITUDE, longitude);
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
@ -530,6 +533,26 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private void getEmbeddedPictures(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
|
||||
Uri uri = Uri.parse(call.argument("uri"));
|
||||
List<byte[]> pictures = new ArrayList<>();
|
||||
MediaMetadataRetriever retriever = StorageUtils.openMetadataRetriever(context, uri);
|
||||
if (retriever != null) {
|
||||
try {
|
||||
byte[] picture = retriever.getEmbeddedPicture();
|
||||
if (picture != null) {
|
||||
pictures.add(picture);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.error("getVideoEmbeddedPictures-failure", "failed to get embedded picture for uri=" + uri, e);
|
||||
} finally {
|
||||
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
|
||||
retriever.release();
|
||||
}
|
||||
}
|
||||
result.success(pictures);
|
||||
}
|
||||
|
||||
private void getExifThumbnails(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
|
||||
Uri uri = Uri.parse(call.argument("uri"));
|
||||
List<byte[]> thumbnails = new ArrayList<>();
|
||||
|
|
|
@ -40,8 +40,8 @@ class VideoThumbnailFetcher implements DataFetcher<InputStream> {
|
|||
}
|
||||
callback.onDataReady(new ByteArrayInputStream(bos.toByteArray()));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
callback.onLoadFailed(ex);
|
||||
} catch (Exception e) {
|
||||
callback.onLoadFailed(e);
|
||||
} finally {
|
||||
// cannot rely on `MediaMetadataRetriever` being `AutoCloseable` on older APIs
|
||||
retriever.release();
|
||||
|
|
|
@ -55,7 +55,7 @@ public class MetadataHelper {
|
|||
DateFormat parser = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.US);
|
||||
parser.setTimeZone((timeZone != null) ? timeZone : TimeZone.getTimeZone("GMT"));
|
||||
date = parser.parse(dateString);
|
||||
} catch (ParseException ex) {
|
||||
} catch (ParseException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,18 @@ class MetadataService {
|
|||
return {};
|
||||
}
|
||||
|
||||
static Future<List<Uint8List>> getEmbeddedPictures(String uri) async {
|
||||
try {
|
||||
final result = await platform.invokeMethod('getEmbeddedPictures', <String, dynamic>{
|
||||
'uri': uri,
|
||||
});
|
||||
return (result as List).cast<Uint8List>();
|
||||
} on PlatformException catch (e) {
|
||||
debugPrint('getEmbeddedPictures failed with code=${e.code}, exception=${e.message}, details=${e.details}');
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
static Future<List<Uint8List>> getExifThumbnails(String uri) async {
|
||||
try {
|
||||
final result = await platform.invokeMethod('getExifThumbnails', <String, dynamic>{
|
||||
|
|
|
@ -36,8 +36,9 @@ class _MetadataSectionSliverState extends State<MetadataSectionSliver> with Auto
|
|||
static const int maxValueLength = 140;
|
||||
|
||||
// directory names from metadata-extractor
|
||||
static const exifThumbnailDirectory = 'Exif Thumbnail';
|
||||
static const xmpDirectory = 'XMP';
|
||||
static const exifThumbnailDirectory = 'Exif Thumbnail'; // from metadata-extractor
|
||||
static const xmpDirectory = 'XMP'; // from metadata-extractor
|
||||
static const videoDirectory = 'Video'; // additional generic video directory
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -106,6 +107,7 @@ class _MetadataSectionSliverState extends State<MetadataSectionSliver> with Auto
|
|||
SizedBox(height: 4),
|
||||
if (dir.name == exifThumbnailDirectory) MetadataThumbnails(source: MetadataThumbnailSource.exif, entry: entry),
|
||||
if (dir.name == xmpDirectory) MetadataThumbnails(source: MetadataThumbnailSource.xmp, entry: entry),
|
||||
if (dir.name == videoDirectory) MetadataThumbnails(source: MetadataThumbnailSource.embedded, entry: entry),
|
||||
Container(
|
||||
alignment: Alignment.topLeft,
|
||||
padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'package:aves/model/image_entry.dart';
|
|||
import 'package:aves/services/metadata_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum MetadataThumbnailSource { exif, xmp }
|
||||
enum MetadataThumbnailSource { embedded, exif, xmp }
|
||||
|
||||
class MetadataThumbnails extends StatefulWidget {
|
||||
final MetadataThumbnailSource source;
|
||||
|
@ -24,15 +24,22 @@ class MetadataThumbnails extends StatefulWidget {
|
|||
class _MetadataThumbnailsState extends State<MetadataThumbnails> {
|
||||
Future<List<Uint8List>> _loader;
|
||||
|
||||
ImageEntry get entry => widget.entry;
|
||||
|
||||
String get uri => entry.uri;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
switch (widget.source) {
|
||||
case MetadataThumbnailSource.embedded:
|
||||
_loader = MetadataService.getEmbeddedPictures(uri);
|
||||
break;
|
||||
case MetadataThumbnailSource.exif:
|
||||
_loader = MetadataService.getExifThumbnails(widget.entry.uri);
|
||||
_loader = MetadataService.getExifThumbnails(uri);
|
||||
break;
|
||||
case MetadataThumbnailSource.xmp:
|
||||
_loader = MetadataService.getXmpThumbnails(widget.entry.uri);
|
||||
_loader = MetadataService.getXmpThumbnails(uri);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +50,7 @@ class _MetadataThumbnailsState extends State<MetadataThumbnails> {
|
|||
future: _loader,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasError && snapshot.connectionState == ConnectionState.done && snapshot.data.isNotEmpty) {
|
||||
final turns = (widget.entry.orientationDegrees / 90).round();
|
||||
final turns = (entry.orientationDegrees / 90).round();
|
||||
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||
return Container(
|
||||
alignment: AlignmentDirectional.topStart,
|
||||
|
|
Loading…
Reference in a new issue