【Camera专题】】HAL层-深入浅出startPreview

说在前面的话

现在阅读的是HAL1的源码,因为项目目前还是Android 7.1,用的是HAL 1,而HAL 3有很大的改动!!!
有点不知道怎么说才好。
不论如何,把一个搞懂了,另一个理解起来也会容易一些吧!

不去抱怨,就努力去做吧!!!

一.知识点

1. C++多线程知识

2. startPreview的流程和深度解析

读完本文,未来在面试的时候,如果面试官问到这一块,希望你得心应手!

二.C++的多线程知识

这是看本文必备的C++基础知识,如果你对多线程不了解,可以阅读以下文章:
1. 菜鸟教程-C++多线程基础
2. pthread_mutex_t 和 pthread_cond_t 配合使用的简要分析
3. 多线程之pthread_create()函数
4. 条件变量、pthread_cond_init
5. linux线程互斥量pthread_mutex_t使用简介

三.startPreview的流程和深度解析

3.1 startPreview的流程图

3.2 从log中看startPreview
QCamera2Factory::cameraDeviceOpen(int, hw_device_t**) :zcf E
QCameraStateMachine(qcamera::QCamera2HardwareInterface*):zcf X
QCameraStateMachine(qcamera::QCamera2HardwareInterface*):zcf thread id=-1401407200
QCameraStateMachine(qcamera::QCamera2HardwareInterface*):zcf E
QCamera2Factory::cameraDeviceOpen(int, hw_device_t**):zcf X

Camera-JNI: zcf startPreview
Camera NA: zcf startPreview
CameraClient: zcf startPreview (pid 3857)
CameraClient: zcf startCameraMode(0)
CameraClient: zcf startPreviewMode
CameraFlashlight: [zcf] startPreview  (0)
QCamera2HardwareInterface::start_preview(camera_device*): zcf E

qcamera::QCameraStateMachine::procEvtPreviewStoppedState(···):
zcf mPreviewWindow != NULL,call preparePreview

QCamera2HWI: int32_t qcamera::QCamera2HardwareInterface::preparePreview(): zcf E
QCamera2HWI: int32_t qcamera::QCamera2HardwareInterface::preparePreview(): zcf X
QCameraStateMachine::procEvtPreviewStoppedState(···):
zcf call startPreview

QCamera2HWI: int qcamera::QCamera2HardwareInterface::startPreview(): zcf  E
QCamera2HWI: int qcamera::QCamera2HardwareInterface::startPreview(): zcf X
QCameraStateMachine::procEvtPreviewStoppedState(···):
zcf start preview success, move to previewing state

QCamera2HardwareInterface::start_preview(camera_device*): zcf X

从log中,可以很清晰的看到方法的调用流程,
有时候,看源码不知道是调用的哪里,自己添加一些log,打印出来,就很清晰了!
log截图

3.3 深度解析

3.3.1 open简析
首先startPreview之前,肯定是先open Camera的流程,但这不是本文的重点,因此简要分析吧!

a) qcamera::QCamera2Factory::cameraDeviceOpen

int QCamera2Factory::cameraDeviceOpen(int camera_id,
                    struct hw_device_t **hw_device)
{
    int rc = NO_ERROR;
    ALOGE("%s zcf E",__func__);
    if (camera_id < 0 || camera_id >= mNumOfCameras)
        return BAD_VALUE;
//这里new了一个QCamera2HardwareInterface 实例(对象)
    QCamera2HardwareInterface *hw = new QCamera2HardwareInterface((uint32_t)camera_id);
    if (!hw) {
        ALOGE("Allocation of hardware interface failed");
        return NO_MEMORY;
    }
//调用QCamera2HardwareInterface 里的openCamera()方法
    rc = hw->openCamera(hw_device);
    if (rc != NO_ERROR) {
        delete hw;
    }
    ALOGE("%s zcf X",__func__);
    return rc;
}
    1. new QCamera2HardwareInterface((uint32_t)camera_id)的实例

当系统new这个QCamera2HardwareInterface对象时,首先会调用QCameraStateMachine的构造方法
然后在调用QCamera2HardwareInterface的构造方法
因为QCameraStateMachine 是QCamera2HardwareInterface的一个成员变量!
其定义如下:

