vendor\sprd\modules\libcamera\hal3_2v6\SprdCamera3OEMIf.cpp 是我们追踪camera流程到hal会经常关注的cpp文件,今天我们就点击拍照这个流程,从SprdCamera3OEMIf.cpp 的log中来看下它的流程。
首先,我们先介绍一下SprdCamera3OEMIf.cpp大致内容(该文件1.3w行,没错,是我见过的最长的文件。。)可分为三个部分:
- 参数管理 SetCameraParaTag
- Memory管理
- 帧数据管理(预览流、拍照流)
其中参数管理贯穿全文。我们知道Camera有海量的参数,整个libcamera可分为三层,hal --> oem --> isp,isp在往下是效果参数,不在我们讨论范围内。参数需要在各层之间传递,hal在收到参数之后,会做一些判断和包装的工作,然后继续往下设置,hal本身并不做实际的工作。比如HDR拍照,hal判断当前hdr参数打开,就负责将hdr需要的5帧或者3帧数据往下向oem层传递,而hal看到是普通拍照,就会只给1帧数据了。
Memory管理包括申请和释放内存,相关方法如下:
int SprdCamera3OEMIf::Callback_ZslFree(cmr_uint *phy_addr, cmr_uint *vir_addr,
int SprdCamera3OEMIf::Callback_CaptureFree(cmr_uint *phy_addr,
int SprdCamera3OEMIf::Callback_Sw3DNRCapturePathFree(cmr_uint *phy_addr,
int SprdCamera3OEMIf::Callback_GraphicBufferFree(
int SprdCamera3OEMIf::Callback_CommonFree(enum camera_mem_cb_type type,
int SprdCamera3OEMIf::Callback_CapturePathFree(cmr_uint *phy_addr,
int SprdCamera3OEMIf::Callback_Free(enum camera_mem_cb_type type,
int SprdCamera3OEMIf::Callback_ZslMalloc(cmr_u32 size, cmr_u32 sum,
int SprdCamera3OEMIf::Callback_Zsl_raw_Malloc(cmr_u32 size, cmr_u32 sum,
int SprdCamera3OEMIf::Callback_CaptureMalloc(cmr_u32 size, cmr_u32 sum,
int SprdCamera3OEMIf::Callback_Sw3DNRCapturePathMalloc(
int SprdCamera3OEMIf::Callback_GraphicBufferMalloc(
int SprdCamera3OEMIf::Callback_CommonMalloc(enum camera_mem_cb_type type,
int SprdCamera3OEMIf::Callback_CapturePathMalloc(cmr_u32 size, cmr_u32 sum,
int SprdCamera3OEMIf::Callback_IonMalloc(enum camera_mem_cb_type type,
int SprdCamera3OEMIf::Callback_GpuMalloc(enum camera_mem_cb_type type,
帧数据管理包括预览流 和 拍照流
这里有个关键函数,处理预览和拍照的关键节点事件:
void SprdCamera3OEMIf::camera_cb(enum camera_cb_type cb,
const void *client_data,
enum camera_func_type func, void *parm4) {
ATRACE_BEGIN(__FUNCTION__);
SprdCamera3OEMIf *obj = (SprdCamera3OEMIf *)client_data;
HAL_LOGV("E");
HAL_LOGV("cb = %d func = %d parm4 = %p", cb, func, parm4);
switch (func) {
case CAMERA_FUNC_START_PREVIEW:
obj->HandleStartPreview(cb, parm4);
break;
case CAMERA_FUNC_STOP_PREVIEW:
obj->HandleStopPreview(cb, parm4);
break;
case CAMERA_FUNC_RELEASE_PICTURE:
obj->HandleCancelPicture(cb, parm4);
break;
case CAMERA_FUNC_TAKE_PICTURE:
obj->HandleTakePicture(cb, parm4);
break;
case CAMERA_FUNC_ENCODE_PICTURE:
obj->HandleEncode(cb, parm4);
break;
case CAMERA_FUNC_START_FOCUS:
obj->HandleFocus(cb, parm4);
break;
case CAMERA_FUNC_AE_STATE_CALLBACK:
obj->HandleAutoExposure(cb, parm4);
break;
case CAMERA_FUNC_START:
obj->HandleStartCamera(cb, parm4);
break;
case CAMERA_FUNC_STOP:
obj->HandleStopCamera(cb, parm4);
break;
case CAMERA_FUNC_GET_BUF_HANDLE:
obj->HandleGetBufHandle(cb, parm4);
break;
case CAMERA_FUNC_RELEASE_BUF_HANDLE:
obj->HandleReleaseBufHandle(cb, parm4);
break;
case CAMERA_FUNC_BUFCACHE:
obj->HandleCachedBuf(cb, parm4);
break;
default:
HAL_LOGE("Unknown camera-callback status %d", cb);
break;
}
ATRACE_END();
HAL_LOGV("X");
}
而该函数又是在openCamera的函数中调用oem层的camera_init函数时作为第二个参数传下去的:
int SprdCamera3OEMIf::openCamera()中
ret = mHalOem->ops->camera_init(mCameraId, camera_cb, this, 0,
&mCameraHandle, (void *)Callback_IonMalloc,
(void *)Callback_Free);
我们以camera_cb函数的第一个case CAMERA_FUNC_START_PREVIEW为例,来追踪下接收到预览流的处理流程
其中我们看到有个叫 PreviewFrameFaceBeauty函数,这个就应该就是处理预览美颜相关的。
现在我们重点看下 PreviewFrameZslStream 函数的流程:
PreviewFrameZslStream 该函数最后将预览帧push到一个集合中去了,这里push,那就有地方pop出来用,我们在追下哪里在使用mZSLQueue这个集合。
果然找到一个pop函数在使用 mZSLQueue:
ZslBufferQueue SprdCamera3OEMIf::popZSLQueue() {
Mutex::Autolock l(&mZslLock);
List<ZslBufferQueue>::iterator frame;
ZslBufferQueue ret;
bzero(&ret, sizeof(ZslBufferQueue));
if (mZSLQueue.size() == 0) {
return ret;
}
frame = mZSLQueue.begin()++;
ret = static_cast<ZslBufferQueue>(*frame);
mZSLQueue.erase(frame);
return ret;
}
一路追上去,看到是在 snapshotZsl 中在调用popZSLQueue获取mZSLQueue中的数据。
zsl_frame = obj->popZslFrame();
snap是拍照的意思,显然这里与拍照的流程接上了,我们抓个拍照的log看下。
拍照首先启动了一个channel_type为2的channel,这个channel是SprdCamera3OEMIf.cpp同目录下的SprdCamera3Channel.cpp文件。
然后调用了ZSLMode_monitor_thread_proc函数,该函数也是来自openCamera,
openCamera – > ZSLMode_monitor_thread_init,在该init中传入了 ZSLMode_monitor_thread_proc,显然是将proc函数作为回调处理的函数了。
ret = cmr_thread_create((cmr_handle *)&obj->mZSLModeMonitorMsgQueHandle,
ZSLMode_MONITOR_QUEUE_SIZE,
ZSLMode_monitor_thread_proc, (void *)obj,
(const char *)"zsl_moni");
在ZSLMode_monitor_thread_proc的 case CMR_EVT_ZSL_MON_SNP下面在调用 processZslSnapshot
case CMR_EVT_ZSL_MON_SNP:
if (mZslCaptureExitLoop == true) break;
obj->mZslShotPushFlag = 1;
obj->processZslSnapshot(p_data);
break;
我们在接着追processZslSnapshot的流程
在snapshotZSL中读取上面预览流程中保存在集合mZSLQueue中的预览帧数据,然后根据当前模式,继续分发给不同函数处理,我们以普通拍照为例,应该走SnapshotZslOther
snapshotZsl调用SnapshotZslOther,并传入pop出来的预览帧数据
ret = SnapshotZslOther(obj, &zsl_frame);
SnapshotZslOther将该帧数据又push到了mJpegDebugQ集合中了
if (s_dbg_ver) {
Mutex::Autolock l(&mJpegDebugQLock);
ZslBufferQueue node;
node.frame = *zsl_frame;
node.heap_array = NULL;
mJpegDebugQ.push_back(node);
HAL_LOGD("Cam%d JpegQueue other fd 0x%x, frame_id %d\n",
mCameraId, zsl_frame->fd, zsl_frame->frame_num);
}
而 mJpegDebugQ 集合被使用的地方,是在 receiveJpegPicture 函数中。
receiveJpegPicture 函数
if (mJpegDebugQ.size() > 0) {
itor = mJpegDebugQ.begin()++;
node = static_cast<ZslBufferQueue>(*itor);
frame = &node.frame;
mJpegDebugQ.erase(itor);
HAL_LOGD("Cam%d JpegQueue pop fd 0x%x, frame_id %d, frame_num %d\n",
mCameraId, frame->fd, frame->frame_num, frame->buf_id);
frame_id = (cmr_s32)frame->frame_num;
}
picChannel->channelCbRoutine(frame_num, timestamp,
CAMERA_STREAM_TYPE_PICTURE_SNAPSHOT);
从log流程中也看到receiveJpegPicture 被调用
拍照后数据处理流程如下:
这样,从预览流程出来的帧数据,到拍照流程拿帧数据并处理 就完成了。
关于SprdCamera3OEMIf.cpp的大致内容介绍就是这样了,关于其更多细节,我们将会持续更新。