improved video fetch

This commit is contained in:
Thibault Deckers 2020-04-07 22:27:38 +09:00
parent a2fc8bfd2f
commit 3328916c86
3 changed files with 32 additions and 6 deletions

View file

@ -17,6 +17,7 @@ import com.drew.metadata.MetadataException;
import com.drew.metadata.avi.AviDirectory; import com.drew.metadata.avi.AviDirectory;
import com.drew.metadata.exif.ExifIFD0Directory; import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.jpeg.JpegDirectory; import com.drew.metadata.jpeg.JpegDirectory;
import com.drew.metadata.mp4.Mp4Directory;
import com.drew.metadata.mp4.media.Mp4VideoDirectory; import com.drew.metadata.mp4.media.Mp4VideoDirectory;
import java.io.File; import java.io.File;
@ -96,11 +97,15 @@ public class ImageEntry {
return width != null && width > 0 && height != null && height > 0; return width != null && width > 0 && height != null && height > 0;
} }
private boolean hasDuration() {
return durationMillis != null && durationMillis > 0;
}
public String getFilename() { public String getFilename() {
return path == null ? null : new File(path).getName(); return path == null ? null : new File(path).getName();
} }
public boolean isImage() { private boolean isImage() {
return mimeType.startsWith(MimeTypes.IMAGE); return mimeType.startsWith(MimeTypes.IMAGE);
} }
@ -123,7 +128,7 @@ public class ImageEntry {
// finds: width, height, orientation/rotation, date, title, duration // finds: width, height, orientation/rotation, date, title, duration
public ImageEntry fillPreCatalogMetadata(Context context) { public ImageEntry fillPreCatalogMetadata(Context context) {
fillByMediaMetadataRetriever(context); fillByMediaMetadataRetriever(context);
if (hasSize()) return this; if (hasSize() && (!isVideo() || hasDuration())) return this;
fillByMetadataExtractor(context); fillByMetadataExtractor(context);
if (hasSize()) return this; if (hasSize()) return this;
fillByBitmapDecode(context); fillByBitmapDecode(context);
@ -218,6 +223,12 @@ public class ImageEntry {
height = mp4VideoDir.getInt(Mp4VideoDirectory.TAG_HEIGHT); height = mp4VideoDir.getInt(Mp4VideoDirectory.TAG_HEIGHT);
} }
} }
Mp4Directory mp4Dir = metadata.getFirstDirectoryOfType(Mp4Directory.class);
if (mp4Dir != null) {
if (mp4Dir.containsTag(Mp4Directory.TAG_DURATION)) {
durationMillis = mp4Dir.getLong(Mp4Directory.TAG_DURATION);
}
}
} else if (MimeTypes.AVI.equals(mimeType)) { } else if (MimeTypes.AVI.equals(mimeType)) {
AviDirectory aviDir = metadata.getFirstDirectoryOfType(AviDirectory.class); AviDirectory aviDir = metadata.getFirstDirectoryOfType(AviDirectory.class);
if (aviDir != null) { if (aviDir != null) {
@ -227,6 +238,9 @@ public class ImageEntry {
if (aviDir.containsTag(AviDirectory.TAG_HEIGHT)) { if (aviDir.containsTag(AviDirectory.TAG_HEIGHT)) {
height = aviDir.getInt(AviDirectory.TAG_HEIGHT); height = aviDir.getInt(AviDirectory.TAG_HEIGHT);
} }
if (aviDir.containsTag(AviDirectory.TAG_DURATION)) {
durationMillis = aviDir.getLong(AviDirectory.TAG_DURATION);
}
} }
} }
} catch (IOException | ImageProcessingException | MetadataException e) { } catch (IOException | ImageProcessingException | MetadataException e) {

View file

@ -86,6 +86,8 @@ public class MediaStoreImageProvider extends ImageProvider {
String orderBy = MediaStore.MediaColumns.DATE_TAKEN + " DESC"; String orderBy = MediaStore.MediaColumns.DATE_TAKEN + " DESC";
int entryCount = 0; int entryCount = 0;
final boolean needDuration = projection == VIDEO_PROJECTION;
try { try {
Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, orderBy); Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, orderBy);
if (cursor != null) { if (cursor != null) {
@ -115,6 +117,7 @@ public class MediaStoreImageProvider extends ImageProvider {
final String mimeType = cursor.getString(mimeTypeColumn); final String mimeType = cursor.getString(mimeTypeColumn);
int width = cursor.getInt(widthColumn); int width = cursor.getInt(widthColumn);
int height = cursor.getInt(heightColumn); int height = cursor.getInt(heightColumn);
long durationMillis = durationColumn != -1 ? cursor.getLong(durationColumn) : 0;
Map<String, Object> entryMap = new HashMap<String, Object>() {{ Map<String, Object> entryMap = new HashMap<String, Object>() {{
put("uri", itemUri.toString()); put("uri", itemUri.toString());
@ -126,14 +129,14 @@ public class MediaStoreImageProvider extends ImageProvider {
put("dateModifiedSecs", cursor.getLong(dateModifiedColumn)); put("dateModifiedSecs", cursor.getLong(dateModifiedColumn));
put("sourceDateTakenMillis", cursor.getLong(dateTakenColumn)); put("sourceDateTakenMillis", cursor.getLong(dateTakenColumn));
put("bucketDisplayName", cursor.getString(bucketDisplayNameColumn)); put("bucketDisplayName", cursor.getString(bucketDisplayNameColumn));
put("durationMillis", durationColumn != -1 ? cursor.getLong(durationColumn) : 0);
// only for map export // only for map export
put("contentId", contentId); put("contentId", contentId);
}}; }};
entryMap.put("width", width); entryMap.put("width", width);
entryMap.put("height", height); entryMap.put("height", height);
entryMap.put("durationMillis", durationMillis);
if ((width <= 0 || height <= 0) && !MimeTypes.SVG.equals(mimeType)) { if (((width <= 0 || height <= 0) && needSize(mimeType)) || (durationMillis == 0 && needDuration)) {
// some images are incorrectly registered in the Media Store, // some images are incorrectly registered in the Media Store,
// they are valid but miss some attributes, such as width, height, orientation // they are valid but miss some attributes, such as width, height, orientation
ImageEntry entry = new ImageEntry(entryMap).fillPreCatalogMetadata(context); ImageEntry entry = new ImageEntry(entryMap).fillPreCatalogMetadata(context);
@ -142,7 +145,7 @@ public class MediaStoreImageProvider extends ImageProvider {
height = entry.height != null ? entry.height : 0; height = entry.height != null ? entry.height : 0;
} }
if ((width <= 0 || height <= 0) && !MimeTypes.SVG.equals(mimeType)) { if ((width <= 0 || height <= 0) && needSize(mimeType)) {
// this is probably not a real image, like "/storage/emulated/0", so we skip it // this is probably not a real image, like "/storage/emulated/0", so we skip it
Log.w(LOG_TAG, "failed to get size for uri=" + itemUri + ", path=" + path + ", mimeType=" + mimeType); Log.w(LOG_TAG, "failed to get size for uri=" + itemUri + ", path=" + path + ", mimeType=" + mimeType);
} else { } else {
@ -158,6 +161,10 @@ public class MediaStoreImageProvider extends ImageProvider {
return entryCount; return entryCount;
} }
private boolean needSize(String mimeType) {
return !MimeTypes.SVG.equals(mimeType);
}
@Override @Override
public void delete(final Activity activity, final String path, final Uri uri, final ImageOpCallback callback) { public void delete(final Activity activity, final String path, final Uri uri, final ImageOpCallback callback) {
// check write access permission to SD card // check write access permission to SD card

View file

@ -155,7 +155,12 @@ class ImageEntry {
return d == null ? null : DateTime(d.year, d.month, d.day); return d == null ? null : DateTime(d.year, d.month, d.day);
} }
String get durationText => formatDuration(Duration(milliseconds: durationMillis)); String _durationText;
String get durationText {
_durationText ??= formatDuration(Duration(milliseconds: durationMillis));
return _durationText;
}
bool get hasGps => isCatalogued && _catalogMetadata.latitude != null; bool get hasGps => isCatalogued && _catalogMetadata.latitude != null;