引用JNI版本----MediaMetadataRetriever获取视频缩略图(真机4.0测试通过)

来源:互联网 发布:图像算法工程师 知乎 编辑:程序博客网 时间:2024/06/12 18:11

在 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;@Overrideprotected 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;    }   }



0 0
原创粉丝点击