Loading core/jni/android_hardware_Camera.cpp +156 −182 Original line number Original line Diff line number Diff line Loading @@ -53,19 +53,33 @@ struct fields_t { static fields_t fields; static fields_t fields; static Mutex sLock; static Mutex sLock; struct camera_context_t { // provides persistent context for calls from native code to Java class JNICameraContext: public CameraListener { public: JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera); ~JNICameraContext() { release(); } virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } void release(); private: void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); jobject mCameraJObjectWeak; // weak reference to java object jobject mCameraJObjectWeak; // weak reference to java object jclass mCameraJClass; // strong reference to java class jclass mCameraJClass; // strong reference to java class sp<Camera> mCamera; // strong reference to native object sp<Camera> mCamera; // strong reference to native object Mutex mLock; }; }; sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pContext) sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) { { sp<Camera> camera; sp<Camera> camera; Mutex::Autolock _l(sLock); Mutex::Autolock _l(sLock); camera_context_t* context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context)); JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); if (context != NULL) { if (context != NULL) { camera = context->mCamera; camera = context->getCamera(); } } LOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); LOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); if (camera == 0) { if (camera == 0) { Loading @@ -76,15 +90,48 @@ sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pCont return camera; return camera; } } static void err_callback(status_t err, void *cookie) JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera) { { camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); mCameraJObjectWeak = env->NewGlobalRef(weak_this); if ((context == NULL) || (context->mCamera == 0)) return; mCameraJClass = (jclass)env->NewGlobalRef(clazz); mCamera = camera; } LOGV("err_callback: context=%p, camera=%p", context, context->mCamera.get()); void JNICameraContext::release() { LOGV("release"); Mutex::Autolock _l(mLock); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mCameraJObjectWeak != NULL) { env->DeleteGlobalRef(mCameraJObjectWeak); mCameraJObjectWeak = NULL; } if (mCameraJClass != NULL) { env->DeleteGlobalRef(mCameraJClass); mCameraJClass = NULL; } mCamera.clear(); } void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2) { LOGV("notify"); // VM pointer will be NULL if object is released Mutex::Autolock _l(mLock); if (mCameraJObjectWeak == NULL) { LOGW("callback on dead camera object"); return; } JNIEnv *env = AndroidRuntime::getJNIEnv(); // parse message switch (msgType) { case CAMERA_MSG_ERROR: LOGV("errorCallback"); int error; int error; switch (err) { switch (ext1) { case DEAD_OBJECT: case DEAD_OBJECT: error = kCameraErrorMediaServer; error = kCameraErrorMediaServer; break; break; Loading @@ -92,14 +139,91 @@ static void err_callback(status_t err, void *cookie) error = kCameraErrorUnknown; error = kCameraErrorUnknown; break; break; } } env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, kErrorCallback, error, 0, NULL); break; case CAMERA_MSG_FOCUS: LOGV("autoFocusCallback"); env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, kAutoFocusCallback, ext1, 0, NULL); break; case CAMERA_MSG_SHUTTER: LOGV("shutterCallback"); env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, kShutterCallback, 0, 0, NULL); break; default: LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2); break; } } void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) { jbyteArray obj = NULL; // allocate Java byte array and copy data if (dataPtr != NULL) { ssize_t offset; size_t size; sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size); LOGV("postData: off=%d, size=%d", offset, size); uint8_t *heapBase = (uint8_t*)heap->base(); if (heapBase != NULL) { uint8_t *data = heapBase + offset; obj = env->NewByteArray(size); if (obj == NULL) { LOGE("Couldn't allocate byte array for JPEG data"); env->ExceptionClear(); } else { jbyte *bytes = env->GetByteArrayElements(obj, NULL); memcpy(bytes, data, size); env->ReleaseByteArrayElements(obj, bytes, 0); } } else { LOGE("image heap is NULL"); } } // post image data to Java env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, msgType, 0, 0, obj); if (obj) { env->DeleteLocalRef(obj); } } void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) { // VM pointer will be NULL if object is released Mutex::Autolock _l(mLock); JNIEnv *env = AndroidRuntime::getJNIEnv(); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("err_callback on dead VM"); // return data based on callback type return; switch(msgType) { case CAMERA_MSG_PREVIEW_FRAME: LOGV("previewCallback"); copyAndPost(env, dataPtr, kPreviewCallback); break; case CAMERA_MSG_VIDEO_FRAME: LOGV("recordingCallback"); break; case CAMERA_MSG_RAW_IMAGE: LOGV("rawCallback"); env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, kRawCallback, 0, 0, NULL); break; case CAMERA_MSG_COMPRESSED_IMAGE: LOGV("jpegCallback"); copyAndPost(env, dataPtr, kJpegCallback); break; default: LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); break; } } env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kErrorCallback, error, 0, NULL); } } // connect to camera service // connect to camera service Loading Loading @@ -127,19 +251,12 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj // We use a weak reference so the Camera object can be garbage collected. // We use a weak reference so the Camera object can be garbage collected. // The reference is only used as a proxy for callbacks. // The reference is only used as a proxy for callbacks. camera_context_t* context = new camera_context_t; sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera); context->mCameraJObjectWeak = env->NewGlobalRef(weak_this); context->incStrong(thiz); context->mCameraJClass = (jclass)env->NewGlobalRef(clazz); camera->setListener(context); context->mCamera = camera; // save context in opaque field // save context in opaque field env->SetIntField(thiz, fields.context, (int)context); env->SetIntField(thiz, fields.context, (int)context.get()); LOGV("native_setup: mCameraJObjectWeak=%x, camera_obj=%x, context=%p", (int)context->mCameraJObjectWeak, (int)thiz, context); // set error callback camera->setErrorCallback(err_callback, context); } } // disconnect from camera service // disconnect from camera service Loading @@ -148,11 +265,11 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj // finalizer is invoked later. // finalizer is invoked later. static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) { { camera_context_t* context = NULL; JNICameraContext* context = NULL; sp<Camera> camera; sp<Camera> camera; { { Mutex::Autolock _l(sLock); Mutex::Autolock _l(sLock); context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context)); context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); // Make sure we do not attempt to callback on a deleted Java object. // Make sure we do not attempt to callback on a deleted Java object. env->SetIntField(thiz, fields.context, 0); env->SetIntField(thiz, fields.context, 0); Loading @@ -160,21 +277,18 @@ static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) // clean up if release has not been called before // clean up if release has not been called before if (context != NULL) { if (context != NULL) { camera = context->mCamera; camera = context->getCamera(); context->mCamera.clear(); context->release(); LOGV("native_release: context=%p camera=%p", context, camera.get()); LOGV("native_release: context=%p camera=%p", context, camera.get()); // clear callbacks // clear callbacks if (camera != NULL) { if (camera != NULL) { camera->setPreviewCallback(NULL, NULL, FRAME_CALLBACK_FLAG_NOOP); camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); camera->setErrorCallback(NULL, NULL); camera->disconnect(); camera->disconnect(); env->DeleteGlobalRef(context->mCameraJObjectWeak); env->DeleteGlobalRef(context->mCameraJClass); } } // remove context to prevent further Java access // remove context to prevent further Java access delete context; context->decStrong(thiz); } } } } Loading @@ -190,48 +304,6 @@ static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, } } } } static void preview_callback(const sp<IMemory>& mem, void *cookie) { LOGV("preview_callback"); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("preview_callback on dead VM"); return; } camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); if ((context == NULL) || (context->mCamera == 0)) { LOGW("context or camera is NULL in preview_callback"); return; } LOGV("native_release: context=%p camera=%p", context, context->mCamera.get()); int arg1 = 0, arg2 = 0; jobject obj = NULL; ssize_t offset; size_t size; sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); uint8_t *data = ((uint8_t *)heap->base()) + offset; jbyteArray array = env->NewByteArray(size); if (array == NULL) { LOGE("Couldn't allocate byte array for YUV data"); env->ExceptionClear(); return; } jbyte *bytes = env->GetByteArrayElements(array, NULL); memcpy(bytes, data, size); env->ReleaseByteArrayElements(array, bytes, 0); obj = array; env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kPreviewCallback, arg1, arg2, obj); env->DeleteLocalRef(array); } static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) { { LOGV("startPreview"); LOGV("startPreview"); Loading Loading @@ -267,7 +339,7 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t // Important: Only install preview_callback if the Java code has called // Important: Only install preview_callback if the Java code has called // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy // each preview frame for nothing. // each preview frame for nothing. camera_context_t* context; JNICameraContext* context; sp<Camera> camera = get_native_camera(env, thiz, &context); sp<Camera> camera = get_native_camera(env, thiz, &context); if (camera == 0) return; if (camera == 0) return; Loading @@ -277,130 +349,32 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t } else { } else { callback_flag = FRAME_CALLBACK_FLAG_NOOP; callback_flag = FRAME_CALLBACK_FLAG_NOOP; } } camera->setPreviewCallback(installed ? preview_callback : NULL, context, callback_flag); camera->setPreviewCallbackFlags(callback_flag); } static void autofocus_callback_impl(bool success, void *cookie) { LOGV("autoFocusCallback"); camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("autofocus_callback on dead VM"); return; } env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kAutoFocusCallback, success, 0, NULL); } } static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) { { LOGV("autoFocus"); LOGV("autoFocus"); camera_context_t* context; JNICameraContext* context; sp<Camera> c = get_native_camera(env, thiz, &context); sp<Camera> c = get_native_camera(env, thiz, &context); if (c == 0) return; if (c == 0) return; c->setAutoFocusCallback(autofocus_callback_impl, context); if (c->autoFocus() != NO_ERROR) { if (c->autoFocus() != NO_ERROR) { jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed"); jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed"); } } } } static void jpeg_callback(const sp<IMemory>& mem, void *cookie) { LOGV("jpegCallback"); camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("jpeg`_callback on dead VM"); return; } int arg1 = 0, arg2 = 0; jobject obj = NULL; if (mem == NULL) { env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, NULL); return; } ssize_t offset; size_t size; sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); LOGV("jpeg_callback: mem off=%d, size=%d", offset, size); uint8_t *heap_base = (uint8_t *)heap->base(); if (heap_base == NULL) { LOGE("YUV heap is NULL"); return; } uint8_t *data = heap_base + offset; jbyteArray array = env->NewByteArray(size); if (array == NULL) { LOGE("Couldn't allocate byte array for JPEG data"); env->ExceptionClear(); return; } jbyte *bytes = env->GetByteArrayElements(array, NULL); memcpy(bytes, data, size); env->ReleaseByteArrayElements(array, bytes, 0); obj = array; env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, obj); env->DeleteLocalRef(array); } static void shutter_callback_impl(void *cookie) { LOGV("shutterCallback"); camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("shutter_callback on dead VM"); return; } env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kShutterCallback, 0, 0, NULL); } static void raw_callback(const sp<IMemory>& mem __attribute__((unused)), void *cookie) { LOGV("rawCallback"); camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("raw_callback on dead VM"); return; } env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kRawCallback, 0, 0, NULL); } static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) { { LOGV("takePicture"); LOGV("takePicture"); camera_context_t* context; JNICameraContext* context; sp<Camera> camera = get_native_camera(env, thiz, &context); sp<Camera> camera = get_native_camera(env, thiz, &context); if (camera == 0) return; if (camera == 0) return; camera->setShutterCallback(shutter_callback_impl, context); camera->setRawCallback(raw_callback, context); camera->setJpegCallback(jpeg_callback, context); if (camera->takePicture() != NO_ERROR) { if (camera->takePicture() != NO_ERROR) { jniThrowException(env, "java/lang/RuntimeException", "takePicture failed"); jniThrowException(env, "java/lang/RuntimeException", "takePicture failed"); return; return; } } return; } } static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) Loading include/ui/Camera.h +13 −0 Original line number Original line Diff line number Diff line Loading @@ -86,6 +86,14 @@ class Surface; class Mutex; class Mutex; class String8; class String8; // ref-counted object for callbacks class CameraListener: virtual public RefBase { public: virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0; virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0; }; typedef void (*shutter_callback)(void *cookie); typedef void (*shutter_callback)(void *cookie); typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie); typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie); typedef void (*autofocus_callback)(bool focused, void *cookie); typedef void (*autofocus_callback)(bool focused, void *cookie); Loading Loading @@ -152,6 +160,9 @@ public: void setErrorCallback(error_callback cb, void *cookie); void setErrorCallback(error_callback cb, void *cookie); void setAutoFocusCallback(autofocus_callback cb, void *cookie); void setAutoFocusCallback(autofocus_callback cb, void *cookie); void setListener(const sp<CameraListener>& listener); void setPreviewCallbackFlags(int preview_callback_flag); // ICameraClient interface // ICameraClient interface virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2); virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2); virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr); virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr); Loading Loading @@ -194,6 +205,8 @@ private: autofocus_callback mAutoFocusCallback; autofocus_callback mAutoFocusCallback; void *mAutoFocusCallbackCookie; void *mAutoFocusCallbackCookie; sp<CameraListener> mListener; friend class DeathNotifier; friend class DeathNotifier; static Mutex mLock; static Mutex mLock; Loading libs/ui/Camera.cpp +33 −0 Original line number Original line Diff line number Diff line Loading @@ -337,9 +337,32 @@ void Camera::setErrorCallback(error_callback cb, void *cookie) mErrorCallbackCookie = cookie; mErrorCallbackCookie = cookie; } } void Camera::setListener(const sp<CameraListener>& listener) { Mutex::Autolock _l(mLock); mListener = listener; } void Camera::setPreviewCallbackFlags(int flag) { LOGV("setPreviewCallbackFlags"); sp <ICamera> c = mCamera; if (c == 0) return; mCamera->setPreviewCallbackFlag(flag); } // callback from camera service // callback from camera service void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) { { sp<CameraListener> listener; { Mutex::Autolock _l(mLock); listener = mListener; } if (listener != NULL) { listener->notify(msgType, ext1, ext2); } switch(msgType) { switch(msgType) { case CAMERA_MSG_ERROR: case CAMERA_MSG_ERROR: LOGV("errorCallback"); LOGV("errorCallback"); Loading Loading @@ -368,6 +391,15 @@ void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) // callback from camera service when frame or image is ready // callback from camera service when frame or image is ready void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr) void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr) { { sp<CameraListener> listener; { Mutex::Autolock _l(mLock); listener = mListener; } if (listener != NULL) { listener->postData(msgType, dataPtr); } switch(msgType) { switch(msgType) { case CAMERA_MSG_PREVIEW_FRAME: case CAMERA_MSG_PREVIEW_FRAME: LOGV("previewCallback"); LOGV("previewCallback"); Loading Loading @@ -401,6 +433,7 @@ void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr) void Camera::binderDied(const wp<IBinder>& who) { void Camera::binderDied(const wp<IBinder>& who) { LOGW("ICamera died"); LOGW("ICamera died"); notifyCallback(CAMERA_MSG_ERROR, DEAD_OBJECT, 0); if (mErrorCallback) { if (mErrorCallback) { mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie); mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie); } } Loading media/jni/android_media_MediaRecorder.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -41,7 +41,7 @@ using namespace android; // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // helper function to extract a native Camera object from a Camera Java object // helper function to extract a native Camera object from a Camera Java object extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct camera_context_t** context); extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct JNICameraContext** context); struct fields_t { struct fields_t { jfieldID context; jfieldID context; Loading Loading
core/jni/android_hardware_Camera.cpp +156 −182 Original line number Original line Diff line number Diff line Loading @@ -53,19 +53,33 @@ struct fields_t { static fields_t fields; static fields_t fields; static Mutex sLock; static Mutex sLock; struct camera_context_t { // provides persistent context for calls from native code to Java class JNICameraContext: public CameraListener { public: JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera); ~JNICameraContext() { release(); } virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } void release(); private: void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); jobject mCameraJObjectWeak; // weak reference to java object jobject mCameraJObjectWeak; // weak reference to java object jclass mCameraJClass; // strong reference to java class jclass mCameraJClass; // strong reference to java class sp<Camera> mCamera; // strong reference to native object sp<Camera> mCamera; // strong reference to native object Mutex mLock; }; }; sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pContext) sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) { { sp<Camera> camera; sp<Camera> camera; Mutex::Autolock _l(sLock); Mutex::Autolock _l(sLock); camera_context_t* context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context)); JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); if (context != NULL) { if (context != NULL) { camera = context->mCamera; camera = context->getCamera(); } } LOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); LOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); if (camera == 0) { if (camera == 0) { Loading @@ -76,15 +90,48 @@ sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pCont return camera; return camera; } } static void err_callback(status_t err, void *cookie) JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera) { { camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); mCameraJObjectWeak = env->NewGlobalRef(weak_this); if ((context == NULL) || (context->mCamera == 0)) return; mCameraJClass = (jclass)env->NewGlobalRef(clazz); mCamera = camera; } LOGV("err_callback: context=%p, camera=%p", context, context->mCamera.get()); void JNICameraContext::release() { LOGV("release"); Mutex::Autolock _l(mLock); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mCameraJObjectWeak != NULL) { env->DeleteGlobalRef(mCameraJObjectWeak); mCameraJObjectWeak = NULL; } if (mCameraJClass != NULL) { env->DeleteGlobalRef(mCameraJClass); mCameraJClass = NULL; } mCamera.clear(); } void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2) { LOGV("notify"); // VM pointer will be NULL if object is released Mutex::Autolock _l(mLock); if (mCameraJObjectWeak == NULL) { LOGW("callback on dead camera object"); return; } JNIEnv *env = AndroidRuntime::getJNIEnv(); // parse message switch (msgType) { case CAMERA_MSG_ERROR: LOGV("errorCallback"); int error; int error; switch (err) { switch (ext1) { case DEAD_OBJECT: case DEAD_OBJECT: error = kCameraErrorMediaServer; error = kCameraErrorMediaServer; break; break; Loading @@ -92,14 +139,91 @@ static void err_callback(status_t err, void *cookie) error = kCameraErrorUnknown; error = kCameraErrorUnknown; break; break; } } env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, kErrorCallback, error, 0, NULL); break; case CAMERA_MSG_FOCUS: LOGV("autoFocusCallback"); env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, kAutoFocusCallback, ext1, 0, NULL); break; case CAMERA_MSG_SHUTTER: LOGV("shutterCallback"); env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, kShutterCallback, 0, 0, NULL); break; default: LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2); break; } } void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) { jbyteArray obj = NULL; // allocate Java byte array and copy data if (dataPtr != NULL) { ssize_t offset; size_t size; sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size); LOGV("postData: off=%d, size=%d", offset, size); uint8_t *heapBase = (uint8_t*)heap->base(); if (heapBase != NULL) { uint8_t *data = heapBase + offset; obj = env->NewByteArray(size); if (obj == NULL) { LOGE("Couldn't allocate byte array for JPEG data"); env->ExceptionClear(); } else { jbyte *bytes = env->GetByteArrayElements(obj, NULL); memcpy(bytes, data, size); env->ReleaseByteArrayElements(obj, bytes, 0); } } else { LOGE("image heap is NULL"); } } // post image data to Java env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, msgType, 0, 0, obj); if (obj) { env->DeleteLocalRef(obj); } } void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) { // VM pointer will be NULL if object is released Mutex::Autolock _l(mLock); JNIEnv *env = AndroidRuntime::getJNIEnv(); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("err_callback on dead VM"); // return data based on callback type return; switch(msgType) { case CAMERA_MSG_PREVIEW_FRAME: LOGV("previewCallback"); copyAndPost(env, dataPtr, kPreviewCallback); break; case CAMERA_MSG_VIDEO_FRAME: LOGV("recordingCallback"); break; case CAMERA_MSG_RAW_IMAGE: LOGV("rawCallback"); env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, kRawCallback, 0, 0, NULL); break; case CAMERA_MSG_COMPRESSED_IMAGE: LOGV("jpegCallback"); copyAndPost(env, dataPtr, kJpegCallback); break; default: LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); break; } } env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kErrorCallback, error, 0, NULL); } } // connect to camera service // connect to camera service Loading Loading @@ -127,19 +251,12 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj // We use a weak reference so the Camera object can be garbage collected. // We use a weak reference so the Camera object can be garbage collected. // The reference is only used as a proxy for callbacks. // The reference is only used as a proxy for callbacks. camera_context_t* context = new camera_context_t; sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera); context->mCameraJObjectWeak = env->NewGlobalRef(weak_this); context->incStrong(thiz); context->mCameraJClass = (jclass)env->NewGlobalRef(clazz); camera->setListener(context); context->mCamera = camera; // save context in opaque field // save context in opaque field env->SetIntField(thiz, fields.context, (int)context); env->SetIntField(thiz, fields.context, (int)context.get()); LOGV("native_setup: mCameraJObjectWeak=%x, camera_obj=%x, context=%p", (int)context->mCameraJObjectWeak, (int)thiz, context); // set error callback camera->setErrorCallback(err_callback, context); } } // disconnect from camera service // disconnect from camera service Loading @@ -148,11 +265,11 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj // finalizer is invoked later. // finalizer is invoked later. static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) { { camera_context_t* context = NULL; JNICameraContext* context = NULL; sp<Camera> camera; sp<Camera> camera; { { Mutex::Autolock _l(sLock); Mutex::Autolock _l(sLock); context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context)); context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); // Make sure we do not attempt to callback on a deleted Java object. // Make sure we do not attempt to callback on a deleted Java object. env->SetIntField(thiz, fields.context, 0); env->SetIntField(thiz, fields.context, 0); Loading @@ -160,21 +277,18 @@ static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) // clean up if release has not been called before // clean up if release has not been called before if (context != NULL) { if (context != NULL) { camera = context->mCamera; camera = context->getCamera(); context->mCamera.clear(); context->release(); LOGV("native_release: context=%p camera=%p", context, camera.get()); LOGV("native_release: context=%p camera=%p", context, camera.get()); // clear callbacks // clear callbacks if (camera != NULL) { if (camera != NULL) { camera->setPreviewCallback(NULL, NULL, FRAME_CALLBACK_FLAG_NOOP); camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); camera->setErrorCallback(NULL, NULL); camera->disconnect(); camera->disconnect(); env->DeleteGlobalRef(context->mCameraJObjectWeak); env->DeleteGlobalRef(context->mCameraJClass); } } // remove context to prevent further Java access // remove context to prevent further Java access delete context; context->decStrong(thiz); } } } } Loading @@ -190,48 +304,6 @@ static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, } } } } static void preview_callback(const sp<IMemory>& mem, void *cookie) { LOGV("preview_callback"); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("preview_callback on dead VM"); return; } camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); if ((context == NULL) || (context->mCamera == 0)) { LOGW("context or camera is NULL in preview_callback"); return; } LOGV("native_release: context=%p camera=%p", context, context->mCamera.get()); int arg1 = 0, arg2 = 0; jobject obj = NULL; ssize_t offset; size_t size; sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); uint8_t *data = ((uint8_t *)heap->base()) + offset; jbyteArray array = env->NewByteArray(size); if (array == NULL) { LOGE("Couldn't allocate byte array for YUV data"); env->ExceptionClear(); return; } jbyte *bytes = env->GetByteArrayElements(array, NULL); memcpy(bytes, data, size); env->ReleaseByteArrayElements(array, bytes, 0); obj = array; env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kPreviewCallback, arg1, arg2, obj); env->DeleteLocalRef(array); } static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) { { LOGV("startPreview"); LOGV("startPreview"); Loading Loading @@ -267,7 +339,7 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t // Important: Only install preview_callback if the Java code has called // Important: Only install preview_callback if the Java code has called // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy // each preview frame for nothing. // each preview frame for nothing. camera_context_t* context; JNICameraContext* context; sp<Camera> camera = get_native_camera(env, thiz, &context); sp<Camera> camera = get_native_camera(env, thiz, &context); if (camera == 0) return; if (camera == 0) return; Loading @@ -277,130 +349,32 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t } else { } else { callback_flag = FRAME_CALLBACK_FLAG_NOOP; callback_flag = FRAME_CALLBACK_FLAG_NOOP; } } camera->setPreviewCallback(installed ? preview_callback : NULL, context, callback_flag); camera->setPreviewCallbackFlags(callback_flag); } static void autofocus_callback_impl(bool success, void *cookie) { LOGV("autoFocusCallback"); camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("autofocus_callback on dead VM"); return; } env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kAutoFocusCallback, success, 0, NULL); } } static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) { { LOGV("autoFocus"); LOGV("autoFocus"); camera_context_t* context; JNICameraContext* context; sp<Camera> c = get_native_camera(env, thiz, &context); sp<Camera> c = get_native_camera(env, thiz, &context); if (c == 0) return; if (c == 0) return; c->setAutoFocusCallback(autofocus_callback_impl, context); if (c->autoFocus() != NO_ERROR) { if (c->autoFocus() != NO_ERROR) { jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed"); jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed"); } } } } static void jpeg_callback(const sp<IMemory>& mem, void *cookie) { LOGV("jpegCallback"); camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("jpeg`_callback on dead VM"); return; } int arg1 = 0, arg2 = 0; jobject obj = NULL; if (mem == NULL) { env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, NULL); return; } ssize_t offset; size_t size; sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); LOGV("jpeg_callback: mem off=%d, size=%d", offset, size); uint8_t *heap_base = (uint8_t *)heap->base(); if (heap_base == NULL) { LOGE("YUV heap is NULL"); return; } uint8_t *data = heap_base + offset; jbyteArray array = env->NewByteArray(size); if (array == NULL) { LOGE("Couldn't allocate byte array for JPEG data"); env->ExceptionClear(); return; } jbyte *bytes = env->GetByteArrayElements(array, NULL); memcpy(bytes, data, size); env->ReleaseByteArrayElements(array, bytes, 0); obj = array; env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, obj); env->DeleteLocalRef(array); } static void shutter_callback_impl(void *cookie) { LOGV("shutterCallback"); camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("shutter_callback on dead VM"); return; } env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kShutterCallback, 0, 0, NULL); } static void raw_callback(const sp<IMemory>& mem __attribute__((unused)), void *cookie) { LOGV("rawCallback"); camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("raw_callback on dead VM"); return; } env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, context->mCameraJObjectWeak, kRawCallback, 0, 0, NULL); } static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) { { LOGV("takePicture"); LOGV("takePicture"); camera_context_t* context; JNICameraContext* context; sp<Camera> camera = get_native_camera(env, thiz, &context); sp<Camera> camera = get_native_camera(env, thiz, &context); if (camera == 0) return; if (camera == 0) return; camera->setShutterCallback(shutter_callback_impl, context); camera->setRawCallback(raw_callback, context); camera->setJpegCallback(jpeg_callback, context); if (camera->takePicture() != NO_ERROR) { if (camera->takePicture() != NO_ERROR) { jniThrowException(env, "java/lang/RuntimeException", "takePicture failed"); jniThrowException(env, "java/lang/RuntimeException", "takePicture failed"); return; return; } } return; } } static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) Loading
include/ui/Camera.h +13 −0 Original line number Original line Diff line number Diff line Loading @@ -86,6 +86,14 @@ class Surface; class Mutex; class Mutex; class String8; class String8; // ref-counted object for callbacks class CameraListener: virtual public RefBase { public: virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0; virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0; }; typedef void (*shutter_callback)(void *cookie); typedef void (*shutter_callback)(void *cookie); typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie); typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie); typedef void (*autofocus_callback)(bool focused, void *cookie); typedef void (*autofocus_callback)(bool focused, void *cookie); Loading Loading @@ -152,6 +160,9 @@ public: void setErrorCallback(error_callback cb, void *cookie); void setErrorCallback(error_callback cb, void *cookie); void setAutoFocusCallback(autofocus_callback cb, void *cookie); void setAutoFocusCallback(autofocus_callback cb, void *cookie); void setListener(const sp<CameraListener>& listener); void setPreviewCallbackFlags(int preview_callback_flag); // ICameraClient interface // ICameraClient interface virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2); virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2); virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr); virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr); Loading Loading @@ -194,6 +205,8 @@ private: autofocus_callback mAutoFocusCallback; autofocus_callback mAutoFocusCallback; void *mAutoFocusCallbackCookie; void *mAutoFocusCallbackCookie; sp<CameraListener> mListener; friend class DeathNotifier; friend class DeathNotifier; static Mutex mLock; static Mutex mLock; Loading
libs/ui/Camera.cpp +33 −0 Original line number Original line Diff line number Diff line Loading @@ -337,9 +337,32 @@ void Camera::setErrorCallback(error_callback cb, void *cookie) mErrorCallbackCookie = cookie; mErrorCallbackCookie = cookie; } } void Camera::setListener(const sp<CameraListener>& listener) { Mutex::Autolock _l(mLock); mListener = listener; } void Camera::setPreviewCallbackFlags(int flag) { LOGV("setPreviewCallbackFlags"); sp <ICamera> c = mCamera; if (c == 0) return; mCamera->setPreviewCallbackFlag(flag); } // callback from camera service // callback from camera service void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) { { sp<CameraListener> listener; { Mutex::Autolock _l(mLock); listener = mListener; } if (listener != NULL) { listener->notify(msgType, ext1, ext2); } switch(msgType) { switch(msgType) { case CAMERA_MSG_ERROR: case CAMERA_MSG_ERROR: LOGV("errorCallback"); LOGV("errorCallback"); Loading Loading @@ -368,6 +391,15 @@ void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) // callback from camera service when frame or image is ready // callback from camera service when frame or image is ready void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr) void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr) { { sp<CameraListener> listener; { Mutex::Autolock _l(mLock); listener = mListener; } if (listener != NULL) { listener->postData(msgType, dataPtr); } switch(msgType) { switch(msgType) { case CAMERA_MSG_PREVIEW_FRAME: case CAMERA_MSG_PREVIEW_FRAME: LOGV("previewCallback"); LOGV("previewCallback"); Loading Loading @@ -401,6 +433,7 @@ void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr) void Camera::binderDied(const wp<IBinder>& who) { void Camera::binderDied(const wp<IBinder>& who) { LOGW("ICamera died"); LOGW("ICamera died"); notifyCallback(CAMERA_MSG_ERROR, DEAD_OBJECT, 0); if (mErrorCallback) { if (mErrorCallback) { mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie); mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie); } } Loading
media/jni/android_media_MediaRecorder.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -41,7 +41,7 @@ using namespace android; // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // helper function to extract a native Camera object from a Camera Java object // helper function to extract a native Camera object from a Camera Java object extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct camera_context_t** context); extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct JNICameraContext** context); struct fields_t { struct fields_t { jfieldID context; jfieldID context; Loading