Android平台上从Camera的jpegquality菜单研究JNI接口(二)

 

3、  Jpeg quality参数的获取

在文件CameraProfile.java中,有下面的code

    static {

        System.loadLibrary("media_jni");

        native_init();

        sJpegEncodingQualityParameters = getImageEncodingQualityLevels();

}

private static int[] getImageEncodingQualityLevels() {

        int nLevels = native_get_num_image_encoding_quality_levels();

        if (nLevels != QUALITY_HIGH + 1) {

            throw new RuntimeException("Unexpected Jpeg encoding quality levels " + nLevels);

        }

 

        int[] levels = new int[nLevels];

        for (int i = 0; i < nLevels; ++i) {

            levels[i] = native_get_image_encoding_quality_level(i);

        }

        Arrays.sort(levels);  // Lower quality level ALWAYS comes before higher one

        return levels;

    }

 

    // Methods implemented by JNI

    private static native final void native_init();

    private static native final int native_get_num_image_encoding_quality_levels();

    private static native final int native_get_image_encoding_quality_level(int index);

}

存储jpeg quality参数的数组sJpegEncodingQualityParameters由函数

getImageEncodingQualityLevels()产生,在该函数中调用了JNI接口

native_get_num_image_encoding_quality_levels()获取了quality等级的数目,然后又通过native_get_image_encoding_quality_level(i)获取每个等级对应的值,并通过Arrays.sort(levels)对这些值进行了排序,最好返回给数组

sJpegEncodingQualityParameters

这里动态加载了库media_jni,并且调用了三个JNI接口,下面我们对JNI层的相关code做以介绍。

 

二、        JNI层介绍

1、  JNI接口注册

在文件/framework/base/media/java/android/media/CameraProfile.java中,code

System.loadLibrary("media_jni");动态加载了库media_jni,同时会调用文件

/framework/base/media/jni/android_media_MediaPlayer.cpp中的函数JNI_OnLoad()。它负责注册android里的JNI接口。其具体code如下:

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

    JNIEnv* env = NULL;

    jint result = -1;

 

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

        LOGE("ERROR: GetEnv failed/n");

        goto bail;

    }

    assert(env != NULL);

 

    if (register_android_media_MediaPlayer(env) < 0) {

        LOGE("ERROR: MediaPlayer native registration failed/n");

        goto bail;

    }

 

    if (register_android_media_MediaRecorder(env) < 0) {

        LOGE("ERROR: MediaRecorder native registration failed/n");

        goto bail;

    }

 

    if (register_android_media_MediaPhone(env) < 0) {

        LOGE("ERROR: MediaPhone native registration failed/n");

        goto bail;

    }

 

    if (register_android_media_MediaScanner(env) < 0) {

        LOGE("ERROR: MediaScanner native registration failed/n");

        goto bail;

    }

 

    if (register_android_media_MediaMetadataRetriever(env) < 0) {

        LOGE("ERROR: MediaMetadataRetriever native registration failed/n");

        goto bail;

    }

 

#ifndef NO_OPENCORE

    if (register_android_media_AmrInputStream(env) < 0) {

        LOGE("ERROR: AmrInputStream native registration failed/n");

        goto bail;

    }

#endif

 

    if (register_android_media_ResampleInputStream(env) < 0) {

        LOGE("ERROR: ResampleInputStream native registration failed/n");

        goto bail;

    }

 

    if (register_android_media_MediaProfiles(env) < 0) {

        LOGE("ERROR: MediaProfiles native registration failed");

        goto bail;

    }

 

    /* success -- return valid version number */

    result = JNI_VERSION_1_4;

 

bail:

    return result;

}

该函数注册了media相关的各大模块的JNI接口,其中包括MediaPlayerMediaRecorderMediaPhone等,当然也包括MediaProfiles

函数register_android_media_MediaProfiles()被定义在文件

/framework/base/media/jni/android_media_MediaProfiles.cpp中。其具体code为:

int register_android_media_MediaProfiles(JNIEnv *env)

{

    int ret1 = AndroidRuntime::registerNativeMethods(env,

               kEncoderCapabilitiesClassPathName,

               gMethodsForEncoderCapabilitiesClass,

               NELEM(gMethodsForEncoderCapabilitiesClass));

 

    int ret2 = AndroidRuntime::registerNativeMethods(env,

               kCamcorderProfileClassPathName,

               gMethodsForCamcorderProfileClass,

               NELEM(gMethodsForCamcorderProfileClass));

 

    int ret3 = AndroidRuntime::registerNativeMethods(env,

               kDecoderCapabilitiesClassPathName,

               gMethodsForDecoderCapabilitiesClass,

               NELEM(gMethodsForDecoderCapabilitiesClass));

 

    int ret4 = AndroidRuntime::registerNativeMethods(env,

               kCameraProfileClassPathName,

               gMethodsForCameraProfileClass,

               NELEM(gMethodsForCameraProfileClass));

 

    // Success if all return values from above are 0

    return (ret1 || ret2 || ret3 || ret4);

}

cameraprofiles相关的是ret4对应的函数,其中,kCameraProfileClassPathName定义为:

static const char* const kCameraProfileClassPathName =

                                            "android/media/CameraProfile";

    这代表什么意思,尚未完全清楚,暂时不写了。

数组gMethodsForCameraProfileClass包含了CameraProfile中所定义的所有JNI接口,其具体定义为:

static JNINativeMethod gMethodsForCameraProfileClass[] = {

    {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},

    {"native_get_num_image_encoding_quality_levels",

                                               "()I",                    (void *)android_media_MediaProfiles_native_get_num_image_encoding_quality_levels},

    {"native_get_image_encoding_quality_level","(I)I",                   (void *)android_media_MediaProfiles_native_get_image_encoding_quality_level},

};

 

2、  JNI接口实现

上面注册的几个JNI接口的具体定义也在文件

/framework/base/media/jni/android_media_MediaProfiles.cpp中,其具体code 为:

MediaProfiles *sProfiles = NULL;

 

// This function is called from a static block in MediaProfiles.java class,

// which won't run until the first time an instance of this class is used.

static void

android_media_MediaProfiles_native_init(JNIEnv *env)

{

    LOGV("native_init");

    Mutex::Autolock lock(sLock);

 

    if (sProfiles == NULL) {

        sProfiles = MediaProfiles::getInstance();

    }

}

 

static jint

android_media_MediaProfiles_native_get_num_image_encoding_quality_levels(JNIEnv *env, jobject thiz)

{

    LOGV("native_get_num_image_encoding_quality_levels");

    return sProfiles->getImageEncodingQualityLevels().size();

}

 

static jint

android_media_MediaProfiles_native_get_image_encoding_quality_level(JNIEnv *env, jobject thiz, jint index)

{

    LOGV("native_get_image_encoding_quality_level");

    Vector<int> levels = sProfiles->getImageEncodingQualityLevels();

    if (index < 0 || index >= levels.size()) {

        jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary");

        return -1;

    }

    return static_cast<jint>(levels[index]);

}

这里调用MediaProfilesgetInstance()getImageEncodingQualityLevels(),这些函数如何实现,需要看看libmedia层的介绍了。

 (待续)

你可能感兴趣的:(Android平台上从Camera的jpegquality菜单研究JNI接口(二))