吐槽
換了新公司,一上來就面對兩個比較棘手的問題,2個問題都是拖了幾個月沒有解決,跟展訊那邊溝通遲遲沒有解決方案。
原本是做MTK平臺的,到了這邊需要做展訊平臺和高通平臺。
證明能力的時候到了!
一週用來熟悉展訊Camera驅動,2個問題基本在加班跟原始碼,3天左右找到解決方案!
事實上還是有些成就感,畢竟,一來面對的是新平臺,另外特別是第二個問題,展訊拖了幾個月都沒有解決辦法。
問題1:視訊通話下,固定幀率為10幀,優化功耗,不影響拍照出幀數。
難點:
1.區分是視訊通話還是camera正常使用。
因為視訊通話和正常使用相機呼叫的都是camera preivew進行預覽。
解決方案:
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;
這個值目標幀長時恆定的,我們可以採取這個點在底層進行區分。
複製程式碼
2.如何修改修改幀率。
Camera sensor知識點(型號:SP2609)
1.fps(幀率)計算方法:
//cur_fr_len 表示當前一幀的長度
if (cur_fr_len > shutter) {
fps = 1000000.0 / (frame length* line_time);
} else {
fps = 1000000.0 / ((shutter + dummy_line) * line_time);
}
複製程式碼
- shutter 是寫入P1: 0x03,0x04暫存器
- dummy_line:P1:0x05(高8位),0x06 (低8位)可以通過改變dummy_line來調整幀長->進而調整幀率
- frame length(即cur_fr_len):可以通過P1:0x4e,0x4f讀出來(只能進行讀操作) 由於控制frame length的0x4e(高8位),0x4f(低8位)是隻讀的,無法寫入,那麼如何改變frame length呢?
2.frame length(幀長)的計算方式
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;
}
複製程式碼
- frame_length:表示一幀幀長,可以理解為一幀的行數;
- shutter:曝光行數,單位是多少個line_time
- dummy_line:用以改變幀長來調節幀率快慢,實際沒有資料輸出;
- line_time:一行曝光時間(是固定值:23114)
幀長:限定最大fps,例如:
在初始化的時候,往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);
}
複製程式碼
3.解決方案:
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);
+ }
···
}
複製程式碼
視訊通話出幀率
問題2.黃色燈光或者夕陽西下環境下,拍照過程中瞬間閃紅問題。
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函式在相機啟動的時候或者拍照的時候都會呼叫。 因此我們需要在拍照的時候跳一幀,啟動的時候還是不跳幀。