diff options
| -rw-r--r-- | api/current.txt | 15 | ||||
| -rw-r--r-- | media/java/android/media/MediaMetadataRetriever.java | 114 | ||||
| -rw-r--r-- | media/jni/android_media_MediaMetadataRetriever.cpp | 205 |
3 files changed, 265 insertions, 69 deletions
diff --git a/api/current.txt b/api/current.txt index fff502a577db..b7a869ef3177 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24015,13 +24015,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; @@ -24067,6 +24067,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; diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index 745eb74d6e20..1aeed6da3a31 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -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 diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index ff854c51c437..3a6714279bb7 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -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 |