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