说在前面的话
现在阅读的是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;
}
-
- 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
···
}
-
- 调用hw->openCamera(hw_device);
QCamera2HardwareInterface 对象有了之后,就去调用openCamera方法,
后续的openCamera就不再分析。
- 调用hw->openCamera(hw_device);
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请求 -
- 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。
总之是调用到CameraHardwareInterface的startPreview
/**
* 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没有冷启动热启动这样的说法