配置及代码改动(ROM)

(一)寄存器配置

按照已经配置好的imx327.lib.h为例,之后新的sensor可以照着配置

.out_info_array =
{
.out_info =
{
#if IMX327_INC_RES_1920x1080P25
{
.x_output = 1948, /* 4+8+1920+9+4+3 */
.y_output = 1097, /* 8+1080+9 */
.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, /* 4+8+1920+9+4+3 */
.y_output = 1097, /* 8+1080+9 */
.line_length_pclk = 4400,
.frame_length_lines = 1125,
.vt_pixel_clk = 148500000,//74250000,
.op_pixel_clk = 237600000,//74250000, //DDR 92.8125,4 lane,10bit
.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帧,会出现没有图像的情况。

//mct_pipeline.c
#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帧跳动

原因:业务那边做过一个根据网络状况改变帧率的逻辑。很可能是由于网络问题,导致设置的帧率一直在跳动,需要让业务修改或者去掉这个逻辑。