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接口,其中包括MediaPlayer,MediaRecorder,MediaPhone等,当然也包括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]);
}
这里调用MediaProfiles的getInstance()和getImageEncodingQualityLevels(),这些函数如何实现,需要看看libmedia层的介绍了。
(待续)