配置及代码改动(ROM)
(一)寄存器配置
按照已经配置好的imx327.lib.h为例,之后新的sensor可以照着配置
.out_info_array = { .out_info = { #if IMX327_INC_RES_1920x1080P25 { .x_output = 1948, .y_output = 1097, .line_length_pclk = 5280, .frame_length_lines = 1125, .vt_pixel_clk = 148500000, .op_pixel_clk = 237600000, .binning_factor = 1, .min_fps = 12.5, .max_fps = 25.0, .mode = SENSOR_DEFAULT_MODE, .offset_x = 0, .offset_y = 0, .scale_factor = 0, }, #endif #if IMX327_INC_RES_1920x1080P30 { .x_output = 1948, .y_output = 1097, .line_length_pclk = 4400, .frame_length_lines = 1125, .vt_pixel_clk = 148500000, .op_pixel_clk = 237600000, .binning_factor = 1, .min_fps = 15.0, .max_fps = 30.0, .mode = SENSOR_DEFAULT_MODE, .offset_x = 0, .offset_y = 0, .scale_factor = 0, }, #endif ... }, .size = 0 #if IMX327_INC_RES_1920x1080P25 +1 #endif #if IMX327_INC_RES_1920x1080P30 +1 #endif ... , },
|
(二)寄存器选择
由于原生高通代码没有切换sensor采集帧率的功能,我们只是在此基础上修改。
out_info_array是每组寄存器配置的属性。sensor_pick_res.c文件中sensor_pick_resolution则是根据上层设置的帧率分辨率等去选择最适合的一组寄存器值。
但是由于这个原先是用来设置分辨率的,相同分辨率的情况下它永远会选择第一套配置,这就导致我们不能根据帧率切换寄存器。因此注释掉下面的函数。
#define IPC_FPS_SWITCH boolean sensor_pick_check_aspect_ratio(sensor_pick_data_t *pick_data) { #ifdef IPC_FPS_SWITCH return 1; #endif ...... }
|
(三)xml配置
每组分辨率以及帧率都有对应的chromatix头文件,如果没有进行配置,会出现没有图像或者崩溃的情况。需要注意!
<ChromatixName sensor_resolution_index="0"> <ISPPreview>imx327_previewISPPreview> <ISPSnapshot>imx327_previewISPSnapshot> <ISPVideo>imx327_previewISPVideo> <CPPPreview>imx327_cpp_previewCPPPreview> <CPPSnapshot>imx327_cpp_previewCPPSnapshot> <CPPVideo>imx327_cpp_previewCPPVideo> <CPPLiveshot>imx327_cpp_previewCPPLiveshot> <A3Preview>imx327_default_preview_3aA3Preview> <A3Video>imx327_default_preview_3aA3Video> ChromatixName> <ChromatixName sensor_resolution_index="1"> <ISPPreview>imx327_previewISPPreview> <ISPSnapshot>imx327_previewISPSnapshot> <ISPVideo>imx327_previewISPVideo> <CPPPreview>imx327_cpp_previewCPPPreview> <CPPSnapshot>imx327_cpp_previewCPPSnapshot> <CPPVideo>imx327_cpp_previewCPPVideo> <CPPLiveshot>imx327_cpp_previewCPPLiveshot> <A3Preview>imx327_default_preview_3aA3Preview> <A3Video>imx327_default_preview_3aA3Video>
|
有几组寄存器配置,sensor_resolution_index就需要写几组。
(四)能力集配置
由于媒控设置帧率的时候需要检测设备是否支持这个帧率,这就需要提供该设备的能力集,告诉媒控我们支持哪些帧率。帧率的能力集不仅仅是我们lib.h中配置的那几个帧率,还有高通默认帧率,这就可能出现设备并不支持这个帧率,能力集中却依旧有的情况。因此我们把默认支持的帧率清空,让这个能力集呈现出来的全部都是我们自己配置的。
注意:部分8953设备不支持,因为老媒控检测到能力集中没有30帧,会停止采集,如果想设置25帧,会出现没有图像的情况。
#define IPC_FPS_SWITCH static cam_fps_range_t default_fps_ranges[] = { #ifdef IPC_FPS_SWITCH { 0.0, 0.0, 0.0, 0.0}, #else { 15.0, 15.0, 15.0, 15.0}, { 20.0, 20.0, 20.0, 20.0}, { 24.0, 24.0, 24.0, 24.0}, { 30.0, 30.0, 30.0, 30.0}, { 60.0, 60.0, 60.0, 60.0}, #endif };
|
(五)hal层设置代码修改
1. 帧率设置需要重启
采集帧率只有在camera启动的时候才会去设置。高通设置参数有两种方式,一种是不需要重启,一种是重启才能把参数设置进去。原生的程序没有去修改采集帧率,所以走的是需要重启的方式。
如果想让设置参数之后重启camera,只需要加上一句m_bNeedRestart = true;
。
2. 删除其他可能对帧率造成影响的代码
防止帧率对,删去温度对帧率的影响代码
3. 需要将帧率立刻传到vendor层
注意:在ADD_SET_PARAM_ENTRY_TO_BATCH
之后需要加上rc = commitSetBatch();
,让帧率立刻传递到vendor层,否则可能会出现启动之后帧率还没有传下去,用的是上一次的值的BUG。
int32_t QCameraParameters::setPreviewFpsRange(int min_fps, int max_fps, int vid_min_fps,int vid_max_fps) { int32_t rc = NO_ERROR; ... #ifndef REMOVE_THERMAL_ADJUST if ( NULL != m_AdjustFPS ) { if (m_ThermalMode == QCAMERA_THERMAL_ADJUST_FPS && !m_bRecordingHint_new) { float minVideoFps = min_fps, maxVideoFps = max_fps; if (isHfrMode()) { minVideoFps = m_hfrFpsRange.video_min_fps; maxVideoFps = m_hfrFpsRange.video_max_fps; } m_AdjustFPS->recalcFPSRange(min_fps, max_fps, minVideoFps, maxVideoFps, fps_range, m_bRecordingHint_new); LOGH("Thermal adjusted Preview fps range %3.2f,%3.2f, %3.2f, %3.2f", fps_range.min_fps, fps_range.max_fps, fps_range.video_min_fps, fps_range.video_max_fps); } } #endif if (ADD_SET_PARAM_ENTRY_TO_BATCH(m_pParamBuf, CAM_INTF_PARM_FPS_RANGE, fps_range)) { return BAD_VALUE; } #ifdef IPC_SET_FPS rc = commitSetBatch(); if (rc != NO_ERROR) { LOGE("Failed to parameter changes"); return rc; } m_bNeedRestart = true; #endif
return NO_ERROR; }
|
对外接口(ispctrl部分)
(一)帧率切换代码逻辑
高通配置sensor输出帧率只有在sensor启动时设置分辨率的时候进行配置。寄存器手册中也要求设置帧率等寄存器时需要先让sensor进入standby模式。也就是说设置帧率的时候,得重启一下。之前切换帧率是媒控帮忙停流,我们再去设置帧率,会浪费比较多的时间。现在我们可以在hal层设置参数后让sensor重启,减少了需要重新设置的模块,实测切换速度不少。
这样帧率可以我们自己控制,我们可以提供给外部接口,这就需要修改ispctrl层的代码。
(二)ispctrl接口修改
解除帧率与抗闪烁的绑定
50Hz的抗闪烁要求快门是1/100的整数倍,60Hz的抗闪烁要求快门是1/120的整数倍。帧率是限制了快门的最大值,30帧意味着快门最大1/30,但是同样是可以支持50Hz的抗闪烁。25帧也可以支持60Hz的抗闪烁,这两者并没有必然联系。因此将它们之间的联系去除。
注意:25帧的采集帧率,有利于50Hz供电频率的抗闪烁。即使曝光时间小于10ms,25帧仍然可以让日光灯产生条纹带稳定在图像的同一个位置。如果是30帧,条纹就会不停的跳动,让人难以接受。所以最后还是加上了采集帧率和抗闪烁的绑定,不过优化了代码结构。
(三)平台的适配
apq8056_one是比较老的设备,更注重稳定性,不会去解除绑定帧率与抗闪烁的关系
平台的识别,取自媒控
platform_e GetPlatform(void) { FILE *pfile; char tmp[128], *buf; static s32 is_first = 1; static platform_e platform = PLATFORM_UNKNOWN; if (is_first) { is_first = 0; pfile = fopen("/proc/cpuinfo", "r"); if (pfile == NULL) { PRINT("open %s error\n", "/proc/cpuinfo"); return PLATFORM_UNKNOWN; } while (1) { buf = fgets(tmp, sizeof(tmp), pfile); if (buf == NULL) { PRINT("%s fgets error\n", __func__); break; } if (!strncmp(tmp, "Hardware", 8)) { PRINT("%s\n", tmp); if (strstr(tmp, "8076") != NULL) { platform = PLATFORM_QCOM8076; PRINT("this platfom is qcom 8076\n"); } if (strstr(tmp, "8056") != NULL) { platform = PLATFORM_QCOM8056; PRINT("this platfom is qcom 8056\n"); } if (strstr(tmp, "8094") != NULL) { platform = PLATFORM_QCOM8094; PRINT("this platfom is qcom 8094\n"); } if (strstr(tmp, "8939") != NULL) { platform = PLATFORM_QCOM8939; PRINT("this platfom is qcom 8039\n"); } if (strstr(tmp, "SDM660") != NULL) { platform = PLATFORM_SDM660; PRINT("this platfom is SDM660\n"); } break; } } fclose(pfile); } return platform; }
|
(四)遇到过的问题
现象:图像偶尔会闪烁
排查结果:采集帧率在25帧和30帧跳动,ispctrl收到业务设置的帧率值也在25和30帧跳动
原因:业务那边做过一个根据网络状况改变帧率的逻辑。很可能是由于网络问题,导致设置的帧率一直在跳动,需要让业务修改或者去掉这个逻辑。