前言
项目中有时候需要获取视频封面(缩略图,类似于图片列表),并展示给用户观看。
下面是整理一下自己测试用的。
总结
目前我知道的就有如下两种方式,但对我来说不是太理想,不知道是否还有其他的更有效的方式获取视频封面,如果有知道的请留言,谢谢。
- 使用ThumbnailUtils的createVideoThumbnail 这种方式获取存在一定的缺陷,因为很多前面都是黑色的。
- 使用MediaMetadataRetriever可以指定某个时间点获取对应的图像帧,这个可以减少获取不到概率。
正文
使用ThumbnailUtils
/**
* 获取视频第一帧
*
* @param path
* @return
*/
public Bitmap getVideoThumbnail(String path) {
if (TextUtils.isEmpty(path)) {
return null;
}
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(path, MediaStore.Video.Thumbnails.MINI_KIND);
return bitmap;
}
除了Thumbnails.MINI_KIND,还有Thumbnails.FULL_SCREEN_KIND 和Thumbnails.MICRO_KIND。
- MINI_KIND 宽是512,但高没有固定的缩略图
- FULL_SCREEN_KIND 完整大小的图片
- MICRO_KIND 96 *96的缩略图
由于现实的高宽可以固定,同时我们不需要512或者固定高宽,因此需要做一定的转换。
//对获取的图进行一定的转换
if (null != bitmap) {
bitmap = ThumbnailUtils.extractThumbnail(bitmap, DEFAULT_WIDTH_125, DEFAULT_HEIGHT_100, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
}
小结一下:
这种方大多数图片是可以解析出来的,但总有一部分无法提取封面,导致用户不满意。
使用MediaMetadataRetriever
由于通过上面方式,不能有效获取封面(反正客户不接受),因此改为使用getFrameAtTime()通过指定时间获取对应的一帧。
getFrameAtTime()方法具体参数如下:
public Bitmap getFrameAtTime(long timeUs, int option)
- 第一个参数 :
是传入截取时间,只能是us(微秒)
- 第二个参数
OPTION_CLOSEST
在给定的时间,检索最近一个帧,这个帧不一定是关键帧。
OPTION_CLOSEST_SYNC
在给定的时间,检索最近一个同步与数据源相关联的的帧(关键帧)。
OPTION_NEXT_SYNC
在给定时间之后检索一个同步与数据源相关联的关键帧。
OPTION_PREVIOUS_SYNC
在给定时间之前检索一个同步与数据源相关的关键帧
这里为了提取我们想要的帧,不使用关键帧,所以用 OPTION_CLOSEST
/**
* 获取缩略图,从第四秒获取,可以获取大多数的帧
* 缺点:低效率和耗时
* @param path
* @return
*/
public Bitmap getVideoThumbnail2(String path) {
if (TextUtils.isEmpty(path)) {
return null;
}
MediaMetadataRetriever mMediaMetadataRetriever = new MediaMetadataRetriever();
try {
if (null != mMediaMetadataRetriever) {
Bitmap thumbTempBitmap = null;
mMediaMetadataRetriever.setDataSource(path);
//跳过前面7秒,这种做法是规律大部分视频前面几秒没有图像的帧,但缺点就是效率低和耗时
for (int i = 8; i < 10; i++) {
thumbTempBitmap = mMediaMetadataRetriever.getFrameAtTime(i * 1000 * 1000, MediaMetadataRetriever.OPTION_CLOSEST);
if (null != thumbTempBitmap) {
break;
}
}
if (null != thumbTempBitmap) {
return thumbTempBitmap;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != mMediaMetadataRetriever) {
mMediaMetadataRetriever.release();
}
}
return null;
}
小结一下
使用这种方式,可以满足客户,但缺点也比较明显:效率低和耗时。
