camera的startpreview流程

一、概述

  本文从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时序图

这里写图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值