前言
前面几篇文章已经把 Camera 控制流的部分梳理得比较清楚了。在 Camera 流程中,还有一个重要的部分,即数据流。
Camera API 1 中,数据流主要是通过函数回调的方式,依照从下往上的方向,逐层 return 到 Applications 中。
本篇将数据流与 Camera 的控制流结合起来,从 takePicture() 方法切入,追踪一个比较完整的 Camera 流程。
1 Open 流程
Camera Open 的流程,在之前的一篇文章中已经比较详细地描述了。在这里,再关注一下这个流程中 Libraries 和 HAL 层的部分。
1.1 CameraService.cpp
- 路径:
frameworks/av/services/camera/libcameraservice/CameraService.cpp connect():- 注意这里真正实现逻辑是在
connectHelper()函数中。
- 注意这里真正实现逻辑是在
connectHelper():- 这个函数实现比较长,截取其中的一段。
- 首先,如果客户端实例已经存在于
MediaRecorder,则直接将其取出返回。 - 若不存在,则先获取
deviceVersion,然后再调用makeClient()函数创建一个客户端。
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
int clientPid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
...
sp<BasicClient> tmp = nullptr;
if(!(ret = makeClient(this, cameraCb, clientPackageName,
cameraId, api1CameraId, facing,
clientPid, clientUid, getpid(), legacyMode,
halVersion, deviceVersion, effectiveApiLevel,
/*out*/&tmp)).isOk()) {
return ret;
}
client = static_cast<CLIENT*>(tmp.get());
...
return ret;
}
makeClient():- 主要是根据
API版本以及HAL版本来选择生成具体的Client实例。 - 如果是
HAL1+Camera1,则创建的是CameraClient,如果是HAL3+Camera1,则创建的是Camera2Client。
- 主要是根据
Status CameraService::makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client) {
if (halVersion < 0 || halVersion == deviceVersion) {
// Default path: HAL version is unspecified by caller, create CameraClient
// based on device version reported by the HAL.
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
if (effectiveApiLevel == API_1) {
// Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName,
api1CameraId, facing, clientPid, clientUid,
getpid(), legacyMode);
} else {
// Camera2 API route
ALOGW("Camera using old HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
"Camera device \"%s\" HAL version %d does not support camera2 API",
cameraId.string(), deviceVersion);
}
break;
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
case CAMERA_DEVICE_API_VERSION_3_3:
case CAMERA_DEVICE_API_VERSION_3_4:
if (effectiveApiLevel == API_1) {
// Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, packageName,
cameraId, api1CameraId,
facing, clientPid, clientUid,
servicePid, legacyMode);
} else {
// Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
*client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
facing, clientPid, clientUid, servicePid);
}
break;
default:
// Should not be reachable
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Camera device \"%s\" has unknown HAL version %d",
cameraId.string(), deviceVersion);
}
} else {
// A particular HAL version is requested by caller. Create CameraClient
// based on the requested HAL version.
if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&
halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
// Only support higher HAL version device opened as HAL1.0 device.
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName,
api1CameraId, facing, clientPid, clientUid,
servicePid, legacyMode);
} else {
// Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
" opened as HAL %x device", halVersion, deviceVersion,
CAMERA_DEVICE_API_VERSION_1_0);
return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
"Camera device \"%s\" (HAL version %d) cannot be opened as HAL version %d",
cameraId.string(), deviceVersion, halVersion);
}
}
return Status::ok();
}
1.2 CameraHardwareInterface.h
- 路径:
frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h setCallback():- 设置
notify回调,这用来通知数据已经更新。 - 设置
data回调以及dataTimestamp回调,对应的是函数指针mDataCb与mDataCvTimestamp。 - 注意到,设置
mDevice->ops对应回调函数时,传入的不是之前设置的函数指针,而是__data_cb这样的函数。在该文件中,实现了__data_cb,将回调函数做了一层封装。
- 设置
/** Set the notification and data callbacks */
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;
// If callback is not set, do not send me callbacks.
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.cpptakePicture():- 获取已经打开的
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;
/*
* When CAMERA_MSG_RAW_IMAGE is requested, if the raw image callback
* buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the
* notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY
* is enabled to receive the callback notification but no data.
*
* Note that CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed to the
* Java application.
*/
if (msgType & CAMERA_MSG_RAW_IMAGE) {
ALOGV("Enable raw image callback buffer");
if (!context->isRawImageCallbackBufferAvailable()) {
ALOGV("Enable raw image notification, since no callback buffer exists");
msgType &= ~CAMERA_MSG_RAW_IMAGE;
msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY;
}
}
if (camera->takePicture(msgType) != NO_ERROR) {
jniThrowRuntimeException(env, "takePicture failed");
return;
}
}
2.3 C/C++ Libraries
2.3.1 Camera.cpp
- 路径:
frameworks/av/camera/Camera.cpp takePicture():- 获取一个
ICamera,调用其takePicture接口。
- 获取一个
// take a picture
status_t Camera::takePicture(int msgType)
{
ALOGV("takePicture: 0x%x", msgType);
sp <::android::hardware::ICamera> c = mCamera;
if (c == 0) return NO_INIT;
return c->takePicture(msgType);
}
2.3.2 ICamera.cpp
- 路径:
frameworks/av/camera/ICamera.cpp takePicture():- 利用
Binder机制发送相应指令到服务端。 - 如果是
HAL1+Camera1,实际调用到的是CameraClient::takePicture()函数。 - 如果是
HAL3+Camera1,实际调用到的是Camera2Client::takePicture()函数。
- 利用
// take a picture - returns an IMemory (ref-counted mmap)
status_t takePicture(int msgType)
{
ALOGV("takePicture: 0x%x", msgType);
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
data.writeInt32(msgType);
remote()->transact(TAKE_PICTURE, data, &reply);
status_t ret = reply.readInt32();
return ret;
}
2.3.3 CameraClient.cpp
- 路径:
frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp takePicture():- 注意,
CAMERA_MSG_RAW_IMAGE指令与CAMERA_MSG_RAW_IMAGE_NOTIFY指令不能同时有效,需要进行对应的检查。 - 对传入的指令过滤,只留下与
takePicture()操作相关的。 - 调用
CameraHardwareInterface中的takePicture()接口。
- 注意,
// take a picture - image is returned in callback
status_t CameraClient::takePicture(int msgType) {
LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType);
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware

最低0.47元/天 解锁文章
9974

被折叠的 条评论
为什么被折叠?