class QCamera2HardwareInterface : public QCameraAllocator,
                                public QCameraThermalCallback,
                                  public QCameraAdjustFPS,
                              public QCameraTorchInterface
{
···
pubulic:
friend class QCameraStateMachine;
···
private:
QCameraStateMachine m_stateMachine;   // state machine
···
}
    1. 调用hw->openCamera(hw_device);
      QCamera2HardwareInterface 对象有了之后,就去调用openCamera方法,
      后续的openCamera就不再分析。

b) QCameraStateMachine::QCameraStateMachine构造方法

QCameraStateMachine::QCameraStateMachine(QCamera2HardwareInterface *ctrl) :
    api_queue(),
    evt_queue()
{
    CDBG_HIGH("%s:zcf X", __func__);
    m_parent = ctrl;//注意 m_parent 就是 QCamera2HardwareInterface 实例对象
    m_state = QCAMERA_SM_STATE_PREVIEW_STOPPED;
    cmd_pid = 0; 
    cam_sem_init(&cmd_sem, 0);//初始化信号量
    //创建线程
    pthread_create(&cmd_pid,
                   NULL,
                   smEvtProcRoutine,
                   this);
    CDBG_HIGH("%s:zcf thread id=%d", __func__,cmd_pid);
    pthread_setname_np(cmd_pid, "CAM_stMachine");
    CDBG_HIGH("%s:zcf E", __func__);
}

QCameraStateMachine这个类是用来管理Camera的运行状态的,
比如:处于预览、拍照或者录屏状态。

  • 1首先初始化了2个队列:
    api_queue():处理来自framework的API请求
    evt_queue():处理来自framework的event请求

    1. m_parent = ctrl; m_parent 就是 QCamera2HardwareInterface 实例对象
  • 3.设置初始状态: m_state = QCAMERA_SM_STATE_PREVIEW_STOPPED;

  • 4.cam_sem_init(&cmd_sem, 0)初始化信号量

  • 5.pthread_create创建线程,名称为:CAM_stMachine,线程函数smEvtProcRoutine
    这里就用到C++多线程知识了,这个线程,下文分析会用到的!

PS:下面的分析会用到这里的知识,请留意!!!


3.3.2 startPreview 分析

a) JNI 层

调用流程:APP->Framework层->JNI->Native->HAL层->Kernel层。
frameworks/base/core/java/android/hardware/Camera.java
framework层中定义native方法:

    /**  
     * Starts capturing and drawing preview frames to the screen.
     * Preview will not actually start until a surface is supplied
     * with {@link #setPreviewDisplay(SurfaceHolder)} or
     * {@link #setPreviewTexture(SurfaceTexture)}.
     *
     * <p>If {@link #setPreviewCallback(Camera.PreviewCallback)},
     * {@link #setOneShotPreviewCallback(Camera.PreviewCallback)}, or
     * {@link #setPreviewCallbackWithBuffer(Camera.PreviewCallback)} were
     * called, {@link Camera.PreviewCallback#onPreviewFrame(byte[], Camera)}
     * will be called when preview data becomes available.
     */
    public native final void startPreview();

进入JNI层调用相关方法:

static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
    ALOGD("zcf startPreview");
    sp<Camera> camera = get_native_camera(env, thiz, NULL);
    if (camera == 0) return;

    if (camera->startPreview() != NO_ERROR) {
        jniThrowRuntimeException(env, "startPreview failed");
        return;
    }    
}

b) Native层

frameworks/av/camera/Camera.cpp

// start preview mode
status_t Camera::startPreview()
{
    ALOGE("zcf startPreview");
    sp <::android::hardware::ICamera> c = mCamera;
    if (c == 0) return NO_INIT;
    return c->startPreview();
}

这里的ICamera类型实际上是CameraClient,因此会调用到CameraClient::startPreview。

另外你也可以从log中看到调用流程:
Camera-JNI: zcf startPreview
Camera NA: zcf startPreview
CameraClient: zcf startPreview (pid 3857)
CameraClient: zcf startPreviewMode

frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp

// start preview mode
status_t CameraClient::startPreview() {
    LOG1("zcf startPreview (pid %d)", getCallingPid());
    return startCameraMode(CAMERA_PREVIEW_MODE);
}

这里传入的类型是CAMERA_PREVIEW_MODE

// start preview or recording
status_t CameraClient::startCameraMode(camera_mode mode) {
    LOG1("zcf 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;
    }
}

