欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

camera的startpreview流程

程序员文章站 2022-05-17 08:50:31
...

一、概述

  本文从framework中的camera native接口开始分析preview流程,文中的…..表示部分代码省略。

二、camera CS简易框图

camera的startpreview流程

三、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时序图

camera的startpreview流程