【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!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349