Merge "heif: add option for specifying bitmap pixel format" into pi-dev

am: 8807436378

Change-Id: If65fcb4cced51af04bdecd58fc27799dc8483b10
This commit is contained in:
Chong Zhang
2018-03-13 03:09:15 +00:00
committed by android-build-merger
3 changed files with 265 additions and 69 deletions

View File

@@ -24052,13 +24052,13 @@ package android.media {
ctor public MediaMetadataRetriever();
method public java.lang.String extractMetadata(int);
method public byte[] getEmbeddedPicture();
method public android.graphics.Bitmap getFrameAtIndex(int);
method public android.graphics.Bitmap getFrameAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getFrameAtTime(long, int);
method public android.graphics.Bitmap getFrameAtTime(long);
method public android.graphics.Bitmap getFrameAtTime();
method public android.graphics.Bitmap[] getFramesAtIndex(int, int);
method public android.graphics.Bitmap getImageAtIndex(int);
method public android.graphics.Bitmap getPrimaryImage();
method public java.util.List<android.graphics.Bitmap> getFramesAtIndex(int, int, android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getImageAtIndex(int, android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getPrimaryImage(android.media.MediaMetadataRetriever.BitmapParams);
method public android.graphics.Bitmap getScaledFrameAtTime(long, int, int, int);
method public void release();
method public void setDataSource(java.lang.String) throws java.lang.IllegalArgumentException;
@@ -24104,6 +24104,13 @@ package android.media {
field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0
}
public static final class MediaMetadataRetriever.BitmapParams {
ctor public MediaMetadataRetriever.BitmapParams();
method public android.graphics.Bitmap.Config getActualConfig();
method public android.graphics.Bitmap.Config getPreferredConfig();
method public void setPreferredConfig(android.graphics.Bitmap.Config);
}
public final class MediaMuxer {
ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
ctor public MediaMuxer(java.io.FileDescriptor, int) throws java.io.IOException;

View File

@@ -17,6 +17,8 @@
package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
@@ -30,7 +32,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Map;
/**
@@ -367,27 +369,79 @@ public class MediaMetadataRetriever
private native Bitmap _getFrameAtTime(long timeUs, int option, int width, int height);
public static final class BitmapParams {
private Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
private Bitmap.Config outActualConfig = Bitmap.Config.ARGB_8888;
/**
* Create a default BitmapParams object. By default, it uses {@link Bitmap.Config#ARGB_8888}
* as the preferred bitmap config.
*/
public BitmapParams() {}
/**
* Set the preferred bitmap config for the decoder to decode into.
*
* If not set, or the request cannot be met, the decoder will output
* in {@link Bitmap.Config#ARGB_8888} config by default.
*
* After decode, the actual config used can be retrieved by {@link #getActualConfig()}.
*
* @param config the preferred bitmap config to use.
*/
public void setPreferredConfig(@NonNull Bitmap.Config config) {
if (config == null) {
throw new IllegalArgumentException("preferred config can't be null");
}
inPreferredConfig = config;
}
/**
* Retrieve the preferred bitmap config in the params.
*
* @return the preferred bitmap config.
*/
public @NonNull Bitmap.Config getPreferredConfig() {
return inPreferredConfig;
}
/**
* Get the actual bitmap config used to decode the bitmap after the decoding.
*
* @return the actual bitmap config used.
*/
public @NonNull Bitmap.Config getActualConfig() {
return outActualConfig;
}
}
/**
* This method retrieves a video frame by its index. It should only be called
* after {@link #setDataSource}.
*
* After the bitmap is returned, you can query the actual parameters that were
* used to create the bitmap from the {@code BitmapParams} argument, for instance
* to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
*
* @param frameIndex 0-based index of the video frame. The frame index must be that of
* a valid frame. The total number of frames available for retrieval can be queried
* via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
* @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
* If null, default config will be chosen.
*
* @throws IllegalStateException if the container doesn't contain video or image sequences.
* @throws IllegalArgumentException if the requested frame index does not exist.
*
* @return A Bitmap containing the requested video frame, or null if the retrieval fails.
*
* @see #getFramesAtIndex(int, int)
* @see #getFramesAtIndex(int, int, BitmapParams)
*/
public Bitmap getFrameAtIndex(int frameIndex) {
Bitmap[] bitmaps = getFramesAtIndex(frameIndex, 1);
if (bitmaps == null || bitmaps.length < 1) {
public Bitmap getFrameAtIndex(int frameIndex, @Nullable BitmapParams params) {
List<Bitmap> bitmaps = getFramesAtIndex(frameIndex, 1, params);
if (bitmaps == null || bitmaps.size() < 1) {
return null;
}
return bitmaps[0];
return bitmaps.get(0);
}
/**
@@ -395,24 +449,31 @@ public class MediaMetadataRetriever
* specified index. It should only be called after {@link #setDataSource}.
*
* If the caller intends to retrieve more than one consecutive video frames,
* this method is preferred over {@link #getFrameAtIndex(int)} for efficiency.
* this method is preferred over {@link #getFrameAtIndex(int, BitmapParams)} for efficiency.
*
* After the bitmaps are returned, you can query the actual parameters that were
* used to create the bitmaps from the {@code BitmapParams} argument, for instance
* to query the bitmap config used for the bitmaps with {@link BitmapParams#getActualConfig}.
*
* @param frameIndex 0-based index of the first video frame to retrieve. The frame index
* must be that of a valid frame. The total number of frames available for retrieval
* can be queried via the {@link #METADATA_KEY_VIDEO_FRAME_COUNT} key.
* @param numFrames number of consecutive video frames to retrieve. Must be a positive
* value. The stream must contain at least numFrames frames starting at frameIndex.
* @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
* If null, default config will be chosen.
*
* @throws IllegalStateException if the container doesn't contain video or image sequences.
* @throws IllegalArgumentException if the frameIndex or numFrames is invalid, or the
* stream doesn't contain at least numFrames starting at frameIndex.
* @return An array of Bitmaps containing the requested video frames. The returned
* @return An list of Bitmaps containing the requested video frames. The returned
* array could contain less frames than requested if the retrieval fails.
*
* @see #getFrameAtIndex(int)
* @see #getFrameAtIndex(int, BitmapParams)
*/
public Bitmap[] getFramesAtIndex(int frameIndex, int numFrames) {
public List<Bitmap> getFramesAtIndex(
int frameIndex, int numFrames, @Nullable BitmapParams params) {
if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO))) {
throw new IllegalStateException("Does not contail video or image sequences");
}
@@ -424,24 +485,32 @@ public class MediaMetadataRetriever
throw new IllegalArgumentException("Invalid frameIndex or numFrames: "
+ frameIndex + ", " + numFrames);
}
return _getFrameAtIndex(frameIndex, numFrames);
return _getFrameAtIndex(frameIndex, numFrames, params);
}
private native Bitmap[] _getFrameAtIndex(int frameIndex, int numFrames);
private native List<Bitmap> _getFrameAtIndex(
int frameIndex, int numFrames, @Nullable BitmapParams params);
/**
* This method retrieves a still image by its index. It should only be called
* after {@link #setDataSource}.
*
* After the bitmap is returned, you can query the actual parameters that were
* used to create the bitmap from the {@code BitmapParams} argument, for instance
* to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
*
* @param imageIndex 0-based index of the image, with negative value indicating
* the primary image.
* @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
* If null, default config will be chosen.
*
* @throws IllegalStateException if the container doesn't contain still images.
* @throws IllegalArgumentException if the requested image does not exist.
*
* @return the requested still image, or null if the image cannot be retrieved.
*
* @see #getPrimaryImage
* @see #getPrimaryImage(BitmapParams)
*/
public Bitmap getImageAtIndex(int imageIndex) {
public Bitmap getImageAtIndex(int imageIndex, @Nullable BitmapParams params) {
if (!"yes".equals(extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE))) {
throw new IllegalStateException("Does not contail still images");
}
@@ -451,24 +520,31 @@ public class MediaMetadataRetriever
throw new IllegalArgumentException("Invalid image index: " + imageCount);
}
return _getImageAtIndex(imageIndex);
return _getImageAtIndex(imageIndex, params);
}
/**
* This method retrieves the primary image of the media content. It should only
* be called after {@link #setDataSource}.
*
* After the bitmap is returned, you can query the actual parameters that were
* used to create the bitmap from the {@code BitmapParams} argument, for instance
* to query the bitmap config used for the bitmap with {@link BitmapParams#getActualConfig}.
*
* @param params BitmapParams that controls the returned bitmap config (such as pixel formats).
* If null, default config will be chosen.
*
* @return the primary image, or null if it cannot be retrieved.
*
* @throws IllegalStateException if the container doesn't contain still images.
*
* @see #getImageAtIndex(int)
* @see #getImageAtIndex(int, BitmapParams)
*/
public Bitmap getPrimaryImage() {
return getImageAtIndex(-1);
public Bitmap getPrimaryImage(@Nullable BitmapParams params) {
return getImageAtIndex(-1, params);
}
private native Bitmap _getImageAtIndex(int imageIndex);
private native Bitmap _getImageAtIndex(int imageIndex, @Nullable BitmapParams params);
/**
* Call this method after setDataSource(). This method finds the optional

View File

@@ -25,6 +25,7 @@
#include <media/IMediaHTTPService.h>
#include <media/mediametadataretriever.h>
#include <media/mediascanner.h>
#include <nativehelper/ScopedLocalRef.h>
#include <private/media/VideoFrame.h>
#include "jni.h"
@@ -45,6 +46,12 @@ struct fields_t {
jmethodID createScaledBitmapMethod;
jclass configClazz; // Must be a global ref
jmethodID createConfigMethod;
jclass bitmapParamsClazz; // Must be a global ref
jfieldID inPreferredConfig;
jfieldID outActualConfig;
jclass arrayListClazz; // Must be a global ref
jmethodID arrayListInit;
jmethodID arrayListAdd;
};
static fields_t fields;
@@ -254,16 +261,18 @@ static void rotate(T *dst, const T *src, size_t width, size_t height, int angle)
}
static jobject getBitmapFromVideoFrame(
JNIEnv *env, VideoFrame *videoFrame, jint dst_width, jint dst_height) {
JNIEnv *env, VideoFrame *videoFrame, jint dst_width, jint dst_height,
SkColorType outColorType) {
ALOGV("getBitmapFromVideoFrame: dimension = %dx%d and bytes = %d",
videoFrame->mDisplayWidth,
videoFrame->mDisplayHeight,
videoFrame->mSize);
jobject config = env->CallStaticObjectMethod(
fields.configClazz,
fields.createConfigMethod,
GraphicsJNI::colorTypeToLegacyBitmapConfig(kRGB_565_SkColorType));
ScopedLocalRef<jobject> config(env,
env->CallStaticObjectMethod(
fields.configClazz,
fields.createConfigMethod,
GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
uint32_t width, height, displayWidth, displayHeight;
bool swapWidthAndHeight = false;
@@ -285,7 +294,7 @@ static jobject getBitmapFromVideoFrame(
fields.createBitmapMethod,
width,
height,
config);
config.get());
if (jBitmap == NULL) {
if (env->ExceptionCheck()) {
env->ExceptionClear();
@@ -297,11 +306,19 @@ static jobject getBitmapFromVideoFrame(
SkBitmap bitmap;
GraphicsJNI::getSkBitmap(env, jBitmap, &bitmap);
rotate((uint16_t*)bitmap.getPixels(),
(uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
videoFrame->mWidth,
videoFrame->mHeight,
videoFrame->mRotationAngle);
if (outColorType == kRGB_565_SkColorType) {
rotate((uint16_t*)bitmap.getPixels(),
(uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
videoFrame->mWidth,
videoFrame->mHeight,
videoFrame->mRotationAngle);
} else {
rotate((uint32_t*)bitmap.getPixels(),
(uint32_t*)((char*)videoFrame + sizeof(VideoFrame)),
videoFrame->mWidth,
videoFrame->mHeight,
videoFrame->mRotationAngle);
}
if (dst_width <= 0 || dst_height <= 0) {
dst_width = displayWidth;
@@ -323,12 +340,46 @@ static jobject getBitmapFromVideoFrame(
dst_width,
dst_height,
true);
env->DeleteLocalRef(jBitmap);
return scaledBitmap;
}
return jBitmap;
}
static int getColorFormat(JNIEnv *env, jobject options) {
if (options == NULL) {
return HAL_PIXEL_FORMAT_RGBA_8888;
}
ScopedLocalRef<jobject> inConfig(env, env->GetObjectField(options, fields.inPreferredConfig));
SkColorType prefColorType = GraphicsJNI::getNativeBitmapColorType(env, inConfig.get());
if (prefColorType == kRGB_565_SkColorType) {
return HAL_PIXEL_FORMAT_RGB_565;
}
return HAL_PIXEL_FORMAT_RGBA_8888;
}
static SkColorType setOutColorType(JNIEnv *env, int colorFormat, jobject options) {
SkColorType outColorType = kN32_SkColorType;
if (colorFormat == HAL_PIXEL_FORMAT_RGB_565) {
outColorType = kRGB_565_SkColorType;
}
if (options != NULL) {
ScopedLocalRef<jobject> config(env,
env->CallStaticObjectMethod(
fields.configClazz,
fields.createConfigMethod,
GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
env->SetObjectField(options, fields.outActualConfig, config.get());
}
return outColorType;
}
static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
JNIEnv *env, jobject thiz, jlong timeUs, jint option, jint dst_width, jint dst_height)
{
@@ -351,11 +402,11 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
return NULL;
}
return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height);
return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, kRGB_565_SkColorType);
}
static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
JNIEnv *env, jobject thiz, jint index)
JNIEnv *env, jobject thiz, jint index, jobject params)
{
ALOGV("getImageAtIndex: index %d", index);
sp<MediaMetadataRetriever> retriever = getRetriever(env, thiz);
@@ -364,9 +415,11 @@ static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
return NULL;
}
int colorFormat = getColorFormat(env, params);
// Call native method to retrieve an image
VideoFrame *videoFrame = NULL;
sp<IMemory> frameMemory = retriever->getImageAtIndex(index);
sp<IMemory> frameMemory = retriever->getImageAtIndex(index, colorFormat);
if (frameMemory != 0) { // cast the shared structure to a VideoFrame object
videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
}
@@ -375,11 +428,13 @@ static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
return NULL;
}
return getBitmapFromVideoFrame(env, videoFrame, -1, -1);
SkColorType outColorType = setOutColorType(env, colorFormat, params);
return getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
}
static jobjectArray android_media_MediaMetadataRetriever_getFrameAtIndex(
JNIEnv *env, jobject thiz, jint frameIndex, jint numFrames)
static jobject android_media_MediaMetadataRetriever_getFrameAtIndex(
JNIEnv *env, jobject thiz, jint frameIndex, jint numFrames, jobject params)
{
ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d", frameIndex, numFrames);
sp<MediaMetadataRetriever> retriever = getRetriever(env, thiz);
@@ -389,31 +444,34 @@ static jobjectArray android_media_MediaMetadataRetriever_getFrameAtIndex(
return NULL;
}
int colorFormat = getColorFormat(env, params);
std::vector<sp<IMemory> > frames;
status_t err = retriever->getFrameAtIndex(&frames, frameIndex, numFrames);
status_t err = retriever->getFrameAtIndex(&frames, frameIndex, numFrames, colorFormat);
if (err != OK || frames.size() == 0) {
ALOGE("failed to get frames from retriever, err=%d, size=%zu",
err, frames.size());
return NULL;
}
jobjectArray bitmapArrayObj = env->NewObjectArray(
frames.size(), fields.bitmapClazz, NULL);
if (bitmapArrayObj == NULL) {
ALOGE("can't create bitmap array object");
jobject arrayList = env->NewObject(fields.arrayListClazz, fields.arrayListInit);
if (arrayList == NULL) {
ALOGE("can't create bitmap array list object");
return NULL;
}
SkColorType outColorType = setOutColorType(env, colorFormat, params);
for (size_t i = 0; i < frames.size(); i++) {
if (frames[i] == NULL || frames[i]->pointer() == NULL) {
ALOGE("video frame at index %zu is a NULL pointer", frameIndex + i);
continue;
}
VideoFrame *videoFrame = static_cast<VideoFrame *>(frames[i]->pointer());
jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1);
env->SetObjectArrayElement(bitmapArrayObj, i, bitmapObj);
jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
env->CallBooleanMethod(arrayList, fields.arrayListAdd, bitmapObj);
env->DeleteLocalRef(bitmapObj);
}
return bitmapArrayObj;
return arrayList;
}
static jbyteArray android_media_MediaMetadataRetriever_getEmbeddedPicture(
@@ -488,21 +546,21 @@ static void android_media_MediaMetadataRetriever_native_finalize(JNIEnv *env, jo
// first time an instance of this class is used.
static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
{
jclass clazz = env->FindClass(kClassPathName);
if (clazz == NULL) {
ScopedLocalRef<jclass> clazz(env, env->FindClass(kClassPathName));
if (clazz.get() == NULL) {
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
fields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
if (fields.context == NULL) {
return;
}
jclass bitmapClazz = env->FindClass("android/graphics/Bitmap");
if (bitmapClazz == NULL) {
clazz.reset(env->FindClass("android/graphics/Bitmap"));
if (clazz.get() == NULL) {
return;
}
fields.bitmapClazz = (jclass) env->NewGlobalRef(bitmapClazz);
fields.bitmapClazz = (jclass) env->NewGlobalRef(clazz.get());
if (fields.bitmapClazz == NULL) {
return;
}
@@ -521,11 +579,11 @@ static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
return;
}
jclass configClazz = env->FindClass("android/graphics/Bitmap$Config");
if (configClazz == NULL) {
clazz.reset(env->FindClass("android/graphics/Bitmap$Config"));
if (clazz.get() == NULL) {
return;
}
fields.configClazz = (jclass) env->NewGlobalRef(configClazz);
fields.configClazz = (jclass) env->NewGlobalRef(clazz.get());
if (fields.configClazz == NULL) {
return;
}
@@ -535,6 +593,42 @@ static void android_media_MediaMetadataRetriever_native_init(JNIEnv *env)
if (fields.createConfigMethod == NULL) {
return;
}
clazz.reset(env->FindClass("android/media/MediaMetadataRetriever$BitmapParams"));
if (clazz.get() == NULL) {
return;
}
fields.bitmapParamsClazz = (jclass) env->NewGlobalRef(clazz.get());
if (fields.bitmapParamsClazz == NULL) {
return;
}
fields.inPreferredConfig = env->GetFieldID(fields.bitmapParamsClazz,
"inPreferredConfig", "Landroid/graphics/Bitmap$Config;");
if (fields.inPreferredConfig == NULL) {
return;
}
fields.outActualConfig = env->GetFieldID(fields.bitmapParamsClazz,
"outActualConfig", "Landroid/graphics/Bitmap$Config;");
if (fields.outActualConfig == NULL) {
return;
}
clazz.reset(env->FindClass("java/util/ArrayList"));
if (clazz.get() == NULL) {
return;
}
fields.arrayListClazz = (jclass) env->NewGlobalRef(clazz.get());
if (fields.arrayListClazz == NULL) {
return;
}
fields.arrayListInit = env->GetMethodID(clazz.get(), "<init>", "()V");
if (fields.arrayListInit == NULL) {
return;
}
fields.arrayListAdd = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
if (fields.arrayListAdd == NULL) {
return;
}
}
static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz)
@@ -556,17 +650,36 @@ static const JNINativeMethod nativeMethods[] = {
(void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders
},
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
{"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{"_getImageAtIndex", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getImageAtIndex},
{"_getFrameAtIndex", "(II)[Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtIndex},
{"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
{"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
{"release", "()V", (void *)android_media_MediaMetadataRetriever_release},
{"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize},
{"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup},
{"native_init", "()V", (void *)android_media_MediaMetadataRetriever_native_init},
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
(void *)android_media_MediaMetadataRetriever_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V",
(void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
{"_getFrameAtTime", "(JIII)Landroid/graphics/Bitmap;",
(void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{
"_getImageAtIndex",
"(ILandroid/media/MediaMetadataRetriever$BitmapParams;)Landroid/graphics/Bitmap;",
(void *)android_media_MediaMetadataRetriever_getImageAtIndex
},
{
"_getFrameAtIndex",
"(IILandroid/media/MediaMetadataRetriever$BitmapParams;)Ljava/util/List;",
(void *)android_media_MediaMetadataRetriever_getFrameAtIndex
},
{"extractMetadata", "(I)Ljava/lang/String;",
(void *)android_media_MediaMetadataRetriever_extractMetadata},
{"getEmbeddedPicture", "(I)[B",
(void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
{"release", "()V",
(void *)android_media_MediaMetadataRetriever_release},
{"native_finalize", "()V",
(void *)android_media_MediaMetadataRetriever_native_finalize},
{"native_setup", "()V",
(void *)android_media_MediaMetadataRetriever_native_setup},
{"native_init", "()V",
(void *)android_media_MediaMetadataRetriever_native_init},
};
// This function only registers the native methods, and is called from