Camera HAL下的SprdCamera3OEMIf.cpp 介绍

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的大致内容介绍就是这样了,关于其更多细节,我们将会持续更新。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值