如何实现手动设置快门和增益?
如何避免因为不同的数据流在不同的地方设置增益和快门?
思路
拍照和预览设置增益可能会发生改变,如果用手动AE也可能出问题。最好的地方是他们共用的地方,可以想到的是sensor模块,sensor模块是和硬件最密切的,在这里可以进行寄存器的设置。我们找到不论何种模式都会进行设置的地方进行修改就行了。
过程
拿imx290举例,它的常用寄存器地址和函数是在imx290_lib.h中定义的。
static sensor_lib_t sensor_lib_ptr = { .sensor_slave_info = { .sensor_name = SENSOR_MODEL, .slave_addr = 0x34, .i2c_freq_mode = SENSOR_I2C_MODE_FAST, .addr_type = CAMERA_I2C_WORD_ADDR, .sensor_id_info = { .sensor_id_reg_addr = 0x301E, .sensor_id = 0xB201, } ... } ... }
|
这是对结构体的乱序赋值,既能初始化时赋值,也可以不考虑顺序。
.exposure_func_table = { .sensor_calculate_exposure = sensor_calculate_exposure, .sensor_fill_exposure_array = sensor_fill_exposure_array, },
|
仔细看其中,会发现这个结构体里还有函数方法。而这个函数就是具体不同型号中对寄存器的操作,就比如写入增益寄存器,可能存在有的有一个字节,有的需要两个字节。给一个相同的函数入口,其实就是实现了面向对象编程中的多态。
我们需要修改的是写入sensor的增益和快门,因此越接近底层越不容易出现问题,比如避免因为预览和拍照流的参数位置不同造成的影响。
sensor_fill_exposure_array
函数是对曝光类寄存器进行操作,
由于sensor_fill_exposure_array
是对曝光表的直接寄存器操作,因此可以说是最底层了,但是不同的sensor这个函数的内容也不一样,因此我们需要先找到调用它的函数。
我们可以看到sensor模块中的sensor_apply_exposure
和sensor_set_exposure
函数不仅仅是在sensor aec的init中进行调用,还有双摄,从摄,手动AE,自动AE的设置,可以说它是所有数据流设置曝光增益流程的必经之处。
在sensor_apply_exposure
中会对aec的最大曝光行最大增益等进行判断,保证不会超过lib.h的限制之后,然后通过sensor_fill_exposure_array
写入。不希望我们写入的值超过了sensor的设置,因此我们最好在apply函数之前,也就是sensor_set_exposure
函数之后进行修改。
在sensor_calculate_exposure
函数中,将增益转换成了可以写入寄存器的整型,因此我们也不要动,在sensor_calculate_exposure
之前进行修改,同时又尽可能的少,就选择在sensor_set_exposure
函数里的sensor_calculate_exposure
对曝光和增益进行修改。
让人吐血的是,这里已经有高通的设置了。
#ifdef ENABLE_MANUAL_EXPOSURE_UPDATE if(updateExtGain(&ext_real_gain) == SENSOR_SUCCESS) real_gain = ext_real_gain;
if(updateExtLinecount(&ext_linecount) == SENSOR_SUCCESS) linecount = ext_linecount; #endif static int32_t updateExtGain(float *real_gain) { char ext_real_gain[PROPERTY_VALUE_MAX];
RETURN_ERROR_ON_NULL(real_gain);
property_get("persist.camera.sensor.gain", ext_real_gain, "0"); *real_gain = atoi(ext_real_gain); if (*real_gain > 0) { SERR("Updated gain: %f", *real_gain); return SENSOR_SUCCESS; }
return SENSOR_FAILURE; } static int32_t updateExtLinecount(uint32_t *linecount) { char ext_linecount[PROPERTY_VALUE_MAX];
RETURN_ERROR_ON_NULL(linecount);
property_get("persist.camera.sensor.linecount", ext_linecount, "0"); *linecount = atoi(ext_linecount); if (*linecount > 0) { SERR("Updated linecount: %d", *linecount); return SENSOR_SUCCESS; }
return SENSOR_FAILURE; }
|
但是将ENABLE_MANUAL_EXPOSURE_UPDATE
定义一下,去修改persist.camera.sensor.gain
和persist.camera.sensor.linecount
,没有发现图像有明显变化。
发现赋值过去的real_gain和linecount两个变量根本没有用到,没有进行设置,于是将
lib->sensor_lib_ptr->exposure_func_table.sensor_calculate_exposure( real_gain, linecount, &exp_info, &exposure.hdr_exposure);
|
对比660设备的代码,发现660代码进行了设置。
if (lib->sensor_lib_ptr->exposure_func_table.calc_exp_array_type == CALC_CUSTOM_IN_LIB && lib->sensor_lib_ptr->exposure_func_table.sensor_calculate_exposure) { lib->sensor_lib_ptr->exposure_func_table.sensor_calculate_exposure( real_gain, linecount, &exp_info, exposure.s_real_gain); } else { sensor_cmn_calc_exposure(lib->sensor_lib_ptr, real_gain, linecount, &exp_info, exposure.s_real_gain); }
|
这里应该是高通之前代码的错误,并没有像手册一样实现手动控制增益的功能。
功能叙述
persist.camera.sensor.gain
用来设置手动增益,默认是整数,我改成了浮点数,方便去细调。如果不设置或者设置为0,则增益是自动
persist.camera.sensor.linecount
用来设置手动快门,需要是整数,同样不进行设置或者设置为0,快门是自动。
注意: 8056平台不适用这套代码逻辑