一、概述
本文从framework中的camera native接口开始分析preview流程,文中的…..表示部分代码省略。
二、camera CS简易框图
三、preview调用过程
2.1 camera.java
public native final void startPreview();
camera进行预览时,APP最终调用的是startPreview,而startPreview是Java本地方法,其具体的实现是在jni中体现的。
2.2 android_hardware_Camera.cpp
static JNINativeMethod camMethods[] = {
.......
{ "startPreview",
"()V",
(void *)android_hardware_Camera_startPreview },
.......
};
通过查看注册的jni native方法映射表可知,Java中调用startpreview对应的具体实现是android_hardware_Camera_startPreview 方法
static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
ALOGV("startPreview");
sp<Camera> camera = get_native_camera(env, thiz, NULL);//camera 是连接服务后创建的代理类
if (camera == 0) return;
if (camera->startPreview() != NO_ERROR) {
jniThrowRuntimeException(env, "startPreview failed");
return;
}
}
获取camera代理类,通过代理类调用接口startpreview
2.3 Camera.cpp
status_t Camera::startPreview()
{
ALOGV("startPreview");
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
return c->startPreview();
}
2.4 ICamera.cpp
virtual status_t startPreview() = 0;
这是个纯虚函数,其实现在它的子类BpCamera中。
status_t startPreview()
{
ALOGV("startPreview");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
remote()->transact(START_PREVIEW, data, &reply);//通过binder远程调用
return reply.readInt32();
}
通过binder远程调用,最终会调用BnCamera::onTransact方法
status_t BnCamera::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
...............
case START_PREVIEW: {
ALOGV("START_PREVIEW");
CHECK_INTERFACE(ICamera, data, reply);
reply->writeInt32(startPreview());
return NO_ERROR;
} break;
...............
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
此处reply->writeInt32(startPreview());其实是省略了this指针,另外它也是继承ICamera类,声明也是纯虚函数,故它调用的是子类(CameraClient)的实现方法。
2.5 CameraClient.cpp
status_t CameraClient::startPreview() {
LOG1("startPreview (pid %d)", getCallingPid());
//开始预览模式
return startCameraMode(CAMERA_PREVIEW_MODE);
}
status_t CameraClient::startCameraMode(camera_mode mode) {
LOG1("startCameraMode(%d)", mode);
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;
switch(mode) {
case CAMERA_PREVIEW_MODE://预览模式
if (mSurface == 0 && mPreviewWindow == 0) {
LOG1("mSurface is not set yet.");
// still able to start preview in this case.
}
return startPreviewMode();
case CAMERA_RECORDING_MODE://录制模式
if (mSurface == 0 && mPreviewWindow == 0) {
ALOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");
return INVALID_OPERATION;
}
return startRecordingMode();
default:
return UNKNOWN_ERROR;
}
}
status_t CameraClient::startPreviewMode() {
LOG1("startPreviewMode");
status_t result = NO_ERROR;
// 如果预览已启用,则不需任何操作直接返回
if (mHardware->previewEnabled()) {
return NO_ERROR;
}
if (mPreviewWindow != 0) {
//设置预览窗口
native_window_set_scaling_mode(mPreviewWindow.get(),
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
//根据新的参数,设置所有缓冲区的显示
native_window_set_buffers_transform(mPreviewWindow.get(),
mOrientation);
}
mHardware->setPreviewWindow(mPreviewWindow);//设置新的预览窗口参数
result = mHardware->startPreview();//启动预览
return result;
}
2.6 CameraHardwareInterface.h
status_t startPreview()
{
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (mDevice->ops->start_preview)
return mDevice->ops->start_preview(mDevice);
return INVALID_OPERATION;
}
2.7 CameraHal_Module.cpp
int camera_start_preview(struct camera_device * device)
{
CAMHAL_LOG_MODULE_FUNCTION_NAME;
int rv = -EINVAL;
ti_camera_device_t* ti_dev = NULL;
if(!device)
return rv;
ti_dev = (ti_camera_device_t*) device;
rv = gCameraHals[ti_dev->cameraid]->startPreview();
return rv;
}
2.8 CameraHal.cpp
status_t CameraHal::startPreview() {
LOG_FUNCTION_NAME;
///Enable the display adapter if present, actual overlay enable happens when we post the buffer
if(mDisplayAdapter.get() != NULL) {
CAMHAL_LOGDA("Enabling display");
int width, height;
mParameters.getPreviewSize(&width, &height);
//设置显示窗口使能
#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
ret = mDisplayAdapter->enableDisplay(width, height, &mStartPreview);
#else
ret = mDisplayAdapter->enableDisplay(width, height, NULL);
#endif
}
///Send START_PREVIEW command to adapter
CAMHAL_LOGDA("Starting CameraAdapter preview mode");
ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_PREVIEW);
mPreviewEnabled = true;
mPreviewStartInProgress = false;
return ret;
}
2.9 BaseCameraAdapter.cpp
status_t BaseCameraAdapter::sendCommand(CameraCommands operation, int value1, int value2, int value3, int value4) {
status_t ret = NO_ERROR;
struct timeval *refTimestamp;
BuffersDescriptor *desc = NULL;
CameraFrame *frame = NULL;
switch ( operation ) {
.........
case CameraAdapter::CAMERA_START_PREVIEW:
{
CAMHAL_LOGDA("Start Preview");
if ( ret == NO_ERROR )
{
ret = setState(operation);
}
if ( ret == NO_ERROR )
{
ret = startPreview();
}
if ( ret == NO_ERROR )
{
ret = commitState();
}
else
{
ret |= rollbackState();
}
break;
}
.........
default:
CAMHAL_LOGEB("Command 0x%x unsupported!", operation);
break;
};
LOG_FUNCTION_NAME_EXIT;
return ret;
}
2.10 V4LCameraAdapter.cpp
status_t V4LCameraAdapter::startPreview()
{
status_t ret = NO_ERROR;
LOG_FUNCTION_NAME;
android::AutoMutex lock(mPreviewBufsLock);
if(mPreviewing) {
ret = BAD_VALUE;
goto EXIT;
}
for (int i = 0; i < mPreviewBufferCountQueueable; i++) {
mVideoInfo->buf.index = i;
mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
if (ret < 0) {
CAMHAL_LOGEA("VIDIOC_QBUF Failed");
goto EXIT;
}
nQueued++;
}
ret = v4lStartStreaming();
// Create and start preview thread for receiving buffers from V4L Camera
if(!mCapturing) {
mPreviewThread = new PreviewThread(this);
CAMHAL_LOGDA("Created preview thread");
}
//Update the flag to indicate we are previewing
mPreviewing = true;
mCapturing = false;
EXIT:
LOG_FUNCTION_NAME_EXIT;
return ret;
}
status_t V4LCameraAdapter::v4lIoctl (int fd, int req, void* argp) {
status_t ret = NO_ERROR;
errno = 0;
do {
ret = ioctl (fd, req, argp);//与驱动交互
}while (-1 == ret && EINTR == errno);
return ret;
}