在照相预览模式中,调用startPreviewMode方法:

status_t CameraClient::startPreviewMode() {
    LOG1("zcf startPreviewMode");
    status_t result = NO_ERROR;

    // if preview has been enabled, nothing needs to be done
    //如果当前已经处于预览模式,则直接返回
    if (mHardware->previewEnabled()) {
        return NO_ERROR;
    }    
     
    if (mPreviewWindow != 0) { 
        //设置窗口的缩放比例
        mHardware->setPreviewScalingMode(
            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
        //设置预览数据的方向:水平,垂直,或者2者结合
        mHardware->setPreviewTransform(mOrientation);
    }    
    //设置当前显示窗口
    mHardware->setPreviewWindow(mPreviewWindow);
   //调用HAL层的startPreview方法
    result = mHardware->startPreview();
    //接收返回值
    if (result == NO_ERROR) {
        //若HAL层返回成功,
        //通过代理通知CameraService当前的camera状态:CAMERA_STATE_ACTIVE
        mCameraService->updateProxyDeviceState(
            ICameraServiceProxy::CAMERA_STATE_ACTIVE,
            String8::format("%d", mCameraId));
    }    
    return result;
}

应用启动时,会设置预览窗口,对应的就是这里的mPreviewWindow。
后续调用HAL的startPreview方法!
这里的mHardware = new CameraHardwareInterface(camera_device_name);

c) HAL层
frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h
先看一下log打印:
CameraFlashlight: [zcf] startPreview (0)
一开始我还以为调用到CameraFlashlight类的startPreview 呢,
这是我添加的log:
ALOGE("[zcf] %s (%s)", FUNCTION, mName.string());
实际上是这个ALOGE定义的问题,它打印的TAG是CameraFlashlight。

总之是调用到CameraHardwareInterfacestartPreview

/** 
 * Start preview mode.
 */
status_t startPreview()
{   
    ALOGE("[zcf] %s (%s)", __FUNCTION__, mName.string());
    if (mDevice->ops->start_preview)
        return mDevice->ops->start_preview(mDevice);
    return INVALID_OPERATION;
} 

其中:mDevice->ops会在Camera初始化的时候【其实就是调用QCamera2HardwareInterface构造方法的时候】,
绑定所有跟camera相关的操作方法。

QCamera2HardwareInterface::QCamera2HardwareInterface(uint32_t cameraId)
{
···
    mCameraDevice.ops = &mCameraOps;
···
}

接下来调用的是:mDevice->ops->start_preview(mDevice)
这是log:
QCamera2HWI: static int qcamera::QCamera2HardwareInterface::start_preview(camera_device*): zcf E

hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.cpp

int QCamera2HardwareInterface::start_preview(struct camera_device *device)
{
    CDBG_HIGH("%s: zcf E", __func__);
    ATRACE_CALL();
    int ret = NO_ERROR;
    //这里的device指针强转成QCamera2HardwareInterface 类型
    QCamera2HardwareInterface *hw =
        reinterpret_cast<QCamera2HardwareInterface *>(device->priv);
    if (!hw) {
        ALOGE("NULL camera device");
        return BAD_VALUE;
    }    
    CDBG_HIGH("[KPI Perf] %s: E PROFILE_START_PREVIEW", __func__);
    //线程锁
    hw->lockAPI();
    qcamera_api_result_t apiResult;
    //事件类型 QCAMERA_SM_EVT_START_PREVIEW
    qcamera_sm_evt_enum_t evt = QCAMERA_SM_EVT_START_PREVIEW;
    if (hw->isNoDisplayMode()) {
        CDBG_HIGH("%s: zcf isNoDisplayMode ", __func__);
        evt = QCAMERA_SM_EVT_START_NODISPLAY_PREVIEW;
    }    
    //发送事件
    ret = hw->processAPI(evt, NULL);
    if (ret == NO_ERROR) {
        //解锁并且等待线程唤醒
        hw->waitAPIResult(evt, &apiResult);
        ret = apiResult.status;
    }    
    //解锁
    hw->unlockAPI();
    hw->m_bPreviewStarted = true;
    CDBG_HIGH("[KPI Perf] %s: X", __func__);
    CDBG_HIGH("%s: zcf X", __func__);
    return ret; 
}

