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

更多相关文章

  1. android获取手机中的短信和,android获取手机通讯录联系人和号码
  2. 半透明Activity方法
  3. android点击状态分析
  4. 自定义Android(安卓)标题栏TitleBar布局
  5. Android(安卓)源码热门改动速查(持续更新.....)
  6. android wifi状态机原理
  7. android webView与js交互
  8. Android控件开发之TextView
  9. Android内嵌H5(2)

随机推荐

  1. Android自动填写验证码
  2. Android(安卓)的性能 V-保持APP的响应
  3. Android(安卓)加载大图片造成OOM异常解决
  4. Android(安卓)静默方式实现批量安装卸载
  5. Android实现通用的ActivityGroup(效果类似
  6. WebRTC android h264 编解码适配
  7. Android(安卓)- SharedPreferences
  8. android 全部使用NDK开发android应用程序
  9. Android(安卓)事件传递机制的理解
  10. android 微信支付接口申请分享