在 DDMS-file browser-system-lib导出jni库函数:libmedia_jni.so
然后在android项目中libs文件夹下面建立armeabi文件夹并把库函数拷贝进来;
然后创建一个android.media包(必须要在这个包下创建,否则出错),并创建MediaMetadataRetriever类,我在网上找到的这个类,Android 视频缩略图之MediaMetadataRetriever
有些方法已经不存在了,应该是版本问题,
没办法我只好看源码的jni(frameworks\base\media\jni)文件,看了之后知道有哪些函数,但是因为没接触过jni,所以要传哪些参数都没看懂,所以偷懒了
去android developers看了API(猛击这里),这样也确认了API的正确,也知道如何传参。
这样我重新在从网上获取到的这个类(MediaMetadataRetriever),再加上几行简单的 native 函数声明就简单粗暴的解决了我的问题。。
之所以导入jni库来获取缩略图是为了不用考虑版本问题,或者说简化维护版本问题。。
在android.media包下的代码:
package android.media; //package android.media; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.net.Uri; /** * MediaMetadataRetriever class provides a unified interface for retrieving * frame and meta data from an input media file. * {@hide} */ public class MediaMetadataRetriever { static { System.loadLibrary("media_jni"); } // The field below is accessed by native methods @SuppressWarnings("unused") private int mNativeContext; public MediaMetadataRetriever() { native_setup(); } /** * Call this method before setDataSource() so that the mode becomes * effective for subsequent operations. This method can be called only once * at the beginning if the intended mode of operation for a * MediaMetadataRetriever object remains the same for its whole lifetime, * and thus it is unnecessary to call this method each time setDataSource() * is called. If this is not never called (which is allowed), by default the * intended mode of operation is to both capture frame and retrieve meta * data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY). * Often, this may not be what one wants, since doing this has negative * performance impact on execution time of a call to setDataSource(), 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 */ public native void setMode(int mode); /** * @return the current mode of operation. A negative return value indicates * some runtime error has occurred. */ public native int getMode(); /** * 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 native void setDataSource(String path) throws IllegalArgumentException; /** * Sets the data source (FileDescriptor) to use. 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 method before 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 */ public native void setDataSource(FileDescriptor fd, long offset, long length) throws IllegalArgumentException; /** * Sets the data source (FileDescriptor) to use. 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 method before 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 */ public void setDataSource(FileDescriptor fd) throws IllegalArgumentException { // intentionally less than LONG_MAX setDataSource(fd, 0, 0x7ffffffffffffffL); } /** * Sets the data source as a content Uri. Call this method before * the rest of the methods in this class. This method may 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. */ public void setDataSource(Context context, Uri uri) throws IllegalArgumentException, SecurityException { if (uri == null) { throw new IllegalArgumentException(); } String scheme = uri.getScheme(); if(scheme == null || scheme.equals("file")) { setDataSource(uri.getPath()); return; } AssetFileDescriptor fd = null; try { ContentResolver resolver = context.getContentResolver(); try { fd = resolver.openAssetFileDescriptor(uri, "r"); } catch(FileNotFoundException e) { throw new IllegalArgumentException(); } if (fd == null) { throw new IllegalArgumentException(); } FileDescriptor descriptor = fd.getFileDescriptor(); if (!descriptor.valid()) { throw new 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(). This method retrieves the * meta data value associated with the keyCode. * * The keyCode currently supported is listed below as METADATA_XXX * constants. With any other value, it returns a null pointer. * * @param keyCode One of the constants listed below at the end of the class. * @return The meta data value associate with the given keyCode on success; * null on failure. */ public native String extractMetadata(int keyCode); /** * Call this method after setDataSource(). * This method finds a representative frame at any time position if possible, * and returns it as a bitmap. T * his 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; * @return A Bitmap containing a representative video frame, * which can be null, if such a frame cannot be retrieved. */ public native Bitmap getFrameAtTime(); /** * Call this method after setDataSource(). This method finds a * representative frame if successful and returns it as a bitmap. This is * useful for generating a thumbnail for an input media source. * * @return A Bitmap containing a representative video frame, which * can be null, if such a frame cannot be retrieved. */ public native Bitmap captureFrame(); /** * Call this method after setDataSource(). This method finds the optional * graphic or album art associated (embedded or external url linked) the * related data source. * * @return null if no such graphic is found. */ public native byte[] extractAlbumArt(); /** * Call it when one is done with the object. This method releases the memory * allocated internally. */ public native void release(); private native void native_setup(); private native final void native_finalize(); @Override protected void finalize() throws Throwable { try { native_finalize(); } finally { super.finalize(); } } public static final int MODE_GET_METADATA_ONLY = 0x01; public static final int MODE_CAPTURE_FRAME_ONLY = 0x02; /* * Do not change these values without updating their counterparts * in include/media/mediametadataretriever.h! */ public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; public static final int METADATA_KEY_ALBUM = 1; public static final int METADATA_KEY_ARTIST = 2; public static final int METADATA_KEY_AUTHOR = 3; public static final int METADATA_KEY_COMPOSER = 4; public static final int METADATA_KEY_DATE = 5; public static final int METADATA_KEY_GENRE = 6; public static final int METADATA_KEY_TITLE = 7; public static final int METADATA_KEY_YEAR = 8; public static final int METADATA_KEY_DURATION = 9; public static final int METADATA_KEY_NUM_TRACKS = 10; public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11; public static final int METADATA_KEY_CODEC = 12; public static final int METADATA_KEY_RATING = 13; public static final int METADATA_KEY_COMMENT = 14; public static final int METADATA_KEY_COPYRIGHT = 15; public static final int METADATA_KEY_BIT_RATE = 16; public static final int METADATA_KEY_FRAME_RATE = 17; public static final int METADATA_KEY_VIDEO_FORMAT = 18; public static final int METADATA_KEY_VIDEO_HEIGHT = 19; public static final int METADATA_KEY_VIDEO_WIDTH = 20; // Add more here... }
在另一个java包(com.example.thumbnaildemo)中的代码:
package com.example.thumbnaildemo; import java.io.File; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.ContentResolver; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.media.MediaMetadataRetriever; import android.media.ThumbnailUtils; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.provider.MediaStore.Video; import android.text.format.DateFormat; import android.util.Log; import android.widget.ImageView; public class MainActivity extends Activity { final static String TAG = "MainActivity"; ImageView thumbnails; @Override protected void onCreate(Bundle savedInstanceState) { Log.i(TAG,"------------------onCreate---------------------------"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); thumbnails=(ImageView)findViewById(R.id.imageView2); /* InputStream input = getResources().openRawResource(R.drawable.girl); BitmapDrawable girl = new BitmapDrawable(input); Bitmap bitmap = girl.getBitmap(); bitmap =ThumbnailUtils.extractThumbnail(bitmap, 50, 50); thumbnails.setImageBitmap(bitmap);*/ File file = new File("/sdcard/mp4/china.mp4"); Bitmap bitmap = createVideoThumbnail(file.getAbsolutePath()); thumbnails.setImageBitmap(bitmap); /*List<Video> allVideoList = null;// 视频信息集合 allVideoList = new ArrayList<Video>(); getVideoFile(allVideoList);// 获得视频文件*/ } private void getVideoFile(final List<Video> list) { Bitmap bitmap = null; ContentResolver mContentResolver = this.getContentResolver(); Cursor cursor = mContentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Video.DEFAULT_SORT_ORDER); Log.i(TAG,"------------------getVideoFile---------------------------"); if (cursor.moveToFirst()) { Log.i(TAG,"------------------getVideoFile-----cursor.moveToFirst----------------------"); //do { //ID:MediaStore.Audio.Media._ID int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)); //名称 :MediaStore.Audio.Media.TITLE String tilte = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE)); //专辑名:MediaStore.Audio.Media.ALBUM String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.ALBUM)); //歌手名: MediaStore.Audio.Media.ARTIST String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.ARTIST)); //路径 :MediaStore.Audio.Media.DATA String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)); //总播放时长 :MediaStore.Audio.Media.DURATION int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)); //大小 :MediaStore.Audio.Media.SIZE int size = (int)cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)); //拍摄时间 int dateTaken = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATE_TAKEN)); String datetime = DateFormat.format("yyyy-MM-dd kk:mm:ss", dateTaken).toString(); bitmap = createVideoThumbnail(url); thumbnails.setImageBitmap(bitmap); } } /** * @param filePath * @return */ private Bitmap createVideoThumbnail(String filePath) { Log.i(TAG,"------------------createVideoThumbnail---------------------------"); Bitmap bitmap = null; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { //retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); retriever.setDataSource(filePath); //bitmap = retriever.captureFrame(); bitmap= retriever.getFrameAtTime(); } catch(IllegalArgumentException ex) { // Assume this is a corrupt video file } catch (RuntimeException ex) { // Assume this is a corrupt video file. } finally { try { retriever.release(); } catch (RuntimeException ex) { // Ignore failures while cleaning up. } } return bitmap; } }