分析到这里,就要用到我们C++的线程知识了

  • 1.首先设置evt = QCAMERA_SM_EVT_START_PREVIEW,通过hw->processAPI(evt, NULL)发送事件。
int QCamera2HardwareInterface::processAPI(qcamera_sm_evt_enum_t api, void *api_payload)
{
    int ret = DEAD_OBJECT;

    if (m_smThreadActive) {
        ret = m_stateMachine.procAPI(api, api_payload);
    }

    return ret;
}

其中m_stateMachine类型:QCameraStateMachine m_stateMachine;
调用procAPI,该函数作用:处理来自framew层的传入API请求。

hardware/qcom/camera/QCamera2/HAL/QCameraStateMachine.cpp

int32_t QCameraStateMachine::procAPI(qcamera_sm_evt_enum_t evt, 
                                     void *api_payload)
{
    //申请内存
    qcamera_sm_cmd_t *node =
        (qcamera_sm_cmd_t *)malloc(sizeof(qcamera_sm_cmd_t));
    if (NULL == node) {
        ALOGE("%s: No memory for qcamera_sm_cmd_t", __func__);
        return NO_MEMORY;
    }    

    memset(node, 0, sizeof(qcamera_sm_cmd_t));
    //设置CMD类型为:QCAMERA_SM_CMD_TYPE_API
    node->cmd = QCAMERA_SM_CMD_TYPE_API;
    node->evt = evt; 
    node->evt_payload = api_payload;
    //node进入事件队列
    if (api_queue.enqueue((void *)node)) {
        //内核锁
        cam_sem_post(&cmd_sem);
        return NO_ERROR;
    } else {
        free(node);
        return UNKNOWN_ERROR;
    }    
}

这里
node->cmd = QCAMERA_SM_CMD_TYPE_API;
node->evt = evt;
node->evt_payload = api_payload;
然后入队!
api_queue.enqueue((void *)node)

这里的线程就是CAM_stMachine,处理了入队,也会处理出队。
还记得我们3.3.1节中分析的
pthread_create创建线程,名称为:CAM_stMachine,线程函数smEvtProcRoutine。
我们来看这个线程函数:

void *QCameraStateMachine::smEvtProcRoutine(void *data)
{
    int running = 1, ret;
    QCameraStateMachine *pme = (QCameraStateMachine *)data;

    CDBG_HIGH("%s: E", __func__);
    do {//死循环
        do {
            //这里线程先条件等待:ret != 0
            ret = cam_sem_wait(&pme->cmd_sem);
            if (ret != 0 && errno != EINVAL) {
                ALOGE("%s: cam_sem_wait error (%s)",
                           __func__, strerror(errno));
                return NULL;
            }
        } while (ret != 0);

        // we got notified about new cmd avail in cmd queue
        // first check API cmd queue:先检查API命令队列
        //前面入队,这里就出队列了,看到了吗
        qcamera_sm_cmd_t *node = (qcamera_sm_cmd_t *)pme->api_queue.dequeue();
        if (node == NULL) {
            // no API cmd, then check evt cmd queue
           //如果没有API命令,在检查evnet命令,这里出队
            node = (qcamera_sm_cmd_t *)pme->evt_queue.dequeue();
        }
        if (node != NULL) {
            switch (node->cmd) {
            //我们对应的是这个API事件
            case QCAMERA_SM_CMD_TYPE_API:
                pme->stateMachine(node->evt, node->evt_payload);
                // API is in a way sync call, so evt_payload is managed by HWI
                // no need to free payload for API
                break;
            case QCAMERA_SM_CMD_TYPE_EVT:
                pme->stateMachine(node->evt, node->evt_payload);

                // EVT is async call, so payload need to be free after use
                free(node->evt_payload);
                node->evt_payload = NULL;
                break;
            case QCAMERA_SM_CMD_TYPE_EXIT:
                running = 0;
                break;
            default:
                break;
            }
            free(node);
            node = NULL;
        }
    } while (running);
    CDBG_HIGH("%s: X", __func__);
    return NULL;
}

3.3.1节就分析过,事件分2种:1.API事件,2.evt事件,优先处理API事件!
这里的TYPE为:QCAMERA_SM_CMD_TYPE_API
因此继续调用:
pme->stateMachine(node->evt, node->evt_payload);

