简介
在前面的几篇笔记中,我已经把 Camera
控制流的部分梳理得比较清楚了。在 Camera
流程中,还有一个重要的部分,即数据流。
Camera API 1
中,数据流主要是通过函数回调的方式,依照从下往上的方向,逐层 return
到 Applications 中。
由于数据流的部分相对来说比较简单,所以我就将其与 Camera
的控制流结合起来,从 takePicture()
方法切入,追踪一个比较完整的 Camera
流程,这个系列的笔记到这篇也就可以结束了。
takePicture() flow
1. Open 流程
Camera Open
的流程,在之前的一篇笔记中已经比较详细地描述了。
在这里,再关注一下这个流程中,HAL
层的部分。
1.1 CameraHardwareInterface.h
位置:frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h
setCallback()
:
设置 notify
回调,这用来通知数据已经更新。
设置 data
回调以及 dataTimestamp
回调,对应的是函数指针 mDataCb
与 mDataCvTimestamp
。
注意到,设置 mDevice->ops
对应回调函数时,传入的不是之前设置的函数指针,而是 __data_cb
这样的函数。在该文件中,实现了 __data_cb
,将回调函数做了一层封装。
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 );
}
}
__data_cb()
:
对原 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 <CameraHardwareInterface *>(user);
sp<CameraHeapMemory> mem(static_cast <CameraHeapMemory *>(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);
}
2. 控制流
2.1 Framework
2.1.1 Camera.java
位置:frameworks/base/core/java/android/hardware/Camera.java
takePicture()
:
设置快门回调。
设置各种类型的图片数据回调。
调用 JNI takePicture
方法。
注意,传入的参数 msgType
是根据相应 CallBack
是否存在而确定的,每种 Callback
应该对应一个二进制中的数位(如 1,10,100 中 1 的位置),于是这里采用 |=
操作给它赋值。
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback postview, PictureCallback jpeg) {
mShutterCallback = shutter;
mRawImageCallback = raw;
mPostviewCallback = postview;
mJpegCallback = jpeg;
int msgType = 0 ;
if (mShutterCallback != null) {
msgType |= CAMERA_MSG_SHUTTER;
}
if (mRawImageCallback != null) {
msgType |= CAMERA_MSG_RAW_IMAGE;
}
if (mPostviewCallback != null) {
msgType |= CAMERA_MSG_POSTVIEW_FRAME;
}
if (mJpegCallback != null) {
msgType |= CAMERA_MSG_COMPRESSED_IMAGE;
}
native_takePicture(msgType);
mFaceDetectionRunning = false ;
}
2.2 Android Runtime
2.2.1 android_hardware_Camera.cpp
位置:frameworks/base/core/jni/android_hardware_Camera.cpp
takePicture()
:
获取已经打开的 camera
实例,调用其 takePicture()
接口。
注意,在这个函数中,对于 RAW_IMAGE
有一些附加操作:
如果设置了 RAW
的 callback
,则要检查上下文中,是否能找到对应 Buffer
。
若无法找到 Buffer
,则将 CAMERA_MSG_RAW_IMAGE
的信息去掉,换成 CAMERA_MSG_RAW_IMAGE_NOTIFY
。
替换后,就只会获得 notification
的消息,而没有对应的图像数据。
static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz, jint msgType)
{
ALOGV("takePicture" );
JNICameraContext* context;
sp<Camera> camera = get_native_camera(env, thiz, &context);
if (camera == 0 ) return ;