Android 获取多媒体文件的缩略图

1、        Video

在Android中获取视频文件的缩略图有三种方法:

1.从媒体库中查询

2. android 2.2以后使用ThumbnailUtils类获取

3.调用jni文件,实现MediaMetadataRetriever类

三种方法各有利弊

第一种方法,新视频增加后需要SDCard重新扫描才能给新增加的文件添加缩略图,灵活性差,而且不是很稳定,适合简单应用

第二种方法,实现简单,但2.2以前的版本不支持

第三种方法,实现复杂,但比较灵活,推荐使用(MediaMetadataRetriever是android中隐藏的一个类,开发者无法调用)

(1)、第一种方法查询视频缩略图的方法和图片的很像。以下为具体查询实例,FileInfo为自定义的数据模型。

public ArrayListqueryAllVideo(final Context context) {

    if (context == null) { //判断传入的参数的有效性

        return null;

    }

    ArrayList videos = new ArrayList();

    ContentResolver resolver = context.getContentResolver();

    Cursor cursor = null;

    try {

        //查询数据库,参数分别为(路径,要查询的列名,条件语句,条件参数,排序)

        cursor =resolver.query(Video.Media.EXTERNAL_CONTENT_URI, null, null ,null, null);

        if (cursor != null) {

            while (cursor.moveToNext()) {

                FileInfo video = newFileInfo();

               video.setId(cursor.getInt(cursor.getColumnIndex(Video.Media._ID))); //获取唯一id

               video.setFilePath(cursor.getString(cursor.getColumnIndex(Video.Media.DATA)));//文件路径

               video.setFileName(cursor.getString(cursor.getColumnIndex(Video.Media.DISPLAY_NAME)));//文件名

                //...   还有很多属性可以设置

                //可以通过下一行查看属性名,然后在Video.Media.里寻找对应常量名

                Log.i(TAG, "queryAllImage--- all column name --- " + cursor.getColumnName(cursor.getPosition()));

 

                //获取缩略图(如果数据量大的话,会很耗时——需要考虑如何开辟子线程加载)

                /*

                 * 可以访问android.provider.MediaStore.Video.Thumbnails查询图片缩略图

                 * Thumbnails下的getThumbnail方法可以获得图片缩略图,其中第三个参数类型还可以选择MINI_KIND

                 */

                Bitmap thumbnail = MediaStore.Video.Thumbnails.getThumbnail(resolver,image.getId(), Video.Thumbnails.MICRO_KIND, null);

                video.setThumbnail(thumbnail);

                videos.add(image);

            }

        }

    } catch (Exception e) {

        e.printStackTrace();

    } finally {

        if (cursor != null) {

            cursor.close();

        }

    }

    return videos;

}

 

(2)、第二种方法:通过ThumbnailUtils的三种静态方法。

1. static BitmapcreateVideoThumbnail(String filePath, int kind) //获取视频文件的缩略图,第一个参数为视频文件的位置,比如/sdcard/android123.3gp,而第二个参数可以为MINI_KIND或 MICRO_KIND最终和分辨率有关
2. static Bitmap extractThumbnail(Bitmap source, int width, int height, intoptions) //直接对Bitmap进行缩略操作,最后一个参数定义为OPTIONS_RECYCLE_INPUT ,来回收资源
3. static Bitmap extractThumbnail(Bitmap source, int width, int height) // 这个和上面的方法一样,无options选项

videoThumbnail.setImageBitmap(getVideoThumbnail(videoPath,60, 60, MediaStore.Images.Thumbnails.MICRO_KIND));

/**

          * 获取视频的缩略图

          * 先通过ThumbnailUtils来创建一个视频的缩略图,然后再利用ThumbnailUtils来生成指定大小的缩略图。

          * 如果想要的缩略图的宽和高都小于MICRO_KIND,则类型要使用MICRO_KIND作为kind的值,这样会节省内存。

          * @param videoPath 视频的路径

          * @param width 指定输出视频缩略图的宽度

          * @param height 指定输出视频缩略图的高度度

          * @param kind 参照MediaStore.Images.Thumbnails类中的常量MINI_KIND和MICRO_KIND。

          *           其中,MINI_KIND: 512 x 384,MICRO_KIND: 96 x 96

          * @return 指定大小的视频缩略图

          */

         private Bitmap getVideoThumbnail(StringvideoPath, int width, int height, int kind) {

                   Bitmap bitmap = null;

                   // 获取视频的缩略图

                   bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, kind);

  if(bitmap != null){  //如果视频已损坏或者格式不支持可能返回null

                    System.out.println("w"+bitmap.getWidth());

                   System.out.println("h"+bitmap.getHeight());

                  bitmap =ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);

   }

                   return bitmap;

         }

 

