summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/jni/android_hardware_Camera.cpp338
-rw-r--r--include/ui/Camera.h13
-rw-r--r--libs/ui/Camera.cpp33
-rw-r--r--media/jni/android_media_MediaRecorder.cpp2
4 files changed, 203 insertions, 183 deletions
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9b92bc5..b07ba7d 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -53,19 +53,33 @@ struct fields_t {
static fields_t fields;
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
jclass mCameraJClass; // strong reference to java class
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;
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) {
- camera = context->mCamera;
+ camera = context->getCamera();
}
LOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
if (camera == 0) {
@@ -76,30 +90,140 @@ sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pCont
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);
- if ((context == NULL) || (context->mCamera == 0)) return;
+ mCameraJObjectWeak = env->NewGlobalRef(weak_this);
+ 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();
- int error;
- switch (err) {
- case DEAD_OBJECT:
- error = kCameraErrorMediaServer;
+ 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;
+ switch (ext1) {
+ case DEAD_OBJECT:
+ error = kCameraErrorMediaServer;
+ break;
+ default:
+ error = kCameraErrorUnknown;
+ 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:
- error = kCameraErrorUnknown;
+ 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();
- if (env == NULL) {
- LOGE("err_callback on dead VM");
- return;
+
+ // return data based on callback type
+ 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
@@ -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.
// The reference is only used as a proxy for callbacks.
- camera_context_t* context = new camera_context_t;
- context->mCameraJObjectWeak = env->NewGlobalRef(weak_this);
- context->mCameraJClass = (jclass)env->NewGlobalRef(clazz);
- context->mCamera = camera;
+ sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
+ context->incStrong(thiz);
+ camera->setListener(context);
// save context in opaque field
- env->SetIntField(thiz, fields.context, (int)context);
-
- LOGV("native_setup: mCameraJObjectWeak=%x, camera_obj=%x, context=%p",
- (int)context->mCameraJObjectWeak, (int)thiz, context);
-
- // set error callback
- camera->setErrorCallback(err_callback, context);
+ env->SetIntField(thiz, fields.context, (int)context.get());
}
// disconnect from camera service
@@ -148,11 +265,11 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj
// finalizer is invoked later.
static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
{
- camera_context_t* context = NULL;
+ JNICameraContext* context = NULL;
sp<Camera> camera;
{
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.
env->SetIntField(thiz, fields.context, 0);
@@ -160,21 +277,18 @@ static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
// clean up if release has not been called before
if (context != NULL) {
- camera = context->mCamera;
- context->mCamera.clear();
+ camera = context->getCamera();
+ context->release();
LOGV("native_release: context=%p camera=%p", context, camera.get());
// clear callbacks
if (camera != NULL) {
- camera->setPreviewCallback(NULL, NULL, FRAME_CALLBACK_FLAG_NOOP);
- camera->setErrorCallback(NULL, NULL);
+ camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
camera->disconnect();
- env->DeleteGlobalRef(context->mCameraJObjectWeak);
- env->DeleteGlobalRef(context->mCameraJClass);
}
// remove context to prevent further Java access
- delete context;
+ context->decStrong(thiz);
}
}
@@ -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)
{
LOGV("startPreview");
@@ -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
// setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
// each preview frame for nothing.
- camera_context_t* context;
+ JNICameraContext* context;
sp<Camera> camera = get_native_camera(env, thiz, &context);
if (camera == 0) return;
@@ -277,130 +349,32 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t
} else {
callback_flag = FRAME_CALLBACK_FLAG_NOOP;
}
- camera->setPreviewCallback(installed ? preview_callback : NULL, context, 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);
+ camera->setPreviewCallbackFlags(callback_flag);
}
static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
{
LOGV("autoFocus");
- camera_context_t* context;
+ JNICameraContext* context;
sp<Camera> c = get_native_camera(env, thiz, &context);
if (c == 0) return;
- c->setAutoFocusCallback(autofocus_callback_impl, context);
if (c->autoFocus() != NO_ERROR) {
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)
{
LOGV("takePicture");
- camera_context_t* context;
+ JNICameraContext* context;
sp<Camera> camera = get_native_camera(env, thiz, &context);
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) {
jniThrowException(env, "java/lang/RuntimeException", "takePicture failed");
return;
}
-
- return;
}
static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 048bdd5..bd4855c 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -86,6 +86,14 @@ class Surface;
class Mutex;
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 (*frame_callback)(const sp<IMemory>& mem, void *cookie);
typedef void (*autofocus_callback)(bool focused, void *cookie);
@@ -152,6 +160,9 @@ public:
void setErrorCallback(error_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
virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
@@ -194,6 +205,8 @@ private:
autofocus_callback mAutoFocusCallback;
void *mAutoFocusCallbackCookie;
+ sp<CameraListener> mListener;
+
friend class DeathNotifier;
static Mutex mLock;
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 6613700..1aa52452 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -337,9 +337,32 @@ void Camera::setErrorCallback(error_callback cb, void *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
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) {
case CAMERA_MSG_ERROR:
LOGV("errorCallback");
@@ -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
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) {
case CAMERA_MSG_PREVIEW_FRAME:
LOGV("previewCallback");
@@ -401,6 +433,7 @@ void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
void Camera::binderDied(const wp<IBinder>& who) {
LOGW("ICamera died");
+ notifyCallback(CAMERA_MSG_ERROR, DEAD_OBJECT, 0);
if (mErrorCallback) {
mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
}
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 7bfeb83..0273a5a 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -41,7 +41,7 @@ using namespace android;
// ----------------------------------------------------------------------------
// 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 {
jfieldID context;