Android获取本地视频文件的截图
发布日期:2021-10-20 03:26:56 浏览次数:7 分类:技术文章

本文共 6879 字,大约阅读时间需要 22 分钟。

531570-eac4c042ab9aeef6.png
插图.png

上次在中我们讲了AsyncTask的基础,这次来再结合新的功能来巩固一下知识点.

阅读本文你需要掌握AsyncTask的基本用法,如果不懂AsyncTask,推荐阅读.

通过阅读本文你将能够学到:

  1. 如何创建本地视频缩略图
  2. 如何AsyncTask使用自带线程池
  3. 如何使用回调
  4. 如何防止ListView加载多张图片造成位置混乱
  5. 如何使用内存/磁盘缓存

由于功能需求要获取本地视频文件的截图,用于显示,而我们所用的图片加载工具为ImageLoader,很不巧,UIL不支持该需求,所以需要我们自己写了.

So,动手开始写吧:

1. 获取本地视频截图

在尝试过许多方法之后,我最终使用了ThumbnailUtils这个类,使用ThumbnailUtils来获取视频的缩略图比较简单,它有个方法可以用来创建视频的缩略图:

/*** Create a video thumbnail for a video. May return null if the video is* corrupt or the format is not supported.** @param filePath the path of video file   文件路径* @param kind could be MINI_KIND or MICRO_KIND   种类,该参数决定了获取到的图片的大小 MINI_KIND:512 x 384 ,MICRO_KIND:96 x 96*/public static Bitmap createVideoThumbnail(String filePath, int kind)

有了这个方法就好办了,我们封装一个方法用于获取:

