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

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

}



你可能感兴趣的:(引用JNI版本----MediaMetadataRetriever获取视频缩略图(真机4.0测试通过))