int32_t QCameraStateMachine::stateMachine(qcamera_sm_evt_enum_t evt, void *payload)
{
    int32_t rc = NO_ERROR;
    switch (m_state) {
    case QCAMERA_SM_STATE_PREVIEW_STOPPED:
        rc = procEvtPreviewStoppedState(evt, payload);
        break;
    case QCAMERA_SM_STATE_PREVIEW_READY:
        rc = procEvtPreviewReadyState(evt, payload);
        break;
    case QCAMERA_SM_STATE_PREVIEWING:
        rc = procEvtPreviewingState(evt, payload);
        break;
    case QCAMERA_SM_STATE_PREPARE_SNAPSHOT:
        rc = procEvtPrepareSnapshotState(evt, payload);
        break;
···省略
    }

这里根据m_sate来调用不同的函数,还记得吗,3.3.1节中分析的:
初始状态: m_state = QCAMERA_SM_STATE_PREVIEW_STOPPED;
因此会继续调用procEvtPreviewStoppedState(evt, payload);

int32_t QCameraStateMachine::procEvtPreviewStoppedState(qcamera_sm_evt_enum_t evt,
                                                        void *payload)
{
    int32_t rc = NO_ERROR;
    qcamera_api_result_t result;
    memset(&result, 0, sizeof(qcamera_api_result_t));

    switch (evt) {
    case QCAMERA_SM_EVT_SET_PREVIEW_WINDOW:
    ···
         break;
    case QCAMERA_SM_EVT_SET_CALLBACKS:
    ···
        break;
···省略多个case
    case QCAMERA_SM_EVT_START_PREVIEW:
        {
            if (m_parent->mPreviewWindow == NULL) {
                    ALOGE("%s: zcf mPreviewWindow == NULL,call preparePreview",__func__);
                rc = m_parent->preparePreview();//preview的准备工作
                if(rc == NO_ERROR) {//设置状态为QCAMERA_SM_STATE_PREVIEW_READY
                    ALOGE("%s: zcf preview window is not set yet, move to previewReady state",__func__);
                    // preview window is not set yet, move to previewReady state
                    m_state = QCAMERA_SM_STATE_PREVIEW_READY;
                } else {
                    ALOGE("%s: preparePreview failed",__func__);
                }
            } else {//我们基本走的是这个分支
                    ALOGE("%s: zcf mPreviewWindow != NULL,call preparePreview",__func__);
                rc = m_parent->preparePreview();//preparePreview准备工作
                if (rc == NO_ERROR) {
                    ALOGE("%s: zcf call startPreview",__func__);
                    rc = m_parent->startPreview();//调用startPreview
                    if (rc != NO_ERROR) {
                        m_parent->unpreparePreview();
                    } else {
                        // start preview success, move to previewing state
                        ALOGE("%s: zcf start preview success, move to previewing state",__func__);
                        m_state = QCAMERA_SM_STATE_PREVIEWING;
                    }
                }
            }
            result.status = rc;//返回结果
            result.request_api = evt;//
            result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
            m_parent->signalAPIResult(&result);//这里去唤醒等待线程
        }
        break;
···
}

这里的 m_parent 就是 QCamera2HardwareInterface 实例对象(3.3.1节分析过)。
因而分别调用的是
QCamera2HardwareInterface::preparePreview()
QCamera2HardwareInterface::startPreview()
我们顺便看一下之前的log流程:

procEvtPreviewStoppedState(···): zcf mPreviewWindow != NULL,call preparePreview
QCamera2HardwareInterface::preparePreview(): zcf E
QCamera2HardwareInterface::preparePreview(): zcf X
procEvtPreviewStoppedState(···): zcf call startPreview

preparePreview简析

int32_t QCamera2HardwareInterface::preparePreview()
{
    ATRACE_CALL();
    int32_t rc = NO_ERROR;

        CDBG_HIGH("%s: zcf E", __func__);
    //如果开启ZSL模式,且不是录像模式
    if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() !=true) {
        rc = addChannel(QCAMERA_CH_TYPE_ZSL);//添加ZSL通道
        if (rc != NO_ERROR) {
            return rc;
        }
    } else {
        bool recordingHint = mParameters.getRecordingHintValue();
        if(recordingHint) {
            //stop face detection,longshot,etc if turned ON in Camera mode
            int32_t arg; //dummy arg
#ifndef VANILLA_HAL
            if (isLongshotEnabled()) {
                sendCommand(CAMERA_CMD_LONGSHOT_OFF, arg, arg);
            }
#endif
            if (mParameters.isFaceDetectionEnabled()) {
                sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, arg, arg);
            }
#ifndef VANILLA_HAL
            if (mParameters.isHistogramEnabled()) {
                sendCommand(CAMERA_CMD_HISTOGRAM_OFF, arg, arg);
            }
#endif

            cam_dimension_t videoSize;
            mParameters.getVideoSize(&videoSize.width, &videoSize.height);
            if (!is4k2kResolution(&videoSize) && !mParameters.isLowPowerEnabled()) {
               rc = addChannel(QCAMERA_CH_TYPE_SNAPSHOT);
               if (rc != NO_ERROR) {
                   return rc;
               }
            }
            rc = addChannel(QCAMERA_CH_TYPE_VIDEO);
            if (rc != NO_ERROR) {
                delChannel(QCAMERA_CH_TYPE_SNAPSHOT);
                return rc;
            }
        }
        //添加preview通道
        rc = addChannel(QCAMERA_CH_TYPE_PREVIEW);
        if (rc != NO_ERROR) {
            if (recordingHint) {
                delChannel(QCAMERA_CH_TYPE_SNAPSHOT);
                delChannel(QCAMERA_CH_TYPE_VIDEO);
            }
            return rc;
        }

        if (!recordingHint) {
            waitDefferedWork(mMetadataJob);
        }
    }

    CDBG_HIGH("%s: zcf X", __func__);
    return rc;
}

