当前位置:网站首页>camera预览流程 --- 从HAL到OEM
camera预览流程 --- 从HAL到OEM
2022-08-10 21:18:00 【Caroline_cheng】
文章目录
- 下发预览请求
- 1,SprdCamera3HWI:channel->request
- 2,SprdCamera3RegularChannel::request
- 3,SprdCamera3Stream::buffDoneQ
- 4,SprdCamera3OEMIf::queueBuffer
- 5,SprdCamera3Stream::getQBufInfoForHandle
- 6,mHalOem->ops->queue_buffer
- 7,SprdOEMCamera::queue_buffer
- 8,cmr_oem::local_queue_buffer
- 9,cmr_preview::cmr_preview_set_preview_buffer
- 10,cmr_preview::prev_set_preview_buffer
- 处理预览帧数据
- 1,cmr_grab::cmr_grab_thread_proc
- 2,cmr_oem::camera_grab_evt_cb
- 3,cmr_oem::camera_send_channel_data
- 4,cmr_preview::cmr_preview_receive_data
- 5,cmr_preview::prev_preview_frame_handle
- 6,cmr_preview::prev_construct_frame
- 7,cmr_preview::prev_pop_preview_buffer
- 8,回调 步骤6 中填充的数据
- 9,cmr_oem处理回调
- 10,SprdCamera3OEMIf::camera_cb
- 11,SprdCamera3OEMIf::receivePreviewFrame
- 12,SprdCamera3OEMIf::PreviewFramePreviewStream
- 13,SprdCamera3RegularChannel::channelCbRoutine (buffDoneDQ)
- log 跟踪
我们在前面的文章中主要是单独介绍hal和oem下的某些关键c/cpp文件的内容,比较分散。因为整个预览流程涉及的内容太多,我们不好在一篇文章中讲清楚,只能先把单个的知识点一一说明,然后才能将整个预览流程串起来。
注:大家阅读本篇前,请先将我之前介绍的 Hal3_2v6 和 OEM 的内容过下。
下发预览请求
我在前一篇文章中介绍了SprdCamera3HWI.cpp ,它的三个关键流程中有一个 processCaptureRequest,即发送预览请求的,我们就从这里开始。
1,SprdCamera3HWI:channel->request
for (i = 0; i < request->num_output_buffers; i++) {
const camera3_stream_buffer_t &output = request->output_buffers[i];
camera3_stream_t *stream = output.stream;
SprdCamera3Channel *channel = (SprdCamera3Channel *)stream->priv;
ret = channel->request(stream, output.buffer, frameNumber);
}
2,SprdCamera3RegularChannel::request
我们知道,channel有两类:预览和拍照。分别对应 SprdCamera3RegularChannel 和 SprdCamera3PicChannel (还有一个负责处理metadata的 SprdCamera3MetadataChannel)。
我们本篇分析预览的流程,那channel走的就是 SprdCamera3RegularChannel,其request的内容不多,我们就全贴出来了。
int SprdCamera3RegularChannel::request(camera3_stream_t *stream,
buffer_handle_t *buffer,
uint32_t frameNumber) {
HAL_LOGD("SprdCamera3RegularChannel request frameNumber:%d", frameNumber);
int ret = NO_ERROR;
int i;
char multicameramode[PROPERTY_VALUE_MAX];
for (i = 0; i < CHANNEL_MAX_STREAM_NUM; i++) {
if (mCamera3Stream[i]) {
camera3_stream_t *new_stream;
mCamera3Stream[i]->getStreamInfo(&new_stream);
if (new_stream == stream) {
ret = mCamera3Stream[i]->buffDoneQ(frameNumber, buffer);
if (ret != NO_ERROR) {
return ret;
}
if (i == 0) {
mOEMIf->queueBuffer(buffer, CAMERA_STREAM_TYPE_PREVIEW);
} else if (i == (CAMERA_STREAM_TYPE_VIDEO -
REGULAR_STREAM_TYPE_BASE)) {
if (mOEMIf->isVideoCopyFromPreview()) {
HAL_LOGD("video stream copy preview stream");
} else {
mOEMIf->queueBuffer(buffer, CAMERA_STREAM_TYPE_VIDEO);
}
} else if (i == (CAMERA_STREAM_TYPE_CALLBACK -
REGULAR_STREAM_TYPE_BASE))
mOEMIf->queueBuffer(buffer, CAMERA_STREAM_TYPE_CALLBACK);
else if (i ==
(CAMERA_STREAM_TYPE_YUV2 - REGULAR_STREAM_TYPE_BASE))
mOEMIf->queueBuffer(buffer, CAMERA_STREAM_TYPE_YUV2);
break;
}
}
}
return ret;
}
channel的request流程主要分为如下两个步骤:
- SprdCamera3Stream::buffDoneQ
- SprdCamera3OEMIf::queueBuffer
3,SprdCamera3Stream::buffDoneQ
cam3Stream的buffDoneQ主要是调用 SprdCamera3GrallocMemory 的map,将入参 buffer_handle_t *buffer_handle 传入GraphicBufferMapper 的 lock 中,获取虚拟地址 addr_vir。
//SprdCamera3Stream
int SprdCamera3Stream::buffDoneQ(uint32_t frameNumber,buffer_handle_t *buffer) {
}
hal_buff_list_t *buff_hal = new hal_buff_list_t;
hal_mem_info_t *buf_mem_info = &(buff_hal->mem_info);
mMemory->map(buffer, buf_mem_info);
//SprdCamera3GrallocMemory
int SprdCamera3GrallocMemory::map(buffer_handle_t *buffer_handle,hal_mem_info_t *mem_info){
}
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
ret = mapper.lock((const native_handle_t *)*buffer_handle, usage,bounds, &vaddr);
mem_info->addr_vir = vaddr;
通过SprdCamera3GrallocMemory 的 map之后,拿到了 addr_vir 保存在 cam3Stream的buff_hal下的hal_mem_info_t 中,然后
mBufferList.add(buff_hal);
我们看到cam3Stream中有明显对称的函数:
- buffDoneQ
- buffDoneQ2
- buffDoneDQ
- buffFirstDoneDQ
他们分别调用SprdCamera3GrallocMemory 中的map 与 unmap,即 GraphicBufferMapper 的 lock与 unlock。
SprdCamera3Stream | SprdCamera3GrallocMemory | SprdCamera3Stream |
---|---|---|
buffDoneQ、buffDoneQ2 | map | mBufferList.add |
buffDoneDQ、buffDoneDQ | unmap | mBufferList.erase |
SprdCamera3Stream中的mBufferList在map时向集合中add、unmap时向集合中erase的数据。
总之,SprdCamera3Stream::buffDoneQ 的主要目的是获取入参 buffer_handle_t *buffer 的 addr_vir 。
4,SprdCamera3OEMIf::queueBuffer
SprdCamera3OEMIf 的 queueBuffer中关于preivew的这条case 代码不多,我们也直接贴出来。也分两步
- stream->getQBufInfoForHandle
- mHalOem->ops->queue_buffer
case CAMERA_STREAM_TYPE_PREVIEW:
channel = reinterpret_cast<SprdCamera3RegularChannel *>(mRegularChan);
if (channel == NULL) {
ret = -1;
HAL_LOGE("mRegularChan is null");
goto exit;
}
ret = channel->getStream(CAMERA_STREAM_TYPE_PREVIEW, &stream);
if (ret || stream == NULL) {
HAL_LOGE("getStream failed");
goto exit;
}
ret = stream->getQBufInfoForHandle(buff_handle, &buffer);
if (ret || buffer.addr_vir == NULL) {
HAL_LOGE("getQBufForHandle failed");
goto exit;
}
mHalOem->ops->queue_buffer(mCameraHandle, buffer,
SPRD_CAM_STREAM_PREVIEW);
break;
5,SprdCamera3Stream::getQBufInfoForHandle
我们在步骤3中介绍了SprdCamera3Stream管理了一个集合 mBufferList,这里就是在该集合中根据入参 buffer_handle_t *buff来获取信息,并将信息封装到 cam_buffer_info_t 对象中,其中最重要的就是 addr_vir。
int SprdCamera3Stream::getQBufInfoForHandle(buffer_handle_t *buff,
cam_buffer_info_t *bufInfo) {
Mutex::Autolock l(mLock);
int ret = NO_ERROR;
Vector<hal_buff_list_t *>::iterator iter;
for (iter = mBufferList.begin(); iter != mBufferList.end(); iter++) {
if ((*iter) && (*iter)->buffer_handle == buff) {
bufInfo->fd = (*iter)->mem_info.fd;
bufInfo->size = (*iter)->mem_info.size;
bufInfo->addr_phy = (*iter)->mem_info.addr_phy;
bufInfo->addr_vir = (*iter)->mem_info.addr_vir;
bufInfo->width = (*iter)->mem_info.width;
bufInfo->height = (*iter)->mem_info.height;
bufInfo->format = (*iter)->mem_info.format;
bufInfo->frame_number = (*iter)->frame_number;
return ret;
}
}
return BAD_VALUE;
}
6,mHalOem->ops->queue_buffer
我们在SprdCamera3OEMIf中看到很多 mHalOem->ops 调用形式。我们来看下 mHalOem 的实例化,在SprdCamera3OEMIf的构造函数中:
if (!mHalOem) {
oem_module_t *omi;
mHalOem = (oem_module_t *)malloc(sizeof(oem_module_t));
if (NULL == mHalOem) {
HAL_LOGE("mHalOem is NULL");
} else {
memset(mHalOem, 0, sizeof(*mHalOem));
mHalOem->dso = dlopen(OEM_LIBRARY_PATH, RTLD_NOW);
if (NULL == mHalOem->dso) {
char const *err_str = dlerror();
HAL_LOGE("dlopen error%s ", err_str ? err_str : "unknown");
}
const char *sym = OEM_MODULE_INFO_SYM_AS_STR;//OMI
omi = (oem_module_t *)dlsym(mHalOem->dso, sym);
if (omi) {
mHalOem->ops = omi->ops;
}
HAL_LOGI("loaded libcamoem.so mHalOem->dso = %p", mHalOem->dso);
}
}
#define OEM_LIBRARY_PATH "libcamoem.so"
我们看到是open了一个 OEM_LIBRARY_PATH,即oem的库。在SprdOEMCamera中找到OEM_MODULE_INFO_SYM 的定义:
struct oem_module OEM_MODULE_INFO_SYM = {
.tag = 0, .ops = &oem_module_ops, .dso = NULL};
其中 ops = &oem_module_ops,即SprdOEMCamera中定义的所有操作:
static oem_ops_t oem_module_ops = {
camera_init, camera_deinit, camera_release_frame, camera_set_param,
camera_start_preview, camera_stop_preview, camera_start_autofocus,
camera_cancel_autofocus, camera_cancel_takepicture,
// camera_safe_scale_th,
NULL, camera_take_picture, camera_get_sn_trim, camera_set_mem_func,
camera_get_redisplay_data, camera_is_change_size,
NULL, camera_get_preview_rect,
camera_get_zsl_capability, camera_get_sensor_info_for_raw,
camera_get_sensor_trim, camera_get_sensor_trim2,
camera_get_preview_rot_angle, camera_fd_enable, camera_flip_enable,
camera_fd_start, camera_is_need_stop_preview, camera_takepicture_process,
camera_get_size_align_page, camera_fast_ctrl, camera_start_preflash,
camera_get_viewangle, camera_get_sensor_exif_info,
camera_get_sensor_result_exif_info, camera_get_iommu_status,
camera_set_preview_buffer, camera_set_video_buffer, camera_set_zsl_buffer,
queue_buffer, camera_set_video_snapshot_buffer,
camera_set_zsl_snapshot_buffer, camera_zsl_snapshot_need_pause,
camera_get_isp_handle, camera_lls_enable, camera_is_lls_enabled,
camera_vendor_hdr_enable, camera_is_vendor_hdr, camera_set_lls_shot_mode,
camera_get_lls_shot_mode, camera_get_last_preflash_time,camera_get_isp_info, camera_start_burst_notice,
camera_end_burst_notice, NULL, NULL, dump_jpeg_file, camera_get_gain_thrs,
camera_set_sensor_info_to_af, camera_get_sensor_max_fps,
camera_snapshot_is_need_flash, camera_get_sensor_otp_info,
camera_get_sensor_vcm_step, camera_set_sensor_close_flag,
camera_set_reprocess_picture_size, camera_start_capture,
camera_stop_capture, camera_set_largest_picture_size, camera_set_alloc_picture_size,
camera_ioctrl,
camera_reprocess_yuv_for_jpeg, image_sw_algorithm_processing,
dump_image_with_isp_info,
#if defined(CONFIG_ISP_2_1)
camera_get_focus_point, camera_isp_sw_check_buf, camera_isp_sw_proc,
camera_raw_post_proc, camera_get_tuning_param,
#endif
#if defined(CONFIG_ISP_2_3) || defined(CONFIG_ISP_2_4) || \ defined(CONFIG_CAMERA_3DNR_CAPTURE_SW) || \ defined(CONFIG_CAMERA_SUPPORT_ULTRA_WIDE)
camera_set_gpu_mem_ops,
#endif
#ifdef CONFIG_CAMERA_MM_DVFS_SUPPORT
camera_set_mm_dvfs_policy,
#endif
camera_set_original_picture_size,
};
那么SprdCamera3OEMIf中调用的queue_buffer 也就走到了SprdOEMCamera中了。
7,SprdOEMCamera::queue_buffer
cmr_s32 queue_buffer(cmr_handle camera_handle, cam_buffer_info_t buffer,
int steam_type) {
cmr_int ret = CMR_CAMERA_SUCCESS;
ret = local_queue_buffer(camera_handle, buffer, steam_type);
return ret;
}
8,cmr_oem::local_queue_buffer
cmr_oem中的实现,我们只截取preview相关的这一条:
cmr_s32 local_queue_buffer(cmr_handle oem_handle, cam_buffer_info_t buffer,
int steam_type) {
cmr_int ret = CMR_CAMERA_SUCCESS;
struct camera_context *cxt;
struct sensor_exp_info exp_info;
if (!oem_handle) {
CMR_LOGE("in parm error");
ret = -CMR_CAMERA_INVALID_PARAM;
goto exit;
}
cxt = (struct camera_context *)oem_handle;
switch (steam_type) {
case SPRD_CAM_STREAM_PREVIEW:
ret = cmr_preview_set_preview_buffer(cxt->prev_cxt.preview_handle,
cxt->camera_id, buffer);
if (ret) {
CMR_LOGE("cmr_preview_set_preview_buffer failed");
goto exit;
}
break;
9,cmr_preview::cmr_preview_set_preview_buffer
cmr_preview的流程我们在之前的文章中也介绍了,我们看到 cmr_preview_set_preview_buffer 就是发送了一个message,最终的处理流程是在 prev_set_preview_buffer
10,cmr_preview::prev_set_preview_buffer
prev_set_preview_buffer的流程主要包括两方面:
- 是将入参 cam_buffer_info_t *buffer 的数据放到如下:
- prev_cxt->prev_fd_array[valid_num]
- prev_cxt->prev_phys_addr_array[valid_num]
- prev_cxt->prev_virt_addr_array[valid_num]
- prev_cxt->prev_frm[valid_num]
- 调用 handle->ops.channel_buff_cfg
channel_buff_cfg 是在cmr_preview.h中定义的结构体 struct preview_md_ops 下的指针函数,我们看不到具体实现,但是可以猜测 channel_buff_cfg 就是要将我们在 SprdCamera3Mem中map得到的 addr_vir 地址给到更底层的DCAM,用来装下一帧的预览数据的。
到这里,我们从SprdCamera3HW中的 channel->request 追过来的流程就结束了。总结下,就是要将map到的 addr_vir 设到底层去装预览数据。
装数据的地址下去了,那么接下来就要去看数据上来的处理流程了, 下面我们再从帧数据上来的地方开始追。
处理预览帧数据
我们之前介绍cmr_grab,说它就是hal端能拿到底层帧数据最开始的地方,我们就从cmr_grab中开始。
1,cmr_grab::cmr_grab_thread_proc
我们在介绍cmr_grab中说过,他拿到的帧数据就是通过grab_evt_cb向上回调的。
(*p_grab->grab_evt_cb)(evt_id, &frame,(void *)p_grab->init_param.oem_handle);
该回调就为cmr_oem中的 camera_grab_evt_cb
2,cmr_oem::camera_grab_evt_cb
我们截取 cmr_grab_evt_reg 的关键内容看下,又调到了 camera_send_channel_data
cmr_grab_evt_reg(grab_handle, camera_grab_evt_cb);
void camera_grab_evt_cb(cmr_int evt, void *data, void *privdata) {
switch (evt) {
case CMR_GRAB_TX_DONE:
if (frame->is_4in1_frame && frame->fmt != CAM_IMG_FMT_BAYER_MIPI_RAW) {
camera_4in1_handle(evt, data, privdata);
}
camera_send_channel_data((cmr_handle)cxt, receiver_handle, evt, data);
3,cmr_oem::camera_send_channel_data
if (cxt->prev_cxt.preview_eb && cxt->prev_cxt.preview_channel_id == frm_ptr->channel_id) {
ret = cmr_preview_receive_data(cxt->prev_cxt.preview_handle,cxt->camera_id, evt, data);
}
流程又转到 cmr_preview中去了
4,cmr_preview::cmr_preview_receive_data
cmr_preivew.c中以cmr_ 开头的函数基本上都是发送一个message,本身没有什么逻辑。其message的处理是prev_receive_data 函数,进一步又会调用 prev_frame_handle。
cmr_preview_receive_data ==》 prev_receive_data ==》 prev_frame_handle ==》prev_preview_frame_handle
5,cmr_preview::prev_preview_frame_handle
prev_preview_frame_handle的主要逻辑分为三步:
- prev_construct_frame
- prev_pop_preview_buffer
- 数据回调
6,cmr_preview::prev_construct_frame
prev_construct_frame 主要是根据入参struct frm_info *info找到 prev_cxt->prev_frm[]中对应的frm_id,由此可以得到对应的 prev_cxt->prev_frm[frm_id]数据,即本次上来的预览帧数据保存的地址信息。该数据用作两处:
- 填充到frame_type
- 发送到预览跑的算法中:包括 fd、3dnr、ai 等等
7,cmr_preview::prev_pop_preview_buffer
prev_pop_preview_buffer 主要是整理 prev_cxt->prev_phys_addr_array[] 和 prev_cxt->prev_frm[]的内容,使数据前移一位,覆盖位置0处的数据。
for (i = 0; i < (cmr_u32)(valid_num - 1); i++) {
prev_cxt->prev_phys_addr_array[i] = prev_cxt->prev_phys_addr_array[i + 1];
prev_cxt->prev_virt_addr_array[i] = prev_cxt->prev_virt_addr_array[i + 1];
prev_cxt->prev_fd_array[i] = prev_cxt->prev_fd_array[i + 1];
memcpy(&prev_cxt->prev_frm[i], &prev_cxt->prev_frm[i + 1],sizeof(struct img_frm));
}
8,回调 步骤6 中填充的数据
cb_data_info.cb_type = PREVIEW_EVT_CB_FRAME;
cb_data_info.func_type = PREVIEW_FUNC_START_PREVIEW;
cb_data_info.frame_data = &frame_type;
prev_cb_start(handle, &cb_data_info);
prev_cb_start 的处理:
case PREV_EVT_CB_START:
cb_data_info = (struct prev_cb_info *)message->data;
if (!handle->oem_cb) {
CMR_LOGE("oem_cb is null");
break;
}
ret = handle->oem_cb(handle->oem_handle, cb_data_info->cb_type,
cb_data_info->func_type, cb_data_info->frame_data);
if (cb_data_info->frame_data) {
free(cb_data_info->frame_data);
cb_data_info->frame_data = NULL;
}
break;
这里继续调到 cmr_oem中处理
9,cmr_oem处理回调
init_param.oem_cb = camera_preview_cb;
camera_preview_cb 会对 cb_type 修改
if (PREVIEW_FUNC_START_PREVIEW == func) {
oem_func = CAMERA_FUNC_START_PREVIEW;
} else if (PREVIEW_FUNC_STOP_PREVIEW == func) {
oem_func = CAMERA_FUNC_STOP_PREVIEW;
} else if (PREVIEW_FUNC_START_CAPTURE == func) {
oem_func = CAMERA_FUNC_TAKE_PICTURE;
} else {
CMR_LOGE("err, %d", func);
goto exit;
}
case PREVIEW_EVT_CB_FRAME:
oem_cb_type = CAMERA_EVT_CB_FRAME;
PREVIEW_FUNC_START_PREVIEW === 》CAMERA_FUNC_START_PREVIEW
PREVIEW_EVT_CB_FRAME ===》CAMERA_EVT_CB_FRAME
10,SprdCamera3OEMIf::camera_cb
case CAMERA_FUNC_START_PREVIEW:
obj->HandleStartPreview(cb, parm4);
break;
// HandleStartPreview 中的处理:
case CAMERA_EVT_CB_FRAME:
HAL_LOGV("CAMERA_EVT_CB_FRAME");
switch (getPreviewState()) {
case SPRD_PREVIEW_IN_PROGRESS:
receivePreviewFrame((struct camera_frame_type *)parm4);
break;
11,SprdCamera3OEMIf::receivePreviewFrame
关于 receivePreviewFrame 的逻辑,我们在之前介绍SprdCamera3OEMIf的文章中有讲过,cam3OEMIf收到预览帧的处理如下:
PreviewFrameFaceBeauty(frame, &beautyLevels);
PreviewFrameCamDebug(frame);
/* video stream */
PreviewFrameVideoStream(frame, buffer_timestamp);
/* preview stream, original code has goto exit */
ret = PreviewFramePreviewStream(frame, buffer_timestamp);
/* callback stream */
PreviewFrameCallbackStream(frame, buffer_timestamp);
/* yuv2 stream */
PreviewFrameYuv2Stream(frame, buffer_timestamp);
/* zsl stream */
PreviewFrameZslStream(frame, buffer_timestamp);
与预览流程相关的就是 PreviewFramePreviewStream 函数
12,SprdCamera3OEMIf::PreviewFramePreviewStream
PreviewFramePreviewStream 的关键逻辑是通过channel将帧数据callback上去
channel->channelCbRoutine(frame_num, buffer_timestamp,CAMERA_STREAM_TYPE_PREVIEW);
13,SprdCamera3RegularChannel::channelCbRoutine (buffDoneDQ)
channelCbRoutine的主要逻辑是构建一个 cam_result_data_info_t result_info ,其中当然是包含了帧数据,然后将 result_info 继续向上回调。
cam_result_data_info_t result_info;
result_info.is_urgent = false;
result_info.buffer = buffer;
result_info.frame_number = frame_number;
result_info.stream = stream;
result_info.timestamp = timestamp;
result_info.buff_status = CAMERA3_BUFFER_STATUS_OK;
result_info.msg_type = CAMERA3_MSG_SHUTTER;
mChannelCB(&result_info, mUserData);
channelCbRoutine还有一个非常重要的操作:
ret = mCamera3Stream[index]->buffDoneDQ(frame_number, &buffer);
还记得我们在 下发预览请求 中的第3步中调用了 buffDoneQ么。 这两者buffDoneDQ 和 buffDoneQ是相反的操作。
- 在预览请求的时候通过 SprdCamera3GrallocMemory 的map 函数得到buffert的虚拟地址
- 在拿到预览帧数据回调的时候通过SprdCamera3GrallocMemory 的unmap 函数释放掉虚拟地址
到这里 处理预览帧数 的流程也完成了。我们也将预览请求和预览回调的整个从 hal 到oem 在到 hal 的流程串通了。本篇涉及的逻辑比较多,有些细节部分我们并没有展开,因为之前有对这些关键的c/cpp文件单独的介绍,如有不清楚的可去翻一翻之前的文章。
log 跟踪
最后,我们通过一份点击桌面的CameraApp来启动camera预览的log来看下两个关键数据
- frameNumber
- addr_vir
顺序增长的 frameNumber
在发送预览请求的HWI下的processCaptureRequest 函数中会有如下log
HAL_LOGD("camId=%d, bufs_num=%d, frame_num=%d, cap_intent=%d, pic_req=%d, "
"first_regular_req=%d",
mCameraId, request->num_output_buffers, request->frame_number,
captureIntent, mPictureRequest, mFirstRegularRequest);
在SprdCamera3OEMIf接收帧数据函数 PreviewFramePreviewStream 中有如下根据帧数据y_vir_addr获取 frame_num的log
cmr_uint buff_vir = (cmr_uint)(frame->y_vir_addr);
ret = pre_stream->getQBufNumForVir(buff_vir, &frame_num);
HAL_LOGD("mCameraId=%d, prev:fd=0x%x, vir=0x%lx, num=%d, width=%d, "
"height=%d, time=0x%llx, iso_value:%d",
mCameraId, (cmr_u32)frame->fd, buff_vir, frame_num, frame->width,
frame->height, buffer_timestamp, ae_iso);
我们来看下log的打印:
可以看到,基本上一帧请求,一帧回调,并且回调的 frame_num 一定小于 请求的 frame_num
Line 219697: 08-09 11:34:44.687 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=2, cap_intent=1, pic_req=0, first_regular_req=0
Line 219737: 08-09 11:34:44.695 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=3, cap_intent=1, pic_req=0, first_regular_req=0
Line 219862: 08-09 11:34:44.991 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x16, vir=0xd92d5000, num=0, width=960, height=720, time=0x3c0ec14062d8, iso_value:2500
Line 219915: 08-09 11:34:45.020 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=4, cap_intent=1, pic_req=0, first_regular_req=0
Line 220022: 08-09 11:34:45.085 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6a, vir=0xd91d7000, num=1, width=960, height=720, time=0x3c0ec7373dd8, iso_value:2500
Line 220054: 08-09 11:34:45.116 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=5, cap_intent=1, pic_req=0, first_regular_req=0
Line 220136: 08-09 11:34:45.189 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6f, vir=0xd90d9000, num=2, width=960, height=720, time=0x3c0ecd2e43d0, iso_value:1000
Line 220159: 08-09 11:34:45.219 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=6, cap_intent=1, pic_req=0, first_regular_req=0
Line 220299: 08-09 11:34:45.290 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x74, vir=0xd8fdb000, num=3, width=960, height=720, time=0x3c0ed3243c40, iso_value:1000
Line 220325: 08-09 11:34:45.320 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=7, cap_intent=1, pic_req=0, first_regular_req=0
Line 220390: 08-09 11:34:45.330 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x68, vir=0xd8dce000, num=4, width=960, height=720, time=0x3c0ed58722e0, iso_value:1250
Line 220428: 08-09 11:34:45.350 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=8, cap_intent=1, pic_req=0, first_regular_req=0
Line 220498: 08-09 11:34:45.369 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x16, vir=0xd92d5000, num=5, width=960, height=720, time=0x3c0ed7ea28c0, iso_value:1250
Line 220526: 08-09 11:34:45.401 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=9, cap_intent=1, pic_req=0, first_regular_req=0
Line 220579: 08-09 11:34:45.407 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6a, vir=0xd91d7000, num=6, width=960, height=720, time=0x3c0eda4cffc0, iso_value:1600
Line 220619: 08-09 11:34:45.435 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=10, cap_intent=1, pic_req=0, first_regular_req=0
Line 220649: 08-09 11:34:45.445 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6f, vir=0xd90d9000, num=7, width=960, height=720, time=0x3c0edcaff600, iso_value:1600
Line 220712: 08-09 11:34:45.474 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=11, cap_intent=1, pic_req=0, first_regular_req=0
Line 220778: 08-09 11:34:45.493 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x74, vir=0xd8fdb000, num=8, width=960, height=720, time=0x3c0edf12d0e8, iso_value:1600
Line 220811: 08-09 11:34:45.524 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=12, cap_intent=1, pic_req=0, first_regular_req=0
Line 220858: 08-09 11:34:45.529 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x68, vir=0xd8dce000, num=9, width=960, height=720, time=0x3c0ee1764fe0, iso_value:1600
Line 220892: 08-09 11:34:45.540 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=13, cap_intent=1, pic_req=0, first_regular_req=0
Line 220950: 08-09 11:34:45.567 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x16, vir=0xd92d5000, num=10, width=960, height=720, time=0x3c0ee3d8adc8, iso_value:1600
Line 220992: 08-09 11:34:45.591 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=14, cap_intent=1, pic_req=0, first_regular_req=0
Line 221062: 08-09 11:34:45.609 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6a, vir=0xd91d7000, num=11, width=960, height=720, time=0x3c0ee63bc730, iso_value:1250
Line 221084: 08-09 11:34:45.623 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=15, cap_intent=1, pic_req=0, first_regular_req=0
Line 221157: 08-09 11:34:45.652 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6f, vir=0xd90d9000, num=12, width=960, height=720, time=0x3c0ee89e7b08, iso_value:1250
Line 221181: 08-09 11:34:45.674 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=16, cap_intent=1, pic_req=0, first_regular_req=0
Line 221247: 08-09 11:34:45.690 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x74, vir=0xd8fdb000, num=13, width=960, height=720, time=0x3c0eeb012710, iso_value:1250
Line 221269: 08-09 11:34:45.708 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=17, cap_intent=1, pic_req=0, first_regular_req=0
Line 221339: 08-09 11:34:45.729 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x68, vir=0xd8dce000, num=14, width=960, height=720, time=0x3c0eed644c30, iso_value:1250
Line 221360: 08-09 11:34:45.741 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=18, cap_intent=1, pic_req=0, first_regular_req=0
Line 221436: 08-09 11:34:45.769 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x16, vir=0xd92d5000, num=15, width=960, height=720, time=0x3c0eefc72330, iso_value:640
Line 221461: 08-09 11:34:45.791 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=19, cap_intent=1, pic_req=0, first_regular_req=0
Line 221560: 08-09 11:34:45.811 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6a, vir=0xd91d7000, num=16, width=960, height=720, time=0x3c0ef22a30e0, iso_value:640
Line 221582: 08-09 11:34:45.825 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=20, cap_intent=1, pic_req=0, first_regular_req=0
Line 221619: 08-09 11:34:45.844 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6f, vir=0xd90d9000, num=17, width=960, height=720, time=0x3c0ef48cfc28, iso_value:640
Line 221641: 08-09 11:34:45.859 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=21, cap_intent=1, pic_req=0, first_regular_req=0
Line 221757: 08-09 11:34:45.935 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x74, vir=0xd8fdb000, num=18, width=960, height=720, time=0x3c0ef9ead348, iso_value:640
Line 221779: 08-09 11:34:45.959 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=22, cap_intent=1, pic_req=0, first_regular_req=0
Line 221874: 08-09 11:34:46.025 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x68, vir=0xd8dce000, num=19, width=960, height=720, time=0x3c0eff48c9a8, iso_value:1250
Line 221896: 08-09 11:34:46.043 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=23, cap_intent=1, pic_req=0, first_regular_req=0
Line 222009: 08-09 11:34:46.120 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x16, vir=0xd92d5000, num=20, width=960, height=720, time=0x3c0f04a69ce0, iso_value:1250
Line 222042: 08-09 11:34:46.144 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=24, cap_intent=1, pic_req=0, first_regular_req=0
Line 222086: 08-09 11:34:46.156 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6a, vir=0xd91d7000, num=21, width=960, height=720, time=0x3c0f07097f98, iso_value:1250
Line 222136: 08-09 11:34:46.178 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=25, cap_intent=1, pic_req=0, first_regular_req=0
Line 222187: 08-09 11:34:46.196 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6f, vir=0xd90d9000, num=22, width=960, height=720, time=0x3c0f096d3158, iso_value:1250
Line 222231: 08-09 11:34:46.211 532 999 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=26, cap_intent=1, pic_req=0, first_regular_req=0
Line 222318: 08-09 11:34:46.244 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x74, vir=0xd8fdb000, num=23, width=960, height=720, time=0x3c0f0bcf9710, iso_value:1250
Line 222381: 08-09 11:34:46.263 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=27, cap_intent=1, pic_req=0, first_regular_req=0
Line 222447: 08-09 11:34:46.282 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x68, vir=0xd8dce000, num=24, width=960, height=720, time=0x3c0f0e325e70, iso_value:1250
Line 222477: 08-09 11:34:46.297 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=28, cap_intent=1, pic_req=0, first_regular_req=0
Line 222546: 08-09 11:34:46.320 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x16, vir=0xd92d5000, num=25, width=960, height=720, time=0x3c0f109525d0, iso_value:1250
Line 222567: 08-09 11:34:46.329 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=29, cap_intent=1, pic_req=0, first_regular_req=0
Line 222648: 08-09 11:34:46.363 532 26402 D Cam3OEMIf: 4437, PreviewFramePreviewStream: mCameraId=0, prev:fd=0x6a, vir=0xd91d7000, num=26, width=960, height=720, time=0x3c0f12f80c70, iso_value:1250
Line 222678: 08-09 11:34:46.380 532 1000 D Cam3HWI : 1708, processCaptureRequest: camId=0, bufs_num=1, frame_num=30, cap_intent=1, pic_req=0, first_regular_req=0
循序使用的fd & addr_vir
SprdCamera3GrallocMemory::map 到的 fd & addr_vir :
SprdCamera3OEMIf在PreviewFramePreviewStream中收到的帧数据的 fd & addr_vir :
我们看到 fd 和 addr_vir 只有5个在一直循环:
fd=0x6f,offset=0x0,addr_vir=0xd90d9000
fd=0x74,offset=0x0,addr_vir=0xd8fdb000
fd=0x68,offset=0x0,addr_vir=0xd8dce000
fd=0x16,offset=0x0,addr_vir=0xd92d5000
fd=0x6a,offset=0x0,addr_vir=0xd91d7000
这与我们在SprdCamera3OEMIf中看到得 mZslNum 的值是一致的,也就是说hal申请了5个buffer,预览帧数据一帧一帧的请求,然后在一帧一帧的回调上去,就是在不停地往这5个buffer写、读。
log也进一步验证的我们之前跟踪的预览请求和回调流程。
到这里,hal 和 oem 模块公同完成的预览请求和回调的流程我们就讲完了。
边栏推荐
- 每次打开chrome会跳出What's new
- 工程师应该怎么学习
- B. Same Parity Summands
- UPDATE:修改数据语法使用例——《mysql 从入门到内卷再到入土》
- [SQL brush questions] Day3----Special exercises for common functions that SQL must know
- 【PCBA solution】Electronic grip strength tester solution she'ji
- Intelligent scheme design - intelligent rope skipping scheme
- 自建函数 测试例和语法——《mysql 从入门到内卷再到入土》
- labelme - block drag and drop events
- C. Even Picture
猜你喜欢
深度学习之 12 循环神经网络RNN2
LeetCode-36-Binary search tree and doubly linked list
化学制品制造业数智化供应链管理系统:建立端到端供应链采购一体化平台
JVM classic fifty questions, now the interview is stable
我的世界整合包 云服务器搭建方法(ECS)
APP UI自动化测试常见面试题,或许有用呢~
FPGA - 7系列 FPGA内部结构之Memory Resources -03- 内置纠错功能
apr_thread使用内存之谜
RADIUS Authentication Server Deployment Costs That Administrators Must Know
Exploration and practice of the "zero trust" protection and data security governance system of the ransomware virus of Meichuang Technology
随机推荐
第五届“强网杯”全国网络安全挑战赛(线上赛)
力扣221题,最大正方形
How to submit a PR?【OpenHarmony Growth Plan】【OpenHarmony Open Source Community】
2021DozerCTF
APP application related instructions in Auto.js
Application of Spatial 3D Model Reconstruction Based on Pix4Dmapper - Spatial Analysis and Site Selection
ArcMap时间滑块功能动态显示图层数据并生成视频或动图
【vulhub】MySql身份认证绕过漏洞复现(CVE-2012-2122)
npm warn config global `--global`, `--local` are deprecated. use `--location=global` instead.
黑猫带你学Makefile第12篇:常见Makefile问题汇总
INSERT:插入操作语法&使用例——《mysql 从入门到内卷再到入土》
优化是一种习惯●出发点是'站在靠近临界'的地方
【nvm】【node多版本管理工具】使用说明和踩坑(exit status 1)
APP UI自动化测试常见面试题,或许有用呢~
Interpretation of the paper (g-U-Nets) "Graph U-Nets"
B. Codeforces Subsequences
【PCBA方案设计】蓝牙跳绳方案
3D model reconstruction of UAV images based on motion structure restoration method based on Pix4Dmapper
ENVI感兴趣区ROI文件由XML格式转为ROI格式
Uniapp编译后小程序的代码反编译一些思路