camera的startpreview流程

来源:互联网 发布:022型导弹艇知乎 编辑:程序博客网 时间:2024/04/28 00:12

一、概述

  本文从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;}

四、preview时序图

这里写图片描述