上一篇文章讲述了camera开启预览的流程,有了预览后,一般常见的操作是拍照。本文将讲述拍照的控制流的下发和数据流的回调整个流程,因为囊括了数据回调,中间会涉及到一点CameraHAL层的代码讲解。
首先依然从java层的接口开始分析,一般在apk代码里会实例化ShutterCallback和PictureCallback类,并实现各自的回调函数,然后把实例传递到camera java接口层,供后续数据回调。
1. takePicture
- Camera.java
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;
}
其中的参数是四个回调实例,这些参数是在apk层实例化,并传递下来的
- ShutterCallback shutter:通知回调,控制播放拍照快门声
- PictureCallback raw: 回调camera原始数据,如yuv或者bayer raw格式的数据,很少使用
- PictureCallback postview:这个很少使用,不清楚具体用途
- PictureCallback jpeg:编码后的JPEG数据,就是拍的照片,主要使用这个
msgType |= CAMERA_MSG_COMPRESSED_IMAGE一定会执行的,这个msgType 会一直传递到HAL层去。
接下来调用到JNI层的native_takePicture函数
- android_hardware_Camera.cpp
{
"native_takePicture",
"(I)V",
(void *)android_hardware_Camera_takePicture },
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;
......
if (camera->takePicture(msgType) != NO_ERROR) {
jniThrowRuntimeException(env, "takePicture failed");
return;
}
}
- Camera.cpp
// take a picture
status_t Camera::takePicture(int msgType)
{
ALOGV("takePicture: 0x%x", msgType);
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
return c->takePicture(msgType);
}
- ICamera.cpp
class BpCamera: public BpInterface<ICamera>
{
public:
// 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;
}
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;
- 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); // 这个type是有的
enableMsgType(picMsgType); // 使能这个类型,一直调用到hal层
return mHardware->takePicture();
}
- CameraHardwareInterface.cpp
/**
* 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;
}
前面这些流程都比较简单,都是直接一步步往下调用,至此framework层的takePicture控制流的下发就完了,接下来会传递到CameraHal中,前面说过我目前主要先分析framework层的流程和代码,所以takePicture下发到hal层的流程暂时就不分析了。
下面将讲述拍照编码后的JPEG数据的回调流程,因为这部分涉及到一些匿名共享内存的分配和传递,会稍微夹带分析一点hal层的代码和流程,这也是为了更方便的理解和阅读framework层的代码。
hal层要想回调数据,必须先获取到framework层的回调接口,将framework层的callback函数指针设置到hal层的函数
2. dataCallback
- CameraClient.cpp
status_t CameraClient::initialize(CameraModule *module) {
......
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)(uintptr_t)mCameraId);
......
}
这个initialize函数在前面的o