Glide - load single frame from video at specific time?

jgads picture jgads · Jun 10, 2015 · Viewed 19.2k times · Source

I'm trying to use Glide to step through frames in a video file (without running into the keyframe seeking issue that Android suffers from). I can do this in Picasso by doing something like:

picasso = new Picasso.Builder(MainActivity.this).addRequestHandler(new PicassoVideoFrameRequestHandler()).build();
picasso.load("videoframe://" + Environment.getExternalStorageDirectory().toString() +
                    "/source.mp4#" + frameNumber)
                    .placeholder(drawable)
                    .memoryPolicy(MemoryPolicy.NO_CACHE)
                    .into(imageView);

(frameNumber is simply an int which increases by 50000 microseconds each time). I also have a PicassoVideoFrameRequestHandler like this:

public class PicassoVideoFrameRequestHandler extends RequestHandler {
public static final String SCHEME = "videoframe";

@Override public boolean canHandleRequest(Request data) {
    return SCHEME.equals(data.uri.getScheme());
}

@Override
public Result load(Request data, int networkPolicy) throws IOException {
    FFmpegMediaMetadataRetriever mediaMetadataRetriever = new FFmpegMediaMetadataRetriever();
    mediaMetadataRetriever.setDataSource(data.uri.getPath());
    String offsetString = data.uri.getFragment();
    long offset = Long.parseLong(offsetString);
    Bitmap bitmap = mediaMetadataRetriever.getFrameAtTime(offset, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
    return new Result(bitmap, Picasso.LoadedFrom.DISK);
}

}

I'd like to use Glide instead, as it handles memory a little better. Is there any way to have this functionality in Glide?

Or, really, any other way to create a set of frames from a video which I can step through!

Thanks!

Answer

Eftekhari picture Eftekhari · Jan 8, 2016

You'll need to pass ".override(width, height)" to make Sam Judd's method to work. Otherwise you'll get only the first frame of the video as I've tested variety of approaches for hours. Hope it saves time for someone.

BitmapPool bitmapPool = Glide.get(getApplicationContext()).getBitmapPool();
int microSecond = 6000000;// 6th second as an example
VideoBitmapDecoder videoBitmapDecoder = new VideoBitmapDecoder(microSecond);
FileDescriptorBitmapDecoder fileDescriptorBitmapDecoder = new FileDescriptorBitmapDecoder(videoBitmapDecoder, bitmapPool, DecodeFormat.PREFER_ARGB_8888);
Glide.with(getApplicationContext())
    .load(yourUri)
    .asBitmap()
    .override(50,50)// Example
    .videoDecoder(fileDescriptorBitmapDecoder)
    .into(yourImageView);