換了新公司,一上來就面對兩個比較棘手的問題,2個問題都是拖了幾個月沒有解決,跟展訊那邊溝通遲遲沒有解決方案。算法
本來是作MTK平臺的,到了這邊須要作展訊平臺和高通平臺。bash
證實能力的時候到了!ide
一週用來熟悉展訊Camera驅動,2個問題基本在加班跟源碼,3天左右找到解決方案!函數
事實上仍是有些成就感,畢竟,一來面對的是新平臺,另外特別是第二個問題,展訊拖了幾個月都沒有解決辦法。工具
難點:優化
由於視頻通話和正常使用相機調用的都是camera preivew進行預覽。ui
解決方案:
1.在上層進行區分:
聯繫微聊APP廠商在接聽通話時,往底層發送一條msg(複雜,不可取)
複製代碼
2.在HAL層進行區分:
視頻通話時camera預覽的寬高(480,360),拍照時camera預覽的寬高(480,480)
void SprdCamera3OEMIf::setCameraPreviewMode(bool isRecordMode) {
···
if(height==360)根據高度進行區分
{
//設定一個標誌,表示正在視頻通話
video_call_flag = true;
}
···
}
可是這個video_call_flag的值怎麼傳到底層,就有些複雜。
方式一:
添加persist_sys_video_call_flag節點,在底層去讀這個節點(無權限,不可取)
方式二:
從hal層經過指針傳參(已實現,改動複雜,不可取)
複製代碼
3.在底層進行區分(最優方案)
經過log分析:因爲視頻通話時,固定輸出幀率位10幀,
所以,目標幀長老是dest_fre_len = dummy_line+shutter = 4326;
這個值目標幀長時恆定的,咱們能夠採起這個點在底層進行區分。
複製代碼
1.fps(幀率)計算方法:spa
//cur_fr_len 表示當前一幀的長度
if (cur_fr_len > shutter) {
fps = 1000000.0 / (frame length* line_time);
} else {
fps = 1000000.0 / ((shutter + dummy_line) * line_time);
}
複製代碼
2.frame length(幀長)的計算方式3d
if (frame length > shutter) {
frame length = 1217+dummy_line,(初始值+dummy_line)
//這裏的1217是當dummy_line的值爲0時,能夠用ISPTool工具去讀4e,4f的值獲得的,也能夠問一下FAE
//舉個例子:若是dummy_line(0x05,0x0C),(0x06,0x25)->0C25->3109十進制
//那麼frame length = 1217 + 3109 = 4326
}else {
frame length = shutter+-1;
}
複製代碼
在初始化的時候,往dummy_line寫(0x05,0x0c),(0x06,0x25); 即忘05,06寄存器寫0c25->3109(十進制) 則frame_length = 1217+dummy_line = 1217+3109;指針
那最大出幀率 max_fps = 1000000.0/(frame length* line_time)
= 1000000.0/(4326*23114)
= 10 (fps)
複製代碼
以上邏輯是作到sensor內部了,因此exposure接口函數只須要配置,平臺的AE Pline中exp變量轉化爲exposure line count,而後寫入exp控制寄存器P1:0x03,0x04 以及P1:0x05,0x06便可,方法能夠參考以下:
//shutter
static uint32_t sp2609_read_shutter(void)
{
uint16_t shutter_h = 0;
uint16_t shutter_l = 0;
Sensor_WriteReg(0xfd, 0x01);//fd寄存器選擇第一頁
shutter_h = Sensor_ReadReg(0x03) & 0xff;//寫入03寄存器(高8位)
shutter_l = Sensor_ReadReg(0x04) & 0xff;//寫入04寄存器(低8位)
return (shutter_h << 8) | shutter_l;//返回高8位和低8位拼接起來的值
}
static void sp2609_write_shutter(uint32_t shutter)
{
Sensor_WriteReg(0xfd, 0x01);
Sensor_WriteReg(0x03, (shutter >> 8) & 0xff);
Sensor_WriteReg(0x04, shutter & 0xff);
Sensor_WriteReg(0x01, 0x01); //讓寫入的值當即生效
}
//dummy_line
static uint32_t sp2609_read_dummy_line(void)
{
uint16_t dummy_line_h = 0;
uint16_t dummy_line_l = 0;
Sensor_WriteReg(0xfd, 0x01);//fd寄存器選擇第一頁
shutter_h = Sensor_ReadReg(0x05) & 0xff;//寫入03寄存器(高8位)
shutter_l = Sensor_ReadReg(0x06) & 0xff;//寫入04寄存器(低8位)
return (dummy_line_h << 8) | dummy_line_l;//返回高8位和低8位拼接起來的值
}
static void sp2609_write_dummy_line(uint32_t dummy_line)
{
Sensor_WriteReg(0xfd, 0x01);
Sensor_WriteReg(0x05, (dummy_line >> 8) & 0xff);
Sensor_WriteReg(0x06, dummy_line & 0xff);
Sensor_WriteReg(0x01, 0x01);
}
複製代碼
vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/Superpix/SP2609/sensor_sp2609_mipi_raw.c
//添加dummy_line接口
+static void sp2609_drv_write_dummy_line(cmr_handle handle, cmr_u32 dest_fr_len) {
SENSOR_IC_CHECK_HANDLE_VOID(handle);
struct sensor_ic_drv_cxt * sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;
if(dest_fr_len == 4326) {
//fix max fps = 10 in video call
hw_sensor_write_reg(sns_drv_cxt->hw_handle, 0xfd, 0x01);
hw_sensor_write_reg(sns_drv_cxt->hw_handle, 0x05, 0x0c);
hw_sensor_write_reg(sns_drv_cxt->hw_handle, 0x06, 0x25);
hw_sensor_write_reg(sns_drv_cxt->hw_handle, 0x01, 0x01);
}else {
//fix max fps = 30 in normol use camera
hw_sensor_write_reg(sns_drv_cxt->hw_handle, 0xfd, 0x01);
hw_sensor_write_reg(sns_drv_cxt->hw_handle, 0x05, 0x00);
hw_sensor_write_reg(sns_drv_cxt->hw_handle, 0x06, 0xe1);
hw_sensor_write_reg(sns_drv_cxt->hw_handle, 0x01, 0x01);
}
}
//在write_exposure_dummy時調用
cmr_int sp2609_drv_write_exposure_dummy(cmr_handle handle,···)
···
+ if (dest_fr_len != cur_fr_len) {
+write_sensor_dummy_line:
+ sp2609_drv_write_dummy_line(handle,dest_fr_len);
+ }
···
}
複製代碼
視頻通話出幀率
1.現象
2.問題根源 這個現象和Camera的啓動時現象是同樣的。 camera啓動時,判斷當前是黃光環境(根據色溫),此時預覽界面偏紅,通過AWB(自動白平衡)算法調整,就會變白一些。
那麼在拍照時,爲啥會出現這個狀況的?
也就是相機啓動或者是拍照切換數據流時,AE都會從新調整,致使出現這個問題。
3.解決方案
1.跳幀
在拍照時,數據流切換的過程當中,咱們跳一幀來解決。
在底層修改這個跳幀無效。
在ISP端進行修改
vendor/sprd/modules/libcamera/camdrv/isp2.3/driver/src/dcam_u_raw_aem.c
cmr_s32 dcam_u_raw_aem_skip_num(cmr_handle handle, cmr_u32 skip_num)
{
···
+ if(拍照時){
+ skip_num = 1
}
param.property_param = &skip_num;
···
}
複製代碼
咱們不能簡單粗暴的讓skip_num = 1,不然會形成相機啓動時,AWB調整會明顯感受到慢一些,事實上dcam_u_raw_aem_skip_num函數在相機啓動的時候或者拍照的時候都會調用。 所以咱們須要在拍照的時候跳一幀,啓動的時候仍是不跳幀。