android_hardware_Camera.cpp revision e00cab707dcaf6f05adb5ccb9c80fdf25c483427
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 <utils/Vector.h> 27 28#include <gui/SurfaceTexture.h> 29#include <surfaceflinger/Surface.h> 30#include <camera/Camera.h> 31#include <binder/IMemory.h> 32 33using namespace android; 34 35struct fields_t { 36 jfieldID context; 37 jfieldID surface; 38 jfieldID surfaceTexture; 39 jfieldID facing; 40 jfieldID orientation; 41 jmethodID post_event; 42}; 43 44static fields_t fields; 45static Mutex sLock; 46 47// provides persistent context for calls from native code to Java 48class JNICameraContext: public CameraListener 49{ 50public: 51 JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera); 52 ~JNICameraContext() { release(); } 53 virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); 54 virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); 55 virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); 56 void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType); 57 void setCallbackMode(JNIEnv *env, bool installed, bool manualMode); 58 sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } 59 bool isRawImageCallbackBufferAvailable() const; 60 void release(); 61 62private: 63 void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); 64 void clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers); 65 void clearCallbackBuffers_l(JNIEnv *env); 66 jbyteArray getCallbackBuffer(JNIEnv *env, Vector<jbyteArray> *buffers, size_t bufferSize); 67 68 jobject mCameraJObjectWeak; // weak reference to java object 69 jclass mCameraJClass; // strong reference to java class 70 sp<Camera> mCamera; // strong reference to native object 71 Mutex mLock; 72 73 /* 74 * Global reference application-managed raw image buffer queue. 75 * 76 * Manual-only mode is supported for raw image callbacks, which is 77 * set whenever method addCallbackBuffer() with msgType = 78 * CAMERA_MSG_RAW_IMAGE is called; otherwise, null is returned 79 * with raw image callbacks. 80 */ 81 Vector<jbyteArray> mRawImageCallbackBuffers; 82 83 /* 84 * Application-managed preview buffer queue and the flags 85 * associated with the usage of the preview buffer callback. 86 */ 87 Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[] 88 bool mManualBufferMode; // Whether to use application managed buffers. 89 bool mManualCameraCallbackSet; // Whether the callback has been set, used to 90 // reduce unnecessary calls to set the callback. 91}; 92 93bool JNICameraContext::isRawImageCallbackBufferAvailable() const 94{ 95 return !mRawImageCallbackBuffers.isEmpty(); 96} 97 98sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) 99{ 100 sp<Camera> camera; 101 Mutex::Autolock _l(sLock); 102 JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 103 if (context != NULL) { 104 camera = context->getCamera(); 105 } 106 LOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); 107 if (camera == 0) { 108 jniThrowException(env, "java/lang/RuntimeException", "Method called after release()"); 109 } 110 111 if (pContext != NULL) *pContext = context; 112 return camera; 113} 114 115JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera) 116{ 117 mCameraJObjectWeak = env->NewGlobalRef(weak_this); 118 mCameraJClass = (jclass)env->NewGlobalRef(clazz); 119 mCamera = camera; 120 121 mManualBufferMode = false; 122 mManualCameraCallbackSet = false; 123} 124 125void JNICameraContext::release() 126{ 127 LOGV("release"); 128 Mutex::Autolock _l(mLock); 129 JNIEnv *env = AndroidRuntime::getJNIEnv(); 130 131 if (mCameraJObjectWeak != NULL) { 132 env->DeleteGlobalRef(mCameraJObjectWeak); 133 mCameraJObjectWeak = NULL; 134 } 135 if (mCameraJClass != NULL) { 136 env->DeleteGlobalRef(mCameraJClass); 137 mCameraJClass = NULL; 138 } 139 clearCallbackBuffers_l(env); 140 mCamera.clear(); 141} 142 143void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2) 144{ 145 LOGV("notify"); 146 147 // VM pointer will be NULL if object is released 148 Mutex::Autolock _l(mLock); 149 if (mCameraJObjectWeak == NULL) { 150 LOGW("callback on dead camera object"); 151 return; 152 } 153 JNIEnv *env = AndroidRuntime::getJNIEnv(); 154 155 /* 156 * If the notification or msgType is CAMERA_MSG_RAW_IMAGE_NOTIFY, change it 157 * to CAMERA_MSG_RAW_IMAGE since CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed 158 * to the Java app. 159 */ 160 if (msgType == CAMERA_MSG_RAW_IMAGE_NOTIFY) { 161 msgType = CAMERA_MSG_RAW_IMAGE; 162 } 163 164 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 165 mCameraJObjectWeak, msgType, ext1, ext2, NULL); 166} 167 168jbyteArray JNICameraContext::getCallbackBuffer( 169 JNIEnv* env, Vector<jbyteArray>* buffers, size_t bufferSize) 170{ 171 jbyteArray obj = NULL; 172 173 // Vector access should be protected by lock in postData() 174 if (!buffers->isEmpty()) { 175 LOGV("Using callback buffer from queue of length %d", buffers->size()); 176 jbyteArray globalBuffer = buffers->itemAt(0); 177 buffers->removeAt(0); 178 179 obj = (jbyteArray)env->NewLocalRef(globalBuffer); 180 env->DeleteGlobalRef(globalBuffer); 181 182 if (obj != NULL) { 183 jsize bufferLength = env->GetArrayLength(obj); 184 if ((int)bufferLength < (int)bufferSize) { 185 LOGE("Callback buffer was too small! Expected %d bytes, but got %d bytes!", 186 bufferSize, bufferLength); 187 env->DeleteLocalRef(obj); 188 return NULL; 189 } 190 } 191 } 192 193 return obj; 194} 195 196void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) 197{ 198 jbyteArray obj = NULL; 199 200 // allocate Java byte array and copy data 201 if (dataPtr != NULL) { 202 ssize_t offset; 203 size_t size; 204 sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size); 205 LOGV("copyAndPost: off=%ld, size=%d", offset, size); 206 uint8_t *heapBase = (uint8_t*)heap->base(); 207 208 if (heapBase != NULL) { 209 const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset); 210 211 if (!mManualBufferMode) { 212 LOGV("Allocating callback buffer"); 213 obj = env->NewByteArray(size); 214 } else { 215 switch (msgType) { 216 case CAMERA_MSG_PREVIEW_FRAME: { 217 obj = getCallbackBuffer(env, &mCallbackBuffers, size); 218 219 if (mCallbackBuffers.isEmpty()) { 220 LOGV("Out of buffers, clearing callback!"); 221 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); 222 mManualCameraCallbackSet = false; 223 224 if (obj == NULL) { 225 return; 226 } 227 } 228 break; 229 } 230 case CAMERA_MSG_RAW_IMAGE: { 231 obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size); 232 break; 233 } 234 default: { 235 jniThrowException(env, 236 "java/lang/RuntimeException", "Unsupported message type"); 237 return; 238 } 239 } 240 } 241 242 if (obj == NULL) { 243 LOGE("Couldn't allocate byte array for JPEG data"); 244 env->ExceptionClear(); 245 } else { 246 env->SetByteArrayRegion(obj, 0, size, data); 247 } 248 } else { 249 LOGE("image heap is NULL"); 250 } 251 } 252 253 // post image data to Java 254 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 255 mCameraJObjectWeak, msgType, 0, 0, obj); 256 if (obj) { 257 env->DeleteLocalRef(obj); 258 } 259} 260 261void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) 262{ 263 // VM pointer will be NULL if object is released 264 Mutex::Autolock _l(mLock); 265 JNIEnv *env = AndroidRuntime::getJNIEnv(); 266 if (mCameraJObjectWeak == NULL) { 267 LOGW("callback on dead camera object"); 268 return; 269 } 270 271 // return data based on callback type 272 switch (msgType) { 273 case CAMERA_MSG_VIDEO_FRAME: 274 // should never happen 275 break; 276 277 // For backward-compatibility purpose, if there is no callback 278 // buffer for raw image, the callback returns null. 279 case CAMERA_MSG_RAW_IMAGE: 280 LOGV("rawCallback"); 281 if (mRawImageCallbackBuffers.isEmpty()) { 282 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 283 mCameraJObjectWeak, msgType, 0, 0, NULL); 284 } else { 285 copyAndPost(env, dataPtr, msgType); 286 } 287 break; 288 289 default: 290 LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); 291 copyAndPost(env, dataPtr, msgType); 292 break; 293 } 294} 295 296void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) 297{ 298 // TODO: plumb up to Java. For now, just drop the timestamp 299 postData(msgType, dataPtr); 300} 301 302void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode) 303{ 304 Mutex::Autolock _l(mLock); 305 mManualBufferMode = manualMode; 306 mManualCameraCallbackSet = false; 307 308 // In order to limit the over usage of binder threads, all non-manual buffer 309 // callbacks use FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now. 310 // 311 // Continuous callbacks will have the callback re-registered from handleMessage. 312 // Manual buffer mode will operate as fast as possible, relying on the finite supply 313 // of buffers for throttling. 314 315 if (!installed) { 316 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); 317 clearCallbackBuffers_l(env, &mCallbackBuffers); 318 } else if (mManualBufferMode) { 319 if (!mCallbackBuffers.isEmpty()) { 320 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); 321 mManualCameraCallbackSet = true; 322 } 323 } else { 324 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER); 325 clearCallbackBuffers_l(env, &mCallbackBuffers); 326 } 327} 328 329void JNICameraContext::addCallbackBuffer( 330 JNIEnv *env, jbyteArray cbb, int msgType) 331{ 332 LOGV("addCallbackBuffer: 0x%x", msgType); 333 if (cbb != NULL) { 334 Mutex::Autolock _l(mLock); 335 switch (msgType) { 336 case CAMERA_MSG_PREVIEW_FRAME: { 337 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); 338 mCallbackBuffers.push(callbackBuffer); 339 340 LOGV("Adding callback buffer to queue, %d total", 341 mCallbackBuffers.size()); 342 343 // We want to make sure the camera knows we're ready for the 344 // next frame. This may have come unset had we not had a 345 // callbackbuffer ready for it last time. 346 if (mManualBufferMode && !mManualCameraCallbackSet) { 347 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); 348 mManualCameraCallbackSet = true; 349 } 350 break; 351 } 352 case CAMERA_MSG_RAW_IMAGE: { 353 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); 354 mRawImageCallbackBuffers.push(callbackBuffer); 355 break; 356 } 357 default: { 358 jniThrowException(env, 359 "java/lang/IllegalArgumentException", 360 "Unsupported message type"); 361 return; 362 } 363 } 364 } else { 365 LOGE("Null byte array!"); 366 } 367} 368 369void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) 370{ 371 clearCallbackBuffers_l(env, &mCallbackBuffers); 372 clearCallbackBuffers_l(env, &mRawImageCallbackBuffers); 373} 374 375void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers) { 376 LOGV("Clearing callback buffers, %d remained", buffers->size()); 377 while (!buffers->isEmpty()) { 378 env->DeleteGlobalRef(buffers->top()); 379 buffers->pop(); 380 } 381} 382 383static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz) 384{ 385 return Camera::getNumberOfCameras(); 386} 387 388static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, 389 jint cameraId, jobject info_obj) 390{ 391 CameraInfo cameraInfo; 392 status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo); 393 if (rc != NO_ERROR) { 394 jniThrowException(env, "java/lang/RuntimeException", 395 "Fail to get camera info"); 396 return; 397 } 398 env->SetIntField(info_obj, fields.facing, cameraInfo.facing); 399 env->SetIntField(info_obj, fields.orientation, cameraInfo.orientation); 400} 401 402// connect to camera service 403static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, 404 jobject weak_this, jint cameraId) 405{ 406 sp<Camera> camera = Camera::connect(cameraId); 407 408 if (camera == NULL) { 409 jniThrowException(env, "java/lang/RuntimeException", 410 "Fail to connect to camera service"); 411 return; 412 } 413 414 // make sure camera hardware is alive 415 if (camera->getStatus() != NO_ERROR) { 416 jniThrowException(env, "java/lang/RuntimeException", "Camera initialization failed"); 417 return; 418 } 419 420 jclass clazz = env->GetObjectClass(thiz); 421 if (clazz == NULL) { 422 jniThrowException(env, "java/lang/RuntimeException", "Can't find android/hardware/Camera"); 423 return; 424 } 425 426 // We use a weak reference so the Camera object can be garbage collected. 427 // The reference is only used as a proxy for callbacks. 428 sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera); 429 context->incStrong(thiz); 430 camera->setListener(context); 431 432 // save context in opaque field 433 env->SetIntField(thiz, fields.context, (int)context.get()); 434} 435 436// disconnect from camera service 437// It's okay to call this when the native camera context is already null. 438// This handles the case where the user has called release() and the 439// finalizer is invoked later. 440static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) 441{ 442 // TODO: Change to LOGV 443 LOGV("release camera"); 444 JNICameraContext* context = NULL; 445 sp<Camera> camera; 446 { 447 Mutex::Autolock _l(sLock); 448 context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 449 450 // Make sure we do not attempt to callback on a deleted Java object. 451 env->SetIntField(thiz, fields.context, 0); 452 } 453 454 // clean up if release has not been called before 455 if (context != NULL) { 456 camera = context->getCamera(); 457 context->release(); 458 LOGV("native_release: context=%p camera=%p", context, camera.get()); 459 460 // clear callbacks 461 if (camera != NULL) { 462 camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); 463 camera->disconnect(); 464 } 465 466 // remove context to prevent further Java access 467 context->decStrong(thiz); 468 } 469} 470 471static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface) 472{ 473 LOGV("setPreviewDisplay"); 474 sp<Camera> camera = get_native_camera(env, thiz, NULL); 475 if (camera == 0) return; 476 477 sp<Surface> surface = NULL; 478 if (jSurface != NULL) { 479 surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface)); 480 } 481 if (camera->setPreviewDisplay(surface) != NO_ERROR) { 482 jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed"); 483 } 484} 485 486static void android_hardware_Camera_setPreviewTexture(JNIEnv *env, 487 jobject thiz, jobject jSurfaceTexture) 488{ 489 LOGV("setPreviewTexture"); 490 sp<Camera> camera = get_native_camera(env, thiz, NULL); 491 if (camera == 0) return; 492 493 sp<SurfaceTexture> surfaceTexture = NULL; 494 if (jSurfaceTexture != NULL) { 495 surfaceTexture = reinterpret_cast<SurfaceTexture*>(env->GetIntField( 496 jSurfaceTexture, fields.surfaceTexture)); 497 } 498 if (camera->setPreviewTexture(surfaceTexture) != NO_ERROR) { 499 jniThrowException(env, "java/io/IOException", 500 "setPreviewTexture failed"); 501 } 502} 503 504static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) 505{ 506 LOGV("startPreview"); 507 sp<Camera> camera = get_native_camera(env, thiz, NULL); 508 if (camera == 0) return; 509 510 if (camera->startPreview() != NO_ERROR) { 511 jniThrowException(env, "java/lang/RuntimeException", "startPreview failed"); 512 return; 513 } 514} 515 516static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz) 517{ 518 LOGV("stopPreview"); 519 sp<Camera> c = get_native_camera(env, thiz, NULL); 520 if (c == 0) return; 521 522 c->stopPreview(); 523} 524 525static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz) 526{ 527 LOGV("previewEnabled"); 528 sp<Camera> c = get_native_camera(env, thiz, NULL); 529 if (c == 0) return false; 530 531 return c->previewEnabled(); 532} 533 534static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean manualBuffer) 535{ 536 LOGV("setHasPreviewCallback: installed:%d, manualBuffer:%d", (int)installed, (int)manualBuffer); 537 // Important: Only install preview_callback if the Java code has called 538 // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy 539 // each preview frame for nothing. 540 JNICameraContext* context; 541 sp<Camera> camera = get_native_camera(env, thiz, &context); 542 if (camera == 0) return; 543 544 // setCallbackMode will take care of setting the context flags and calling 545 // camera->setPreviewCallbackFlags within a mutex for us. 546 context->setCallbackMode(env, installed, manualBuffer); 547} 548 549static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) { 550 LOGV("addCallbackBuffer: 0x%x", msgType); 551 552 JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 553 554 if (context != NULL) { 555 context->addCallbackBuffer(env, bytes, msgType); 556 } 557} 558 559static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) 560{ 561 LOGV("autoFocus"); 562 JNICameraContext* context; 563 sp<Camera> c = get_native_camera(env, thiz, &context); 564 if (c == 0) return; 565 566 if (c->autoFocus() != NO_ERROR) { 567 jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed"); 568 } 569} 570 571static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz) 572{ 573 LOGV("cancelAutoFocus"); 574 JNICameraContext* context; 575 sp<Camera> c = get_native_camera(env, thiz, &context); 576 if (c == 0) return; 577 578 if (c->cancelAutoFocus() != NO_ERROR) { 579 jniThrowException(env, "java/lang/RuntimeException", "cancelAutoFocus failed"); 580 } 581} 582 583static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz, int msgType) 584{ 585 LOGV("takePicture"); 586 JNICameraContext* context; 587 sp<Camera> camera = get_native_camera(env, thiz, &context); 588 if (camera == 0) return; 589 590 /* 591 * When CAMERA_MSG_RAW_IMAGE is requested, if the raw image callback 592 * buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the 593 * notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY 594 * is enabled to receive the callback notification but no data. 595 * 596 * Note that CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed to the 597 * Java application. 598 */ 599 if (msgType & CAMERA_MSG_RAW_IMAGE) { 600 LOGV("Enable raw image callback buffer"); 601 if (!context->isRawImageCallbackBufferAvailable()) { 602 LOGV("Enable raw image notification, since no callback buffer exists"); 603 msgType &= ~CAMERA_MSG_RAW_IMAGE; 604 msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY; 605 } 606 } 607 608 if (camera->takePicture(msgType) != NO_ERROR) { 609 jniThrowException(env, "java/lang/RuntimeException", "takePicture failed"); 610 return; 611 } 612} 613 614static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) 615{ 616 LOGV("setParameters"); 617 sp<Camera> camera = get_native_camera(env, thiz, NULL); 618 if (camera == 0) return; 619 620 const jchar* str = env->GetStringCritical(params, 0); 621 String8 params8; 622 if (params) { 623 params8 = String8(str, env->GetStringLength(params)); 624 env->ReleaseStringCritical(params, str); 625 } 626 if (camera->setParameters(params8) != NO_ERROR) { 627 jniThrowException(env, "java/lang/RuntimeException", "setParameters failed"); 628 return; 629 } 630} 631 632static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz) 633{ 634 LOGV("getParameters"); 635 sp<Camera> camera = get_native_camera(env, thiz, NULL); 636 if (camera == 0) return 0; 637 638 return env->NewStringUTF(camera->getParameters().string()); 639} 640 641static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz) 642{ 643 LOGV("reconnect"); 644 sp<Camera> camera = get_native_camera(env, thiz, NULL); 645 if (camera == 0) return; 646 647 if (camera->reconnect() != NO_ERROR) { 648 jniThrowException(env, "java/io/IOException", "reconnect failed"); 649 return; 650 } 651} 652 653static void android_hardware_Camera_lock(JNIEnv *env, jobject thiz) 654{ 655 LOGV("lock"); 656 sp<Camera> camera = get_native_camera(env, thiz, NULL); 657 if (camera == 0) return; 658 659 if (camera->lock() != NO_ERROR) { 660 jniThrowException(env, "java/lang/RuntimeException", "lock failed"); 661 } 662} 663 664static void android_hardware_Camera_unlock(JNIEnv *env, jobject thiz) 665{ 666 LOGV("unlock"); 667 sp<Camera> camera = get_native_camera(env, thiz, NULL); 668 if (camera == 0) return; 669 670 if (camera->unlock() != NO_ERROR) { 671 jniThrowException(env, "java/lang/RuntimeException", "unlock failed"); 672 } 673} 674 675static void android_hardware_Camera_startSmoothZoom(JNIEnv *env, jobject thiz, jint value) 676{ 677 LOGV("startSmoothZoom"); 678 sp<Camera> camera = get_native_camera(env, thiz, NULL); 679 if (camera == 0) return; 680 681 status_t rc = camera->sendCommand(CAMERA_CMD_START_SMOOTH_ZOOM, value, 0); 682 if (rc == BAD_VALUE) { 683 char msg[64]; 684 sprintf(msg, "invalid zoom value=%d", value); 685 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 686 } else if (rc != NO_ERROR) { 687 jniThrowException(env, "java/lang/RuntimeException", "start smooth zoom failed"); 688 } 689} 690 691static void android_hardware_Camera_stopSmoothZoom(JNIEnv *env, jobject thiz) 692{ 693 LOGV("stopSmoothZoom"); 694 sp<Camera> camera = get_native_camera(env, thiz, NULL); 695 if (camera == 0) return; 696 697 if (camera->sendCommand(CAMERA_CMD_STOP_SMOOTH_ZOOM, 0, 0) != NO_ERROR) { 698 jniThrowException(env, "java/lang/RuntimeException", "stop smooth zoom failed"); 699 } 700} 701 702static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject thiz, 703 jint value) 704{ 705 LOGV("setDisplayOrientation"); 706 sp<Camera> camera = get_native_camera(env, thiz, NULL); 707 if (camera == 0) return; 708 709 if (camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION, value, 0) != NO_ERROR) { 710 jniThrowException(env, "java/lang/RuntimeException", "set display orientation failed"); 711 } 712} 713 714//------------------------------------------------- 715 716static JNINativeMethod camMethods[] = { 717 { "getNumberOfCameras", 718 "()I", 719 (void *)android_hardware_Camera_getNumberOfCameras }, 720 { "getCameraInfo", 721 "(ILandroid/hardware/Camera$CameraInfo;)V", 722 (void*)android_hardware_Camera_getCameraInfo }, 723 { "native_setup", 724 "(Ljava/lang/Object;I)V", 725 (void*)android_hardware_Camera_native_setup }, 726 { "native_release", 727 "()V", 728 (void*)android_hardware_Camera_release }, 729 { "setPreviewDisplay", 730 "(Landroid/view/Surface;)V", 731 (void *)android_hardware_Camera_setPreviewDisplay }, 732 { "setPreviewTexture", 733 "(Landroid/graphics/SurfaceTexture;)V", 734 (void *)android_hardware_Camera_setPreviewTexture }, 735 { "startPreview", 736 "()V", 737 (void *)android_hardware_Camera_startPreview }, 738 { "stopPreview", 739 "()V", 740 (void *)android_hardware_Camera_stopPreview }, 741 { "previewEnabled", 742 "()Z", 743 (void *)android_hardware_Camera_previewEnabled }, 744 { "setHasPreviewCallback", 745 "(ZZ)V", 746 (void *)android_hardware_Camera_setHasPreviewCallback }, 747 { "_addCallbackBuffer", 748 "([BI)V", 749 (void *)android_hardware_Camera_addCallbackBuffer }, 750 { "native_autoFocus", 751 "()V", 752 (void *)android_hardware_Camera_autoFocus }, 753 { "native_cancelAutoFocus", 754 "()V", 755 (void *)android_hardware_Camera_cancelAutoFocus }, 756 { "native_takePicture", 757 "(I)V", 758 (void *)android_hardware_Camera_takePicture }, 759 { "native_setParameters", 760 "(Ljava/lang/String;)V", 761 (void *)android_hardware_Camera_setParameters }, 762 { "native_getParameters", 763 "()Ljava/lang/String;", 764 (void *)android_hardware_Camera_getParameters }, 765 { "reconnect", 766 "()V", 767 (void*)android_hardware_Camera_reconnect }, 768 { "lock", 769 "()V", 770 (void*)android_hardware_Camera_lock }, 771 { "unlock", 772 "()V", 773 (void*)android_hardware_Camera_unlock }, 774 { "startSmoothZoom", 775 "(I)V", 776 (void *)android_hardware_Camera_startSmoothZoom }, 777 { "stopSmoothZoom", 778 "()V", 779 (void *)android_hardware_Camera_stopSmoothZoom }, 780 { "setDisplayOrientation", 781 "(I)V", 782 (void *)android_hardware_Camera_setDisplayOrientation }, 783}; 784 785struct field { 786 const char *class_name; 787 const char *field_name; 788 const char *field_type; 789 jfieldID *jfield; 790}; 791 792static int find_fields(JNIEnv *env, field *fields, int count) 793{ 794 for (int i = 0; i < count; i++) { 795 field *f = &fields[i]; 796 jclass clazz = env->FindClass(f->class_name); 797 if (clazz == NULL) { 798 LOGE("Can't find %s", f->class_name); 799 return -1; 800 } 801 802 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type); 803 if (field == NULL) { 804 LOGE("Can't find %s.%s", f->class_name, f->field_name); 805 return -1; 806 } 807 808 *(f->jfield) = field; 809 } 810 811 return 0; 812} 813 814// Get all the required offsets in java class and register native functions 815int register_android_hardware_Camera(JNIEnv *env) 816{ 817 field fields_to_find[] = { 818 { "android/hardware/Camera", "mNativeContext", "I", &fields.context }, 819 { "android/view/Surface", ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface }, 820 { "android/graphics/SurfaceTexture", 821 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I", &fields.surfaceTexture }, 822 { "android/hardware/Camera$CameraInfo", "facing", "I", &fields.facing }, 823 { "android/hardware/Camera$CameraInfo", "orientation", "I", &fields.orientation }, 824 }; 825 826 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) 827 return -1; 828 829 jclass clazz = env->FindClass("android/hardware/Camera"); 830 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 831 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 832 if (fields.post_event == NULL) { 833 LOGE("Can't find android/hardware/Camera.postEventFromNative"); 834 return -1; 835 } 836 837 838 // Register native functions 839 return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera", 840 camMethods, NELEM(camMethods)); 841} 842