Glide - 在特定时间从视频加载单帧?
Glide - load single frame from video at specific time?
我正在尝试使用 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 只是一个整数,每次增加 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 中实现这个功能吗?
或者,实际上,我可以通过任何其他方式从视频创建一组帧!
谢谢!
您可以传入一个帧时间(以微秒为单位,参见 MediaMetadataRetriever docs) to 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);
您需要传递“.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);
谢谢,这个 Post 帮助我到达那里。顺便说一句,如果您使用的是 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" 它是您想要图像的视频位置的长变量。
我正在尝试使用 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 只是一个整数,每次增加 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 中实现这个功能吗?
或者,实际上,我可以通过任何其他方式从视频创建一组帧!
谢谢!
您可以传入一个帧时间(以微秒为单位,参见 MediaMetadataRetriever docs) to 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);
您需要传递“.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);
谢谢,这个 Post 帮助我到达那里。顺便说一句,如果您使用的是 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" 它是您想要图像的视频位置的长变量。