android_hardware_Camera.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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 <utils/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 56struct camera_context_t { 57 jobject mCameraJObjectWeak; // weak reference to java object 58 jclass mCameraJClass; // strong reference to java class 59 sp<Camera> mCamera; // strong reference to native object 60}; 61 62sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pContext) 63{ 64 sp<Camera> camera; 65 Mutex::Autolock _l(sLock); 66 camera_context_t* context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context)); 67 if (context != NULL) { 68 camera = context->mCamera; 69 } 70 LOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); 71 if (camera == 0) { 72 jniThrowException(env, "java/lang/RuntimeException", "Method called after release()"); 73 } 74 75 if (pContext != NULL) *pContext = context; 76 return camera; 77} 78 79static void err_callback(status_t err, void *cookie) 80{ 81 camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); 82 if ((context == NULL) || (context->mCamera == 0)) return; 83 84 LOGV("err_callback: context=%p, camera=%p", context, context->mCamera.get()); 85 86 int error; 87 switch (err) { 88 case DEAD_OBJECT: 89 error = kCameraErrorMediaServer; 90 break; 91 default: 92 error = kCameraErrorUnknown; 93 break; 94 } 95 96 JNIEnv *env = AndroidRuntime::getJNIEnv(); 97 if (env == NULL) { 98 LOGE("err_callback on dead VM"); 99 return; 100 } 101 env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, 102 context->mCameraJObjectWeak, kErrorCallback, error, 0, NULL); 103} 104 105// connect to camera service 106static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) 107{ 108 sp<Camera> camera = Camera::connect(); 109 110 if (camera == NULL) { 111 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 112 return; 113 } 114 115 // make sure camera hardware is alive 116 if (camera->getStatus() != NO_ERROR) { 117 jniThrowException(env, "java/io/IOException", "Camera initialization failed"); 118 return; 119 } 120 121 jclass clazz = env->GetObjectClass(thiz); 122 if (clazz == NULL) { 123 LOGE("Can't find android/hardware/Camera"); 124 // XXX no idea what to throw here, can this even happen? 125 jniThrowException(env, "java/lang/Exception", NULL); 126 return; 127 } 128 129 // We use a weak reference so the Camera object can be garbage collected. 130 // The reference is only used as a proxy for callbacks. 131 camera_context_t* context = new camera_context_t; 132 context->mCameraJObjectWeak = env->NewGlobalRef(weak_this); 133 context->mCameraJClass = (jclass)env->NewGlobalRef(clazz); 134 context->mCamera = camera; 135 136 // save context in opaque field 137 env->SetIntField(thiz, fields.context, (int)context); 138 139 LOGV("native_setup: mCameraJObjectWeak=%x, camera_obj=%x, context=%p", 140 (int)context->mCameraJObjectWeak, (int)thiz, context); 141 142 // set error callback 143 camera->setErrorCallback(err_callback, context); 144} 145 146// disconnect from camera service 147// It's okay to call this when the native camera context is already null. 148// This handles the case where the user has called release() and the 149// finalizer is invoked later. 150static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) 151{ 152 camera_context_t* context = NULL; 153 sp<Camera> camera; 154 { 155 Mutex::Autolock _l(sLock); 156 context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context)); 157 158 // Make sure we do not attempt to callback on a deleted Java object. 159 env->SetIntField(thiz, fields.context, 0); 160 } 161 162 // clean up if release has not been called before 163 if (context != NULL) { 164 camera = context->mCamera; 165 context->mCamera.clear(); 166 LOGV("native_release: context=%p camera=%p", context, camera.get()); 167 168 // clear callbacks 169 if (camera != NULL) { 170 camera->setPreviewCallback(NULL, NULL, FRAME_CALLBACK_FLAG_NOOP); 171 camera->setErrorCallback(NULL, NULL); 172 camera->disconnect(); 173 env->DeleteGlobalRef(context->mCameraJObjectWeak); 174 env->DeleteGlobalRef(context->mCameraJClass); 175 } 176 177 // remove context to prevent further Java access 178 delete context; 179 } 180} 181 182static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface) 183{ 184 LOGV("setPreviewDisplay"); 185 sp<Camera> camera = get_native_camera(env, thiz, NULL); 186 if (camera == 0) return; 187 188 sp<Surface> surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface)); 189 if (camera->setPreviewDisplay(surface) != NO_ERROR) { 190 jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed"); 191 } 192} 193 194static void preview_callback(const sp<IMemory>& mem, void *cookie) 195{ 196 LOGV("preview_callback"); 197 JNIEnv *env = AndroidRuntime::getJNIEnv(); 198 if (env == NULL) { 199 LOGE("preview_callback on dead VM"); 200 return; 201 } 202 camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); 203 if ((context == NULL) || (context->mCamera == 0)) { 204 LOGW("context or camera is NULL in preview_callback"); 205 return; 206 } 207 LOGV("native_release: context=%p camera=%p", context, context->mCamera.get()); 208 209 int arg1 = 0, arg2 = 0; 210 jobject obj = NULL; 211 212 ssize_t offset; 213 size_t size; 214 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); 215 216 uint8_t *data = ((uint8_t *)heap->base()) + offset; 217 218 jbyteArray array = env->NewByteArray(size); 219 if (array == NULL) { 220 LOGE("Couldn't allocate byte array for YUV data"); 221 env->ExceptionClear(); 222 return; 223 } 224 225 jbyte *bytes = env->GetByteArrayElements(array, NULL); 226 memcpy(bytes, data, size); 227 env->ReleaseByteArrayElements(array, bytes, 0); 228 229 obj = array; 230 231 env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, 232 context->mCameraJObjectWeak, kPreviewCallback, arg1, arg2, obj); 233 env->DeleteLocalRef(array); 234} 235 236static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) 237{ 238 LOGV("startPreview"); 239 sp<Camera> camera = get_native_camera(env, thiz, NULL); 240 if (camera == 0) return; 241 242 if (camera->startPreview() != NO_ERROR) { 243 jniThrowException(env, "java/io/IOException", "startPreview failed"); 244 return; 245 } 246} 247 248static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz) 249{ 250 LOGV("stopPreview"); 251 sp<Camera> c = get_native_camera(env, thiz, NULL); 252 if (c == 0) return; 253 254 c->stopPreview(); 255} 256 257static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz) 258{ 259 LOGV("previewEnabled"); 260 sp<Camera> c = get_native_camera(env, thiz, NULL); 261 if (c == 0) return false; 262 263 return c->previewEnabled(); 264} 265 266static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean oneshot) 267{ 268 // Important: Only install preview_callback if the Java code has called 269 // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy 270 // each preview frame for nothing. 271 camera_context_t* context; 272 sp<Camera> camera = get_native_camera(env, thiz, &context); 273 if (camera == 0) return; 274 275 int callback_flag; 276 if (installed) { 277 callback_flag = oneshot ? FRAME_CALLBACK_FLAG_BARCODE_SCANNER : FRAME_CALLBACK_FLAG_CAMERA; 278 } else { 279 callback_flag = FRAME_CALLBACK_FLAG_NOOP; 280 } 281 camera->setPreviewCallback(installed ? preview_callback : NULL, context, callback_flag); 282} 283 284static void autofocus_callback_impl(bool success, void *cookie) 285{ 286 LOGV("autoFocusCallback"); 287 camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); 288 289 JNIEnv *env = AndroidRuntime::getJNIEnv(); 290 if (env == NULL) { 291 LOGE("autofocus_callback on dead VM"); 292 return; 293 } 294 env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, 295 context->mCameraJObjectWeak, kAutoFocusCallback, success, 0, NULL); 296} 297 298static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) 299{ 300 LOGV("autoFocus"); 301 camera_context_t* context; 302 sp<Camera> c = get_native_camera(env, thiz, &context); 303 if (c == 0) return; 304 305 c->setAutoFocusCallback(autofocus_callback_impl, context); 306 if (c->autoFocus() != NO_ERROR) { 307 jniThrowException(env, "java/io/IOException", "autoFocus failed"); 308 } 309} 310 311static void jpeg_callback(const sp<IMemory>& mem, void *cookie) 312{ 313 LOGV("jpegCallback"); 314 camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); 315 316 JNIEnv *env = AndroidRuntime::getJNIEnv(); 317 if (env == NULL) { 318 LOGE("jpeg`_callback on dead VM"); 319 return; 320 } 321 int arg1 = 0, arg2 = 0; 322 jobject obj = NULL; 323 324 if (mem == NULL) { 325 env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, 326 context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, NULL); 327 return; 328 } 329 ssize_t offset; 330 size_t size; 331 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); 332 LOGV("jpeg_callback: mem off=%d, size=%d", offset, size); 333 334 uint8_t *heap_base = (uint8_t *)heap->base(); 335 if (heap_base == NULL) { 336 LOGE("YUV heap is NULL"); 337 return; 338 } 339 340 uint8_t *data = heap_base + offset; 341 342 jbyteArray array = env->NewByteArray(size); 343 if (array == NULL) { 344 LOGE("Couldn't allocate byte array for JPEG data"); 345 env->ExceptionClear(); 346 return; 347 } 348 349 jbyte *bytes = env->GetByteArrayElements(array, NULL); 350 memcpy(bytes, data, size); 351 env->ReleaseByteArrayElements(array, bytes, 0); 352 353 obj = array; 354 355 env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, 356 context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, obj); 357 env->DeleteLocalRef(array); 358} 359 360static void shutter_callback_impl(void *cookie) 361{ 362 LOGV("shutterCallback"); 363 camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); 364 365 JNIEnv *env = AndroidRuntime::getJNIEnv(); 366 if (env == NULL) { 367 LOGE("shutter_callback on dead VM"); 368 return; 369 } 370 env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, 371 context->mCameraJObjectWeak, kShutterCallback, 0, 0, NULL); 372} 373 374static void raw_callback(const sp<IMemory>& mem __attribute__((unused)), 375 void *cookie) 376{ 377 LOGV("rawCallback"); 378 camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); 379 380 JNIEnv *env = AndroidRuntime::getJNIEnv(); 381 if (env == NULL) { 382 LOGE("raw_callback on dead VM"); 383 return; 384 } 385 env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, 386 context->mCameraJObjectWeak, kRawCallback, 0, 0, NULL); 387} 388 389static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) 390{ 391 LOGV("takePicture"); 392 camera_context_t* context; 393 sp<Camera> camera = get_native_camera(env, thiz, &context); 394 if (camera == 0) return; 395 396 camera->setShutterCallback(shutter_callback_impl, context); 397 camera->setRawCallback(raw_callback, context); 398 camera->setJpegCallback(jpeg_callback, context); 399 if (camera->takePicture() != NO_ERROR) { 400 jniThrowException(env, "java/io/IOException", "takePicture failed"); 401 return; 402 } 403 404 return; 405} 406 407static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) 408{ 409 LOGV("setParameters"); 410 sp<Camera> camera = get_native_camera(env, thiz, NULL); 411 if (camera == 0) return; 412 413 const jchar* str = env->GetStringCritical(params, 0); 414 String8 params8; 415 if (params) { 416 params8 = String8(str, env->GetStringLength(params)); 417 env->ReleaseStringCritical(params, str); 418 } 419 if (camera->setParameters(params8) != NO_ERROR) { 420 jniThrowException(env, "java/lang/IllegalArgumentException", "setParameters failed"); 421 return; 422 } 423} 424 425static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz) 426{ 427 LOGV("getParameters"); 428 sp<Camera> camera = get_native_camera(env, thiz, NULL); 429 if (camera == 0) return 0; 430 431 return env->NewStringUTF(camera->getParameters().string()); 432} 433 434static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz) 435{ 436 LOGV("reconnect"); 437 sp<Camera> camera = get_native_camera(env, thiz, NULL); 438 if (camera == 0) return; 439 440 if (camera->reconnect() != NO_ERROR) { 441 jniThrowException(env, "java/io/IOException", "reconnect failed"); 442 return; 443 } 444} 445 446static jint android_hardware_Camera_lock(JNIEnv *env, jobject thiz) 447{ 448 LOGV("lock"); 449 sp<Camera> camera = get_native_camera(env, thiz, NULL); 450 if (camera == 0) return INVALID_OPERATION; 451 return (jint) camera->lock(); 452} 453 454static jint android_hardware_Camera_unlock(JNIEnv *env, jobject thiz) 455{ 456 LOGV("unlock"); 457 sp<Camera> camera = get_native_camera(env, thiz, NULL); 458 if (camera == 0) return INVALID_OPERATION; 459 return (jint) camera->unlock(); 460} 461 462//------------------------------------------------- 463 464static JNINativeMethod camMethods[] = { 465 { "native_setup", 466 "(Ljava/lang/Object;)V", 467 (void*)android_hardware_Camera_native_setup }, 468 { "native_release", 469 "()V", 470 (void*)android_hardware_Camera_release }, 471 { "setPreviewDisplay", 472 "(Landroid/view/Surface;)V", 473 (void *)android_hardware_Camera_setPreviewDisplay }, 474 { "startPreview", 475 "()V", 476 (void *)android_hardware_Camera_startPreview }, 477 { "stopPreview", 478 "()V", 479 (void *)android_hardware_Camera_stopPreview }, 480 { "previewEnabled", 481 "()Z", 482 (void *)android_hardware_Camera_previewEnabled }, 483 { "setHasPreviewCallback", 484 "(ZZ)V", 485 (void *)android_hardware_Camera_setHasPreviewCallback }, 486 { "native_autoFocus", 487 "()V", 488 (void *)android_hardware_Camera_autoFocus }, 489 { "native_takePicture", 490 "()V", 491 (void *)android_hardware_Camera_takePicture }, 492 { "native_setParameters", 493 "(Ljava/lang/String;)V", 494 (void *)android_hardware_Camera_setParameters }, 495 { "native_getParameters", 496 "()Ljava/lang/String;", 497 (void *)android_hardware_Camera_getParameters }, 498 { "reconnect", 499 "()V", 500 (void*)android_hardware_Camera_reconnect }, 501 { "lock", 502 "()I", 503 (void*)android_hardware_Camera_lock }, 504 { "unlock", 505 "()I", 506 (void*)android_hardware_Camera_unlock }, 507}; 508 509struct field { 510 const char *class_name; 511 const char *field_name; 512 const char *field_type; 513 jfieldID *jfield; 514}; 515 516static int find_fields(JNIEnv *env, field *fields, int count) 517{ 518 for (int i = 0; i < count; i++) { 519 field *f = &fields[i]; 520 jclass clazz = env->FindClass(f->class_name); 521 if (clazz == NULL) { 522 LOGE("Can't find %s", f->class_name); 523 return -1; 524 } 525 526 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type); 527 if (field == NULL) { 528 LOGE("Can't find %s.%s", f->class_name, f->field_name); 529 return -1; 530 } 531 532 *(f->jfield) = field; 533 } 534 535 return 0; 536} 537 538// Get all the required offsets in java class and register native functions 539int register_android_hardware_Camera(JNIEnv *env) 540{ 541 field fields_to_find[] = { 542 { "android/hardware/Camera", "mNativeContext", "I", &fields.context }, 543 { "android/view/Surface", "mSurface", "I", &fields.surface } 544 }; 545 546 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) 547 return -1; 548 549 jclass clazz = env->FindClass("android/hardware/Camera"); 550 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 551 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 552 if (fields.post_event == NULL) { 553 LOGE("Can't find android/hardware/Camera.postEventFromNative"); 554 return -1; 555 } 556 557 558 // Register native functions 559 return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera", 560 camMethods, NELEM(camMethods)); 561} 562 563