android_hardware_Camera.cpp revision 2387208c9ecb5dba01bd933312c80c5133bd3c41
1/* 2** 3** Copyright 2008, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18//#define LOG_NDEBUG 0 19#define LOG_TAG "Camera-JNI" 20#include <utils/Log.h> 21 22#include "jni.h" 23#include "JNIHelp.h" 24#include "android_runtime/AndroidRuntime.h" 25 26#include <ui/Surface.h> 27#include <ui/Camera.h> 28#include <binder/IMemory.h> 29 30using namespace android; 31 32enum CallbackMessageID { 33 kShutterCallback = 0, 34 kRawCallback = 1, 35 kJpegCallback = 2, 36 kPreviewCallback = 3, 37 kAutoFocusCallback = 4, 38 kErrorCallback = 5 39}; 40 41enum CameraError { 42 kCameraErrorUnknown = 1, 43 kCameraErrorMediaServer = 100 44}; 45 46 47struct fields_t { 48 jfieldID context; 49 jfieldID surface; 50 jmethodID post_event; 51}; 52 53static fields_t fields; 54static Mutex sLock; 55 56// provides persistent context for calls from native code to Java 57class JNICameraContext: public CameraListener 58{ 59public: 60 JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera); 61 ~JNICameraContext() { release(); } 62 virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); 63 virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); 64 sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } 65 void release(); 66 67private: 68 void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); 69 70 jobject mCameraJObjectWeak; // weak reference to java object 71 jclass mCameraJClass; // strong reference to java class 72 sp<Camera> mCamera; // strong reference to native object 73 Mutex mLock; 74}; 75 76sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) 77{ 78 sp<Camera> camera; 79 Mutex::Autolock _l(sLock); 80 JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 81 if (context != NULL) { 82 camera = context->getCamera(); 83 } 84 LOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); 85 if (camera == 0) { 86 jniThrowException(env, "java/lang/RuntimeException", "Method called after release()"); 87 } 88 89 if (pContext != NULL) *pContext = context; 90 return camera; 91} 92 93JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera) 94{ 95 mCameraJObjectWeak = env->NewGlobalRef(weak_this); 96 mCameraJClass = (jclass)env->NewGlobalRef(clazz); 97 mCamera = camera; 98} 99 100void JNICameraContext::release() 101{ 102 LOGV("release"); 103 Mutex::Autolock _l(mLock); 104 JNIEnv *env = AndroidRuntime::getJNIEnv(); 105 106 if (mCameraJObjectWeak != NULL) { 107 env->DeleteGlobalRef(mCameraJObjectWeak); 108 mCameraJObjectWeak = NULL; 109 } 110 if (mCameraJClass != NULL) { 111 env->DeleteGlobalRef(mCameraJClass); 112 mCameraJClass = NULL; 113 } 114 mCamera.clear(); 115} 116 117void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2) 118{ 119 LOGV("notify"); 120 121 // VM pointer will be NULL if object is released 122 Mutex::Autolock _l(mLock); 123 if (mCameraJObjectWeak == NULL) { 124 LOGW("callback on dead camera object"); 125 return; 126 } 127 JNIEnv *env = AndroidRuntime::getJNIEnv(); 128 129 // parse message 130 switch (msgType) { 131 case CAMERA_MSG_ERROR: 132 LOGV("errorCallback"); 133 int error; 134 switch (ext1) { 135 case DEAD_OBJECT: 136 error = kCameraErrorMediaServer; 137 break; 138 default: 139 error = kCameraErrorUnknown; 140 break; 141 } 142 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 143 mCameraJObjectWeak, kErrorCallback, error, 0, NULL); 144 break; 145 case CAMERA_MSG_FOCUS: 146 LOGV("autoFocusCallback"); 147 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 148 mCameraJObjectWeak, kAutoFocusCallback, ext1, 0, NULL); 149 break; 150 case CAMERA_MSG_SHUTTER: 151 LOGV("shutterCallback"); 152 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 153 mCameraJObjectWeak, kShutterCallback, 0, 0, NULL); 154 break; 155 default: 156 LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2); 157 break; 158 } 159} 160 161void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) 162{ 163 jbyteArray obj = NULL; 164 165 // allocate Java byte array and copy data 166 if (dataPtr != NULL) { 167 ssize_t offset; 168 size_t size; 169 sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size); 170 LOGV("postData: off=%d, size=%d", offset, size); 171 uint8_t *heapBase = (uint8_t*)heap->base(); 172 173 if (heapBase != NULL) { 174 uint8_t *data = heapBase + offset; 175 obj = env->NewByteArray(size); 176 if (obj == NULL) { 177 LOGE("Couldn't allocate byte array for JPEG data"); 178 env->ExceptionClear(); 179 } else { 180 jbyte *bytes = env->GetByteArrayElements(obj, NULL); 181 memcpy(bytes, data, size); 182 env->ReleaseByteArrayElements(obj, bytes, 0); 183 184 } 185 } else { 186 LOGE("image heap is NULL"); 187 } 188 } 189 190 // post image data to Java 191 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 192 mCameraJObjectWeak, msgType, 0, 0, obj); 193 if (obj) { 194 env->DeleteLocalRef(obj); 195 } 196} 197 198void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) 199{ 200 // VM pointer will be NULL if object is released 201 Mutex::Autolock _l(mLock); 202 JNIEnv *env = AndroidRuntime::getJNIEnv(); 203 204 // return data based on callback type 205 switch(msgType) { 206 case CAMERA_MSG_PREVIEW_FRAME: 207 LOGV("previewCallback"); 208 copyAndPost(env, dataPtr, kPreviewCallback); 209 break; 210 case CAMERA_MSG_VIDEO_FRAME: 211 LOGV("recordingCallback"); 212 break; 213 case CAMERA_MSG_RAW_IMAGE: 214 LOGV("rawCallback"); 215 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 216 mCameraJObjectWeak, kRawCallback, 0, 0, NULL); 217 break; 218 case CAMERA_MSG_COMPRESSED_IMAGE: 219 LOGV("jpegCallback"); 220 copyAndPost(env, dataPtr, kJpegCallback); 221 break; 222 default: 223 LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); 224 break; 225 } 226 227} 228 229// connect to camera service 230static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) 231{ 232 sp<Camera> camera = Camera::connect(); 233 234 if (camera == NULL) { 235 jniThrowException(env, "java/lang/RuntimeException", 236 "Fail to connect to camera service"); 237 return; 238 } 239 240 // make sure camera hardware is alive 241 if (camera->getStatus() != NO_ERROR) { 242 jniThrowException(env, "java/lang/RuntimeException", "Camera initialization failed"); 243 return; 244 } 245 246 jclass clazz = env->GetObjectClass(thiz); 247 if (clazz == NULL) { 248 jniThrowException(env, "java/lang/RuntimeException", "Can't find android/hardware/Camera"); 249 return; 250 } 251 252 // We use a weak reference so the Camera object can be garbage collected. 253 // The reference is only used as a proxy for callbacks. 254 sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera); 255 context->incStrong(thiz); 256 camera->setListener(context); 257 258 // save context in opaque field 259 env->SetIntField(thiz, fields.context, (int)context.get()); 260} 261 262// disconnect from camera service 263// It's okay to call this when the native camera context is already null. 264// This handles the case where the user has called release() and the 265// finalizer is invoked later. 266static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) 267{ 268 JNICameraContext* context = NULL; 269 sp<Camera> camera; 270 { 271 Mutex::Autolock _l(sLock); 272 context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 273 274 // Make sure we do not attempt to callback on a deleted Java object. 275 env->SetIntField(thiz, fields.context, 0); 276 } 277 278 // clean up if release has not been called before 279 if (context != NULL) { 280 camera = context->getCamera(); 281 context->release(); 282 LOGV("native_release: context=%p camera=%p", context, camera.get()); 283 284 // clear callbacks 285 if (camera != NULL) { 286 camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); 287 camera->disconnect(); 288 } 289 290 // remove context to prevent further Java access 291 context->decStrong(thiz); 292 } 293} 294 295static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface) 296{ 297 LOGV("setPreviewDisplay"); 298 sp<Camera> camera = get_native_camera(env, thiz, NULL); 299 if (camera == 0) return; 300 301 sp<Surface> surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface)); 302 if (camera->setPreviewDisplay(surface) != NO_ERROR) { 303 jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed"); 304 } 305} 306 307static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) 308{ 309 LOGV("startPreview"); 310 sp<Camera> camera = get_native_camera(env, thiz, NULL); 311 if (camera == 0) return; 312 313 if (camera->startPreview() != NO_ERROR) { 314 jniThrowException(env, "java/lang/RuntimeException", "startPreview failed"); 315 return; 316 } 317} 318 319static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz) 320{ 321 LOGV("stopPreview"); 322 sp<Camera> c = get_native_camera(env, thiz, NULL); 323 if (c == 0) return; 324 325 c->stopPreview(); 326} 327 328static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz) 329{ 330 LOGV("previewEnabled"); 331 sp<Camera> c = get_native_camera(env, thiz, NULL); 332 if (c == 0) return false; 333 334 return c->previewEnabled(); 335} 336 337static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean oneshot) 338{ 339 // Important: Only install preview_callback if the Java code has called 340 // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy 341 // each preview frame for nothing. 342 JNICameraContext* context; 343 sp<Camera> camera = get_native_camera(env, thiz, &context); 344 if (camera == 0) return; 345 346 int callback_flag; 347 if (installed) { 348 callback_flag = oneshot ? FRAME_CALLBACK_FLAG_BARCODE_SCANNER : FRAME_CALLBACK_FLAG_CAMERA; 349 } else { 350 callback_flag = FRAME_CALLBACK_FLAG_NOOP; 351 } 352 camera->setPreviewCallbackFlags(callback_flag); 353} 354 355static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) 356{ 357 LOGV("autoFocus"); 358 JNICameraContext* context; 359 sp<Camera> c = get_native_camera(env, thiz, &context); 360 if (c == 0) return; 361 362 if (c->autoFocus() != NO_ERROR) { 363 jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed"); 364 } 365} 366 367static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) 368{ 369 LOGV("takePicture"); 370 JNICameraContext* context; 371 sp<Camera> camera = get_native_camera(env, thiz, &context); 372 if (camera == 0) return; 373 374 if (camera->takePicture() != NO_ERROR) { 375 jniThrowException(env, "java/lang/RuntimeException", "takePicture failed"); 376 return; 377 } 378} 379 380static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) 381{ 382 LOGV("setParameters"); 383 sp<Camera> camera = get_native_camera(env, thiz, NULL); 384 if (camera == 0) return; 385 386 const jchar* str = env->GetStringCritical(params, 0); 387 String8 params8; 388 if (params) { 389 params8 = String8(str, env->GetStringLength(params)); 390 env->ReleaseStringCritical(params, str); 391 } 392 if (camera->setParameters(params8) != NO_ERROR) { 393 jniThrowException(env, "java/lang/RuntimeException", "setParameters failed"); 394 return; 395 } 396} 397 398static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz) 399{ 400 LOGV("getParameters"); 401 sp<Camera> camera = get_native_camera(env, thiz, NULL); 402 if (camera == 0) return 0; 403 404 return env->NewStringUTF(camera->getParameters().string()); 405} 406 407static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz) 408{ 409 LOGV("reconnect"); 410 sp<Camera> camera = get_native_camera(env, thiz, NULL); 411 if (camera == 0) return; 412 413 if (camera->reconnect() != NO_ERROR) { 414 jniThrowException(env, "java/io/IOException", "reconnect failed"); 415 return; 416 } 417} 418 419static jint android_hardware_Camera_lock(JNIEnv *env, jobject thiz) 420{ 421 LOGV("lock"); 422 sp<Camera> camera = get_native_camera(env, thiz, NULL); 423 if (camera == 0) return INVALID_OPERATION; 424 return (jint) camera->lock(); 425} 426 427static jint android_hardware_Camera_unlock(JNIEnv *env, jobject thiz) 428{ 429 LOGV("unlock"); 430 sp<Camera> camera = get_native_camera(env, thiz, NULL); 431 if (camera == 0) return INVALID_OPERATION; 432 return (jint) camera->unlock(); 433} 434 435//------------------------------------------------- 436 437static JNINativeMethod camMethods[] = { 438 { "native_setup", 439 "(Ljava/lang/Object;)V", 440 (void*)android_hardware_Camera_native_setup }, 441 { "native_release", 442 "()V", 443 (void*)android_hardware_Camera_release }, 444 { "setPreviewDisplay", 445 "(Landroid/view/Surface;)V", 446 (void *)android_hardware_Camera_setPreviewDisplay }, 447 { "startPreview", 448 "()V", 449 (void *)android_hardware_Camera_startPreview }, 450 { "stopPreview", 451 "()V", 452 (void *)android_hardware_Camera_stopPreview }, 453 { "previewEnabled", 454 "()Z", 455 (void *)android_hardware_Camera_previewEnabled }, 456 { "setHasPreviewCallback", 457 "(ZZ)V", 458 (void *)android_hardware_Camera_setHasPreviewCallback }, 459 { "native_autoFocus", 460 "()V", 461 (void *)android_hardware_Camera_autoFocus }, 462 { "native_takePicture", 463 "()V", 464 (void *)android_hardware_Camera_takePicture }, 465 { "native_setParameters", 466 "(Ljava/lang/String;)V", 467 (void *)android_hardware_Camera_setParameters }, 468 { "native_getParameters", 469 "()Ljava/lang/String;", 470 (void *)android_hardware_Camera_getParameters }, 471 { "reconnect", 472 "()V", 473 (void*)android_hardware_Camera_reconnect }, 474 { "lock", 475 "()I", 476 (void*)android_hardware_Camera_lock }, 477 { "unlock", 478 "()I", 479 (void*)android_hardware_Camera_unlock }, 480}; 481 482struct field { 483 const char *class_name; 484 const char *field_name; 485 const char *field_type; 486 jfieldID *jfield; 487}; 488 489static int find_fields(JNIEnv *env, field *fields, int count) 490{ 491 for (int i = 0; i < count; i++) { 492 field *f = &fields[i]; 493 jclass clazz = env->FindClass(f->class_name); 494 if (clazz == NULL) { 495 LOGE("Can't find %s", f->class_name); 496 return -1; 497 } 498 499 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type); 500 if (field == NULL) { 501 LOGE("Can't find %s.%s", f->class_name, f->field_name); 502 return -1; 503 } 504 505 *(f->jfield) = field; 506 } 507 508 return 0; 509} 510 511// Get all the required offsets in java class and register native functions 512int register_android_hardware_Camera(JNIEnv *env) 513{ 514 field fields_to_find[] = { 515 { "android/hardware/Camera", "mNativeContext", "I", &fields.context }, 516 { "android/view/Surface", "mSurface", "I", &fields.surface } 517 }; 518 519 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) 520 return -1; 521 522 jclass clazz = env->FindClass("android/hardware/Camera"); 523 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 524 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 525 if (fields.post_event == NULL) { 526 LOGE("Can't find android/hardware/Camera.postEventFromNative"); 527 return -1; 528 } 529 530 531 // Register native functions 532 return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera", 533 camMethods, NELEM(camMethods)); 534} 535 536