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