(3)、对于视频,取第一帧作为缩略图,也就是怎样从filePath得到一个Bitmap对象。(MediaMetadataRetriever是android中隐藏的一个类,开发者无法调用,只能实现一个相同的类来完成相关功能。

一种方式: 是修改android源码,将frameworks  MediaMetadataRetriever.java中@hide标签去掉,在current.xml中添加MediaMetadataRetriever到可用.重新编译frameworks,应用就可以调用到MediaMetadataRetriever这个类了…这样是不适合应用开发的。推荐的方法: 是实现MediaMetadataRetriever类,第一步:首先需要下载JNI库:libmedia_jni.so

进入SDK的Tools目录下,运行DDMS,
在DDMS中的菜单栏中,执行Device–FileExplore,
在弹出的文件列表中选择: System-Lib-libmedia_jni.so
选中这个文件后, 在弹出的文件列表的又上脚执行PULL file from device,提取出libmedia_jni.so文件
在Eclipse中新建文件夹libs-armeabi-,在里面放入libmedia_jni.so文件;

第二部:实现MediaMetadataRetriever, 详见文档末尾)

 

private BitmapcreateVideoThumbnail(String filePath) {

Bitmap bitmap = null;

MediaMetadataRetrieverretriever = new MediaMetadataRetriever();

try{

retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);

retriever.setDataSource(filePath);

/**

*getFrameAtTime()有其他重载函数,该函数会随机选择一帧抓取,如果想要指定具体时间的缩略图,*可以用函数getFrameAtTime(long timeUs),getFrameAtTime(long timeUs, int option),具体如何使用可以*查doc。

*/

bitmap= retriever.captureFrame();

} catch(IllegalArgumentException ex) {

// Assume this isa corrupt video file

} catch (RuntimeException ex) {

// Assume this isa corrupt video file.

} finally {

try {

retriever.release();

} catch (RuntimeException ex) {

// Ignore failureswhile cleaning up.

}

}

return bitmap;

}

