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 "core_jni_helpers.h" 25 #include <android_runtime/android_graphics_SurfaceTexture.h> 26 #include <android_runtime/android_view_Surface.h> 27 28 #include <cutils/properties.h> 29 #include <utils/Vector.h> 30 #include <utils/Errors.h> 31 32 #include <gui/GLConsumer.h> 33 #include <gui/Surface.h> 34 #include <camera/Camera.h> 35 #include <binder/IMemory.h> 36 37 using namespace android; 38 39 enum { 40 // Keep up to date with Camera.java 41 CAMERA_HAL_API_VERSION_NORMAL_CONNECT = -2, 42 }; 43 44 struct fields_t { 45 jfieldID context; 46 jfieldID facing; 47 jfieldID orientation; 48 jfieldID canDisableShutterSound; 49 jfieldID face_rect; 50 jfieldID face_score; 51 jfieldID face_id; 52 jfieldID face_left_eye; 53 jfieldID face_right_eye; 54 jfieldID face_mouth; 55 jfieldID rect_left; 56 jfieldID rect_top; 57 jfieldID rect_right; 58 jfieldID rect_bottom; 59 jfieldID point_x; 60 jfieldID point_y; 61 jmethodID post_event; 62 jmethodID rect_constructor; 63 jmethodID face_constructor; 64 jmethodID point_constructor; 65 }; 66 67 static fields_t fields; 68 static Mutex sLock; 69 70 // provides persistent context for calls from native code to Java 71 class JNICameraContext: public CameraListener 72 { 73 public: 74 JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera); 75 ~JNICameraContext() { release(); } 76 virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); 77 virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr, 78 camera_frame_metadata_t *metadata); 79 virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); 80 virtual void postRecordingFrameHandleTimestamp(nsecs_t timestamp, native_handle_t* handle); 81 void postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata); 82 void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType); 83 void setCallbackMode(JNIEnv *env, bool installed, bool manualMode); 84 sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } 85 bool isRawImageCallbackBufferAvailable() const; 86 void release(); 87 88 private: 89 void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); 90 void clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers); 91 void clearCallbackBuffers_l(JNIEnv *env); 92 jbyteArray getCallbackBuffer(JNIEnv *env, Vector<jbyteArray> *buffers, size_t bufferSize); 93 94 jobject mCameraJObjectWeak; // weak reference to java object 95 jclass mCameraJClass; // strong reference to java class 96 sp<Camera> mCamera; // strong reference to native object 97 jclass mFaceClass; // strong reference to Face class 98 jclass mRectClass; // strong reference to Rect class 99 jclass mPointClass; // strong reference to Point class 100 Mutex mLock; 101 102 /* 103 * Global reference application-managed raw image buffer queue. 104 * 105 * Manual-only mode is supported for raw image callbacks, which is 106 * set whenever method addCallbackBuffer() with msgType = 107 * CAMERA_MSG_RAW_IMAGE is called; otherwise, null is returned 108 * with raw image callbacks. 109 */ 110 Vector<jbyteArray> mRawImageCallbackBuffers; 111 112 /* 113 * Application-managed preview buffer queue and the flags 114 * associated with the usage of the preview buffer callback. 115 */ 116 Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[] 117 bool mManualBufferMode; // Whether to use application managed buffers. 118 bool mManualCameraCallbackSet; // Whether the callback has been set, used to 119 // reduce unnecessary calls to set the callback. 120 }; 121 122 bool JNICameraContext::isRawImageCallbackBufferAvailable() const 123 { 124 return !mRawImageCallbackBuffers.isEmpty(); 125 } 126 127 sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) 128 { 129 sp<Camera> camera; 130 Mutex::Autolock _l(sLock); 131 JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context)); 132 if (context != NULL) { 133 camera = context->getCamera(); 134 } 135 ALOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); 136 if (camera == 0) { 137 jniThrowRuntimeException(env, 138 "Camera is being used after Camera.release() was called"); 139 } 140 141 if (pContext != NULL) *pContext = context; 142 return camera; 143 } 144 145 JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera) 146 { 147 mCameraJObjectWeak = env->NewGlobalRef(weak_this); 148 mCameraJClass = (jclass)env->NewGlobalRef(clazz); 149 mCamera = camera; 150 151 jclass faceClazz = env->FindClass("android/hardware/Camera$Face"); 152 mFaceClass = (jclass) env->NewGlobalRef(faceClazz); 153 154 jclass rectClazz = env->FindClass("android/graphics/Rect"); 155 mRectClass = (jclass) env->NewGlobalRef(rectClazz); 156 157 jclass pointClazz = env->FindClass("android/graphics/Point"); 158 mPointClass = (jclass) env->NewGlobalRef(pointClazz); 159 160 mManualBufferMode = false; 161 mManualCameraCallbackSet = false; 162 } 163 164 void JNICameraContext::release() 165 { 166 ALOGV("release"); 167 Mutex::Autolock _l(mLock); 168 JNIEnv *env = AndroidRuntime::getJNIEnv(); 169 170 if (mCameraJObjectWeak != NULL) { 171 env->DeleteGlobalRef(mCameraJObjectWeak); 172 mCameraJObjectWeak = NULL; 173 } 174 if (mCameraJClass != NULL) { 175 env->DeleteGlobalRef(mCameraJClass); 176 mCameraJClass = NULL; 177 } 178 if (mFaceClass != NULL) { 179 env->DeleteGlobalRef(mFaceClass); 180 mFaceClass = NULL; 181 } 182 if (mRectClass != NULL) { 183 env->DeleteGlobalRef(mRectClass); 184 mRectClass = NULL; 185 } 186 if (mPointClass != NULL) { 187 env->DeleteGlobalRef(mPointClass); 188 mPointClass = NULL; 189 } 190 clearCallbackBuffers_l(env); 191 mCamera.clear(); 192 } 193 194 void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2) 195 { 196 ALOGV("notify"); 197 198 // VM pointer will be NULL if object is released 199 Mutex::Autolock _l(mLock); 200 if (mCameraJObjectWeak == NULL) { 201 ALOGW("callback on dead camera object"); 202 return; 203 } 204 JNIEnv *env = AndroidRuntime::getJNIEnv(); 205 206 /* 207 * If the notification or msgType is CAMERA_MSG_RAW_IMAGE_NOTIFY, change it 208 * to CAMERA_MSG_RAW_IMAGE since CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed 209 * to the Java app. 210 */ 211 if (msgType == CAMERA_MSG_RAW_IMAGE_NOTIFY) { 212 msgType = CAMERA_MSG_RAW_IMAGE; 213 } 214 215 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 216 mCameraJObjectWeak, msgType, ext1, ext2, NULL); 217 } 218 219 jbyteArray JNICameraContext::getCallbackBuffer( 220 JNIEnv* env, Vector<jbyteArray>* buffers, size_t bufferSize) 221 { 222 jbyteArray obj = NULL; 223 224 // Vector access should be protected by lock in postData() 225 if (!buffers->isEmpty()) { 226 ALOGV("Using callback buffer from queue of length %zu", buffers->size()); 227 jbyteArray globalBuffer = buffers->itemAt(0); 228 buffers->removeAt(0); 229 230 obj = (jbyteArray)env->NewLocalRef(globalBuffer); 231 env->DeleteGlobalRef(globalBuffer); 232 233 if (obj != NULL) { 234 jsize bufferLength = env->GetArrayLength(obj); 235 if ((int)bufferLength < (int)bufferSize) { 236 ALOGE("Callback buffer was too small! Expected %zu bytes, but got %d bytes!", 237 bufferSize, bufferLength); 238 env->DeleteLocalRef(obj); 239 return NULL; 240 } 241 } 242 } 243 244 return obj; 245 } 246 247 void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) 248 { 249 jbyteArray obj = NULL; 250 251 // allocate Java byte array and copy data 252 if (dataPtr != NULL) { 253 ssize_t offset; 254 size_t size; 255 sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size); 256 ALOGV("copyAndPost: off=%zd, size=%zu", offset, size); 257 uint8_t *heapBase = (uint8_t*)heap->base(); 258 259 if (heapBase != NULL) { 260 const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset); 261 262 if (msgType == CAMERA_MSG_RAW_IMAGE) { 263 obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size); 264 } else if (msgType == CAMERA_MSG_PREVIEW_FRAME && mManualBufferMode) { 265 obj = getCallbackBuffer(env, &mCallbackBuffers, size); 266 267 if (mCallbackBuffers.isEmpty()) { 268 ALOGV("Out of buffers, clearing callback!"); 269 mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP); 270 mManualCameraCallbackSet = false; 271 272 if (obj == NULL) { 273 return; 274 } 275 } 276 } else { 277 ALOGV("Allocating callback buffer"); 278 obj = env->NewByteArray(size); 279 } 280 281 if (obj == NULL) { 282 ALOGE("Couldn't allocate byte array for JPEG data"); 283 env->ExceptionClear(); 284 } else { 285 env->SetByteArrayRegion(obj, 0, size, data); 286 } 287 } else { 288 ALOGE("image heap is NULL"); 289 } 290 } 291 292 // post image data to Java 293 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 294 mCameraJObjectWeak, msgType, 0, 0, obj); 295 if (obj) { 296 env->DeleteLocalRef(obj); 297 } 298 } 299 300 void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr, 301 camera_frame_metadata_t *metadata) 302 { 303 // VM pointer will be NULL if object is released 304 Mutex::Autolock _l(mLock); 305 JNIEnv *env = AndroidRuntime::getJNIEnv(); 306 if (mCameraJObjectWeak == NULL) { 307 ALOGW("callback on dead camera object"); 308 return; 309 } 310 311 int32_t dataMsgType = msgType & ~CAMERA_MSG_PREVIEW_METADATA; 312 313 // return data based on callback type 314 switch (dataMsgType) { 315 case CAMERA_MSG_VIDEO_FRAME: 316 // should never happen 317 break; 318 319 // For backward-compatibility purpose, if there is no callback 320 // buffer for raw image, the callback returns null. 321 case CAMERA_MSG_RAW_IMAGE: 322 ALOGV("rawCallback"); 323 if (mRawImageCallbackBuffers.isEmpty()) { 324 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 325 mCameraJObjectWeak, dataMsgType, 0, 0, NULL); 326 } else { 327 copyAndPost(env, dataPtr, dataMsgType); 328 } 329 break; 330 331 // There is no data. 332 case 0: 333 break; 334 335 default: 336 ALOGV("dataCallback(%d, %p)", dataMsgType, dataPtr.get()); 337 copyAndPost(env, dataPtr, dataMsgType); 338 break; 339 } 340 341 // post frame metadata to Java 342 if (metadata && (msgType & CAMERA_MSG_PREVIEW_METADATA)) { 343 postMetadata(env, CAMERA_MSG_PREVIEW_METADATA, metadata); 344 } 345 } 346 347 void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) 348 { 349 // TODO: plumb up to Java. For now, just drop the timestamp 350 postData(msgType, dataPtr, NULL); 351 } 352 353 void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t*) { 354 // This is not needed at app layer. This should not be called because JNICameraContext cannot 355 // start video recording. 356 } 357 358 void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata) 359 { 360 jobjectArray obj = NULL; 361 obj = (jobjectArray) env->NewObjectArray(metadata->number_of_faces, 362 mFaceClass, NULL); 363 if (obj == NULL) { 364 ALOGE("Couldn't allocate face metadata array"); 365 return; 366 } 367 368 for (int i = 0; i < metadata->number_of_faces; i++) { 369 jobject face = env->NewObject(mFaceClass, fields.face_constructor); 370 env->SetObjectArrayElement(obj, i, face); 371 372 jobject rect = env->NewObject(mRectClass, fields.rect_constructor); 373 env->SetIntField(rect, fields.rect_left, metadata->faces[i].rect[0]); 374 env->SetIntField(rect, fields.rect_top, metadata->faces[i].rect[1]); 375 env->SetIntField(rect, fields.rect_right, metadata->faces[i].rect[2]); 376 env->SetIntField(rect, fields.rect_bottom, metadata->faces[i].rect[3]); 377 378 env->SetObjectField(face, fields.face_rect, rect); 379 env->SetIntField(face, fields.face_score, metadata->faces[i].score); 380 381 bool optionalFields = metadata->faces[i].id != 0 382 && metadata->faces[i].left_eye[0] != -2000 && metadata->faces[i].left_eye[1] != -2000 383 && metadata->faces[i].right_eye[0] != -2000 && metadata->faces[i].right_eye[1] != -2000 384 && metadata->faces[i].mouth[0] != -2000 && metadata->faces[i].mouth[1] != -2000; 385 if (optionalFields) { 386 int32_t id = metadata->faces[i].id; 387 env->SetIntField(face, fields.face_id, id); 388 389 jobject leftEye = env->NewObject(mPointClass, fields.point_constructor); 390 env->SetIntField(leftEye, fields.point_x, metadata->faces[i].left_eye[0]); 391 env->SetIntField(leftEye, fields.point_y, metadata->faces[i].left_eye[1]); 392 env->SetObjectField(face, fields.face_left_eye, leftEye); 393 env->DeleteLocalRef(leftEye); 394 395 jobject rightEye = env->NewObject(mPointClass, fields.point_constructor); 396 env->SetIntField(rightEye, fields.point_x, metadata->faces[i].right_eye[0]); 397 env->SetIntField(rightEye, fields.point_y, metadata->faces[i].right_eye[1]); 398 env->SetObjectField(face, fields.face_right_eye, rightEye); 399 env->DeleteLocalRef(rightEye); 400 401 jobject mouth = env->NewObject(mPointClass, fields.point_constructor); 402 env->SetIntField(mouth, fields.point_x, metadata->faces[i].mouth[0]); 403 env->SetIntField(mouth, fields.point_y, metadata->faces[i].mouth[1]); 404 env->SetObjectField(face, fields.face_mouth, mouth); 405 env->DeleteLocalRef(mouth); 406 } 407 408 env->DeleteLocalRef(face); 409 env->DeleteLocalRef(rect); 410 } 411 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 412 mCameraJObjectWeak, msgType, 0, 0, obj); 413 env->DeleteLocalRef(obj); 414 } 415 416 void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode) 417 { 418 Mutex::Autolock _l(mLock); 419 mManualBufferMode = manualMode; 420 mManualCameraCallbackSet = false; 421 422 // In order to limit the over usage of binder threads, all non-manual buffer 423 // callbacks use CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now. 424 // 425 // Continuous callbacks will have the callback re-registered from handleMessage. 426 // Manual buffer mode will operate as fast as possible, relying on the finite supply 427 // of buffers for throttling. 428 429 if (!installed) { 430 mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP); 431 clearCallbackBuffers_l(env, &mCallbackBuffers); 432 } else if (mManualBufferMode) { 433 if (!mCallbackBuffers.isEmpty()) { 434 mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA); 435 mManualCameraCallbackSet = true; 436 } 437 } else { 438 mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER); 439 clearCallbackBuffers_l(env, &mCallbackBuffers); 440 } 441 } 442 443 void JNICameraContext::addCallbackBuffer( 444 JNIEnv *env, jbyteArray cbb, int msgType) 445 { 446 ALOGV("addCallbackBuffer: 0x%x", msgType); 447 if (cbb != NULL) { 448 Mutex::Autolock _l(mLock); 449 switch (msgType) { 450 case CAMERA_MSG_PREVIEW_FRAME: { 451 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); 452 mCallbackBuffers.push(callbackBuffer); 453 454 ALOGV("Adding callback buffer to queue, %zu total", 455 mCallbackBuffers.size()); 456 457 // We want to make sure the camera knows we're ready for the 458 // next frame. This may have come unset had we not had a 459 // callbackbuffer ready for it last time. 460 if (mManualBufferMode && !mManualCameraCallbackSet) { 461 mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA); 462 mManualCameraCallbackSet = true; 463 } 464 break; 465 } 466 case CAMERA_MSG_RAW_IMAGE: { 467 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); 468 mRawImageCallbackBuffers.push(callbackBuffer); 469 break; 470 } 471 default: { 472 jniThrowException(env, 473 "java/lang/IllegalArgumentException", 474 "Unsupported message type"); 475 return; 476 } 477 } 478 } else { 479 ALOGE("Null byte array!"); 480 } 481 } 482 483 void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) 484 { 485 clearCallbackBuffers_l(env, &mCallbackBuffers); 486 clearCallbackBuffers_l(env, &mRawImageCallbackBuffers); 487 } 488 489 void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers) { 490 ALOGV("Clearing callback buffers, %zu remained", buffers->size()); 491 while (!buffers->isEmpty()) { 492 env->DeleteGlobalRef(buffers->top()); 493 buffers->pop(); 494 } 495 } 496 497 static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz) 498 { 499 return Camera::getNumberOfCameras(); 500 } 501 502 static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, 503 jint cameraId, jobject info_obj) 504 { 505 CameraInfo cameraInfo; 506 if (cameraId >= Camera::getNumberOfCameras() || cameraId < 0) { 507 ALOGE("%s: Unknown camera ID %d", __FUNCTION__, cameraId); 508 jniThrowRuntimeException(env, "Unknown camera ID"); 509 return; 510 } 511 512 status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo); 513 if (rc != NO_ERROR) { 514 jniThrowRuntimeException(env, "Fail to get camera info"); 515 return; 516 } 517 env->SetIntField(info_obj, fields.facing, cameraInfo.facing); 518 env->SetIntField(info_obj, fields.orientation, cameraInfo.orientation); 519 520 char value[PROPERTY_VALUE_MAX]; 521 property_get("ro.camera.sound.forced", value, "0"); 522 jboolean canDisableShutterSound = (strncmp(value, "0", 2) == 0); 523 env->SetBooleanField(info_obj, fields.canDisableShutterSound, 524 canDisableShutterSound); 525 } 526 527 // connect to camera service 528 static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, 529 jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName) 530 { 531 // Convert jstring to String16 532 const char16_t *rawClientName = reinterpret_cast<const char16_t*>( 533 env->GetStringChars(clientPackageName, NULL)); 534 jsize rawClientNameLen = env->GetStringLength(clientPackageName); 535 String16 clientName(rawClientName, rawClientNameLen); 536 env->ReleaseStringChars(clientPackageName, 537 reinterpret_cast<const jchar*>(rawClientName)); 538 539 sp<Camera> camera; 540 if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) { 541 // Default path: hal version is don't care, do normal camera connect. 542 camera = Camera::connect(cameraId, clientName, 543 Camera::USE_CALLING_UID, Camera::USE_CALLING_PID); 544 } else { 545 jint status = Camera::connectLegacy(cameraId, halVersion, clientName, 546 Camera::USE_CALLING_UID, camera); 547 if (status != NO_ERROR) { 548 return status; 549 } 550 } 551 552 if (camera == NULL) { 553 return -EACCES; 554 } 555 556 // make sure camera hardware is alive 557 if (camera->getStatus() != NO_ERROR) { 558 return NO_INIT; 559 } 560 561 jclass clazz = env->GetObjectClass(thiz); 562 if (clazz == NULL) { 563 // This should never happen 564 jniThrowRuntimeException(env, "Can't find android/hardware/Camera"); 565 return INVALID_OPERATION; 566 } 567 568 // We use a weak reference so the Camera object can be garbage collected. 569 // The reference is only used as a proxy for callbacks. 570 sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera); 571 context->incStrong((void*)android_hardware_Camera_native_setup); 572 camera->setListener(context); 573 574 // save context in opaque field 575 env->SetLongField(thiz, fields.context, (jlong)context.get()); 576 577 // Update default display orientation in case the sensor is reverse-landscape 578 CameraInfo cameraInfo; 579 status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo); 580 if (rc != NO_ERROR) { 581 return rc; 582 } 583 int defaultOrientation = 0; 584 switch (cameraInfo.orientation) { 585 case 0: 586 break; 587 case 90: 588 if (cameraInfo.facing == CAMERA_FACING_FRONT) { 589 defaultOrientation = 180; 590 } 591 break; 592 case 180: 593 defaultOrientation = 180; 594 break; 595 case 270: 596 if (cameraInfo.facing != CAMERA_FACING_FRONT) { 597 defaultOrientation = 180; 598 } 599 break; 600 default: 601 ALOGE("Unexpected camera orientation %d!", cameraInfo.orientation); 602 break; 603 } 604 if (defaultOrientation != 0) { 605 ALOGV("Setting default display orientation to %d", defaultOrientation); 606 rc = camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION, 607 defaultOrientation, 0); 608 if (rc != NO_ERROR) { 609 ALOGE("Unable to update default orientation: %s (%d)", 610 strerror(-rc), rc); 611 return rc; 612 } 613 } 614 615 return NO_ERROR; 616 } 617 618 // disconnect from camera service 619 // It's okay to call this when the native camera context is already null. 620 // This handles the case where the user has called release() and the 621 // finalizer is invoked later. 622 static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) 623 { 624 ALOGV("release camera"); 625 JNICameraContext* context = NULL; 626 sp<Camera> camera; 627 { 628 Mutex::Autolock _l(sLock); 629 context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context)); 630 631 // Make sure we do not attempt to callback on a deleted Java object. 632 env->SetLongField(thiz, fields.context, 0); 633 } 634 635 // clean up if release has not been called before 636 if (context != NULL) { 637 camera = context->getCamera(); 638 context->release(); 639 ALOGV("native_release: context=%p camera=%p", context, camera.get()); 640 641 // clear callbacks 642 if (camera != NULL) { 643 camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP); 644 camera->disconnect(); 645 } 646 647 // remove context to prevent further Java access 648 context->decStrong((void*)android_hardware_Camera_native_setup); 649 } 650 } 651 652 static void android_hardware_Camera_setPreviewSurface(JNIEnv *env, jobject thiz, jobject jSurface) 653 { 654 ALOGV("setPreviewSurface"); 655 sp<Camera> camera = get_native_camera(env, thiz, NULL); 656 if (camera == 0) return; 657 658 sp<IGraphicBufferProducer> gbp; 659 sp<Surface> surface; 660 if (jSurface) { 661 surface = android_view_Surface_getSurface(env, jSurface); 662 if (surface != NULL) { 663 gbp = surface->getIGraphicBufferProducer(); 664 } 665 } 666 667 if (camera->setPreviewTarget(gbp) != NO_ERROR) { 668 jniThrowException(env, "java/io/IOException", "setPreviewTexture failed"); 669 } 670 } 671 672 static void android_hardware_Camera_setPreviewTexture(JNIEnv *env, 673 jobject thiz, jobject jSurfaceTexture) 674 { 675 ALOGV("setPreviewTexture"); 676 sp<Camera> camera = get_native_camera(env, thiz, NULL); 677 if (camera == 0) return; 678 679 sp<IGraphicBufferProducer> producer = NULL; 680 if (jSurfaceTexture != NULL) { 681 producer = SurfaceTexture_getProducer(env, jSurfaceTexture); 682 if (producer == NULL) { 683 jniThrowException(env, "java/lang/IllegalArgumentException", 684 "SurfaceTexture already released in setPreviewTexture"); 685 return; 686 } 687 688 } 689 690 if (camera->setPreviewTarget(producer) != NO_ERROR) { 691 jniThrowException(env, "java/io/IOException", 692 "setPreviewTexture failed"); 693 } 694 } 695 696 static void android_hardware_Camera_setPreviewCallbackSurface(JNIEnv *env, 697 jobject thiz, jobject jSurface) 698 { 699 ALOGV("setPreviewCallbackSurface"); 700 JNICameraContext* context; 701 sp<Camera> camera = get_native_camera(env, thiz, &context); 702 if (camera == 0) return; 703 704 sp<IGraphicBufferProducer> gbp; 705 sp<Surface> surface; 706 if (jSurface) { 707 surface = android_view_Surface_getSurface(env, jSurface); 708 if (surface != NULL) { 709 gbp = surface->getIGraphicBufferProducer(); 710 } 711 } 712 // Clear out normal preview callbacks 713 context->setCallbackMode(env, false, false); 714 // Then set up callback surface 715 if (camera->setPreviewCallbackTarget(gbp) != NO_ERROR) { 716 jniThrowException(env, "java/io/IOException", "setPreviewCallbackTarget failed"); 717 } 718 } 719 720 static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) 721 { 722 ALOGV("startPreview"); 723 sp<Camera> camera = get_native_camera(env, thiz, NULL); 724 if (camera == 0) return; 725 726 if (camera->startPreview() != NO_ERROR) { 727 jniThrowRuntimeException(env, "startPreview failed"); 728 return; 729 } 730 } 731 732 static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz) 733 { 734 ALOGV("stopPreview"); 735 sp<Camera> c = get_native_camera(env, thiz, NULL); 736 if (c == 0) return; 737 738 c->stopPreview(); 739 } 740 741 static jboolean android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz) 742 { 743 ALOGV("previewEnabled"); 744 sp<Camera> c = get_native_camera(env, thiz, NULL); 745 if (c == 0) return JNI_FALSE; 746 747 return c->previewEnabled() ? JNI_TRUE : JNI_FALSE; 748 } 749 750 static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean manualBuffer) 751 { 752 ALOGV("setHasPreviewCallback: installed:%d, manualBuffer:%d", (int)installed, (int)manualBuffer); 753 // Important: Only install preview_callback if the Java code has called 754 // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy 755 // each preview frame for nothing. 756 JNICameraContext* context; 757 sp<Camera> camera = get_native_camera(env, thiz, &context); 758 if (camera == 0) return; 759 760 // setCallbackMode will take care of setting the context flags and calling 761 // camera->setPreviewCallbackFlags within a mutex for us. 762 context->setCallbackMode(env, installed, manualBuffer); 763 } 764 765 static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, jint msgType) { 766 ALOGV("addCallbackBuffer: 0x%x", msgType); 767 768 JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context)); 769 770 if (context != NULL) { 771 context->addCallbackBuffer(env, bytes, msgType); 772 } 773 } 774 775 static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) 776 { 777 ALOGV("autoFocus"); 778 JNICameraContext* context; 779 sp<Camera> c = get_native_camera(env, thiz, &context); 780 if (c == 0) return; 781 782 if (c->autoFocus() != NO_ERROR) { 783 jniThrowRuntimeException(env, "autoFocus failed"); 784 } 785 } 786 787 static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz) 788 { 789 ALOGV("cancelAutoFocus"); 790 JNICameraContext* context; 791 sp<Camera> c = get_native_camera(env, thiz, &context); 792 if (c == 0) return; 793 794 if (c->cancelAutoFocus() != NO_ERROR) { 795 jniThrowRuntimeException(env, "cancelAutoFocus failed"); 796 } 797 } 798 799 static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz, jint msgType) 800 { 801 ALOGV("takePicture"); 802 JNICameraContext* context; 803 sp<Camera> camera = get_native_camera(env, thiz, &context); 804 if (camera == 0) return; 805 806 /* 807 * When CAMERA_MSG_RAW_IMAGE is requested, if the raw image callback 808 * buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the 809 * notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY 810 * is enabled to receive the callback notification but no data. 811 * 812 * Note that CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed to the 813 * Java application. 814 */ 815 if (msgType & CAMERA_MSG_RAW_IMAGE) { 816 ALOGV("Enable raw image callback buffer"); 817 if (!context->isRawImageCallbackBufferAvailable()) { 818 ALOGV("Enable raw image notification, since no callback buffer exists"); 819 msgType &= ~CAMERA_MSG_RAW_IMAGE; 820 msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY; 821 } 822 } 823 824 if (camera->takePicture(msgType) != NO_ERROR) { 825 jniThrowRuntimeException(env, "takePicture failed"); 826 return; 827 } 828 } 829 830 static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) 831 { 832 ALOGV("setParameters"); 833 sp<Camera> camera = get_native_camera(env, thiz, NULL); 834 if (camera == 0) return; 835 836 const jchar* str = env->GetStringCritical(params, 0); 837 String8 params8; 838 if (params) { 839 params8 = String8(reinterpret_cast<const char16_t*>(str), 840 env->GetStringLength(params)); 841 env->ReleaseStringCritical(params, str); 842 } 843 if (camera->setParameters(params8) != NO_ERROR) { 844 jniThrowRuntimeException(env, "setParameters failed"); 845 return; 846 } 847 } 848 849 static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz) 850 { 851 ALOGV("getParameters"); 852 sp<Camera> camera = get_native_camera(env, thiz, NULL); 853 if (camera == 0) return 0; 854 855 String8 params8 = camera->getParameters(); 856 if (params8.isEmpty()) { 857 jniThrowRuntimeException(env, "getParameters failed (empty parameters)"); 858 return 0; 859 } 860 return env->NewStringUTF(params8.string()); 861 } 862 863 static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz) 864 { 865 ALOGV("reconnect"); 866 sp<Camera> camera = get_native_camera(env, thiz, NULL); 867 if (camera == 0) return; 868 869 if (camera->reconnect() != NO_ERROR) { 870 jniThrowException(env, "java/io/IOException", "reconnect failed"); 871 return; 872 } 873 } 874 875 static void android_hardware_Camera_lock(JNIEnv *env, jobject thiz) 876 { 877 ALOGV("lock"); 878 sp<Camera> camera = get_native_camera(env, thiz, NULL); 879 if (camera == 0) return; 880 881 if (camera->lock() != NO_ERROR) { 882 jniThrowRuntimeException(env, "lock failed"); 883 } 884 } 885 886 static void android_hardware_Camera_unlock(JNIEnv *env, jobject thiz) 887 { 888 ALOGV("unlock"); 889 sp<Camera> camera = get_native_camera(env, thiz, NULL); 890 if (camera == 0) return; 891 892 if (camera->unlock() != NO_ERROR) { 893 jniThrowRuntimeException(env, "unlock failed"); 894 } 895 } 896 897 static void android_hardware_Camera_startSmoothZoom(JNIEnv *env, jobject thiz, jint value) 898 { 899 ALOGV("startSmoothZoom"); 900 sp<Camera> camera = get_native_camera(env, thiz, NULL); 901 if (camera == 0) return; 902 903 status_t rc = camera->sendCommand(CAMERA_CMD_START_SMOOTH_ZOOM, value, 0); 904 if (rc == BAD_VALUE) { 905 char msg[64]; 906 sprintf(msg, "invalid zoom value=%d", value); 907 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 908 } else if (rc != NO_ERROR) { 909 jniThrowRuntimeException(env, "start smooth zoom failed"); 910 } 911 } 912 913 static void android_hardware_Camera_stopSmoothZoom(JNIEnv *env, jobject thiz) 914 { 915 ALOGV("stopSmoothZoom"); 916 sp<Camera> camera = get_native_camera(env, thiz, NULL); 917 if (camera == 0) return; 918 919 if (camera->sendCommand(CAMERA_CMD_STOP_SMOOTH_ZOOM, 0, 0) != NO_ERROR) { 920 jniThrowRuntimeException(env, "stop smooth zoom failed"); 921 } 922 } 923 924 static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject thiz, 925 jint value) 926 { 927 ALOGV("setDisplayOrientation"); 928 sp<Camera> camera = get_native_camera(env, thiz, NULL); 929 if (camera == 0) return; 930 931 if (camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION, value, 0) != NO_ERROR) { 932 jniThrowRuntimeException(env, "set display orientation failed"); 933 } 934 } 935 936 static jboolean android_hardware_Camera_enableShutterSound(JNIEnv *env, jobject thiz, 937 jboolean enabled) 938 { 939 ALOGV("enableShutterSound"); 940 sp<Camera> camera = get_native_camera(env, thiz, NULL); 941 if (camera == 0) return JNI_FALSE; 942 943 int32_t value = (enabled == JNI_TRUE) ? 1 : 0; 944 status_t rc = camera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, value, 0); 945 if (rc == NO_ERROR) { 946 return JNI_TRUE; 947 } else if (rc == PERMISSION_DENIED) { 948 return JNI_FALSE; 949 } else { 950 jniThrowRuntimeException(env, "enable shutter sound failed"); 951 return JNI_FALSE; 952 } 953 } 954 955 static void android_hardware_Camera_startFaceDetection(JNIEnv *env, jobject thiz, 956 jint type) 957 { 958 ALOGV("startFaceDetection"); 959 JNICameraContext* context; 960 sp<Camera> camera = get_native_camera(env, thiz, &context); 961 if (camera == 0) return; 962 963 status_t rc = camera->sendCommand(CAMERA_CMD_START_FACE_DETECTION, type, 0); 964 if (rc == BAD_VALUE) { 965 char msg[64]; 966 snprintf(msg, sizeof(msg), "invalid face detection type=%d", type); 967 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 968 } else if (rc != NO_ERROR) { 969 jniThrowRuntimeException(env, "start face detection failed"); 970 } 971 } 972 973 static void android_hardware_Camera_stopFaceDetection(JNIEnv *env, jobject thiz) 974 { 975 ALOGV("stopFaceDetection"); 976 sp<Camera> camera = get_native_camera(env, thiz, NULL); 977 if (camera == 0) return; 978 979 if (camera->sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, 0, 0) != NO_ERROR) { 980 jniThrowRuntimeException(env, "stop face detection failed"); 981 } 982 } 983 984 static void android_hardware_Camera_enableFocusMoveCallback(JNIEnv *env, jobject thiz, jint enable) 985 { 986 ALOGV("enableFocusMoveCallback"); 987 sp<Camera> camera = get_native_camera(env, thiz, NULL); 988 if (camera == 0) return; 989 990 if (camera->sendCommand(CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG, enable, 0) != NO_ERROR) { 991 jniThrowRuntimeException(env, "enable focus move callback failed"); 992 } 993 } 994 995 //------------------------------------------------- 996 997 static const JNINativeMethod camMethods[] = { 998 { "getNumberOfCameras", 999 "()I", 1000 (void *)android_hardware_Camera_getNumberOfCameras }, 1001 { "_getCameraInfo", 1002 "(ILandroid/hardware/Camera$CameraInfo;)V", 1003 (void*)android_hardware_Camera_getCameraInfo }, 1004 { "native_setup", 1005 "(Ljava/lang/Object;IILjava/lang/String;)I", 1006 (void*)android_hardware_Camera_native_setup }, 1007 { "native_release", 1008 "()V", 1009 (void*)android_hardware_Camera_release }, 1010 { "setPreviewSurface", 1011 "(Landroid/view/Surface;)V", 1012 (void *)android_hardware_Camera_setPreviewSurface }, 1013 { "setPreviewTexture", 1014 "(Landroid/graphics/SurfaceTexture;)V", 1015 (void *)android_hardware_Camera_setPreviewTexture }, 1016 { "setPreviewCallbackSurface", 1017 "(Landroid/view/Surface;)V", 1018 (void *)android_hardware_Camera_setPreviewCallbackSurface }, 1019 { "startPreview", 1020 "()V", 1021 (void *)android_hardware_Camera_startPreview }, 1022 { "_stopPreview", 1023 "()V", 1024 (void *)android_hardware_Camera_stopPreview }, 1025 { "previewEnabled", 1026 "()Z", 1027 (void *)android_hardware_Camera_previewEnabled }, 1028 { "setHasPreviewCallback", 1029 "(ZZ)V", 1030 (void *)android_hardware_Camera_setHasPreviewCallback }, 1031 { "_addCallbackBuffer", 1032 "([BI)V", 1033 (void *)android_hardware_Camera_addCallbackBuffer }, 1034 { "native_autoFocus", 1035 "()V", 1036 (void *)android_hardware_Camera_autoFocus }, 1037 { "native_cancelAutoFocus", 1038 "()V", 1039 (void *)android_hardware_Camera_cancelAutoFocus }, 1040 { "native_takePicture", 1041 "(I)V", 1042 (void *)android_hardware_Camera_takePicture }, 1043 { "native_setParameters", 1044 "(Ljava/lang/String;)V", 1045 (void *)android_hardware_Camera_setParameters }, 1046 { "native_getParameters", 1047 "()Ljava/lang/String;", 1048 (void *)android_hardware_Camera_getParameters }, 1049 { "reconnect", 1050 "()V", 1051 (void*)android_hardware_Camera_reconnect }, 1052 { "lock", 1053 "()V", 1054 (void*)android_hardware_Camera_lock }, 1055 { "unlock", 1056 "()V", 1057 (void*)android_hardware_Camera_unlock }, 1058 { "startSmoothZoom", 1059 "(I)V", 1060 (void *)android_hardware_Camera_startSmoothZoom }, 1061 { "stopSmoothZoom", 1062 "()V", 1063 (void *)android_hardware_Camera_stopSmoothZoom }, 1064 { "setDisplayOrientation", 1065 "(I)V", 1066 (void *)android_hardware_Camera_setDisplayOrientation }, 1067 { "_enableShutterSound", 1068 "(Z)Z", 1069 (void *)android_hardware_Camera_enableShutterSound }, 1070 { "_startFaceDetection", 1071 "(I)V", 1072 (void *)android_hardware_Camera_startFaceDetection }, 1073 { "_stopFaceDetection", 1074 "()V", 1075 (void *)android_hardware_Camera_stopFaceDetection}, 1076 { "enableFocusMoveCallback", 1077 "(I)V", 1078 (void *)android_hardware_Camera_enableFocusMoveCallback}, 1079 }; 1080 1081 struct field { 1082 const char *class_name; 1083 const char *field_name; 1084 const char *field_type; 1085 jfieldID *jfield; 1086 }; 1087 1088 static void find_fields(JNIEnv *env, field *fields, int count) 1089 { 1090 for (int i = 0; i < count; i++) { 1091 field *f = &fields[i]; 1092 jclass clazz = FindClassOrDie(env, f->class_name); 1093 jfieldID field = GetFieldIDOrDie(env, clazz, f->field_name, f->field_type); 1094 *(f->jfield) = field; 1095 } 1096 } 1097 1098 // Get all the required offsets in java class and register native functions 1099 int register_android_hardware_Camera(JNIEnv *env) 1100 { 1101 field fields_to_find[] = { 1102 { "android/hardware/Camera", "mNativeContext", "J", &fields.context }, 1103 { "android/hardware/Camera$CameraInfo", "facing", "I", &fields.facing }, 1104 { "android/hardware/Camera$CameraInfo", "orientation", "I", &fields.orientation }, 1105 { "android/hardware/Camera$CameraInfo", "canDisableShutterSound", "Z", 1106 &fields.canDisableShutterSound }, 1107 { "android/hardware/Camera$Face", "rect", "Landroid/graphics/Rect;", &fields.face_rect }, 1108 { "android/hardware/Camera$Face", "leftEye", "Landroid/graphics/Point;", &fields.face_left_eye}, 1109 { "android/hardware/Camera$Face", "rightEye", "Landroid/graphics/Point;", &fields.face_right_eye}, 1110 { "android/hardware/Camera$Face", "mouth", "Landroid/graphics/Point;", &fields.face_mouth}, 1111 { "android/hardware/Camera$Face", "score", "I", &fields.face_score }, 1112 { "android/hardware/Camera$Face", "id", "I", &fields.face_id}, 1113 { "android/graphics/Rect", "left", "I", &fields.rect_left }, 1114 { "android/graphics/Rect", "top", "I", &fields.rect_top }, 1115 { "android/graphics/Rect", "right", "I", &fields.rect_right }, 1116 { "android/graphics/Rect", "bottom", "I", &fields.rect_bottom }, 1117 { "android/graphics/Point", "x", "I", &fields.point_x}, 1118 { "android/graphics/Point", "y", "I", &fields.point_y}, 1119 }; 1120 1121 find_fields(env, fields_to_find, NELEM(fields_to_find)); 1122 1123 jclass clazz = FindClassOrDie(env, "android/hardware/Camera"); 1124 fields.post_event = GetStaticMethodIDOrDie(env, clazz, "postEventFromNative", 1125 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 1126 1127 clazz = FindClassOrDie(env, "android/graphics/Rect"); 1128 fields.rect_constructor = GetMethodIDOrDie(env, clazz, "<init>", "()V"); 1129 1130 clazz = FindClassOrDie(env, "android/hardware/Camera$Face"); 1131 fields.face_constructor = GetMethodIDOrDie(env, clazz, "<init>", "()V"); 1132 1133 clazz = env->FindClass("android/graphics/Point"); 1134 fields.point_constructor = env->GetMethodID(clazz, "<init>", "()V"); 1135 if (fields.point_constructor == NULL) { 1136 ALOGE("Can't find android/graphics/Point()"); 1137 return -1; 1138 } 1139 1140 // Register native functions 1141 return RegisterMethodsOrDie(env, "android/hardware/Camera", camMethods, NELEM(camMethods)); 1142 } 1143