/**     * @param videoPath 视频路径     * @param width       图片宽度     * @param height      图片高度     * @param kind      eg:MediaStore.Video.Thumbnails.MICRO_KIND   MINI_KIND: 512 x 384,MICRO_KIND: 96 x 96     * @return     */private Bitmap getVideoThumbnail(String videoPath, int width, int height,int kind) {        // 获取视频的缩略图        Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, kind);       //extractThumbnail 方法二次处理,以指定的大小提取居中的图片,获取最终我们想要的图片        bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);        return bitmap;    }

2.自定义VideoThumbnailLoader

方法我们写完了,但是实际运用时候,发现非常的卡,因为创建bitmap耗时非常严重,达到上百毫秒,按16毫秒1帧算,加载一个缩略图就要卡上好几帧!!卡爆了!!

相信机智的你早已经想到,下一步我们需要把创建缩略图的处理放在异步线程中去.

另外我们需要考虑一个问题,我们不停地去加载,会发现,同一个视频我们加载了好几次缩略图,这个时候怎么办?

这个时候就需要引入缓存了,使用过UIL等图片加载工具的同学应该知道了一级缓存(内存缓存),二级缓存(文件/磁盘缓存)这些概念.

刚好,我们项目中使用了UIL,所以为了进一步提高加载效率,我顺带加了缓存.写了一个单例VideoThumbnailLoader类,来负责加载.

那么问题又来了,我用的单例,那么多图片在加载,我怎么通知界面我加载完成了呢?

这个时候回调就派上大用场了,在VideoThumbnailLoader中我增加了一个回调,通过回调方式告诉外部,我加载完成了,你可以显示了:

//自己定义一个回调,通知外部图片加载完毕public interface ThumbnailListener{    void onThumbnailLoadCompleted(String url,ImageView iv,Bitmap bitmap);}

好了,思考完毕,准备完毕,上代码!~

最终代码如下:

public class VideoThumbnailLoader {    private static final String TAG = "VideoThumbnailLoader";    private MemoryCache mMCache;//一级缓存,内存缓存    private static VideoThumbnailLoader ins = new VideoThumbnailLoader();    public static VideoThumbnailLoader getIns(){        return ins;    }    private VideoThumbnailLoader() {        mMCache = ImageLoader.getInstance().getMemoryCache();    }    public void display(TLLiveEntity mEntity,String url,ImageView iv,int width,int height,ThumbnailListener thumbnailListener){        new ThumbnailLoadTask(mEntity,url,iv,width,height,thumbnailListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);//使用AsyncTask自带的线程池    }    private class ThumbnailLoadTask extends AsyncTask
{ private String url; private ImageView iv; private ThumbnailListener thumbnailListener; private int width; private int height; public ThumbnailLoadTask(String url,ImageView iv,int width,int height,ThumbnailListener thumbnailListener){ this.url = url; this.iv = iv; this.width = width; this.height = height; this.thumbnailListener = thumbnailListener; } @Override protected Bitmap doInBackground(Void... params) { /** * 注意,由于我们使用了缓存,所以在加载缩略图之前,我们需要去缓存里读取,如果缓存里有,我们则直接获取,如果没有,则去加载.并且加载完成之后记得放入缓存. */ Bitmap bitmap = null; if (!TextUtils.isEmpty(url)) { String key = getMemoryKey(url); bitmap = mMCache.get(key);//先去内存缓存取 if (bitmap == null||bitmap.isRecycled()) { File file = TLFileUtils.getExternalFile(path, "xxx.png");//创建文件,这里由于项目原因,我就随便写一个,实际情况不是这样,大家留意一下 if (null != file && file.exists()) {//去磁盘缓存取 bitmap = BitmapFactory.decodeFile(file.getPath()); if (null==bitmap) { bitmap = getVideoThumbnail(url, width, height, MediaStore.Video.Thumbnails.MICRO_KIND); //将图片保存到磁盘文件,作为缓存 BitmapUtils.saveBitmapToFile(file, bitmap,Bitmap.CompressFormat.PNG); } } else { bitmap = getVideoThumbnail(url, width, height, MediaStore.Video.Thumbnails.MICRO_KIND); if (null==bitmap) { bitmap = getVideoThumbnail(url, width, height, MediaStore.Video.Thumbnails.MICRO_KIND); //将图片保存到磁盘文件,作为缓存 BitmapUtils.saveBitmapToFile(file, bitmap,Bitmap.CompressFormat.PNG); } } if (null != bitmap) { mMCache.put(key, bitmap);//存入内存缓存 } } } return bitmap; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); thumbnailListener.onThumbnailLoadCompleted(url, iv, bitmap);//回调 } } /** * @param videoPath 视频路径 * @param width * @param height * @param kind eg:MediaStore.Video.Thumbnails.MICRO_KIND MINI_KIND: 512 x 384,MICRO_KIND: 96 x 96 * @return */ private Bitmap getVideoThumbnail(String videoPath, int width, int height, int kind) { // 获取视频的缩略图 Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, kind); bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT); return bitmap; } /** * imageloader 的内存缓存的 key 以_ 结尾 截取key比较的时候如果没有加_ 会报错崩溃,所以自己自定义 * @param filePath 文件地址 * @return */ private String getMemoryKey(String filePath) { String key ; int index = filePath.lastIndexOf("/"); key = filePath.substring(index + 1, filePath.length())+"_"; return key; } //自己定义一个回调,通知外部图片加载完毕 public interface ThumbnailListener{ void onThumbnailLoadCompleted(String url,ImageView iv,Bitmap bitmap); }}

在需要加载的地方使用:

mHolder.ivBg.setTag(imgUrl);  //这里注意,我们给imageview设置了一个Tag,后面自有妙用VideoThumbnailLoader.getIns().display(entity,url, mHolder.ivBg,mImgWidth,mImgHeight, new VideoThumbnailLoader.ThumbnailListener() {            @Override            public void onThumbnailLoadCompleted(String url, ImageView iv, Bitmap bitmap) {                //通过判断imageview的tag,和我们加载的图片的url是否是同一个来判断是否显示,这样可以避免滑动造成的位置错乱等问题.                String tag = (String) iv.getTag();                if (null != bitmap&&null!=tag&&tag.equals(url)) {                    iv.setImageBitmap(bitmap);                }else{                    iv.setImageResource(R.mipmap.defaultvideo);                }            }        });

至此功能已经实现,并且使用了线程池,缓存,效率比一开始提高不少,不过还是有地方可以优化,至于优化,后面有机会再写吧~

好了,本文结束,如果有疑问,欢迎提问,如果喜欢,欢迎点赞,欢迎关注我,关注我的专题~~

谢谢,下次见!

与我联系,交个朋友

打个广告:新建了一个qq群用于简书用户交流,进群请报简书地址:

531570-54cc222304e8d0e1.jpg
qq群

转载地址:https://blog.csdn.net/u014400934/article/details/103160966 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:在代码中修改Shape的solid属性的color值
下一篇:一步一步教你实现Periscope点赞效果

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年02月28日 11时06分33秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

技校毕业是什么学历_中等职业学校是什么_中等职业学校毕业是什么学历 2019-04-21
2压缩备份数据库_MySQL数据备份与恢复(二) xtrabackup工具 2019-04-21
英特尔cpu发布时间表_被嘲讽的英特尔核显,强大能力其实超乎你的想象 2019-04-21
chi2inv函数 matlab_MATLAB概率和统计(2) 2019-04-21
lisp修改上一个图素_在Windows上安装Haskell 2019-04-21
ad19 导出step 没有pcb_几款主流PCB软件哪个最好用,你用过几款? 2019-04-21
json mysql 字段 默认值_Newtonsoft.Json 六个超简单又实用的特性,值得一试 【上篇】... 2019-04-21
ocdma相干非相干_《Acconeer 60GHz脉冲相干雷达芯片:A111》 2019-04-21
修改表格字体颜色_Excel技巧:Excel如何修改字体颜色 2019-04-21
native react 变颜色 点击_React Native主动更改StackNavigator标头颜色 2019-04-21
prism项目搭建 wpf_WPF MVVM使用prism4.1搭建 2019-04-21
python发微信红包群_用Python实现微信自动化抢红包,再也不用担心抢不到红包了... 2019-04-21
python中func自定义函数_Python函数之自定义函数&作用域&闭包 2019-04-21
wget连接指定端口_端口通不通 telnet wget ssh 2019-04-21
eureka 调用服务_Spring Cloud微服务架构从入门到会用(二)—服务注册中心Eureka... 2019-04-21
easyexcel 工具类_问了个在阿里的同学,他们常用的15款开发者工具! 2019-04-21
mysql统计结果大于0时返回true_mysql表查询练习 2019-04-21
c语言对结构体排序中间变量,求助:c语言怎么实现结构体的排序? 总是弄不对啊... 2019-04-21
c语言宏定义只能在最前面吗,C语言宏定义注意事项 2019-04-21
android悬浮窗服务卡死,Android 悬浮窗兼容问题谈 2019-04-21