上篇文章Android视频图片缩略图的获取,我们使用ThumbnailUtils工具类进行图片和视频的缩略图获取,我们提到了
这三个玩意,但是没具体说,只是在ThumbnailUtils的源码中见到了他们的影子。其实,深入了解的原因来源于:项目中,我们拍摄的照片和视频上传后,那么我们再次获取视频的时候,视频是在服务器,我们不可能将视频下载下来,然后仅仅为了获取一个缩略图使用的,这样岂不是很坑。所以就需要深入的学习下如何获取视频缩略图。
上篇文章中,我们在分析ThumbnailUtils.createVideoThumbnail方法的源码时,见到该方法的内部使用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.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类的内部定义了多个静态类,其中就包含我们的:
我们查看这两个静态内部类的内部结构:
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