android 7相机拍照功能介绍,android7 相机拍照流程

在前面的几篇笔记中,我已经把 Camera 控制流的部分梳理得比较清楚了。在 Camera 流程中,还有一个重要的部分,即数据流。

Camera API 1 中,数据流主要是通过函数回调的方式,依照从下往上的方向,逐层 return 到 Applications 中。

由于数据流的部分相对来说比较简单,所以我就将其与 Camera 的控制流结合起来,从 takePicture() 方法切入,追踪一个比较完整的 Camera 流程,这个系列的笔记到这篇也就可以结束了。

位置: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(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);

}

位置: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;

//先前有分析,https://my.oschina.net/u/920274/blog/5034592

sp 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;

}

}

调用camera->takePicture(msgType)后,来到下面的地方。

位置:frameworks/av/camera/Camera.cpp

takePicture():

获取一个 ICamera,调用其 takePicture 接口。

这里直接用 return 的方式调用,比较简单。

// take a picture

status_t Camera::takePicture(int msgType)

{

ALOGV("takePicture: 0x%x", msgType);

sp c = mCamera;

if (c == 0) return NO_INIT;

return c->takePicture(msgType);

}

然后跳转到

位置:frameworks/av/camera/ICamera.cpp

takePicture():

利用 Binder 机制发送相应指令到服务端。

实际调用到的是 CameraClient::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;

}

remote()->transact(TAKE_PICTURE, data, &reply);

binder调用到文件的CameraService.cpp的CameraService::onTransact方法

status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,

uint32_t flags) {

const int pid = getCallingPid();

const int selfPid = getpid();

// Permission checks

switch (code) {

case BnCameraService::CONNECT:

case BnCameraService::CONNECT_DEVICE:

case BnCameraService::CONNECT_LEGACY: {

if (pid != selfPid) {

// we're called from a different process, do the real check

if (!checkCallingPermission(

String16("android.permission.CAMERA"))) {

const int uid = getCallingUid();

ALOGE("Permission Denial: "

"can't use the camera pid=%d, uid=%d", pid, uid);

return PERMISSION_DENIED;

}

}

break;

}

case BnCameraService::NOTIFY_SYSTEM_EVENT: {

if (pid != selfPid) {

// Ensure we're being called by system_server, or similar process with

// permissions to notify the camera service about system events

if (!checkCallingPermission(

String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {

const int uid = getCallingUid();

ALOGE("Permission Denial: cannot send updates to camera service about system"

" events from pid=%d, uid=%d", pid, uid);

return PERMISSION_DENIED;

}

}

break;

}

}

return BnCameraService::onTransact(code, data, reply, flags); //然后会调用到这来

}

继续往下到文件ICameraService.cpp

status_t BnCameraService::onTransact(

uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

switch(code) {

。。。

。。。

default:

return BBinder::onTransact(code, data, reply, flags);

}

}

继续会调用到文件ICamera.cpp

status_t BnCamera::onTransact(

uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

switch(code) {

case TAKE_PICTURE: {

ALOGV("TAKE_PICTURE");

CHECK_INTERFACE(ICamera, data, reply);

int msgType = data.readInt32();

reply->writeInt32(takePicture(msgType));

return NO_ERROR;

} break;

default:

return BBinder::onTransact(code, data, reply, flags);

}

}

会调用到文件CameraClient.cpp下的takePicture(),是因为CameraClient继承 BnCamera

继续往下看文件 CameraClient.cpp

// 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();

if (result != NO_ERROR) return result;

if ((msgType & CAMERA_MSG_RAW_IMAGE) &&

(msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {

ALOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"

" cannot be both enabled");

return BAD_VALUE;

}

// We only accept picture related message types

// and ignore other types of messages for takePicture().

int picMsgType = msgType

& (CAMERA_MSG_SHUTTER |

CAMERA_MSG_POSTVIEW_FRAME |

CAMERA_MSG_RAW_IMAGE |

CAMERA_MSG_RAW_IMAGE_NOTIFY |

CAMERA_MSG_COMPRESSED_IMAGE);

enableMsgType(picMsgType);

return mHardware->takePicture();

}

位置:frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h

takePicture():

通过 mDevice 中设置的函数指针,调用 HAL 层中具体平台对应的 takePicture 操作的实现逻辑。

接下来就是与具体的平台相关的流程了,这部分内容对我并非主要,而且在上一篇笔记中已经有比较深入的探索,所以在这里就不继续向下挖掘了。

控制流程到了 HAL 层后,再向 Linux Drivers 发送控制指令,从而使具体的 Camera 设备执行指令,并获取数据。

/**

* Take a picture.

*/

status_t takePicture()

{

ALOGV("%s(%s)", __FUNCTION__, mName.string());

if (mDevice->ops->take_picture)

return mDevice->ops->take_picture(mDevice);

return INVALID_OPERATION;

}

后面就是 数据流

由于数据流是通过 callback 函数实现的,所以探究其流程的时候我是从底层向上层进行分析的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值