video: sized thumbnails match content resolver ones
This commit is contained in:
parent
c252ce7828
commit
bb08f3dcb6
3 changed files with 29 additions and 7 deletions
|
@ -1,7 +1,9 @@
|
|||
package deckers.thibault.aves.decoder
|
||||
|
||||
import android.content.Context
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.Priority
|
||||
import com.bumptech.glide.Registry
|
||||
|
@ -48,9 +50,29 @@ internal class VideoThumbnailFetcher(private val model: VideoThumbnail) : DataFe
|
|||
val retriever = openMetadataRetriever(model.context, model.uri)
|
||||
if (retriever != null) {
|
||||
try {
|
||||
val picture = retriever.embeddedPicture ?: retriever.frameAtTime?.getBytes(canHaveAlpha = false, recycle = false)
|
||||
if (picture != null) {
|
||||
callback.onDataReady(ByteArrayInputStream(picture))
|
||||
var bytes = retriever.embeddedPicture
|
||||
if (bytes == null) {
|
||||
// try to match the thumbnails returned by the content resolver / Media Store
|
||||
// the following strategies are from empirical evidence from a few test devices:
|
||||
// - API 29: sync frame closest to the middle
|
||||
// - API 26/27: default representative frame at any time position
|
||||
var timeMillis: Long? = null
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val durationMillis = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLongOrNull()
|
||||
if (durationMillis != null) {
|
||||
timeMillis = durationMillis / 2
|
||||
}
|
||||
}
|
||||
val frame = if (timeMillis != null) {
|
||||
retriever.getFrameAtTime(timeMillis * 1000)
|
||||
} else {
|
||||
retriever.frameAtTime
|
||||
}
|
||||
bytes = frame?.getBytes(canHaveAlpha = false, recycle = false)
|
||||
}
|
||||
|
||||
if (bytes != null) {
|
||||
callback.onDataReady(ByteArrayInputStream(bytes))
|
||||
} else {
|
||||
callback.onLoadFailed(Exception("failed to get embedded picture or any frame"))
|
||||
}
|
||||
|
|
|
@ -70,10 +70,8 @@ class _RasterImageThumbnailState extends State<RasterImageThumbnail> {
|
|||
if (!entry.canDecode) return;
|
||||
|
||||
_fastThumbnailProvider = entry.getThumbnail();
|
||||
if (!entry.isVideo) {
|
||||
_sizedThumbnailProvider = entry.getThumbnail(extent: extent);
|
||||
}
|
||||
}
|
||||
|
||||
void _pauseProvider() {
|
||||
final isScrolling = widget.isScrollingNotifier?.value ?? false;
|
||||
|
|
|
@ -3,6 +3,8 @@ import 'dart:ui';
|
|||
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/entry_images.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/widgets/collection/collection_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
|
||||
|
||||
|
@ -98,7 +100,7 @@ class _VideoViewState extends State<VideoView> {
|
|||
backgroundColor: Colors.transparent,
|
||||
)
|
||||
: Image(
|
||||
image: entry.getBestThumbnail(entry.displaySize.longestSide),
|
||||
image: entry.getBestThumbnail(settings.getTileExtent(CollectionPage.routeName)),
|
||||
fit: BoxFit.contain,
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue