【Camera專題】-Camera幀率、黃光環境下拍照閃紅問題-【展訊平臺】

吐槽

換了新公司,一上來就面對兩個比較棘手的問題,2個問題都是拖了幾個月沒有解決,跟展訊那邊溝通遲遲沒有解決方案。算法

本來是作MTK平臺的,到了這邊須要作展訊平臺和高通平臺。bash

證實能力的時候到了!ide

一週用來熟悉展訊Camera驅動,2個問題基本在加班跟源碼,3天左右找到解決方案!函數

事實上仍是有些成就感,畢竟,一來面對的是新平臺,另外特別是第二個問題,展訊拖了幾個月都沒有解決辦法。工具

問題1:視頻通話下,固定幀率爲10幀,優化功耗,不影響拍照出幀數。

難點:優化

1.區分是視頻通話仍是camera正常使用。

由於視頻通話和正常使用相機調用的都是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;
	這個值目標幀長時恆定的,咱們能夠採起這個點在底層進行區分。
	
複製代碼

2.如何修改修改幀率。

Camera sensor知識點(型號:SP2609)

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);
    }
複製代碼
  • 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(幀長)的計算方式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;
}
複製代碼
  • 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函數在相機啓動的時候或者拍照的時候都會調用。 所以咱們須要在拍照的時候跳一幀,啓動的時候仍是不跳幀。

Stay hungry,Stay foolish!

相關文章
相關標籤/搜索