Pass camera frame metadata from camera service to Java.

bug:4460717
Change-Id: I2fae6e1dfca6b8f3a5ee5716fc7817f5417bf657
This commit is contained in:
Wu-cheng Li
2011-07-30 05:00:37 +08:00
parent 0175028b73
commit bb1e275c0e
9 changed files with 154 additions and 49 deletions

View File

@@ -131,7 +131,7 @@ public class Camera {
private static final int CAMERA_MSG_RAW_IMAGE = 0x080;
private static final int CAMERA_MSG_COMPRESSED_IMAGE = 0x100;
private static final int CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x200;
private static final int CAMERA_MSG_METADATA_FACE = 0x400;
private static final int CAMERA_MSG_PREVIEW_METADATA = 0x400;
private static final int CAMERA_MSG_ALL_MSGS = 0x4FF;
private int mNativeContext; // accessed by native methods
@@ -721,7 +721,7 @@ public class Camera {
}
return;
case CAMERA_MSG_METADATA_FACE:
case CAMERA_MSG_PREVIEW_METADATA:
if (mFaceListener != null) {
mFaceListener.onFaceDetection((Face[])msg.obj, mCamera);
}
@@ -1156,6 +1156,9 @@ public class Camera {
* @hide
*/
public static class Face {
public Face() {
}
/**
* Bounds of the face. (-1000, -1000) represents the top-left of the
* camera field of view, and (1000, 1000) represents the bottom-right of
@@ -1168,7 +1171,7 @@ public class Camera {
*
* @see #startFaceDetection(int)
*/
Rect rect;
public Rect rect;
/**
* The confidence level of the face. The range is 1 to 100. 100 is the
@@ -1177,32 +1180,32 @@ public class Camera {
*
* @see #startFaceDetection(int)
*/
int score;
public int score;
/**
* An unique id per face while the face is visible to the tracker. If
* the face leaves the field-of-view and comes back, it will get a new
* id. If the value is 0, id is not supported.
*/
int id;
public int id;
/**
* The coordinates of the center of the left eye. The range is -1000 to
* 1000. null if this is not supported.
*/
Point leftEye;
public Point leftEye;
/**
* The coordinates of the center of the right eye. The range is -1000 to
* 1000. null if this is not supported.
*/
Point rightEye;
public Point rightEye;
/**
* The coordinates of the center of the mouth. The range is -1000 to
* 1000. null if this is not supported.
*/
Point mouth;
public Point mouth;
}
// Error codes match the enum in include/ui/Camera.h

View File

@@ -45,6 +45,8 @@ struct fields_t {
jfieldID rect_right;
jfieldID rect_bottom;
jmethodID post_event;
jmethodID rect_constructor;
jmethodID face_constructor;
};
static fields_t fields;
@@ -57,8 +59,10 @@ 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);
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata);
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
void postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata);
void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType);
void setCallbackMode(JNIEnv *env, bool installed, bool manualMode);
sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
@@ -74,6 +78,8 @@ private:
jobject mCameraJObjectWeak; // weak reference to java object
jclass mCameraJClass; // strong reference to java class
sp<Camera> mCamera; // strong reference to native object
jclass mFaceClass; // strong reference to Face class
jclass mRectClass; // strong reference to Rect class
Mutex mLock;
/*
@@ -124,6 +130,12 @@ JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz,
mCameraJClass = (jclass)env->NewGlobalRef(clazz);
mCamera = camera;
jclass faceClazz = env->FindClass("android/hardware/Camera$Face");
mFaceClass = (jclass) env->NewGlobalRef(faceClazz);
jclass rectClazz = env->FindClass("android/graphics/Rect");
mRectClass = (jclass) env->NewGlobalRef(rectClazz);
mManualBufferMode = false;
mManualCameraCallbackSet = false;
}
@@ -142,6 +154,14 @@ void JNICameraContext::release()
env->DeleteGlobalRef(mCameraJClass);
mCameraJClass = NULL;
}
if (mFaceClass != NULL) {
env->DeleteGlobalRef(mFaceClass);
mFaceClass = NULL;
}
if (mRectClass != NULL) {
env->DeleteGlobalRef(mRectClass);
mRectClass = NULL;
}
clearCallbackBuffers_l(env);
mCamera.clear();
}
@@ -263,7 +283,8 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int
}
}
void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr)
void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata)
{
// VM pointer will be NULL if object is released
Mutex::Autolock _l(mLock);
@@ -273,8 +294,10 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr)
return;
}
int32_t dataMsgType = msgType & ~CAMERA_MSG_PREVIEW_METADATA;
// return data based on callback type
switch (msgType) {
switch (dataMsgType) {
case CAMERA_MSG_VIDEO_FRAME:
// should never happen
break;
@@ -285,23 +308,63 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr)
LOGV("rawCallback");
if (mRawImageCallbackBuffers.isEmpty()) {
env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
mCameraJObjectWeak, msgType, 0, 0, NULL);
mCameraJObjectWeak, dataMsgType, 0, 0, NULL);
} else {
copyAndPost(env, dataPtr, msgType);
copyAndPost(env, dataPtr, dataMsgType);
}
break;
default:
LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
copyAndPost(env, dataPtr, msgType);
// There is no data.
case 0:
break;
default:
LOGV("dataCallback(%d, %p)", dataMsgType, dataPtr.get());
copyAndPost(env, dataPtr, dataMsgType);
break;
}
// post frame metadata to Java
if (metadata && (msgType & CAMERA_MSG_PREVIEW_METADATA)) {
postMetadata(env, CAMERA_MSG_PREVIEW_METADATA, metadata);
}
}
void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr)
{
// TODO: plumb up to Java. For now, just drop the timestamp
postData(msgType, dataPtr);
postData(msgType, dataPtr, NULL);
}
void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata)
{
jobjectArray obj = NULL;
obj = (jobjectArray) env->NewObjectArray(metadata->number_of_faces,
mFaceClass, NULL);
if (obj == NULL) {
LOGE("Couldn't allocate face metadata array");
return;
}
for (int i = 0; i < metadata->number_of_faces; i++) {
jobject face = env->NewObject(mFaceClass, fields.face_constructor);
env->SetObjectArrayElement(obj, i, face);
jobject rect = env->NewObject(mRectClass, fields.rect_constructor);
env->SetIntField(rect, fields.rect_left, metadata->faces[i].rect[0]);
env->SetIntField(rect, fields.rect_top, metadata->faces[i].rect[1]);
env->SetIntField(rect, fields.rect_right, metadata->faces[i].rect[2]);
env->SetIntField(rect, fields.rect_bottom, metadata->faces[i].rect[3]);
env->SetObjectField(face, fields.face_rect, rect);
env->SetIntField(face, fields.face_score, metadata->faces[i].score);
env->DeleteLocalRef(face);
env->DeleteLocalRef(rect);
}
env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
mCameraJObjectWeak, msgType, 0, 0, obj);
env->DeleteLocalRef(obj);
}
void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualMode)
@@ -715,7 +778,7 @@ static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject t
}
static void android_hardware_Camera_startFaceDetection(JNIEnv *env, jobject thiz,
jint type, jobjectArray face)
jint type)
{
LOGV("startFaceDetection");
JNICameraContext* context;
@@ -878,6 +941,19 @@ int register_android_hardware_Camera(JNIEnv *env)
return -1;
}
clazz = env->FindClass("android/graphics/Rect");
fields.rect_constructor = env->GetMethodID(clazz, "<init>", "()V");
if (fields.rect_constructor == NULL) {
LOGE("Can't find android/graphics/Rect.Rect()");
return -1;
}
clazz = env->FindClass("android/hardware/Camera$Face");
fields.face_constructor = env->GetMethodID(clazz, "<init>", "()V");
if (fields.face_constructor == NULL) {
LOGE("Can't find android/hardware/Camera$Face.Face()");
return -1;
}
// Register native functions
return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",

View File

@@ -59,7 +59,8 @@ 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;
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata) = 0;
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
};
@@ -138,7 +139,8 @@ public:
// ICameraClient interface
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,
camera_frame_metadata_t *metadata);
virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
sp<ICamera> remote();

View File

@@ -22,6 +22,7 @@
#include <binder/Parcel.h>
#include <binder/IMemory.h>
#include <utils/Timers.h>
#include <system/camera.h>
namespace android {
@@ -31,7 +32,8 @@ public:
DECLARE_META_INTERFACE(CameraClient);
virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
virtual void dataCallback(int32_t msgType, const sp<IMemory>& data) = 0;
virtual void dataCallback(int32_t msgType, const sp<IMemory>& data,
camera_frame_metadata_t *metadata) = 0;
virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data) = 0;
};

View File

@@ -360,7 +360,8 @@ 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)
void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata)
{
sp<CameraListener> listener;
{
@@ -368,7 +369,7 @@ void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
listener = mListener;
}
if (listener != NULL) {
listener->postData(msgType, dataPtr);
listener->postData(msgType, dataPtr, metadata);
}
}

View File

@@ -51,13 +51,18 @@ public:
}
// generic data callback from camera service to app with image data
void dataCallback(int32_t msgType, const sp<IMemory>& imageData)
void dataCallback(int32_t msgType, const sp<IMemory>& imageData,
camera_frame_metadata_t *metadata)
{
LOGV("dataCallback");
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeInt32(msgType);
data.writeStrongBinder(imageData->asBinder());
if (metadata) {
data.writeInt32(metadata->number_of_faces);
data.write(metadata->faces, sizeof(camera_face_t) * metadata->number_of_faces);
}
remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
}
@@ -96,7 +101,15 @@ status_t BnCameraClient::onTransact(
CHECK_INTERFACE(ICameraClient, data, reply);
int32_t msgType = data.readInt32();
sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
dataCallback(msgType, imageData);
camera_frame_metadata_t *metadata = NULL;
if (data.dataAvail() > 0) {
metadata = new camera_frame_metadata_t;
metadata->number_of_faces = data.readInt32();
metadata->faces = (camera_face_t *) data.readInplace(
sizeof(camera_face_t) * metadata->number_of_faces);
}
dataCallback(msgType, imageData, metadata);
if (metadata) delete metadata;
return NO_ERROR;
} break;
case DATA_CALLBACK_TIMESTAMP: {

View File

@@ -37,7 +37,8 @@ struct CameraSourceListener : public CameraListener {
CameraSourceListener(const sp<CameraSource> &source);
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr);
virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr,
camera_frame_metadata_t *metadata);
virtual void postDataTimestamp(
nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
@@ -63,7 +64,8 @@ void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
}
void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr) {
void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
camera_frame_metadata_t *metadata) {
LOGV("postData(%d, ptr:%p, size:%d)",
msgType, dataPtr->pointer(), dataPtr->size());

View File

@@ -350,10 +350,9 @@ CameraService::Client::Client(const sp<CameraService>& cameraService,
dataCallbackTimestamp,
(void *)cameraId);
// Enable zoom, error, and focus messages by default
enableMsgType(CAMERA_MSG_ERROR |
CAMERA_MSG_ZOOM |
CAMERA_MSG_FOCUS);
// Enable zoom, error, focus, and metadata messages by default
enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
CAMERA_MSG_PREVIEW_METADATA);
// Callback is disabled by default
mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
@@ -995,15 +994,15 @@ void CameraService::Client::dataCallback(int32_t msgType,
if (client == 0) return;
if (!client->lockIfMessageWanted(msgType)) return;
if (dataPtr == 0) {
if (dataPtr == 0 && metadata == NULL) {
LOGE("Null data returned in data callback");
client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
return;
}
switch (msgType) {
switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
case CAMERA_MSG_PREVIEW_FRAME:
client->handlePreviewData(dataPtr);
client->handlePreviewData(msgType, dataPtr, metadata);
break;
case CAMERA_MSG_POSTVIEW_FRAME:
client->handlePostview(dataPtr);
@@ -1015,7 +1014,7 @@ void CameraService::Client::dataCallback(int32_t msgType,
client->handleCompressedPicture(dataPtr);
break;
default:
client->handleGenericData(msgType, dataPtr);
client->handleGenericData(msgType, dataPtr, metadata);
break;
}
}
@@ -1055,7 +1054,9 @@ void CameraService::Client::handleShutter(void) {
}
// preview callback - frame buffer update
void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {
void CameraService::Client::handlePreviewData(int32_t msgType,
const sp<IMemory>& mem,
camera_frame_metadata_t *metadata) {
ssize_t offset;
size_t size;
sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
@@ -1087,11 +1088,11 @@ void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {
// Is the received frame copied out or not?
if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
LOG2("frame is copied");
copyFrameAndPostCopiedFrame(c, heap, offset, size);
copyFrameAndPostCopiedFrame(msgType, c, heap, offset, size, metadata);
} else {
LOG2("frame is forwarded");
mLock.unlock();
c->dataCallback(CAMERA_MSG_PREVIEW_FRAME, mem);
c->dataCallback(msgType, mem, metadata);
}
} else {
mLock.unlock();
@@ -1105,7 +1106,7 @@ void CameraService::Client::handlePostview(const sp<IMemory>& mem) {
sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != 0) {
c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem);
c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem, NULL);
}
}
@@ -1120,7 +1121,7 @@ void CameraService::Client::handleRawPicture(const sp<IMemory>& mem) {
sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != 0) {
c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem);
c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem, NULL);
}
}
@@ -1131,7 +1132,7 @@ void CameraService::Client::handleCompressedPicture(const sp<IMemory>& mem) {
sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != 0) {
c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem);
c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL);
}
}
@@ -1146,11 +1147,11 @@ void CameraService::Client::handleGenericNotify(int32_t msgType,
}
void CameraService::Client::handleGenericData(int32_t msgType,
const sp<IMemory>& dataPtr) {
const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata) {
sp<ICameraClient> c = mCameraClient;
mLock.unlock();
if (c != 0) {
c->dataCallback(msgType, dataPtr);
c->dataCallback(msgType, dataPtr, metadata);
}
}
@@ -1164,8 +1165,9 @@ void CameraService::Client::handleGenericDataTimestamp(nsecs_t timestamp,
}
void CameraService::Client::copyFrameAndPostCopiedFrame(
const sp<ICameraClient>& client, const sp<IMemoryHeap>& heap,
size_t offset, size_t size) {
int32_t msgType, const sp<ICameraClient>& client,
const sp<IMemoryHeap>& heap, size_t offset, size_t size,
camera_frame_metadata_t *metadata) {
LOG2("copyFrameAndPostCopiedFrame");
// It is necessary to copy out of pmem before sending this to
// the callback. For efficiency, reuse the same MemoryHeapBase
@@ -1197,7 +1199,7 @@ void CameraService::Client::copyFrameAndPostCopiedFrame(
}
mLock.unlock();
client->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
client->dataCallback(msgType, frame, metadata);
}
int CameraService::Client::getOrientation(int degrees, bool mirror) {

View File

@@ -147,18 +147,22 @@ private:
static sp<Client> getClientFromCookie(void* user);
// handlers for messages
void handleShutter(void);
void handlePreviewData(const sp<IMemory>& mem);
void handlePreviewData(int32_t msgType, const sp<IMemory>& mem,
camera_frame_metadata_t *metadata);
void handlePostview(const sp<IMemory>& mem);
void handleRawPicture(const sp<IMemory>& mem);
void handleCompressedPicture(const sp<IMemory>& mem);
void handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2);
void handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr);
void handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata);
void handleGenericDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
void copyFrameAndPostCopiedFrame(
int32_t msgType,
const sp<ICameraClient>& client,
const sp<IMemoryHeap>& heap,
size_t offset, size_t size);
size_t offset, size_t size,
camera_frame_metadata_t *metadata);
int getOrientation(int orientation, bool mirror);