您的位置:首页 > 其它

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

2014-10-28 12:19 423 查看
在 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;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