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