#115 changed video thumbnail strategy

This commit is contained in:
Thibault Deckers 2021-11-08 17:23:35 +09:00
parent 2d8d49a282
commit d43a6f1865
2 changed files with 26 additions and 14 deletions

View file

@ -3,7 +3,6 @@ package deckers.thibault.aves.decoder
import android.content.Context import android.content.Context
import android.media.MediaMetadataRetriever import android.media.MediaMetadataRetriever
import android.net.Uri import android.net.Uri
import android.os.Build
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.Priority import com.bumptech.glide.Priority
import com.bumptech.glide.Registry import com.bumptech.glide.Registry
@ -58,16 +57,13 @@ internal class VideoThumbnailFetcher(private val model: VideoThumbnail) : DataFe
try { try {
var bytes = retriever.embeddedPicture var bytes = retriever.embeddedPicture
if (bytes == null) { if (bytes == null) {
// try to match the thumbnails returned by the content resolver / Media Store // there is no consistent strategy across devices to match
// the following strategies are from empirical evidence from a few test devices: // the thumbnails returned by the content resolver / Media Store
// - API 29: sync frame closest to the middle // so we derive one in an arbitrary way
// - API 26/27: default representative frame at any time position
var timeMillis: Long? = null var timeMillis: Long? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val durationMillis = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLongOrNull()
val durationMillis = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLongOrNull() if (durationMillis != null) {
if (durationMillis != null) { timeMillis = if (durationMillis < 15000) 0 else 15000
timeMillis = durationMillis / 2
}
} }
val frame = if (timeMillis != null) { val frame = if (timeMillis != null) {
retriever.getFrameAtTime(timeMillis * 1000) retriever.getFrameAtTime(timeMillis * 1000)

View file

@ -94,18 +94,34 @@ class _ThumbnailImageState extends State<ThumbnailImage> {
_lastException = null; _lastException = null;
_providers.clear(); _providers.clear();
final highQuality = entry.getThumbnail(extent: extent);
ThumbnailProvider? lowQuality;
if (widget.progressive && !entry.isSvg) {
if (entry.isVideo) {
// previously fetched thumbnail
final cached = entry.bestCachedThumbnail;
final lowQualityExtent = cached.key.extent;
if (lowQualityExtent > 0 && lowQualityExtent != extent) {
lowQuality = cached;
}
} else {
// default platform thumbnail
lowQuality = entry.getThumbnail();
}
}
_providers.addAll([ _providers.addAll([
if (widget.progressive && !entry.isSvg) if (lowQuality != null)
_ConditionalImageProvider( _ConditionalImageProvider(
ScrollAwareImageProvider( ScrollAwareImageProvider(
context: _scrollAwareContext, context: _scrollAwareContext,
imageProvider: entry.getThumbnail(), imageProvider: lowQuality,
), ),
), ),
_ConditionalImageProvider( _ConditionalImageProvider(
ScrollAwareImageProvider( ScrollAwareImageProvider(
context: _scrollAwareContext, context: _scrollAwareContext,
imageProvider: entry.getThumbnail(extent: extent), imageProvider: highQuality,
), ),
_needSizedProvider, _needSizedProvider,
), ),
@ -233,7 +249,7 @@ class _ThumbnailImageState extends State<ThumbnailImage> {
if (animate && widget.heroTag != null) { if (animate && widget.heroTag != null) {
final background = settings.imageBackground; final background = settings.imageBackground;
final backgroundColor = background.isColor? background.color : null; final backgroundColor = background.isColor ? background.color : null;
image = Hero( image = Hero(
tag: widget.heroTag!, tag: widget.heroTag!,
flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) { flightShuttleBuilder: (flight, animation, direction, fromHero, toHero) {