android_hardware_Camera.cpp revision 69a017bc1d1649350f830dfada5c6ed5eac0b770
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 jniThrowRuntimeException(env, "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 jniThrowRuntimeException(env, "Unsupported message type"); 236 return; 237 } 238 } 239 } 240 241 if (obj == NULL) { 242 LOGE("Couldn't allocate byte array for JPEG data"); 243 env->ExceptionClear(); 244 } else { 245 env->SetByteArrayRegion(obj, 0, size, data); 246 } 247 } else { 248 LOGE("image heap is NULL"); 249 } 250 } 251 252 // post image data to Java 253 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 254 mCameraJObjectWeak, msgType, 0, 0, obj); 255 if (obj) { 256 env->DeleteLocalRef(obj); 257 } 258} 259 260void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) 261{ 262 // VM pointer will be NULL if object is released 263 Mutex::Autolock _l(mLock); 264 JNIEnv *env = AndroidRuntime::getJNIEnv(); 265 if (mCameraJObjectWeak == NULL) { 266 LOGW("callback on dead camera object"); 267 return; 268 } 269 270 // return data based on callback type 271 switch (msgType) { 272 case CAMERA_MSG_VIDEO_FRAME: 273 // should never happen 274 break; 275 276 // For backward-compatibility purpose, if there is no callback 277 // buffer for raw image, the callback returns null. 278 case CAMERA_MSG_RAW_IMAGE: 279 LOGV("rawCallback"); 280 if (mRawImageCallbackBuffers.isEmpty()) { 281 env->CallStaticVoidMethod(mCameraJClass, fields.post_event, 282 mCameraJObjectWeak, msgType, 0, 0, NULL); 283 } else { 284 copyAndPost(env, dataPtr, msgType); 285 } 286 break; 287 288 default: 289 LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); 290 copyAndPost(env, dataPtr, msgType); 291 break; 292 } 293} 294 295void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) 296{ 297 // TODO: plumb up to Java. For now, just drop the timestamp 298 postData(msgType, dataPtr); 299} 300 301void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode) 302{ 303 Mutex::Autolock _l(mLock); 304 mManualBufferMode = manualMode; 305 mManualCameraCallbackSet = false; 306 307 // In order to limit the over usage of binder threads, all non-manual buffer 308 // callbacks use FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now. 309 // 310 // Continuous callbacks will have the callback re-registered from handleMessage. 311 // Manual buffer mode will operate as fast as possible, relying on the finite supply 312 // of buffers for throttling. 313 314 if (!installed) { 315 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); 316 clearCallbackBuffers_l(env, &mCallbackBuffers); 317 } else if (mManualBufferMode) { 318 if (!mCallbackBuffers.isEmpty()) { 319 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); 320 mManualCameraCallbackSet = true; 321 } 322 } else { 323 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER); 324 clearCallbackBuffers_l(env, &mCallbackBuffers); 325 } 326} 327 328void JNICameraContext::addCallbackBuffer( 329 JNIEnv *env, jbyteArray cbb, int msgType) 330{ 331 LOGV("addCallbackBuffer: 0x%x", msgType); 332 if (cbb != NULL) { 333 Mutex::Autolock _l(mLock); 334 switch (msgType) { 335 case CAMERA_MSG_PREVIEW_FRAME: { 336 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); 337 mCallbackBuffers.push(callbackBuffer); 338 339 LOGV("Adding callback buffer to queue, %d total", 340 mCallbackBuffers.size()); 341 342 // We want to make sure the camera knows we're ready for the 343 // next frame. This may have come unset had we not had a 344 // callbackbuffer ready for it last time. 345 if (mManualBufferMode && !mManualCameraCallbackSet) { 346 mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); 347 mManualCameraCallbackSet = true; 348 } 349 break; 350 } 351 case CAMERA_MSG_RAW_IMAGE: { 352 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); 353 mRawImageCallbackBuffers.push(callbackBuffer); 354 break; 355 } 356 default: { 357 jniThrowException(env, 358 "java/lang/IllegalArgumentException", 359 "Unsupported message type"); 360 return; 361 } 362 } 363 } else { 364 LOGE("Null byte array!"); 365 } 366} 367 368void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) 369{ 370 clearCallbackBuffers_l(env, &mCallbackBuffers); 371 clearCallbackBuffers_l(env, &mRawImageCallbackBuffers); 372} 373 374void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers) { 375 LOGV("Clearing callback buffers, %d remained", buffers->size()); 376 while (!buffers->isEmpty()) { 377 env->DeleteGlobalRef(buffers->top()); 378 buffers->pop(); 379 } 380} 381 382static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz) 383{ 384 return Camera::getNumberOfCameras(); 385} 386 387static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, 388 jint cameraId, jobject info_obj) 389{ 390 CameraInfo cameraInfo; 391 status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo); 392 if (rc != NO_ERROR) { 393 jniThrowRuntimeException(env, "Fail to get camera info"); 394 return; 395 } 396 env->SetIntField(info_obj, fields.facing, cameraInfo.facing); 397 env->SetIntField(info_obj, fields.orientation, cameraInfo.orientation); 398} 399 400// connect to camera service 401static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, 402 jobject weak_this, jint cameraId) 403{ 404 sp<Camera> camera = Camera::connect(cameraId); 405 406 if (camera == NULL) { 407 jniThrowRuntimeException(env, "Fail to connect to camera service"); 408 return; 409 } 410 411 // make sure camera hardware is alive 412 if (camera->getStatus() != NO_ERROR) { 413 jniThrowRuntimeException(env, "Camera initialization failed"); 414 return; 415 } 416 417 jclass clazz = env->GetObjectClass(thiz); 418 if (clazz == NULL) { 419 jniThrowRuntimeException(env, "Can't find android/hardware/Camera"); 420 return; 421 } 422 423 // We use a weak reference so the Camera object can be garbage collected. 424 // The reference is only used as a proxy for callbacks. 425 sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera); 426 context->incStrong(thiz); 427 camera->setListener(context); 428 429 // save context in opaque field 430 env->SetIntField(thiz, fields.context, (int)context.get()); 431} 432 433// disconnect from camera service 434// It's okay to call this when the native camera context is already null. 435// This handles the case where the user has called release() and the 436// finalizer is invoked later. 437static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) 438{ 439 // TODO: Change to LOGV 440 LOGV("release camera"); 441 JNICameraContext* context = NULL; 442 sp<Camera> camera; 443 { 444 Mutex::Autolock _l(sLock); 445 context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 446 447 // Make sure we do not attempt to callback on a deleted Java object. 448 env->SetIntField(thiz, fields.context, 0); 449 } 450 451 // clean up if release has not been called before 452 if (context != NULL) { 453 camera = context->getCamera(); 454 context->release(); 455 LOGV("native_release: context=%p camera=%p", context, camera.get()); 456 457 // clear callbacks 458 if (camera != NULL) { 459 camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); 460 camera->disconnect(); 461 } 462 463 // remove context to prevent further Java access 464 context->decStrong(thiz); 465 } 466} 467 468static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface) 469{ 470 LOGV("setPreviewDisplay"); 471 sp<Camera> camera = get_native_camera(env, thiz, NULL); 472 if (camera == 0) return; 473 474 sp<Surface> surface = NULL; 475 if (jSurface != NULL) { 476 surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface)); 477 } 478 if (camera->setPreviewDisplay(surface) != NO_ERROR) { 479 jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed"); 480 } 481} 482 483static void android_hardware_Camera_setPreviewTexture(JNIEnv *env, 484 jobject thiz, jobject jSurfaceTexture) 485{ 486 LOGV("setPreviewTexture"); 487 sp<Camera> camera = get_native_camera(env, thiz, NULL); 488 if (camera == 0) return; 489 490 sp<SurfaceTexture> surfaceTexture = NULL; 491 if (jSurfaceTexture != NULL) { 492 surfaceTexture = reinterpret_cast<SurfaceTexture*>(env->GetIntField( 493 jSurfaceTexture, fields.surfaceTexture)); 494 } 495 if (camera->setPreviewTexture(surfaceTexture) != NO_ERROR) { 496 jniThrowException(env, "java/io/IOException", 497 "setPreviewTexture failed"); 498 } 499} 500 501static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) 502{ 503 LOGV("startPreview"); 504 sp<Camera> camera = get_native_camera(env, thiz, NULL); 505 if (camera == 0) return; 506 507 if (camera->startPreview() != NO_ERROR) { 508 jniThrowRuntimeException(env, "startPreview failed"); 509 return; 510 } 511} 512 513static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz) 514{ 515 LOGV("stopPreview"); 516 sp<Camera> c = get_native_camera(env, thiz, NULL); 517 if (c == 0) return; 518 519 c->stopPreview(); 520} 521 522static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz) 523{ 524 LOGV("previewEnabled"); 525 sp<Camera> c = get_native_camera(env, thiz, NULL); 526 if (c == 0) return false; 527 528 return c->previewEnabled(); 529} 530 531static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean manualBuffer) 532{ 533 LOGV("setHasPreviewCallback: installed:%d, manualBuffer:%d", (int)installed, (int)manualBuffer); 534 // Important: Only install preview_callback if the Java code has called 535 // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy 536 // each preview frame for nothing. 537 JNICameraContext* context; 538 sp<Camera> camera = get_native_camera(env, thiz, &context); 539 if (camera == 0) return; 540 541 // setCallbackMode will take care of setting the context flags and calling 542 // camera->setPreviewCallbackFlags within a mutex for us. 543 context->setCallbackMode(env, installed, manualBuffer); 544} 545 546static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) { 547 LOGV("addCallbackBuffer: 0x%x", msgType); 548 549 JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); 550 551 if (context != NULL) { 552 context->addCallbackBuffer(env, bytes, msgType); 553 } 554} 555 556static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) 557{ 558 LOGV("autoFocus"); 559 JNICameraContext* context; 560 sp<Camera> c = get_native_camera(env, thiz, &context); 561 if (c == 0) return; 562 563 if (c->autoFocus() != NO_ERROR) { 564 jniThrowRuntimeException(env, "autoFocus failed"); 565 } 566} 567 568static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz) 569{ 570 LOGV("cancelAutoFocus"); 571 JNICameraContext* context; 572 sp<Camera> c = get_native_camera(env, thiz, &context); 573 if (c == 0) return; 574 575 if (c->cancelAutoFocus() != NO_ERROR) { 576 jniThrowRuntimeException(env, "cancelAutoFocus failed"); 577 } 578} 579 580static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz, int msgType) 581{ 582 LOGV("takePicture"); 583 JNICameraContext* context; 584 sp<Camera> camera = get_native_camera(env, thiz, &context); 585 if (camera == 0) return; 586 587 /* 588 * When CAMERA_MSG_RAW_IMAGE is requested, if the raw image callback 589 * buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the 590 * notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY 591 * is enabled to receive the callback notification but no data. 592 * 593 * Note that CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed to the 594 * Java application. 595 */ 596 if (msgType & CAMERA_MSG_RAW_IMAGE) { 597 LOGV("Enable raw image callback buffer"); 598 if (!context->isRawImageCallbackBufferAvailable()) { 599 LOGV("Enable raw image notification, since no callback buffer exists"); 600 msgType &= ~CAMERA_MSG_RAW_IMAGE; 601 msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY; 602 } 603 } 604 605 if (camera->takePicture(msgType) != NO_ERROR) { 606 jniThrowRuntimeException(env, "takePicture failed"); 607 return; 608 } 609} 610 611static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) 612{ 613 LOGV("setParameters"); 614 sp<Camera> camera = get_native_camera(env, thiz, NULL); 615 if (camera == 0) return; 616 617 const jchar* str = env->GetStringCritical(params, 0); 618 String8 params8; 619 if (params) { 620 params8 = String8(str, env->GetStringLength(params)); 621 env->ReleaseStringCritical(params, str); 622 } 623 if (camera->setParameters(params8) != NO_ERROR) { 624 jniThrowRuntimeException(env, "setParameters failed"); 625 return; 626 } 627} 628 629static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz) 630{ 631 LOGV("getParameters"); 632 sp<Camera> camera = get_native_camera(env, thiz, NULL); 633 if (camera == 0) return 0; 634 635 return env->NewStringUTF(camera->getParameters().string()); 636} 637 638static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz) 639{ 640 LOGV("reconnect"); 641 sp<Camera> camera = get_native_camera(env, thiz, NULL); 642 if (camera == 0) return; 643 644 if (camera->reconnect() != NO_ERROR) { 645 jniThrowException(env, "java/io/IOException", "reconnect failed"); 646 return; 647 } 648} 649 650static void android_hardware_Camera_lock(JNIEnv *env, jobject thiz) 651{ 652 LOGV("lock"); 653 sp<Camera> camera = get_native_camera(env, thiz, NULL); 654 if (camera == 0) return; 655 656 if (camera->lock() != NO_ERROR) { 657 jniThrowRuntimeException(env, "lock failed"); 658 } 659} 660 661static void android_hardware_Camera_unlock(JNIEnv *env, jobject thiz) 662{ 663 LOGV("unlock"); 664 sp<Camera> camera = get_native_camera(env, thiz, NULL); 665 if (camera == 0) return; 666 667 if (camera->unlock() != NO_ERROR) { 668 jniThrowRuntimeException(env, "unlock failed"); 669 } 670} 671 672static void android_hardware_Camera_startSmoothZoom(JNIEnv *env, jobject thiz, jint value) 673{ 674 LOGV("startSmoothZoom"); 675 sp<Camera> camera = get_native_camera(env, thiz, NULL); 676 if (camera == 0) return; 677 678 status_t rc = camera->sendCommand(CAMERA_CMD_START_SMOOTH_ZOOM, value, 0); 679 if (rc == BAD_VALUE) { 680 char msg[64]; 681 sprintf(msg, "invalid zoom value=%d", value); 682 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 683 } else if (rc != NO_ERROR) { 684 jniThrowRuntimeException(env, "start smooth zoom failed"); 685 } 686} 687 688static void android_hardware_Camera_stopSmoothZoom(JNIEnv *env, jobject thiz) 689{ 690 LOGV("stopSmoothZoom"); 691 sp<Camera> camera = get_native_camera(env, thiz, NULL); 692 if (camera == 0) return; 693 694 if (camera->sendCommand(CAMERA_CMD_STOP_SMOOTH_ZOOM, 0, 0) != NO_ERROR) { 695 jniThrowRuntimeException(env, "stop smooth zoom failed"); 696 } 697} 698 699static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject thiz, 700 jint value) 701{ 702 LOGV("setDisplayOrientation"); 703 sp<Camera> camera = get_native_camera(env, thiz, NULL); 704 if (camera == 0) return; 705 706 if (camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION, value, 0) != NO_ERROR) { 707 jniThrowRuntimeException(env, "set display orientation failed"); 708 } 709} 710 711//------------------------------------------------- 712 713static JNINativeMethod camMethods[] = { 714 { "getNumberOfCameras", 715 "()I", 716 (void *)android_hardware_Camera_getNumberOfCameras }, 717 { "getCameraInfo", 718 "(ILandroid/hardware/Camera$CameraInfo;)V", 719 (void*)android_hardware_Camera_getCameraInfo }, 720 { "native_setup", 721 "(Ljava/lang/Object;I)V", 722 (void*)android_hardware_Camera_native_setup }, 723 { "native_release", 724 "()V", 725 (void*)android_hardware_Camera_release }, 726 { "setPreviewDisplay", 727 "(Landroid/view/Surface;)V", 728 (void *)android_hardware_Camera_setPreviewDisplay }, 729 { "setPreviewTexture", 730 "(Landroid/graphics/SurfaceTexture;)V", 731 (void *)android_hardware_Camera_setPreviewTexture }, 732 { "startPreview", 733 "()V", 734 (void *)android_hardware_Camera_startPreview }, 735 { "stopPreview", 736 "()V", 737 (void *)android_hardware_Camera_stopPreview }, 738 { "previewEnabled", 739 "()Z", 740 (void *)android_hardware_Camera_previewEnabled }, 741 { "setHasPreviewCallback", 742 "(ZZ)V", 743 (void *)android_hardware_Camera_setHasPreviewCallback }, 744 { "_addCallbackBuffer", 745 "([BI)V", 746 (void *)android_hardware_Camera_addCallbackBuffer }, 747 { "native_autoFocus", 748 "()V", 749 (void *)android_hardware_Camera_autoFocus }, 750 { "native_cancelAutoFocus", 751 "()V", 752 (void *)android_hardware_Camera_cancelAutoFocus }, 753 { "native_takePicture", 754 "(I)V", 755 (void *)android_hardware_Camera_takePicture }, 756 { "native_setParameters", 757 "(Ljava/lang/String;)V", 758 (void *)android_hardware_Camera_setParameters }, 759 { "native_getParameters", 760 "()Ljava/lang/String;", 761 (void *)android_hardware_Camera_getParameters }, 762 { "reconnect", 763 "()V", 764 (void*)android_hardware_Camera_reconnect }, 765 { "lock", 766 "()V", 767 (void*)android_hardware_Camera_lock }, 768 { "unlock", 769 "()V", 770 (void*)android_hardware_Camera_unlock }, 771 { "startSmoothZoom", 772 "(I)V", 773 (void *)android_hardware_Camera_startSmoothZoom }, 774 { "stopSmoothZoom", 775 "()V", 776 (void *)android_hardware_Camera_stopSmoothZoom }, 777 { "setDisplayOrientation", 778 "(I)V", 779 (void *)android_hardware_Camera_setDisplayOrientation }, 780}; 781 782struct field { 783 const char *class_name; 784 const char *field_name; 785 const char *field_type; 786 jfieldID *jfield; 787}; 788 789static int find_fields(JNIEnv *env, field *fields, int count) 790{ 791 for (int i = 0; i < count; i++) { 792 field *f = &fields[i]; 793 jclass clazz = env->FindClass(f->class_name); 794 if (clazz == NULL) { 795 LOGE("Can't find %s", f->class_name); 796 return -1; 797 } 798 799 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type); 800 if (field == NULL) { 801 LOGE("Can't find %s.%s", f->class_name, f->field_name); 802 return -1; 803 } 804 805 *(f->jfield) = field; 806 } 807 808 return 0; 809} 810 811// Get all the required offsets in java class and register native functions 812int register_android_hardware_Camera(JNIEnv *env) 813{ 814 field fields_to_find[] = { 815 { "android/hardware/Camera", "mNativeContext", "I", &fields.context }, 816 { "android/view/Surface", ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface }, 817 { "android/graphics/SurfaceTexture", 818 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I", &fields.surfaceTexture }, 819 { "android/hardware/Camera$CameraInfo", "facing", "I", &fields.facing }, 820 { "android/hardware/Camera$CameraInfo", "orientation", "I", &fields.orientation }, 821 }; 822 823 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) 824 return -1; 825 826 jclass clazz = env->FindClass("android/hardware/Camera"); 827 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 828 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 829 if (fields.post_event == NULL) { 830 LOGE("Can't find android/hardware/Camera.postEventFromNative"); 831 return -1; 832 } 833 834 835 // Register native functions 836 return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera", 837 camMethods, NELEM(camMethods)); 838} 839