Android4.4 Camera callback登録とコールバックプロセス分析
一、登録プロセス
cameraのcallbackはcameraclientのinitializeインタフェースに登録されていますが、このインタフェースは上位初期化によって呼び出されます.
res = mHardware->initialize(&module->common); HALとの通信の架け橋としてインタフェースヘッダファイルを呼び出すのは、CameraHardwareInterfaceというインタフェースパッケージです.h
ここでopen関数を呼び出してcameraを開きます.こちらのオープンはHALに登録されています.
したがって、上位転送のid、すなわちopenの最初のパラメータmoduleがcameraHALと一致すると、cameraHALレイヤのインタフェース:camera_device_open
この関数camera_device_Openは重要な役割を果たし,登録cameraに関するインタフェースを初期化し,HAL層のインタフェースをFramework層CamaraClientのインタフェースに一つ一つ対応させる.
このopenの操作もCameraHalクラスを初期化し,一連のスレッドがloop状態になった.
ここで引き続きCameraClientのinitializeを見て
callbackの登録もこちらが初期化された時点で登録されています.
対応する下層もインタフェース層ファイルにあります.
主な内容は上位から伝わる値をローカル変数に付与することであり,また最終的にはset_を判断することである.callbacksというインタフェースが初期化されているかどうかは、open cameraのときに初期化されています.
camera_ops->set_callbacks = camera_set_callbacks;
ここでmDevice->ops->set_callbacksとcamera_ops->set_callbacksとは、同じ構造体の中のインタフェースを指します.注意してください.こちらのパッケージsetcallbacksには関数ポインタが追加されています.get_メモリー、彼の実現もこの書類の中にある.hの中.ここで注意すれば、後でcameraのメモリ申請プロセスに関係します.このコールバックはここに登録すればいいことを覚えておいてください.次は本当の登録callbackです.
彼の原理はさっき地元に保存したcallbackインタフェースを包装したことだが、ここには大きな文章があり、下層callbackのデータ型はcameraだ.memory_tは,この層でmem->mBuffers[index]タイプ,すなわちIMemoryのタイプがCameraClientクラスにおけるcallbackパラメータタイプと一致するように変換され,適合と理解できるだろう.
こちらの操作はdata->handleというハンドルをc++で強制的にCameraHeapMemoryクラスに変換することですこちらは別の文章でcameraの全体的なデータストリーム方向とメモリ管理方式を詳しく説明します.
ここまでcamera初期化が完了しました.
引き続きcamerahal層setcallbacksの実装を見てみましょう.
次のように呼び出されます.
ここまでhalレイヤの関数ポインタに登録できました.この初期化に注意:mRequestMemory=get_memory;これはmemmoryを申請する過程です.
二、コールバックプロセス
これは登録プロセスです.逆にコールバックプロセスを見てみましょう.
上はcamerahalレイヤのコールバックコールです.cameraclientレイヤのdatacallbackに移動しますが、暗黙的な変換プロセスがあります.彼はcamerahardwareinterfaceのcallbackに戻ります.
上のコードはhal層camera_をmemory_tタイプのデータはCameraHeapMemoryタイプに変換され、最後に上位にコールバックされたのはIMemoryタイプのmem->mBuffers[index];次に、cameraclientにコールバックするdataCallbackです.
最初にクライアントオブジェクトの取得はセキュリティを考慮します.ソースコードではこのように説明されています.//Provide client pointer for callbacks. Client lock returned from getClientLockFromCookie should be acquired for this to be safe
次のように呼び出されます.
具体的な実装:
ここでdataデータを処理します:sp heap=mem->getMemory(&offset,&size);
実は上層部に伝わる全体の過程は基本的に取り外して再組み立てて、詰めて再分解して、具体的な細部はcamera memoryの章で深く分析します.
Datacallbackの呼び出しを続行するとbinderメカニズムで上位レベルのインタフェースが呼び出されます.このときのクライアントはlibcameraserviceであり、サービス側はcamera clientである.callbackに関連するbinderクラス:BpCameraClient,BnCameraClient,ICameraClientそれぞれの役割はここでは後述しない.
この時上層部のBnCameraClientまで見て、
まずbinderポートからdataデータを取得する:sp imageData=interface_cast(data.readStrongBinder());
そしてdataCallbackを呼び出す
このようなCSモードでは、上位のCameraはBnCameraClientを継承するので、関連する実装はすべてCamerクラスにある.
まず、このリスニングの例がいつ初期化されたかを見てみましょう.cameraが初期化されたときを想像してみてください.
camera->setListener(context);これが初期化された良いcontextをcameraクラスのメンバー変数に格納することです.
ここでjava-cインタフェースファイルのインタフェースに移動しますandroid_hardware_Camera.cppファイル:class JNICameraContext:public CameraListener
コールバックのタイプに応じてcopyAndPost(env,dataPtr,dataMsgType)を呼び出し続けます.
ここでjavaのインタフェースを呼び出し、dataデータをjavaレイヤに送信します.javaレイヤには関数があります.
ここでjavaレイヤに変更したら、分析しません.
cameraのcallbackはcameraclientのinitializeインタフェースに登録されていますが、このインタフェースは上位初期化によって呼び出されます.
status_t CameraClient::initialize(camera_module_t *module) {
int callingPid = getCallingPid();
status_t res;
LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
// Verify ops permissions
res = startCameraOps();
if (res != OK) {
return res;
}
char camera_device_name[10];
snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
mHardware = new CameraHardwareInterface(camera_device_name);
res = mHardware->initialize(&module->common);
if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
mHardware.clear();
return NO_INIT;
}
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)mCameraId);
// Enable zoom, error, focus, and metadata messages by default
enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
return OK;
}
res = mHardware->initialize(&module->common); HALとの通信の架け橋としてインタフェースヘッダファイルを呼び出すのは、CameraHardwareInterfaceというインタフェースパッケージです.h
status_t initialize(hw_module_t *module)
{
ALOGI("Opening camera %s", mName.string());
int rc = module->methods->open(module, mName.string(),
(hw_device_t **)&mDevice);
if (rc != OK) {
ALOGE("Could not open camera %s: %d", mName.string(), rc);
return rc;
}
initHalPreviewWindow();
return rc;
}
ここでopen関数を呼び出してcameraを開きます.こちらのオープンはHALに登録されています.
static int camera_device_open(const hw_module_t* module, const char* name,
hw_device_t** device);
static struct hw_module_methods_t camera_module_methods = {
open: camera_device_open
};
したがって、上位転送のid、すなわちopenの最初のパラメータmoduleがcameraHALと一致すると、cameraHALレイヤのインタフェース:camera_device_open
この関数camera_device_Openは重要な役割を果たし,登録cameraに関するインタフェースを初期化し,HAL層のインタフェースをFramework層CamaraClientのインタフェースに一つ一つ対応させる.
int camera_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
int rv = 0;
int cameraid;
rk_camera_device_t* camera_device = NULL;
camera_device_ops_t* camera_ops = NULL;
android::CameraHal* camera = NULL;
android::Mutex::Autolock lock(gCameraHalDeviceLock);
LOGI("camera_device open : name = %s", name);
if (name != NULL) {
cameraid = atoi(name);
if(cameraid > gCamerasNumber) {
LOGE("camera service provided cameraid out of bounds, "
"cameraid = %d, num supported = %d",
cameraid, gCamerasNumber);
rv = -EINVAL;
goto fail;
}
if(gCamerasOpen >= CAMERAS_SUPPORTED_SIMUL_MAX) {
LOGE("maximum number(%d) of cameras already open",gCamerasOpen);
rv = -ENOMEM;
goto fail;
}
camera_device = (rk_camera_device_t*)malloc(sizeof(*camera_device));
if(!camera_device) {
LOGE("camera_device allocation fail");
rv = -ENOMEM;
goto fail;
}
camera_ops = (camera_device_ops_t*)malloc(sizeof(*camera_ops));
if(!camera_ops) {
LOGE("camera_ops allocation fail");
rv = -ENOMEM;
goto fail;
}
memset(camera_device, 0, sizeof(*camera_device));
memset(camera_ops, 0, sizeof(*camera_ops));
camera_device->base.common.tag = HARDWARE_DEVICE_TAG;
camera_device->base.common.version = 0;
camera_device->base.common.module = (hw_module_t *)(module);
camera_device->base.common.close = camera_device_close;
camera_device->base.ops = camera_ops;
camera_ops->set_preview_window = camera_set_preview_window;
camera_ops->set_callbacks = camera_set_callbacks;
camera_ops->enable_msg_type = camera_enable_msg_type;
camera_ops->disable_msg_type = camera_disable_msg_type;
camera_ops->msg_type_enabled = camera_msg_type_enabled;
camera_ops->start_preview = camera_start_preview;
camera_ops->stop_preview = camera_stop_preview;
camera_ops->preview_enabled = camera_preview_enabled;
camera_ops->store_meta_data_in_buffers = camera_store_meta_data_in_buffers;
camera_ops->start_recording = camera_start_recording;
camera_ops->stop_recording = camera_stop_recording;
camera_ops->recording_enabled = camera_recording_enabled;
camera_ops->release_recording_frame = camera_release_recording_frame;
camera_ops->auto_focus = camera_auto_focus;
camera_ops->cancel_auto_focus = camera_cancel_auto_focus;
camera_ops->take_picture = camera_take_picture;
camera_ops->cancel_picture = camera_cancel_picture;
camera_ops->set_parameters = camera_set_parameters;
camera_ops->get_parameters = camera_get_parameters;
camera_ops->put_parameters = camera_put_parameters;
camera_ops->send_command = camera_send_command;
camera_ops->release = camera_release;
camera_ops->dump = camera_dump;
*device = &camera_device->base.common;
// -------- RockChip specific stuff --------
camera_device->cameraid = cameraid;
camera = new android::CameraHal(cameraid);
if(!camera) {
LOGE("Couldn't create instance of CameraHal class");
rv = -ENOMEM;
goto fail;
}
gCameraHals[cameraid] = camera;
gCamerasOpen++;
}
return rv;
fail:
if(camera_device) {
free(camera_device);
camera_device = NULL;
}
if(camera_ops) {
free(camera_ops);
camera_ops = NULL;
}
if(camera) {
delete camera;
camera = NULL;
}
*device = NULL;
return rv;
}
このopenの操作もCameraHalクラスを初期化し,一連のスレッドがloop状態になった.
ここで引き続きCameraClientのinitializeを見て
status_t CameraClient::initialize(camera_module_t *module) {
int callingPid = getCallingPid();
status_t res;
LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
// Verify ops permissions
res = startCameraOps();
if (res != OK) {
return res;
}
char camera_device_name[10];
snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
mHardware = new CameraHardwareInterface(camera_device_name);
res = mHardware->initialize(&module->common);
if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
mHardware.clear();
return NO_INIT;
}
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)mCameraId);
// Enable zoom, error, focus, and metadata messages by default
enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
return OK;
}
callbackの登録もこちらが初期化された時点で登録されています.
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)mCameraId);
対応する下層もインタフェース層ファイルにあります.
void setCallbacks(notify_callback notify_cb,
data_callback data_cb,
data_callback_timestamp data_cb_timestamp,
void* user)
{
mNotifyCb = notify_cb;
mDataCb = data_cb;
mDataCbTimestamp = data_cb_timestamp;
mCbUser = user;
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (mDevice->ops->set_callbacks) {
mDevice->ops->set_callbacks(mDevice,
__notify_cb,
__data_cb,
__data_cb_timestamp,
__get_memory,
this);
}
}
主な内容は上位から伝わる値をローカル変数に付与することであり,また最終的にはset_を判断することである.callbacksというインタフェースが初期化されているかどうかは、open cameraのときに初期化されています.
camera_ops->set_callbacks = camera_set_callbacks;
ここでmDevice->ops->set_callbacksとcamera_ops->set_callbacksとは、同じ構造体の中のインタフェースを指します.注意してください.こちらのパッケージsetcallbacksには関数ポインタが追加されています.get_メモリー、彼の実現もこの書類の中にある.hの中.ここで注意すれば、後でcameraのメモリ申請プロセスに関係します.このコールバックはここに登録すればいいことを覚えておいてください.次は本当の登録callbackです.
static void __data_cb(int32_t msg_type,
const camera_memory_t *data, unsigned int index,
camera_frame_metadata_t *metadata,
void *user)
{
ALOGV("%s", __FUNCTION__);
CameraHardwareInterface *__this =
static_cast(user);
sp mem(static_cast(data->handle));
if (index >= mem->mNumBufs) {
ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
index, mem->mNumBufs);
return;
}
__this->mDataCb(msg_type, mem->mBuffers[index], metadata, __this->mCbUser);
}
彼の原理はさっき地元に保存したcallbackインタフェースを包装したことだが、ここには大きな文章があり、下層callbackのデータ型はcameraだ.memory_tは,この層でmem->mBuffers[index]タイプ,すなわちIMemoryのタイプがCameraClientクラスにおけるcallbackパラメータタイプと一致するように変換され,適合と理解できるだろう.
こちらの操作はdata->handleというハンドルをc++で強制的にCameraHeapMemoryクラスに変換することですこちらは別の文章でcameraの全体的なデータストリーム方向とメモリ管理方式を詳しく説明します.
ここまでcamera初期化が完了しました.
引き続きcamerahal層setcallbacksの実装を見てみましょう.
void CameraHal::setCallbacks(camera_notify_callback notify_cb,
camera_data_callback data_cb,
camera_data_timestamp_callback data_cb_timestamp,
camera_request_memory get_memory,
void *user)
{
LOG_FUNCTION_NAME
Mutex::Autolock lock(mLock);
mEventNotifier->setCallbacks(notify_cb, data_cb,data_cb_timestamp,get_memory,user);
LOG_FUNCTION_NAME_EXIT
}
次のように呼び出されます.
void AppMsgNotifier::setCallbacks(camera_notify_callback notify_cb,
camera_data_callback data_cb,
camera_data_timestamp_callback data_cb_timestamp,
camera_request_memory get_memory,
void *user)
{
LOG_FUNCTION_NAME
mNotifyCb = notify_cb;
mDataCb = data_cb;
mDataCbTimestamp = data_cb_timestamp;
mRequestMemory = get_memory;
mCallbackCookie = user;
LOG_FUNCTION_NAME_EXIT
}
ここまでhalレイヤの関数ポインタに登録できました.この初期化に注意:mRequestMemory=get_memory;これはmemmoryを申請する過程です.
二、コールバックプロセス
これは登録プロセスです.逆にコールバックプロセスを見てみましょう.
mDataCb(CAMERA_MSG_PREVIEW_FRAME, tmpPreviewMemory, 0,NULL,mCallbackCookie);
上はcamerahalレイヤのコールバックコールです.cameraclientレイヤのdatacallbackに移動しますが、暗黙的な変換プロセスがあります.彼はcamerahardwareinterfaceのcallbackに戻ります.
static void __data_cb(int32_t msg_type,
const camera_memory_t *data, unsigned int index,
camera_frame_metadata_t *metadata,
void *user)
{
ALOGV("%s", __FUNCTION__);
CameraHardwareInterface *__this =
static_cast(user);
sp mem(static_cast(data->handle));
if (index >= mem->mNumBufs) {
ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
index, mem->mNumBufs);
return;
}
__this->mDataCb(msg_type, mem->mBuffers[index], metadata, __this->mCbUser);
}
上のコードはhal層camera_をmemory_tタイプのデータはCameraHeapMemoryタイプに変換され、最後に上位にコールバックされたのはIMemoryタイプのmem->mBuffers[index];次に、cameraclientにコールバックするdataCallbackです.
void CameraClient::dataCallback(int32_t msgType,
const sp& dataPtr, camera_frame_metadata_t *metadata, void* user) {
LOG2("dataCallback(%d)", msgType);
Mutex* lock = getClientLockFromCookie(user);
if (lock == NULL) return;
Mutex::Autolock alock(*lock);
CameraClient* client =
static_cast(getClientFromCookie(user));
if (client == NULL) return;
if (!client->lockIfMessageWanted(msgType)) return;
if (dataPtr == 0 && metadata == NULL) {
ALOGE("Null data returned in data callback");
client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
return;
}
switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
case CAMERA_MSG_PREVIEW_FRAME:
client->handlePreviewData(msgType, dataPtr, metadata);
break;
case CAMERA_MSG_POSTVIEW_FRAME:
client->handlePostview(dataPtr);
break;
case CAMERA_MSG_RAW_IMAGE:
client->handleRawPicture(dataPtr);
break;
case CAMERA_MSG_COMPRESSED_IMAGE:
client->handleCompressedPicture(dataPtr);
break;
default:
client->handleGenericData(msgType, dataPtr, metadata);
break;
}
}
最初にクライアントオブジェクトの取得はセキュリティを考慮します.ソースコードではこのように説明されています.//Provide client pointer for callbacks. Client lock returned from getClientLockFromCookie should be acquired for this to be safe
次のように呼び出されます.
case CAMERA_MSG_PREVIEW_FRAME:
client->handlePreviewData(msgType, dataPtr, metadata);
具体的な実装:
void CameraClient::handlePreviewData(int32_t msgType,
const sp& mem,
camera_frame_metadata_t *metadata) {
ssize_t offset;
size_t size;
sp heap = mem->getMemory(&offset, &size);
// local copy of the callback flags
int flags = mPreviewCallbackFlag;
// is callback enabled?
if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
// If the enable bit is off, the copy-out and one-shot bits are ignored
LOG2("frame callback is disabled");
mLock.unlock();
return;
}
// hold a strong pointer to the client
sp c = mRemoteCallback;
// clear callback flags if no client or one-shot mode
if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
LOG2("Disable preview callback");
mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
}
if (c != 0) {
// Is the received frame copied out or not?
if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
LOG2("frame is copied");
copyFrameAndPostCopiedFrame(msgType, c, heap, offset, size, metadata);
} else {
LOG2("frame is forwarded");
mLock.unlock();
c->dataCallback(msgType, mem, metadata);
}
} else {
mLock.unlock();
}
}
ここでdataデータを処理します:sp heap=mem->getMemory(&offset,&size);
実は上層部に伝わる全体の過程は基本的に取り外して再組み立てて、詰めて再分解して、具体的な細部はcamera memoryの章で深く分析します.
Datacallbackの呼び出しを続行するとbinderメカニズムで上位レベルのインタフェースが呼び出されます.このときのクライアントはlibcameraserviceであり、サービス側はcamera clientである.callbackに関連するbinderクラス:BpCameraClient,BnCameraClient,ICameraClientそれぞれの役割はここでは後述しない.
この時上層部のBnCameraClientまで見て、
case DATA_CALLBACK: {
ALOGV("DATA_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
int32_t msgType = data.readInt32();
sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
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;
まずbinderポートからdataデータを取得する:sp imageData=interface_cast(data.readStrongBinder());
そしてdataCallbackを呼び出す
このようなCSモードでは、上位のCameraはBnCameraClientを継承するので、関連する実装はすべてCamerクラスにある.
// callback from camera service when frame or image is ready
void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata)
{
sp<CameraListener> listener;
{
Mutex::Autolock _l(mLock);
listener = mListener;
}
if (listener != NULL) {
listener->postData(msgType, dataPtr, metadata);
}
}
まず、このリスニングの例がいつ初期化されたかを見てみましょう.cameraが初期化されたときを想像してみてください.
// connect to camera service
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jstring clientPackageName)
{
// Convert jstring to String16
const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);
jsize rawClientNameLen = env->GetStringLength(clientPackageName);
String16 clientName(rawClientName, rawClientNameLen);
env->ReleaseStringChars(clientPackageName, rawClientName);
sp<Camera> camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID);
if (camera == NULL) {
jniThrowRuntimeException(env, "Fail to connect to camera service");
return;
}
// make sure camera hardware is alive
if (camera->getStatus() != NO_ERROR) {
jniThrowRuntimeException(env, "Camera initialization failed");
return;
}
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
jniThrowRuntimeException(env, "Can't find android/hardware/Camera");
return;
}
// We use a weak reference so the Camera object can be garbage collected.
// The reference is only used as a proxy for callbacks.
sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
context->incStrong((void*)android_hardware_Camera_native_setup);
camera->setListener(context);
// save context in opaque field
env->SetIntField(thiz, fields.context, (int)context.get());
}
camera->setListener(context);これが初期化された良いcontextをcameraクラスのメンバー変数に格納することです.
ここでjava-cインタフェースファイルのインタフェースに移動しますandroid_hardware_Camera.cppファイル:class JNICameraContext:public CameraListener
void JNICameraContext::postData(int32_t msgType, const sp& dataPtr,
camera_frame_metadata_t *metadata)
{
// VM pointer will be NULL if object is released
Mutex::Autolock _l(mLock);
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (mCameraJObjectWeak == NULL) {
ALOGW("callback on dead camera object");
return;
}
int32_t dataMsgType = msgType & ~CAMERA_MSG_PREVIEW_METADATA;
// return data based on callback type
switch (dataMsgType) {
case CAMERA_MSG_VIDEO_FRAME:
// should never happen
break;
// For backward-compatibility purpose, if there is no callback
// buffer for raw image, the callback returns null.
case CAMERA_MSG_RAW_IMAGE:
ALOGV("rawCallback");
if (mRawImageCallbackBuffers.isEmpty()) {
env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
mCameraJObjectWeak, dataMsgType, 0, 0, NULL);
} else {
copyAndPost(env, dataPtr, dataMsgType);
}
break;
// There is no data.
case 0:
break;
default:
ALOGV("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);
}
}
コールバックのタイプに応じてcopyAndPost(env,dataPtr,dataMsgType)を呼び出し続けます.
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);
ALOGV("copyAndPost: off=%ld, size=%d", offset, size);
uint8_t *heapBase = (uint8_t*)heap->base();
if (heapBase != NULL) {
const jbyte* data = reinterpret_cast<const jbyte*>(heapBase + offset);
if (msgType == CAMERA_MSG_RAW_IMAGE) {
obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size);
} else if (msgType == CAMERA_MSG_PREVIEW_FRAME && mManualBufferMode) {
obj = getCallbackBuffer(env, &mCallbackBuffers, size);
if (mCallbackBuffers.isEmpty()) {
ALOGV("Out of buffers, clearing callback!");
mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
mManualCameraCallbackSet = false;
if (obj == NULL) {
return;
}
}
} else {
ALOGV("Allocating callback buffer");
obj = env->NewByteArray(size);
}
if (obj == NULL) {
ALOGE("Couldn't allocate byte array for JPEG data");
env->ExceptionClear();
} else {
env->SetByteArrayRegion(obj, 0, size, data);
}
} else {
ALOGE("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);
}
}
ここでjavaのインタフェースを呼び出し、dataデータをjavaレイヤに送信します.javaレイヤには関数があります.
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case CAMERA_MSG_SHUTTER:
if (mShutterCallback != null) {
mShutterCallback.onShutter();
}
return;
case CAMERA_MSG_RAW_IMAGE:
if (mRawImageCallback != null) {
mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_COMPRESSED_IMAGE:
if (mJpegCallback != null) {
mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_PREVIEW_FRAME:
PreviewCallback pCb = mPreviewCallback;
if (pCb != null) {
if (mOneShot) {
// Clear the callback variable before the callback
// in case the app calls setPreviewCallback from
// the callback function
mPreviewCallback = null;
} else if (!mWithBuffer) {
// We're faking the camera preview mode to prevent
// the app from being flooded with preview frames.
// Set to oneshot mode again.
setHasPreviewCallback(true, false);
}
pCb.onPreviewFrame((byte[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_POSTVIEW_FRAME:
if (mPostviewCallback != null) {
mPostviewCallback.onPictureTaken((byte[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_FOCUS:
AutoFocusCallback cb = null;
synchronized (mAutoFocusCallbackLock) {
cb = mAutoFocusCallback;
}
if (cb != null) {
boolean success = msg.arg1 == 0 ? false : true;
cb.onAutoFocus(success, mCamera);
}
return;
case CAMERA_MSG_ZOOM:
if (mZoomListener != null) {
mZoomListener.onZoomChange(msg.arg1, msg.arg2 != 0, mCamera);
}
return;
case CAMERA_MSG_PREVIEW_METADATA:
if (mFaceListener != null) {
mFaceListener.onFaceDetection((Face[])msg.obj, mCamera);
}
return;
case CAMERA_MSG_ERROR :
Log.e(TAG, "Error " + msg.arg1);
if (mErrorCallback != null) {
mErrorCallback.onError(msg.arg1, mCamera);
}
return;
case CAMERA_MSG_FOCUS_MOVE:
if (mAutoFocusMoveCallback != null) {
mAutoFocusMoveCallback.onAutoFocusMoving(msg.arg1 == 0 ? false : true, mCamera);
}
return;
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
}
}
}
ここでjavaレイヤに変更したら、分析しません.