Подтвердить что ты не робот

Скольжение - загрузка одного кадра из видео в определенное время?

Я пытаюсь использовать Glide для перехода через кадры в видеофайл (без использования ключевого кадра, ищущего проблему, от которой страдает Android). Я могу сделать это в Picasso, делая что-то вроде:

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 - это просто int, который увеличивается на 50000 микросекунд каждый раз). У меня также есть PicassoVideoFrameRequestHandler:

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);
}

}

Вместо этого я хотел бы использовать Glide, поскольку он немного исправляет память. Есть ли способ иметь эту функциональность в Glide?

Или, действительно, любой другой способ создать набор кадров из видео, которое я могу выполнить!

Спасибо!

4b9b3361

Ответ 1

Вам нужно передать ".override(width, height)", чтобы заставить работать метод Sam Judd. В противном случае вы получите только первый кадр видео, поскольку я тестировал множество подходов в течение нескольких часов. Надеюсь, это сэкономит время для кого-то.

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);

Ответ 2

Вы можете передать время кадра (в микросекундах, см. Документы MediaMetadataRetriever) в VideoBitmapDecoder. Это не проверено, но оно должно работать:

BitmapPool bitmapPool = Glide.get(context).getBitmapPool();
FileDescriptorBitmapDecoder decoder = new FileDescriptorBitmapDecoder(
    new VideoBitmapDecoder(frameTimeMicros),
    bitmapPool,
    DecodeFormat.PREFER_ARGB_8888);

Glide.with(fragment)
    .load(uri)
    .asBitmap()
    .videoDecoder(decoder)
    .into(imageView);

Ответ 3

Спасибо, этот пост поможет мне туда добраться. Btw, если вы используете Glide 4.4, они меняют способ получения этого результата. Чтобы загрузить определенный кадр из видео uri.

Вам просто нужно использовать объект RequestOptions следующим образом:

long interval = positionInMillis * 1000;
RequestOptions options = new RequestOptions().frame(interval);
Glide.with(context).asBitmap()
                    .load(videoUri)
                    .apply(options)
                    .into(viewHolder.imgPreview);

Где "positionInMillis" - это длинная переменная из положения видео, которое требуется для изображения.