本文主要是介绍Android获取多个在线视频的略缩图,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章参考:
- (1)、http://stackoverflow.com/questions/13743223/it-is-possible-to-display-a-video-thumbnail-from-a-url-on-android-4-and-above
- (2)、http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html
- 开源工具参考:
https://github.com/wseemann/FFmpegMediaMetadataRetriever
1、熟悉加载视频略缩图的工具
用android自带的方法无法加载在线视频的略缩图,就像参考的第一个网址里面提的问题一样,用这条语句来实现,ThumbnailUtils.extractThumbnail(ThumbnailUtils.createVideoThumbnail(objectURL[0], Thumbnails.MINI_KIND), 100, 100);但是不成功。后面有人回复说:Use FFmpegMediaMetadataRetriever to extract a thumbnail at the desired position: www.github.com/wseemann/FFmpegMediaMetadataRetriever。自此知道可以使用这个开源工具来加载在线视频略缩图(其实来自于FFmpeg)。
下载这个网站提供的包(https://github.com/wseemann/FFmpegMediaMetadataRetriever/blob/master/fmmr-library/prebuilt-libs.tar.gz),解压后发现有一个“fmmr-demo”的文件夹,这个就是官方的demo,此时将其libs文件夹下的fmmr.jar和armeabi文件夹复制到自己android工程的libs目录下就行了,其余平台下的so库视具体情况添加。
- 更新(2019/4/17):这个下载链接已经无法打开,请在github下载:
https://github.com/cg229836277/RelativesChat/tree/master/RelativesChat/libs
将这个“fmmr-demo”下的android工程导入eclipse下看一下他的代码是如何实现加载视频的略缩图的,其实现代码如下:
FFmpegMediaMetadataRetriever fmmr = new FFmpegMediaMetadataRetriever();
try {fmmr.setDataSource(mUri);for (int i = 0; i < Constants.METADATA_KEYS.length; i++) {String key = Constants.METADATA_KEYS[i];String value = fmmr.extractMetadata(key);if (value != null) {metadata.add(new Metadata(key, value));Log.i(MetadataLoader.class.getName(), "Key: " + key + " Value: " + value);}}Bitmap b = fmmr.getFrameAtTime();if (b != null) {Bitmap b2 = fmmr.getFrameAtTime(4000000,FFmpegMediaMetadataRetriever.OPTION_CLOSEST_SYNC);if (b2 != null) {b = b2;}}
} catch(Exception e){
}
中间有些代码不用去看,只需要关心三行代码并且在源码FFmpegMediaMetadataRetriever.java中有详细解释:
- fmmr.setDataSource(mUri);
设置视频的来源,在其他的方法之前调用,并且这个方法可能耗时。 - Bitmap b = fmmr.getFrameAtTime();
这个方法在setDataSource后面调用,并且这个方法获取任意一帧的图像,并且返回bitmap,对于获取略缩图所在的时间点没有限制的话,这个方法是有用的,否则调用其他带参数的方法。 - Bitmap b2 = fmmr.getFrameAtTime(4000000,FFmpegMediaMetadataRetriever.OPTION_CLOSEST_SYNC)
函数在源码中的原型是public Bitmap getFrameAtTime(long timeUs, int option),解释如下:在setDataSource()后面调用这个方法,在尽可能考虑给予的条件限制下找到靠近时间点的一帧图像并返回Bitmap,这个方法用来生成视频资源的略缩图或者用来获取和展示某个时间的一帧图像。timeUs
这个时间点的帧将会被获取到,但是不能保证视频资源在这个时间的位置有一帧图像,如果没有,那么这个时间点附近的一帧图像将会被返回。如果这个参数为负数,那么这个函数中的两个参数的中将会被忽略,并且返回任意一帧的图像。option
获取帧图像的方式:
OPTION_PREVIOUS_SYNC,在给予的时间戳之前获取同步帧
OPTION_NEXT_SYNC,在给予的时间戳之后获取同步帧
OPTION_CLOSEST_SYNC,在给予的时间戳附近
OPTION_CLOSEST,可能返回一个同步或者不同步的帧,但是是在这个时间戳附近,并且对于系统性能的开销 比较大
至此,这些关键的方法知道怎么用了,注意在加载完了之后,要释放fmmr对象,即fmmr.release()。
2、加载单个在线视频的略缩图
熟悉了上面的方法之后,现在就要写加载视频略缩图的方法了,代码如下:
public Bitmap getVideoThumbnail(String videoUrl){Bitmap generateBitmap = null;FFmpegMediaMetadataRetriever fmmr = new FFmpegMediaMetadataRetriever();try {fmmr.setDataSource(videoUrl);generateBitmap = fmmr.getFrameAtTime();if (generateBitmap != null) {Bitmap b2 = fmmr.getFrameAtTime(4000000,FFmpegMediaMetadataRetriever.OPTION_CLOS EST_SYNC);if (b2 != null) {//获取到了Bitmap之后用android自带的ThumbnailUtils获取自定义大小的略缩图generateBitmap = ThumbnailUtils.extractThumbnail(b2,640, 640,ThumbnailUtils.OPTIONS_RECYCLE_INPUT);}}} catch (IllegalArgumentException ex) {ex.printStackTrace();} finally {fmmr.release();}if(generateBitmap != null){return generateBitmap;}return null;
}
将这个方法封装到自己的工具类中就可以加载单个在线视频的略缩图了。
3、加载多个视频的略缩图
对于项目需要从服务器上面获取多个视频的略缩图,并且这些略缩图是放在ListView里面展示,问题来了,ListView显示多张图片在滑动的时候容易发生显示错乱,以及OOM,针对这个问题参考了google大神的博客,并且是android的官方博客(http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html),里面详细的分析了各个方法的使用,并且有完整源码可供下载,并且对于加载Bitmap的各种问题,参考了android官方文档,即android Training下的文章(http://developer.android.com/training/displaying-bitmaps/index.html)。
现在将博客中的方法整合成自己的工具类用来加载多个在线视频的略缩图,在原来的方法中修改了三个方法:
/**
* @author Chuck Chan
* @date 2014-10-28 下午4:48:56
* @param url 要加载资源的地址
* @param imageView 显示略缩图的ImageView控件
*/
public void loadVideoBitmap(String url, ImageView imageView) {//缓存中的BitmapBitmap bitmap = getBitmapFromCache(url);//缓存中不存在就从网络上获取资源if (bitmap == null) {forceDownload(url, imageView);} else {imageView.setVisibility(View.VISIBLE);cancelPotentialDownload(url, imageView); //imageView.setTag(bitmap);imageView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap, 72,72));}
}
/**
* @author Chuck Chan
* @date 2014-10-28 下午4:53:49
* @param url 资源地址
* @param imageView 加载略缩图的ImageView控件
*/
private void forceDownload(String url, ImageView imageView) {// State sanity: url is guaranteed to never be null in DownloadedDrawable and cache keys.if (url == null) {imageView.setImageDrawable(null);return;}//判断是否需要下载if (cancelPotentialDownload(url, imageView)) {imageView.setVisibility(View.VISIBLE);BitmapWorkerTask task = new BitmapWorkerTask(imageView);Bitmap defaultBimap = BitmapFactory.decodeStream(mContext.getResources().openRawResource(R.drawable.user_icon_default));AsyncDrawable downloadedDrawable = new AsyncDrawable(mContext.getResources() , defaultBimap , task);imageView.setImageDrawable(downloadedDrawable);imageView.setMinimumHeight(72);task.execute(url);}
}
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {private final WeakReference<ImageView> imageViewReference;private String url;public BitmapWorkerTask(ImageView imageView) {// Use a WeakReference to ensure the ImageView can be garbage collectedimageViewReference = new WeakReference<ImageView>(imageView);}@Overrideprotected Bitmap doInBackground(String... params) {url = params[0];//获取在线视频的帧的图像,返回BitmapBitmap tempBitmap = getVideoThumbnail(url);return tempBitmap;}@Overrideprotected void onPostExecute(Bitmap bitmap) {if (isCancelled()) {bitmap = null;}addBitmapToCache(url, bitmap);if (imageViewReference != null && bitmap != null) {final ImageView imageView = imageViewReference.get();final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);//判断当前的异步对象是否与ImageView所在的异步对象是否相等,以此来防止加载错乱if (this == bitmapWorkerTask && imageView != null) { // imageView.setTag(bitmap);imageView.setImageBitmap(ThumbnailUtils.extractThumbnail(bitmap, 72,72));}}}
}
将google博客中的方法结合自己修改的方法封装到工具类中,方便以后复用。
这篇关于Android获取多个在线视频的略缩图的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!