Android视频缩略图(二)
Android视频缩略图(二)
上篇文章Android视频图片缩略图的获取,我们使用ThumbnailUtils工具类进行图片和视频的缩略图获取,我们提到了
- android.provider.MediaStore.Images.Thumbnails
- android.provider.MediaStore.Video.Thumbnails
- MediaMetadataRetriever
这三个玩意,但是没具体说,只是在ThumbnailUtils的源码中见到了他们的影子。其实,深入了解的原因来源于:项目中,我们拍摄的照片和视频上传后,那么我们再次获取视频的时候,视频是在服务器,我们不可能将视频下载下来,然后仅仅为了获取一个缩略图使用的,这样岂不是很坑。所以就需要深入的学习下如何获取视频缩略图。
上篇文章中,我们在分析ThumbnailUtils.createVideoThumbnail方法的源码时,见到该方法的内部使用MediaMetadataRetriever对象进行视频缩略图的获取,好吧!终于发现,原来是MediaMetadataRetriever我们真正获取视频缩略图的处理类。下面让我们一起来看看MediaMetadataRetriever的真面目吧!
MediaMetadataRetriever
1、包路径:android.media.MediaMetadataRetriever
2、方法集合:
通过研究ThumbnailUtils.createVideoThumbnail源码中MediaMetadataRetriever的使用方法,我们可以依葫芦画瓢来使用MediaMetadataRetriever的用法。
简要介绍下核心方法:
1、setDataSource()
设置数据源的方法,设置数据源绝对路径,可以为本地路径也可以为网络url地址。但是要注意,我们要判断api的版本,因为setDataSource()方法在不同api版本中不同,所以在使用前应使用android.os.Build.VERSION.SDK_INT获取当前SDK版本。
MediaMetadataRetriever media = new MediaMetadataRetriever(); if(SDKVersion >= 14){//根据不同的api等级进行调用方法 media.setDataSource(info.srcPath,new HashMap<String, String>()); }else{ media.setDataSource(info.srcPath); } info.bitmap = media.getFrameAtTime();
2、getFrameAtTime()
该方法就是用于获取我们的缩略图,我们可以获取指定时间的缩略图。注意可能返回为null,所以需要我们在使用时进行判断。
3、release()方法
使用后,进行释放。
简要看下源码:
1、setDataSource()方法
/** * Sets the data source (file pathname) to use. Call this * method before the rest of the methods in this class. This method may be * time-consuming. * * @param path The path of the input media file. * @throws IllegalArgumentException If the path is invalid. */ public void setDataSource(String path) throws IllegalArgumentException { FileInputStream is = null; try { is = new FileInputStream(path); FileDescriptor fd = is.getFD(); setDataSource(fd, 0, 0x7ffffffffffffffL); } catch (FileNotFoundException fileEx) { throw new IllegalArgumentException(); } catch (IOException ioEx) { throw new IllegalArgumentException(); } try { if (is != null) { is.close(); } } catch (Exception e) {} }
源码中首先根据路径创建一个文件流,然后调用 setDataSource(FileDescriptor fd, long offset, long length)方法。我们看下这个方法的源码:
public native void setDataSource(FileDescriptor fd, long offset, long length) throws IllegalArgumentException;
发现这个方法是个native方法,关于native的介绍,大家可以google。同样对于别的几个setDataSource方法,底部也是调用固定的native方法去执行。
(2)、getFrameAtTime
源码:
/** * Call this method after setDataSource(). This method finds a * representative frame at any time position if possible, * and returns it as a bitmap. This is useful for generating a thumbnail * for an input data source. Call this method if one does not * care about where the frame is located; otherwise, please call * {@link #getFrameAtTime(long)} or {@link #getFrameAtTime(long, int)} * * @return A Bitmap containing a representative video frame, which * can be null, if such a frame cannot be retrieved. * * @see #getFrameAtTime(long) * @see #getFrameAtTime(long, int) */ public Bitmap getFrameAtTime() { return getFrameAtTime(-1, OPTION_CLOSEST_SYNC); }
最底部还是调用
private native Bitmap _getFrameAtTime(long timeUs, int option);
基本的介绍就是这么多,我们做个案例了解下,还是基于上篇文章的那个demo。我们只修改获取视频缩略图的部分。
private void getBitmapFromFile() { Bitmap bitmap = null; if(infor.type == 0){//若果是图片,即拍照 //直接通过路径利用BitmapFactory来形成bitmap bitmap = BitmapFactory.decodeFile(infor.srcPath); }else if(infor.type == 1){//如果是视频,即拍摄视频 //利用ThumnailUtils //bitmap = ThumbnailUtils.createVideoThumbnail(infor.srcPath, Images.Thumbnails.MINI_KIND); MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever(); try{ if(android.os.Build.VERSION.SDK_INT >= 14){ metadataRetriever.setDataSource(infor.srcPath, new HashMap<String, String>());; }else{ metadataRetriever.setDataSource(infor.srcPath); } bitmap = metadataRetriever.getFrameAtTime(); infor.bitmap = bitmap; }catch(Exception ex){ ex.printStackTrace(); }finally{ metadataRetriever.release(); } }
我们测试下,效果图:
MediaMetadataRetriever的基本使用就是这么多,更多的研究,去看源码吧!
* android.provider.MediaStore.Images.Thumbnails * android.provider.MediaStore.Video.Thumbnails
为什么先说上一个,就是因为上一个简单,这两个货比较复杂,首先通过包名路径即可看出,这俩二货不是android.media包下的东西,而是属于android.provider下的东西。是不是很吃惊,竟然属于系统ContentProvider下的东西。思前想后,我们想象ContentProvider有什么用途呢?数据存储。莫非通过这俩货,我们可以获取手机里所有的图片or缩略图。好吧!我们暂且这样,我们先到手机的/data/data/com.android.providers.media目录下的数据库整出来看看。导出external和internal两个数据库。
如图:
我们通过SQLiteSpy打开数据库看看,我们查看thumbnails数据表,关于thumbnails表,百度词条有个描述可以看看。如图:
在这张表中,我们看到了众多的图片信息,参照一片文档说的‘表thumbnails和images通过thumbnails.image_id与images._id关联的,通过images的_id,就可以找出来’。但是我并没有发现有images这张表,不知道为什么?哪位大侠知道,麻烦留言指教。
通过上面的数据表展示,在结合对ContentProvider的分析,基本可以确定我们能通过ContentProvider这条路径获取手机里所有的图片。
源码简介:
打开MediaStore类的源码,我们可以看到定义的这两个变量:
public static final String AUTHORITY = "media"; private static final String CONTENT_AUTHORITY_SLASH = "content://" + AUTHORITY + "/";
显然这就是为了我们ContentProvider的使用服务的。接着往下看,我们发现了在MediaStore类的内部定义了多个静态类,其中就包含我们的:
- android.provider.MediaStore.Images
- android.provider.MediaStore.Video
我们查看这两个静态内部类的内部结构:
Images如下图:
Video如下图:
我们发现在二者的内部,都包含一个Thumbnails静态类,这个类就是我们查询的通口。
我们对源码就看这么多吧!也不贴了,有兴趣的可以自己到sdk下看源码,我们只了解下这几个类的组织结构关系吧!通过一些截图,看看类的说明和成员变量。下面我们就通过一个小实例来看看怎么用的吧!
案例还是基于上篇的demo,这次新增的地方有:我们新增一个媒体信息集合
private ArrayList<MeadiaInformation> list;
下面直接看查询的代码:
/** * 获取数据库中存储的图片 */private void getImagesFromDb(){ //获取系统的ContentResolver ContentResolver contentResolver = getContentResolver(); //列出我们需要获取的字段信息 String[] projection = { Thumbnails._ID, Thumbnails.IMAGE_ID, Thumbnails.DATA }; //查询需要的信息 Cursor cursor = contentResolver.query(Thumbnails.EXTERNAL_CONTENT_URI, projection, null, null, null); getColumnData(cursor); //设置到listviewAdapter listViewAdapter.addInformationList(list);}/** * 获取数据表中的数据 * @param cur */private void getColumnData(Cursor cur) { if (cur.moveToFirst()) { int _id; int image_id; String image_path; int _idColumn = cur.getColumnIndex(Thumbnails._ID); int image_idColumn = cur.getColumnIndex(Thumbnails.IMAGE_ID); int dataColumn = cur.getColumnIndex(Thumbnails.DATA); do { //获取id _id = cur.getInt(_idColumn); //获取图片id image_id = cur.getInt(image_idColumn); //获取图片路径 image_path = cur.getString(dataColumn); Log.d("Images:", "_id:" + _id + "\n" + "image_id:" + image_id + "\n" + "image_path:"+image_path); //形成文件 Bitmap bitmap = BitmapFactory.decodeFile(image_path); infor = new MeadiaInformation(); infor.bitmap = bitmap; infor.srcPath = image_path; infor.type = 0; list.add(infor); } while (cur.moveToNext()); } }
我们在onCreate中调用getImagesFromDb()方法,让我们的程序刚进来就加载。看下效果图吧!
更多内容可参考:
【Android】缩略图Thumbnails
Android thumbnail 图片的获得及与原始图片的映射
========================================
作者:mr_dsw 欢迎转载,与人分享是进步的源泉!
转载请保留地址:http://blog.csdn.net/mr_dsw
更多相关文章
- android获取手机中的短信和,android获取手机通讯录联系人和号码
- 半透明Activity方法
- android点击状态分析
- 自定义Android(安卓)标题栏TitleBar布局
- Android(安卓)源码热门改动速查(持续更新.....)
- android wifi状态机原理
- android webView与js交互
- Android控件开发之TextView
- Android内嵌H5(2)