应用层处理CPU、GPU框架下TextureView、GLSurfaceView所对应的Surface获取到的ImageReader数据以及dump相关的方法前面已经讲了,本次主要以展讯平台的HAL层dump预览的相关节点看一下如何抓取我们想要的任何节点下的帧数据
一、平台HAL层预览Dump数据分析
vendor/sprd/modules/libcamera/oem2v6/src/cmr_preview.c
cmr_int prev_construct_frame(struct prev_handle *handle, cmr_u32 camera_id,
struct frm_info *info,
struct camera_frame_type *frame_type) {
ATRACE_BEGIN(__FUNCTION__);
...
char value[PROPERTY_VALUE_MAX];
//dump命令节点
property_get("debug.camera.preview.dump.count", value, "null");
cmr_uint dump_num = atoi(value);
if (strcmp(value, "null")) {
if (g_preview_frame_dump_cnt < dump_num) {
char tag_name[30]={0};
char cameraId[2] ={0};
strcpy(tag_name, "prev_construct_frame_id");
sprintf(cameraId, "%d", camera_id);
strcat(tag_name, cameraId);
//dump数据接口
dump_image(tag_name, CAM_IMG_FMT_YUV420_NV21,
frame_type->width, frame_type->height,
prev_cxt->prev_frm_cnt,
&prev_cxt->prev_frm[frm_id].addr_vir,
frame_type->width * frame_type->height * 3 / 2);
g_preview_frame_dump_cnt++;
}
}
...
}
// tag used for description, for example, preview, video, snapshot and so on
cmr_int dump_image(char *tag, cmr_u32 img_fmt, cmr_u32 width, cmr_u32 height,
cmr_u32 index, struct img_addr *vir_addr,
cmr_u32 image_size) {
cmr_int ret = CMR_CAMERA_SUCCESS;
char file_name[0x80];
char tmp_str[80];
char datetime[15];
FILE *fp = NULL;
CMR_LOGD("%s: format %d width %d height %d", tag, img_fmt, width, height);
time_t timep;
struct tm *p;
time(&timep);
p = localtime(&timep);
sprintf(datetime, "%04d%02d%02d%02d%02d%02d", (1900 + p->tm_year),
(1 + p->tm_mon), p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
cmr_bzero(file_name, 0x80);
strcpy(file_name, CAMERA_DUMP_PATH);
sprintf(tmp_str, "%s_", tag);
strcat(file_name, tmp_str);
sprintf(tmp_str, "%d", width);
strcat(file_name, tmp_str);
strcat(file_name, "X");
sprintf(tmp_str, "%d", height);
strcat(file_name, tmp_str);
strcat(file_name, "_");
sprintf(tmp_str, "_frame_num_%d", index);
strcat(file_name, tmp_str);
sprintf(tmp_str, "_%s", datetime);
strcat(file_name, tmp_str);
if (CAM_IMG_FMT_YUV420_NV21 == img_fmt) {
strcat(file_name, ".yuv");
CMR_LOGD("file name %s", file_name);
fp = fopen(file_name, "wb");
if (NULL == fp) {
CMR_LOGE("can not open file: %s", file_name);
return 0;
}
CMR_LOGV("yuv addr_vir:0x%x,0x%x,0x%x", vir_addr->addr_y,
vir_addr->addr_u, vir_addr->addr_v);
// dump y
fwrite((void *)vir_addr->addr_y, 1, width * height * 1, fp);
// dump uv, uv can independent of y
fwrite((void *)vir_addr->addr_u, 1, width * height * 1 / 2, fp);
fclose(fp);
} else if (CAM_IMG_FMT_BAYER_MIPI_RAW == img_fmt) {
strcat(file_name, ".mipi_raw");
CMR_LOGD("file name %s", file_name);
fp = fopen(file_name, "wb");
if (NULL == fp) {
CMR_LOGE("can not open file: %s", file_name);
return 0;
}
fwrite((void *)vir_addr->addr_y, 1, (uint32_t)width * height * 5 / 4,
fp);
fclose(fp);
} else if (CAM_IMG_FMT_BAYER_SPRD_DCAM_RAW == img_fmt) {
strcat(file_name, "_mipi2.raw");
CMR_LOGD("file name %s", file_name);
fp = fopen(file_name, "wb");
if (NULL == fp) {
CMR_LOGE("can not open file: %s", file_name);
return 0;
}
fwrite((void *)vir_addr->addr_y, 1, (uint32_t)width * height * 5 / 4,
fp);
fclose(fp);
} else if (CAM_IMG_FMT_JPEG == img_fmt) {
strcat(file_name, ".jpg");
CMR_LOGD("file name %s", file_name);
fp = fopen(file_name, "wb");
if (NULL == fp) {
CMR_LOGE("can not open file: %s", file_name);
return 0;
}
fwrite((void *)vir_addr->addr_y, 1, image_size, fp);
fclose(fp);
}
return 0;
具体调用以及dump信息如下:
二、平台其他节点Dump数据指令
由此及彼,根据预览的相关介绍,可以直接衍生到平台的各个算法以及流程节点的相关命令,入拍照、缩略图等。
/vendor/sprd/modules/libcamera/oem2v6/cmr_snapshot.c
以微距拍照的相关节点进行check
#ifdef SUPER_MACRO
cmr_int snp_save_yuv_for_macro(cmr_handle snp_handle, struct snp_jpeg_param *jpeg_in)
{
cmr_u32 tmp = 0;
cmr_int ret = 0;
cmr_uint tmp_dst_addr = 0;
cmr_uint tmp_src_addr = 0;
cmr_uint rotation = 0;
char name[20] = {0};
char value[PROPERTY_VALUE_MAX] = {0};
...
memcpy((char *)tmp_dst_addr, (char *)&tmp_src_addr, sizeof(int));
property_get("persist.vendor.cam.macro.dump", value, "0");
if (atoi(value) == 1) {
sprintf(name, "sp_yuv_rot_%d", rotation);
dump_image(name, CAM_IMG_FMT_YUV420_NV21,
jpeg_in->super.size.width, jpeg_in->super.size.height,
FORM_DUMPINDEX(SNP_ENCODE_SRC_DATA, 1, 0),
&jpeg_in->super.addr_vir,
jpeg_in->super.size.width * jpeg_in->super.size.height *
3 / 2);
}
return ret;
}
诸如此等,各位有需要的可以自己查看相关的平台代码以及相关的节点,进行dump数据分析,更利于check Camera各个流程的状态是否正常。
三、HAL层自己添加节点dump指令
可以参考平台的相关流程,在自己的算法节点前后进行dump以check算法的input、output节点是否异常。
static cmr_int xxx_thread_proc(struct cmr_msg *message, void *data) {
cmr_int ret = CMR_CAMERA_SUCCESS;
struct xxx *xxxhandle
...
//dump before algo
char value[VALUE_MAX];
if (!strcmp(value, "true")) {
addr = &in->src_frame.addr_vir;
dump_image("wsj_befor", CAM_IMG_FMT_YUV420_NV21, image.width, image.height, 0, addr, (image.width) * (image.height) * 3 / 2);
}
//run related algo
...
//dump after algo
property_get("debug.dump.after.singlertbokeh", value, "null");
if (!strcmp(value, "true")) {
addr = &in->src_frame.addr_vir;
dump_image("wsj_after", CAM_IMG_FMT_YUV420_NV21, out_image.width, out_image.height, 1, addr, (out_image.width) * (out_image.height) * 3 / 2);
}
free(xxx);
}
总结
关键的节点check关键信息不管对于什么process都是百利无一害的,dump各个流程节点对于快速定位、分析问题至关重要。