Android提供了MediaMetadataRetriever,由JNI(media_jni)实现。看得出MediaMetadataRetriever主要有两个功能:MODE_GET_METADATA_ONLY和MODE_CAPTURE_FRAME_ONLY,这里设mode为MODE_CAPTURE_FRAME_ONLY,调用captureFrame取得一帧。另外还有两个方法可以用:(1、extractMetadata 提取文件信息,ARTIST、DATE、YEAR、DURATION、RATING、FRAME_RATE、VIDEO_FORMAT;(2、extractAlbumArt 提取专辑信息,这个下面的音乐文件可以用到。

 

2、Image

(1)首先,查询Android固有数据库,图片的Uri为Images.Media.EXTERNAL_CONTENT_URI。

以下为具体查询实例,FileInfo为自定义的数据模型。

 

public ArrayListqueryAllImage(final Context context) {

    if (context == null) { //判断传入的参数的有效性

        return null;

    }

    ArrayList images = new ArrayList();

    ContentResolver resolver =context.getContentResolver();

    Cursor cursor = null;

    try {

        //查询数据库,参数分别为(路径,要查询的列名,条件语句,条件参数,排序)

        cursor =resolver.query(Images.Media.EXTERNAL_CONTENT_URI, null, null ,null, null);

        if (cursor != null) {

            while (cursor.moveToNext()) {

                FileInfo image = newFileInfo();

               image.setId(cursor.getInt(cursor.getColumnIndex(Images.Media._ID))); //获取唯一id

               image.setFilePath(cursor.getString(cursor.getColumnIndex(Images.Media.DATA)));//文件路径

               image.setFileName(cursor.getString(cursor.getColumnIndex(Images.Media.DISPLAY_NAME)));//文件名

                //...   还有很多属性可以设置

                //可以通过下一行查看属性名,然后在Images.Media.里寻找对应常量名

                Log.i(TAG, "queryAllImage--- all column name --- " + cursor.getColumnName(cursor.getPosition()));

                //获取缩略图(如果数据量大的话,会很耗时——需要考虑如何开辟子线程加载)

                /*

                 * 可以访问android.provider.MediaStore.Images.Thumbnails查询图片缩略图

                 * Thumbnails下的getThumbnail方法可以获得图片缩略图,其中第三个参数类型还可以选择MINI_KIND

                 */

                Bitmap thumbnail =MediaStore.Images.Thumbnails.getThumbnail(resolver, image.getId(),Images.Thumbnails.MICRO_KIND, null);

                image.setThumbnail(thumbnail);

 

                images.add(image);

            }

        }

    } catch (Exception e) {

        e.printStackTrace();

    } finally {

        if (cursor != null) {

            cursor.close();

        }

    }

    return images;

}

 

  (2)、图片通过BitmapFactory获取缩略图,能直接得到Bitmap对象

     /**
     * 根据指定的图像路径和大小来获取缩略图
     * 此方法有两点好处:
     * 1.使用较小的内存空间,第一次获取的bitmap实际上为null,只是为了读取宽度和高度,第二次读取的bitmap是根据比例压缩过的图像,
     * 第三次读取的bitmap是所要的缩略图。
     * 2.缩略图对于原图像来讲没有拉伸,这里使用了2.2版本的新工具ThumbnailUtils,使用这个工具生成的图像不会被拉伸。
     *
     * @param imagePath 图像的路径
     * @param width     指定输出图像的宽度
     * @param height    指定输出图像的高度
     * @return 生成的缩略图
     */
    private Bitmap getImageThumbnail(String imagePath, int width, int height) {
        Bitmap bitmap = null;
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        // 获取这个图片的宽和高,注意此处的bitmap为null
        bitmap = BitmapFactory.decodeFile(imagePath, options);
        options.inJustDecodeBounds = false; // 设为 false
        // 计算缩放比
        int h = options.outHeight;
        int w = options.outWidth;
        int beWidth = w / width;
        int beHeight = h / height;
        int be = (beWidth < beHeight) ? beWidth : beHeight;
        if (be <= 0) {
            be = 1;
        }
        options.inSampleSize = be;
        // 重新读入图片,读取缩放后的bitmap,注意这次要把options.inJustDecodeBounds 设为 false
        bitmap = BitmapFactory.decodeFile(imagePath, options);
        // 利用ThumbnailUtils来创建缩略图,这里要指定要缩放哪个Bitmap对象
        bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);

        return bitmap;
    }

 

3、Music

(1)首先,查询Android固有数据库,图片的Uri为Images.Media.EXTERNAL_CONTENT_URI。

以下为具体查询实例,FileInfo为自定义的数据模型。

 

publicArrayList<MeidaFileInfo> queryAllAudio(final Context context) {

    if (context == null) { //判断传入的参数的有效性

        return null;

    }

    ArrayList<MeidaFileInfo> audios = newArrayList<>();

    ContentResolver resolver =context.getContentResolver();

    Cursor cursor = null;

    try {

        //查询数据库,参数分别为(路径,要查询的列名,条件语句,条件参数,排序)

        cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null, null ,null, null);

        if (cursor != null) {

            while (cursor.moveToNext()) {

                MeidaFileInfo audio = newMeidaFileInfo();

                audio.setId(cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media._ID)));//获取唯一id

               audio.setFilePath(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA)));//文件路径

               audio.setFileName(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME)));//文件名

                //...   还有很多属性可以设置

                //可以通过下一行查看属性名,然后去Audio.Media里寻找对应常量名

                Logg.i(TAG, "queryAllImage--- all column name --- " + cursor.getColumnName(cursor.getPosition()));

 

                //获取专辑封面(如果数据量大的话,会很耗时——需要考虑如何开辟子线程加载)

                Bitmap albumArt =createAlbumArt(audio.getFilePath());

                audio.setThumbnail(albumArt);

 

                audios.add(audio);

            }

        }

    } catch (Exception e) {

        e.printStackTrace();

    } finally {

        if (cursor != null) {

            cursor.close();

        }

    }

    return audios;

}

 

/**

 * @Description 获取专辑封面

 * @param filePath 文件路径,like XXX/XXX/XX.mp3

 * @return 专辑封面bitmap

 */

public Bitmap createAlbumArt(finalString filePath) {

    Bitmap bitmap = null;

    //能够获取多媒体文件元数据的类

    MediaMetadataRetrieverretriever = new MediaMetadataRetriever();

    try {

       retriever.setDataSource(filePath); //设置数据源

        byte[]embedPic = retriever.getEmbeddedPicture(); //得到字节型数据

        bitmap =BitmapFactory.decodeByteArray(embedPic, 0, embedPic.length); //转换为图片

    } catch (Exception e) {

        e.printStackTrace();

    } finally {

        try {

            retriever.release();

        } catch (Exception e2) {

            e2.printStackTrace();

        }

    }

    return bitmap;

}

 

把图片缩小到合适大小就OK。同样上面的Video和Music,retrive到Bitmap后也需要缩小处理

 

 

*******************************************************************************

*******************************************************************************

*******************************************************************************

*******************************************************************************

 

import java.io.FileDescriptor;

import java.io.FileNotFoundException;

