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