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();
            }
        }

我们测试下,效果图:
medat

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两个数据库。
如图:
provider
databse

我们通过SQLiteSpy打开数据库看看,我们查看thumbnails数据表,关于thumbnails表,百度词条有个描述可以看看。如图:
table

在这张表中,我们看到了众多的图片信息,参照一片文档说的‘表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如下图:
images

Video如下图:
vids

我们发现在二者的内部,都包含一个Thumbnails静态类,这个类就是我们查询的通口。
thumbnaiimage
thumbnails_source

我们对源码就看这么多吧!也不贴了,有兴趣的可以自己到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()方法,让我们的程序刚进来就加载。看下效果图吧!

result

更多内容可参考:
【Android】缩略图Thumbnails

Android thumbnail 图片的获得及与原始图片的映射

========================================
作者:mr_dsw 欢迎转载,与人分享是进步的源泉!

转载请保留地址:http://blog.csdn.net/mr_dsw

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值