1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "MediaProfilesJNI" 19 #include <utils/Log.h> 20 21 #include <stdio.h> 22 #include <utils/threads.h> 23 24 #include "jni.h" 25 #include "JNIHelp.h" 26 #include "android_runtime/AndroidRuntime.h" 27 #include <media/MediaProfiles.h> 28 29 using namespace android; 30 31 static Mutex sLock; 32 MediaProfiles *sProfiles = NULL; 33 34 // This function is called from a static block in MediaProfiles.java class, 35 // which won't run until the first time an instance of this class is used. 36 static void 37 android_media_MediaProfiles_native_init(JNIEnv* /* env */) 38 { 39 ALOGV("native_init"); 40 Mutex::Autolock lock(sLock); 41 42 if (sProfiles == NULL) { 43 sProfiles = MediaProfiles::getInstance(); 44 } 45 } 46 47 static jint 48 android_media_MediaProfiles_native_get_num_file_formats(JNIEnv* /* env */, jobject /* thiz */) 49 { 50 ALOGV("native_get_num_file_formats"); 51 return (jint) sProfiles->getOutputFileFormats().size(); 52 } 53 54 static jint 55 android_media_MediaProfiles_native_get_file_format(JNIEnv *env, jobject /* thiz */, jint index) 56 { 57 ALOGV("native_get_file_format: %d", index); 58 Vector<output_format> formats = sProfiles->getOutputFileFormats(); 59 int nSize = formats.size(); 60 if (index < 0 || index >= nSize) { 61 jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary"); 62 return -1; 63 } 64 return static_cast<jint>(formats[index]); 65 } 66 67 static jint 68 android_media_MediaProfiles_native_get_num_video_encoders(JNIEnv* /* env */, jobject /* thiz */) 69 { 70 ALOGV("native_get_num_video_encoders"); 71 return sProfiles->getVideoEncoders().size(); 72 } 73 74 static jobject 75 android_media_MediaProfiles_native_get_video_encoder_cap(JNIEnv *env, jobject /* thiz */, 76 jint index) 77 { 78 ALOGV("native_get_video_encoder_cap: %d", index); 79 Vector<video_encoder> encoders = sProfiles->getVideoEncoders(); 80 int nSize = encoders.size(); 81 if (index < 0 || index >= nSize) { 82 jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary"); 83 return NULL; 84 } 85 86 video_encoder encoder = encoders[index]; 87 int minBitRate = sProfiles->getVideoEncoderParamByName("enc.vid.bps.min", encoder); 88 int maxBitRate = sProfiles->getVideoEncoderParamByName("enc.vid.bps.max", encoder); 89 int minFrameRate = sProfiles->getVideoEncoderParamByName("enc.vid.fps.min", encoder); 90 int maxFrameRate = sProfiles->getVideoEncoderParamByName("enc.vid.fps.max", encoder); 91 int minFrameWidth = sProfiles->getVideoEncoderParamByName("enc.vid.width.min", encoder); 92 int maxFrameWidth = sProfiles->getVideoEncoderParamByName("enc.vid.width.max", encoder); 93 int minFrameHeight = sProfiles->getVideoEncoderParamByName("enc.vid.height.min", encoder); 94 int maxFrameHeight = sProfiles->getVideoEncoderParamByName("enc.vid.height.max", encoder); 95 96 // Check on the values retrieved 97 if ((minBitRate == -1 || maxBitRate == -1) || 98 (minFrameRate == -1 || maxFrameRate == -1) || 99 (minFrameWidth == -1 || maxFrameWidth == -1) || 100 (minFrameHeight == -1 || maxFrameHeight == -1)) { 101 102 jniThrowException(env, "java/lang/RuntimeException", "Error retrieving video encoder capability params"); 103 return NULL; 104 } 105 106 // Construct an instance of the VideoEncoderCap and set its member variables 107 jclass videoEncoderCapClazz = env->FindClass("android/media/EncoderCapabilities$VideoEncoderCap"); 108 jmethodID videoEncoderCapConstructorMethodID = env->GetMethodID(videoEncoderCapClazz, "<init>", "(IIIIIIIII)V"); 109 jobject cap = env->NewObject(videoEncoderCapClazz, 110 videoEncoderCapConstructorMethodID, 111 static_cast<int>(encoder), 112 minBitRate, maxBitRate, 113 minFrameRate, maxFrameRate, 114 minFrameWidth, maxFrameWidth, 115 minFrameHeight, maxFrameHeight); 116 return cap; 117 } 118 119 static jint 120 android_media_MediaProfiles_native_get_num_audio_encoders(JNIEnv* /* env */, jobject /* thiz */) 121 { 122 ALOGV("native_get_num_audio_encoders"); 123 return (jint) sProfiles->getAudioEncoders().size(); 124 } 125 126 static jobject 127 android_media_MediaProfiles_native_get_audio_encoder_cap(JNIEnv *env, jobject /* thiz */, 128 jint index) 129 { 130 ALOGV("native_get_audio_encoder_cap: %d", index); 131 Vector<audio_encoder> encoders = sProfiles->getAudioEncoders(); 132 int nSize = encoders.size(); 133 if (index < 0 || index >= nSize) { 134 jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary"); 135 return NULL; 136 } 137 138 audio_encoder encoder = encoders[index]; 139 int minBitRate = sProfiles->getAudioEncoderParamByName("enc.aud.bps.min", encoder); 140 int maxBitRate = sProfiles->getAudioEncoderParamByName("enc.aud.bps.max", encoder); 141 int minSampleRate = sProfiles->getAudioEncoderParamByName("enc.aud.hz.min", encoder); 142 int maxSampleRate = sProfiles->getAudioEncoderParamByName("enc.aud.hz.max", encoder); 143 int minChannels = sProfiles->getAudioEncoderParamByName("enc.aud.ch.min", encoder); 144 int maxChannels = sProfiles->getAudioEncoderParamByName("enc.aud.ch.max", encoder); 145 146 // Check on the values retrieved 147 if ((minBitRate == -1 || maxBitRate == -1) || 148 (minSampleRate == -1 || maxSampleRate == -1) || 149 (minChannels == -1 || maxChannels == -1)) { 150 151 jniThrowException(env, "java/lang/RuntimeException", "Error retrieving video encoder capability params"); 152 return NULL; 153 } 154 155 jclass audioEncoderCapClazz = env->FindClass("android/media/EncoderCapabilities$AudioEncoderCap"); 156 jmethodID audioEncoderCapConstructorMethodID = env->GetMethodID(audioEncoderCapClazz, "<init>", "(IIIIIII)V"); 157 jobject cap = env->NewObject(audioEncoderCapClazz, 158 audioEncoderCapConstructorMethodID, 159 static_cast<int>(encoder), 160 minBitRate, maxBitRate, 161 minSampleRate, maxSampleRate, 162 minChannels, maxChannels); 163 return cap; 164 } 165 166 static bool isCamcorderQualityKnown(int quality) 167 { 168 return ((quality >= CAMCORDER_QUALITY_LIST_START && 169 quality <= CAMCORDER_QUALITY_LIST_END) || 170 (quality >= CAMCORDER_QUALITY_TIME_LAPSE_LIST_START && 171 quality <= CAMCORDER_QUALITY_TIME_LAPSE_LIST_END) || 172 (quality >= CAMCORDER_QUALITY_HIGH_SPEED_LIST_START && 173 quality <= CAMCORDER_QUALITY_HIGH_SPEED_LIST_END)); 174 } 175 176 static jobject 177 android_media_MediaProfiles_native_get_camcorder_profile(JNIEnv *env, jobject /* thiz */, jint id, 178 jint quality) 179 { 180 ALOGV("native_get_camcorder_profile: %d %d", id, quality); 181 if (!isCamcorderQualityKnown(quality)) { 182 jniThrowException(env, "java/lang/RuntimeException", "Unknown camcorder profile quality"); 183 return NULL; 184 } 185 186 camcorder_quality q = static_cast<camcorder_quality>(quality); 187 int duration = sProfiles->getCamcorderProfileParamByName("duration", id, q); 188 int fileFormat = sProfiles->getCamcorderProfileParamByName("file.format", id, q); 189 int videoCodec = sProfiles->getCamcorderProfileParamByName("vid.codec", id, q); 190 int videoBitRate = sProfiles->getCamcorderProfileParamByName("vid.bps", id, q); 191 int videoFrameRate = sProfiles->getCamcorderProfileParamByName("vid.fps", id, q); 192 int videoFrameWidth = sProfiles->getCamcorderProfileParamByName("vid.width", id, q); 193 int videoFrameHeight = sProfiles->getCamcorderProfileParamByName("vid.height", id, q); 194 int audioCodec = sProfiles->getCamcorderProfileParamByName("aud.codec", id, q); 195 int audioBitRate = sProfiles->getCamcorderProfileParamByName("aud.bps", id, q); 196 int audioSampleRate = sProfiles->getCamcorderProfileParamByName("aud.hz", id, q); 197 int audioChannels = sProfiles->getCamcorderProfileParamByName("aud.ch", id, q); 198 199 // Check on the values retrieved 200 if (duration == -1 || fileFormat == -1 || videoCodec == -1 || audioCodec == -1 || 201 videoBitRate == -1 || videoFrameRate == -1 || videoFrameWidth == -1 || videoFrameHeight == -1 || 202 audioBitRate == -1 || audioSampleRate == -1 || audioChannels == -1) { 203 204 jniThrowException(env, "java/lang/RuntimeException", "Error retrieving camcorder profile params"); 205 return NULL; 206 } 207 208 jclass camcorderProfileClazz = env->FindClass("android/media/CamcorderProfile"); 209 jmethodID camcorderProfileConstructorMethodID = env->GetMethodID(camcorderProfileClazz, "<init>", "(IIIIIIIIIIII)V"); 210 return env->NewObject(camcorderProfileClazz, 211 camcorderProfileConstructorMethodID, 212 duration, 213 quality, 214 fileFormat, 215 videoCodec, 216 videoBitRate, 217 videoFrameRate, 218 videoFrameWidth, 219 videoFrameHeight, 220 audioCodec, 221 audioBitRate, 222 audioSampleRate, 223 audioChannels); 224 } 225 226 static jboolean 227 android_media_MediaProfiles_native_has_camcorder_profile(JNIEnv* /* env */, jobject /* thiz */, 228 jint id, jint quality) 229 { 230 ALOGV("native_has_camcorder_profile: %d %d", id, quality); 231 if (!isCamcorderQualityKnown(quality)) { 232 return JNI_FALSE; 233 } 234 235 camcorder_quality q = static_cast<camcorder_quality>(quality); 236 return sProfiles->hasCamcorderProfile(id, q) ? JNI_TRUE : JNI_FALSE; 237 } 238 239 static jint 240 android_media_MediaProfiles_native_get_num_video_decoders(JNIEnv* /* env */, jobject /* thiz */) 241 { 242 ALOGV("native_get_num_video_decoders"); 243 return (jint) sProfiles->getVideoDecoders().size(); 244 } 245 246 static jint 247 android_media_MediaProfiles_native_get_video_decoder_type(JNIEnv *env, jobject /* thiz */, 248 jint index) 249 { 250 ALOGV("native_get_video_decoder_type: %d", index); 251 Vector<video_decoder> decoders = sProfiles->getVideoDecoders(); 252 int nSize = decoders.size(); 253 if (index < 0 || index >= nSize) { 254 jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary"); 255 return -1; 256 } 257 258 return static_cast<jint>(decoders[index]); 259 } 260 261 static jint 262 android_media_MediaProfiles_native_get_num_audio_decoders(JNIEnv* /* env */, jobject /* thiz */) 263 { 264 ALOGV("native_get_num_audio_decoders"); 265 return (jint) sProfiles->getAudioDecoders().size(); 266 } 267 268 static jint 269 android_media_MediaProfiles_native_get_audio_decoder_type(JNIEnv *env, jobject /* thiz */, 270 jint index) 271 { 272 ALOGV("native_get_audio_decoder_type: %d", index); 273 Vector<audio_decoder> decoders = sProfiles->getAudioDecoders(); 274 int nSize = decoders.size(); 275 if (index < 0 || index >= nSize) { 276 jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary"); 277 return -1; 278 } 279 280 return static_cast<jint>(decoders[index]); 281 } 282 283 static jint 284 android_media_MediaProfiles_native_get_num_image_encoding_quality_levels(JNIEnv* /* env */, 285 jobject /* thiz */, 286 jint cameraId) 287 { 288 ALOGV("native_get_num_image_encoding_quality_levels"); 289 return (jint) sProfiles->getImageEncodingQualityLevels(cameraId).size(); 290 } 291 292 static jint 293 android_media_MediaProfiles_native_get_image_encoding_quality_level(JNIEnv *env, jobject /* thiz */, 294 jint cameraId, jint index) 295 { 296 ALOGV("native_get_image_encoding_quality_level"); 297 Vector<int> levels = sProfiles->getImageEncodingQualityLevels(cameraId); 298 if (index < 0 || index >= (jint) levels.size()) { 299 jniThrowException(env, "java/lang/IllegalArgumentException", "out of array boundary"); 300 return -1; 301 } 302 return static_cast<jint>(levels[index]); 303 } 304 static const JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = { 305 {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, 306 {"native_get_num_file_formats", "()I", (void *)android_media_MediaProfiles_native_get_num_file_formats}, 307 {"native_get_file_format", "(I)I", (void *)android_media_MediaProfiles_native_get_file_format}, 308 {"native_get_num_video_encoders", "()I", (void *)android_media_MediaProfiles_native_get_num_video_encoders}, 309 {"native_get_num_audio_encoders", "()I", (void *)android_media_MediaProfiles_native_get_num_audio_encoders}, 310 311 {"native_get_video_encoder_cap", "(I)Landroid/media/EncoderCapabilities$VideoEncoderCap;", 312 (void *)android_media_MediaProfiles_native_get_video_encoder_cap}, 313 314 {"native_get_audio_encoder_cap", "(I)Landroid/media/EncoderCapabilities$AudioEncoderCap;", 315 (void *)android_media_MediaProfiles_native_get_audio_encoder_cap}, 316 }; 317 318 static const JNINativeMethod gMethodsForCamcorderProfileClass[] = { 319 {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, 320 {"native_get_camcorder_profile", "(II)Landroid/media/CamcorderProfile;", 321 (void *)android_media_MediaProfiles_native_get_camcorder_profile}, 322 {"native_has_camcorder_profile", "(II)Z", 323 (void *)android_media_MediaProfiles_native_has_camcorder_profile}, 324 }; 325 326 static const JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = { 327 {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, 328 {"native_get_num_video_decoders", "()I", (void *)android_media_MediaProfiles_native_get_num_video_decoders}, 329 {"native_get_num_audio_decoders", "()I", (void *)android_media_MediaProfiles_native_get_num_audio_decoders}, 330 {"native_get_video_decoder_type", "(I)I", (void *)android_media_MediaProfiles_native_get_video_decoder_type}, 331 {"native_get_audio_decoder_type", "(I)I", (void *)android_media_MediaProfiles_native_get_audio_decoder_type}, 332 }; 333 334 static const JNINativeMethod gMethodsForCameraProfileClass[] = { 335 {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, 336 {"native_get_num_image_encoding_quality_levels", 337 "(I)I", (void *)android_media_MediaProfiles_native_get_num_image_encoding_quality_levels}, 338 {"native_get_image_encoding_quality_level","(II)I", (void *)android_media_MediaProfiles_native_get_image_encoding_quality_level}, 339 }; 340 341 static const char* const kEncoderCapabilitiesClassPathName = "android/media/EncoderCapabilities"; 342 static const char* const kDecoderCapabilitiesClassPathName = "android/media/DecoderCapabilities"; 343 static const char* const kCamcorderProfileClassPathName = "android/media/CamcorderProfile"; 344 static const char* const kCameraProfileClassPathName = "android/media/CameraProfile"; 345 346 // This function only registers the native methods, and is called from 347 // JNI_OnLoad in android_media_MediaPlayer.cpp 348 int register_android_media_MediaProfiles(JNIEnv *env) 349 { 350 int ret1 = AndroidRuntime::registerNativeMethods(env, 351 kEncoderCapabilitiesClassPathName, 352 gMethodsForEncoderCapabilitiesClass, 353 NELEM(gMethodsForEncoderCapabilitiesClass)); 354 355 int ret2 = AndroidRuntime::registerNativeMethods(env, 356 kCamcorderProfileClassPathName, 357 gMethodsForCamcorderProfileClass, 358 NELEM(gMethodsForCamcorderProfileClass)); 359 360 int ret3 = AndroidRuntime::registerNativeMethods(env, 361 kDecoderCapabilitiesClassPathName, 362 gMethodsForDecoderCapabilitiesClass, 363 NELEM(gMethodsForDecoderCapabilitiesClass)); 364 365 int ret4 = AndroidRuntime::registerNativeMethods(env, 366 kCameraProfileClassPathName, 367 gMethodsForCameraProfileClass, 368 NELEM(gMethodsForCameraProfileClass)); 369 370 // Success if all return values from above are 0 371 return (ret1 || ret2 || ret3 || ret4); 372 } 373