import java.io.IOException;

import android.content.ContentResolver;

import android.content.Context;

importandroid.content.res.AssetFileDescriptor;

import android.graphics.Bitmap;

import android.net.Uri;

 

public class MediaMetadataRetriever {

         static{

                   System.loadLibrary("media_jni");

                   native_init();

         }

         //The field below is accessed by native methods

         @SuppressWarnings("unused")

         privateint mNativeContext;

 

         publicMediaMetadataRetriever() {

                   native_setup();

         }

 

         /**

          * Call this method before setDataSource() sothat the mode becomes

          * effective for subsequent operations. Thismethod can be called only once

          * at the beginning if the intended mode ofoperation for a

          * MediaMetadataRetriever object remains thesame for its whole lifetime,

          * and thus it is unnecessary to call thismethod each time setDataSource()

          * is called. If this is not never called(which is allowed), by default the

          * intended mode of operation is to bothcapture frame and retrieve meta

          * data (i.e., MODE_GET_METADATA_ONLY |MODE_CAPTURE_FRAME_ONLY). Often,

          * this may not be what one wants, since doingthis has negative performance

          * impact on execution time of a call tosetDataSource(), since both types

          * of operations may be time consuming.

          *

          * @param mode

          *           The intended mode of operation. Can be any combination of

          *           MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY: 1.

          *           MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY: For neither

          *           frame capture nor meta data retrieval 2.

          *           MODE_GET_METADATA_ONLY: For meta data retrieval only 3.

          *           MODE_CAPTURE_FRAME_ONLY: For frame capture only 4.

          *           MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY: For both

          *           frame capture and meta data retrieval

          */

         publicnative void setMode(int mode);

 

         /**

          * @return the current mode of operation. Anegative return value indicates

          *        some runtime error has occurred.

          */

         publicnative int getMode();

 

         /**

          * Sets the data source (file pathname) to use.Call this method before the

          * rest of the methods in this class. Thismethod may be time-consuming.

          *

          * @param path

          *           The path of the input media file.

          * @throws IllegalArgumentException

          *            If the path is invalid.

          */

         publicnative void setDataSource(String path)

                            throwsIllegalArgumentException;

 

         /**

          * Sets the data source (FileDescriptor) touse. It is the caller’s

          * responsibility to close the file descriptor.It is safe to do so as soon

          * as this call returns. Call this methodbefore the rest of the methods in

          * this class. This method may be time-consuming.

          *

          * @param fd

          *           the FileDescriptor for the file you want to play

          * @param offset

          *           the offset into the file where the data to be played starts,

          *           in bytes. It must be non-negative

          * @param length

          *           the length in bytes of the data to be played. It must be

          *           non-negative.

          * @throws IllegalArgumentException

          *            if the arguments are invalid

          */

         publicnative void setDataSource(FileDescriptor fd, long offset, long length)

                            throwsIllegalArgumentException;

 

         /**

          * Sets the data source (FileDescriptor) touse. It is the caller’s

          * responsibility to close the file descriptor.It is safe to do so as soon

          * as this call returns. Call this methodbefore the rest of the methods in

          * this class. This method may be time-consuming.

          *

          * @param fd

          *           the FileDescriptor for the file you want to play

          * @throws IllegalArgumentException

          *            if the FileDescriptor is invalid

          */

         publicvoid setDataSource(FileDescriptor fd)

                            throwsIllegalArgumentException {

                   //intentionally less than LONG_MAX

                   setDataSource(fd,0, 0x7ffffffffffffffL);

         }

 

         /**

          * Sets the data source as a content Uri. Callthis method before the rest

          * of the methods in this class. This methodmay be time-consuming.

          *

          * @param context

          *           the Context to use when resolving the Uri

          * @param uri

          *           the Content URI of the data you want to play

          * @throws IllegalArgumentException

          *            if the Uri is invalid

          * @throws SecurityException

          *            if the Uri cannot be used due to lack of permission.

          */

         publicvoid setDataSource(Context context, Uri uri)