最主要的是 rc = addChannel(QCAMERA_CH_TYPE_PREVIEW);添加Preview通道!
后续addChannel涉及到数据流的东西,暂时先不分析了,另起一篇文章分析!
接下来调用QCamera2HardwareInterface::startPreview()

QCamera2HardwareInterface::startPreview()分析

hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.cpp

int QCamera2HardwareInterface::startPreview()
{
    ATRACE_CALL();
    int32_t rc = NO_ERROR;
    CDBG_HIGH("%s: zcf  E", __func__);
    updateThermalLevel(mThermalLevel);
    // start preview stream 开启数据流
    if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() !=true) {
        //ZSL模式,添加ZSL数据流
        rc = startChannel(QCAMERA_CH_TYPE_ZSL);
    } else {
        //非ZSL模式,普通Preview数据流
        rc = startChannel(QCAMERA_CH_TYPE_PREVIEW);
        /*
          CAF needs cancel auto focus to resume after snapshot.
          Focus should be locked till take picture is done.
          In Non-zsl case if focus mode is CAF then calling cancel auto focus
          to resume CAF.
        */
        cam_focus_mode_type focusMode = mParameters.getFocusMode();
        if (focusMode == CAM_FOCUS_MODE_CONTINOUS_PICTURE)
            mCameraHandle->ops->cancel_auto_focus(mCameraHandle->camera_handle);
    }
#ifdef TARGET_TS_MAKEUP
    if (mMakeUpBuf == NULL) {
        int pre_width, pre_height;
        mParameters.getPreviewSize(&pre_width, &pre_height);
        mMakeUpBuf = new unsigned char[pre_width*pre_height*3/2];
        CDBG_HIGH("prewidht=%d,preheight=%d",pre_width, pre_height);
    }
#endif
    CDBG_HIGH("%s: zcf X", __func__);
    return rc;
}

兜兜转转,最后调用到
rc = startChannel(QCAMERA_CH_TYPE_PREVIEW);
通过该函数preview数据流,至于startChannel做了什么,就涉及到数据流的东西了,
另起一篇文章分析!
再看看log

QCamera2HWI: int qcamera::QCamera2HardwareInterface::startPreview(): zcf  E
QCamera2HWI: int qcamera::QCamera2HardwareInterface::startPreview(): zcf X
QCameraStateMachine: int32_t qcamera::QCameraStateMachine::procEvtPreviewStoppedState(···): 
zcf start preview success, move to previewing state
QCamera2HWI: static int qcamera::QCamera2HardwareInterface::start_preview(camera_device*): zcf X

执行完QCamera2HardwareInterface::startPreview之后,
最终设置Camera状态:QCAMERA_SM_STATE_PREVIEWING

贴一份log截图:startPreview没有冷启动热启动这样的说法

Stay Hungry!Stay Foolish!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值