Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88074363 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents 07c1cc1f a89f6e1b
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -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;
+95 −19
Original line number Diff line number Diff line
@@ -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
+159 −46
Original line number Diff line number Diff line
@@ -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(
    ScopedLocalRef<jobject> config(env,
            env->CallStaticObjectMethod(
                    fields.configClazz,
                    fields.createConfigMethod,
                        GraphicsJNI::colorTypeToLegacyBitmapConfig(kRGB_565_SkColorType));
                    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);

    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