                            throwsIllegalArgumentException, SecurityException {

                   if(uri == null) {

                            thrownew IllegalArgumentException();

                   }

                   Stringscheme = uri.getScheme();

                   if(scheme == null || scheme.equals("file")) {

                            setDataSource(uri.getPath());

                            return;

                   }

                   AssetFileDescriptorfd = null;

                   try{

                            ContentResolverresolver = context.getContentResolver();

                            try{

                                     fd= resolver.openAssetFileDescriptor(uri, "r");

                            }catch (FileNotFoundException e) {

                                     thrownew IllegalArgumentException();

                            }

                            if(fd == null) {

                                     thrownew IllegalArgumentException();

                            }

                            FileDescriptordescriptor = fd.getFileDescriptor();

                            if(!descriptor.valid()) {

                                     thrownew IllegalArgumentException();

                            }

                            //Note: using getDeclaredLength so that our behavior is the same

                            //as previous versions when the content provider is returning

                            //a full file.

                            if(fd.getDeclaredLength() < 0) {

                                     setDataSource(descriptor);

                            }else {

                                     setDataSource(descriptor,fd.getStartOffset(),

                                                        fd.getDeclaredLength());

                            }

                            return;

                   }catch (SecurityException ex) {

                   }finally {

                            try{

                                     if(fd != null) {

                                               fd.close();

                                     }

                            }catch (IOException ioEx) {

                            }

                   }

                   setDataSource(uri.toString());

         }

 

         /**

          * Call this method after setDataSource(). Thismethod retrieves the meta

          * data value associated with the keyCode.

          *

          * The keyCode currently supported is listedbelow as METADATA_XXX

          * constants. With any other value, it returnsa null pointer.

          *

          * @param keyCode

          *           One of the constants listed below at the end of the class.

          * @return The meta data value associate withthe given keyCode on success;

          *        null on failure.

          */

         publicnative String extractMetadata(int keyCode);

 

         /**

          * Call this method after setDataSource(). Thismethod finds a

          * representative frame if successful andreturns it as a bitmap. This is

          * useful for generating a thumbnail for aninput media source.

          *

          * @return A Bitmap containing a representativevideo frame, which can be

          *        null, if such a frame cannot be retrieved.

          */

         publicnative Bitmap captureFrame();

 

         /**

          * Call this method after setDataSource(). Thismethod finds the optional

          * graphic or album art associated (embedded orexternal url linked) the

          * related data source.

          *

          * @return null if no such graphic is found.

          */

         publicnative byte[] extractAlbumArt();

 

         /**

          * Call it when one is done with the object.This method releases the memory

          * allocated internally.

          */

         publicnative void release();

 

         privatenative void native_setup();

 

         privatestatic native void native_init();

 

         privatenative final void native_finalize();

 

         @Override

         protectedvoid finalize() throws Throwable {

                   try{

                            native_finalize();

                   }finally {

                            super.finalize();

                   }

         }

 

         publicstatic final int MODE_GET_METADATA_ONLY = 0x01;

         publicstatic final int MODE_CAPTURE_FRAME_ONLY = 0x02;

         /*

          * Do not change these values without updatingtheir counterparts in

          * include/media/mediametadataretriever.h!

          */

         publicstatic final int METADATA_KEY_CD_TRACK_NUMBER = 0;

         publicstatic final int METADATA_KEY_ALBUM = 1;

         publicstatic final int METADATA_KEY_ARTIST = 2;

         publicstatic final int METADATA_KEY_AUTHOR = 3;

         publicstatic final int METADATA_KEY_COMPOSER = 4;

         publicstatic final int METADATA_KEY_DATE = 5;

         publicstatic final int METADATA_KEY_GENRE = 6;

         publicstatic final int METADATA_KEY_TITLE = 7;

         publicstatic final int METADATA_KEY_YEAR = 8;

         publicstatic final int METADATA_KEY_DURATION = 9;

         publicstatic final int METADATA_KEY_NUM_TRACKS = 10;

         publicstatic final int METADATA_KEY_IS_DRM_CRIPPLED = 11;

         publicstatic final int METADATA_KEY_CODEC = 12;

         publicstatic final int METADATA_KEY_RATING = 13;

         publicstatic final int METADATA_KEY_COMMENT = 14;

         publicstatic final int METADATA_KEY_COPYRIGHT = 15;

         publicstatic final int METADATA_KEY_BIT_RATE = 16;

         publicstatic final int METADATA_KEY_FRAME_RATE = 17;

         publicstatic final int METADATA_KEY_VIDEO_FORMAT = 18;

         publicstatic final int METADATA_KEY_VIDEO_HEIGHT = 19;

         publicstatic final int METADATA_KEY_VIDEO_WIDTH = 20;

         publicstatic final int METADATA_KEY_WRITER = 21;

         publicstatic final int METADATA_KEY_MIMETYPE = 22;

         publicstatic final int METADATA_KEY_DISCNUMBER = 23;

         publicstatic final int METADATA_KEY_ALBUMARTIST = 24;

         //Add more here…

}


                   System.out.println("w"+bitmap.getWidth());

                   System.out.println("h"+bitmap.getHeight());

                   bitmap =ThumbnailUtils.extractThumbnail(bitmap, width, height, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值