高通將android的camera模塊從新修改了一下,與原生的方式存在一些差別。這裏將前段時間學習的一些零散知識進行一下總結,便於之後查閱。linux
1.整個模塊主要巡行三個主線程:control、config及frame,control用來執行總的控制,是上層控制接口(這個線程還未去了 解)?config主要進行一些配置,這個線程裏面主要進行3A的工做,另外還有一些跟效果有關的設置;至於frame線程好像主要用來作預覽吧。目前還 只是大體瞭解config線程。android
2.在Qualcomm執行初始化時就會調用到mm_camera_exec()函數來創建config線程 launch_cam_conf_thread();閱讀此線程函數體會發現裏面使用了select機制來檢測配置指令並進行分發(調用不一樣的分支函 數)。後面就是一連串的function call了。 關於select機制還有很多疑點須要進一步學習:指令的來源?如何對文件進行控制的?git
好比下面這一段LOG就能夠看到對AE、AWB及HIS設置的過程(只貼了部分):算法
E/CAM_FD ( 194): ...... entering config duty loop ......
E/CAM_FD ( 194): cam_conf: MSM_CAM_IOCTL_GET_STATS: resptype=1 ctrl_cmd.type=4
E/mm-camera( 194): +++++++++++++ config_proc_vfe_event_message type 0 // event類型
E/mm-camera( 194): camconfig_proc_vfe_event_message received msgId = 9
E/mm-camera( 194): vfe_process_msg_evt msg_id = 9
E/mm-camera( 194): vfe_process_VFE_ID_COMMON, vfe common message = 0x4a000 // AE、AWB、IHIS
E/mm-camera( 194): received AEC stats: buf = 0x40821000, fd = 52
E/mm-camera( 194): VFE_ID_STATS_AE numReg 256, opt_mode 4
E/mm-camera( 194): vfe_util_do_aec: numReg = 256, num_pixels_per_region_aec = 30856
E/CAM_FD ( 194): isp3a_execute stats_type: 0 // 執行AEC
E/mm-camera( 194): vfe_util_do_aec: no pendingPrepSnapCtrlCmd
......shell
看過Qualcomm攝像頭部分代碼的都知道,裏面充斥了一些全局及靜態變量,在未徹底理清楚前看起來很費勁,好比我如今就處於這種狀態。下面就將一些已發現的變量總結一下寫在這裏,方便之後查閱。在海量代碼中查閱一些數據結構真是一件使人頭痛的事情。後端
1.config線程相關:服務器
config線程主要負責攝像頭的配置工做,由它完成模塊的大部分工做,調試的重點也在這部分。數據結構
首先定義了一個全局的變量config_ctrl_t cfgctrl,全部的config相關的 數據都跟這個變量相關,好比調試過程當中經常使用到的isp3a_ctrl_t及sensor_ctrl_t等,都掛在這裏。從這個結構體層層往下找就能慢慢理 清Qualcomm中的數據結構。在config線程裏面發生的ctrl command和vfe event message都將傳入cfgctrl地址及須要刷新的值,進行後續的操做並保持一些狀態到cfgctrl中。因此若是須要了解某個狀態,只要讀取cfgctrl中的相關字段便可。ctrl command主要是一些菜單的設置,而vfe event message主要是vfe一些event的反饋處理。架構
Qualcomm提供了一些接口來設置,但獲取狀態的接口基本沒有,只能本身編寫。框架
2.AWB相關(Bayer格式):
在AWB的處理過程當中,除了上面提到的isp3a_ctrl_t結構體用於對外交互外,AWB模塊內部還定義了一個靜態變量awb_algo_ctrl_t*awbCtrl用於保存AWB相關的數據及狀態。這裏面最重要的一個結構體awb_advanced_grey_world_t就是爲加強的灰度世界法算法服務的。
項目比較緊,3周內把一個帶有外置ISP,MIPI數據通訊,800萬像素的camera從無驅動到實現客戶所有需求。
1日 搭平臺,建環境,編譯內核,燒寫代碼。
我是一直在Window下搭個虛擬機登服務器搞開發的,對Linux系統環境實在無愛,往往一到項目剛開始要搭環境了,心裏總有點排斥,過程就比較糾結,看來之後仍是要搞個linux真機玩玩。
2日 編寫camera驅動大體框架,配置GPIO,I2C,MIPI,電壓,時鐘等。
不多能碰到FAE只給硬件手冊,沒有Linux和Android驅動的。由於是camerasensor外接ISP芯片,杯具就發生了。整個系統是這樣, 高通平臺的開發板,本身寫驅動來控制ISP芯片,ISP芯片與camerasensor封裝在一塊兒,ISP控制sensor,實質就是sensor寫寄存 器。
開始寫驅動了,說好聽的那是站在巨人的肩膀上借鑑別的驅動,說難聽的就是照葫蘆畫瓢,反正再改下Kconfig,Makefile,這驅動框架就算是有了。
對驅動開發而言,前期的主要工做應該就是配置GPIO口和芯片上電時序了。
每一個特定平臺在操做GPIO,電壓,時鐘上都會有本身的一套內核API封裝實現,只要能看懂會用這些API便可。配置完後,須在驅動初始化函數裏,正確設置芯片的上電時序,確保芯片硬件上能正常工做起來。
3日 編寫I2C通訊的封裝函數,調試CPU與ISP間的I2C通訊
對於一些成熟方案,上面的工做完成順利的話,驅動就差很少了。。很惋惜,這塊ISP芯片在提高800萬camera性能的同時,並無給我帶來足夠多的技術支持,只能說,成也ISP,敗也ISP,解決方案全都本身來吧。萬里長征第一道坎即是I2C。
I2C通訊自己要注意兩點,
1) SDA第9位ACK位爲低時說明從設備有響應。
2) Slave address
芯片手冊對這個從設備地址沒有統一的寫法,有的給出8位地址,有的給出7位地址,一開始容易混淆。若是給出的是8位地址,那第8位是指Write- 0或者Read-1,實際的I2C芯片地址是7位的。Linux源碼裏structi2c_board_info的板基信息應填寫7位I2C地址,另 外,I2C芯片地址能夠經過開發板shell環境下$ ls/sys/bus/i2c/devices/ 查看。舉個例子,
static struct i2c_board_info msm_camera_boardinfo[] __initdata ={
{
I2C_BOARD_INFO("ov8820", 0x78>> 1),
},
4日 FAE現場支持
FAE過來了,就確認了一件事,沒有現成驅動了,我完全死心了。後來還發現一個規律,只要FAE來現場那就意味着啥都搞不出來了。。幾我的匯聚思想還不如一我的靜下心來研究。不過他們此行至少留下一份重要的資料-ISP芯片指令序列,camera全部功能的實現就靠它了。
5日 調通I2C
I2C的調通具備里程碑式的意義,它不只標誌着硬件性能正常開啓,更爲後來璀璨絢爛的camera世界奠基了堅實的基礎。。
有段時間卡在I2C 通訊上,給ISP芯片0x3c寫入開啓芯片命令0xf0成功,可是再發送其餘命令所有失敗。
分析現象,I2C總線已經能夠通訊了,問題只能是在ISP芯片上,因而,查電路圖,抄傢伙起來把電路板上的電和時鐘所有再量一遍。。
結果發現,有一路來自自動對焦馬達的電壓只有1.7V,沒有達到要求,驅動裏沒有把它的GPIO拉高,致使芯片沒法正常開啓工做。
6日 編寫預覽驅動,測量MIPI數據
根據葵花寶典裏的ISP指令序列,在Linux驅動裏和Android高通抽象層裏填寫相關代碼,即可實現預覽功能。不過很不幸,光靠那兩下子預覽 仍是出不來的。開啓預覽程序時,用示波器量MIPI總線上的圖像數據,可以獲得理想的MIPI波形,說明底層驅動的預覽功能OK,問題在於高通平臺的 CAMIFVFE上,因而,翻閱高通的技術資料,學習添加VFE的一些配置。
7日 配置VFE,點亮預覽
預覽的成功具備劃時代的意義,它不只標誌着camera模塊在整個Android系統架構中的成型,更爲後來的拍照,錄像,圖像效果等功能奠基了堅 實的基礎。預覽的出現,意味着我不用再回答那些相似像「camera亮沒」之類的只注重表面現象的問題,從那一刻起,我彷彿站上了另外一個高度,有種夢迴漢 唐的感受。。
8日 健壯代碼,編寫拍照功能,對焦功能
至此,整個camera模塊從上層應用到底層驅動已所有打通,接下來就能夠見神殺神,見佛殺佛了。。
9日 編寫白平衡,色彩效果,場景模式,ISO,防震,閃光燈等功能
這年頭碼農傷不起啊!就按葵花寶典上的ISP指令序列往裏使勁填充。
10日 登錄服務器提交代碼
最近負責一個項目(手機)上camera的功能,其 中有要求作zoom這個功能(項目上要求對全部的分辨率均可以支持4X的zoom),因此把這個部分比較全面的學習了一下,本文對高通在android平 臺上zoom的實現原理作一個深刻的分析,包括的部分主要有zoom功能所涉及高通HW模塊的原理架構、高通在android軟件中 digitalzoom的實現流程以及具體的相關接口參數介紹,旨在讓讀者可以對高通android平臺下digitalzoom的實現原理及架構有一個 清楚的瞭解。
這裏提到的digitalzoom,即數碼變焦,是相機變焦的一種;另一種爲光學變焦,主要是在數碼相機中有所應用,它經過相機鏡頭的移動來放大與縮小須要拍攝的景物,光學變焦倍數越大,能拍攝的景物就越遠,並且不會影響畫質。本章節重點介紹數碼變焦部分,這種變焦在手機中應該較爲普遍。
手機上的數碼變焦是經過手機內的處理器,把圖片內的每一個象素面積增大,從而達到放大目 的。這種手法如同用圖像處理軟件把圖片的面積改大,不過程序在手機內進行,把原來sensor上的一部份像素使用"插值"處理手段作放大,將sensor 上的像素用插值算法將畫面放大到整個畫面。經過數碼變焦,拍攝的景物放大了,但它的清晰度會有必定程度的降低,因此數碼變焦並無太大的實際意義。
下圖是數碼變焦和光學變焦的效果對比,一目瞭然。
數碼變焦通常分爲分爲2個步驟,crop和插值放大。另外,數碼變焦有2種情況:一種是用戶須要拍照畫面的尺寸和sensor輸出畫面的尺寸是一致的;另外一種則是用戶須要拍照畫面的尺寸×zoom等級後比sensor輸出畫面的尺寸小。在第二種狀況下只須要crop就能夠了(具體要根據zoom等級計算)
關於zoom的等級,倍數越高,crop的像素就越少,以拍照3M(2048×1536,sensor輸出的原始照片爲3M)的照片爲例,若是作2X的zoom,那麼須要從原始照片中crop出1024×768的畫面,而後再插值放大成2048×1536;若是是4X的zoom,那麼須要從原始照片中crop出512×384的畫面,而後再插值放大成2048×1536,以此類推。倍數是指寬和高的倍數,而非面積。
下面結合圖片來講明一下數碼變焦的原理:
1、當用戶須要拍照畫面的尺寸和sensor輸出畫面的尺寸一致
原始照片,紅色部分爲zoom後須要crop的部分
Zoom後的照片,crop後並插值放大
能夠發現,zoom先後照片大小是一致的,但照片的範圍變小了,感受是鏡頭拉近了,其實就是經過crop後再插值放大來完成,zoom的倍數越高,須要插值的像素就越多,zoom後的照片就會越模糊。
Note:這裏的插值放大是指軟件算法,和圖像處理軟件中那種線性放大是不一樣的,關於算法的實現這裏很少介紹了。
2、用戶須要拍照畫面的尺寸×zoom等級後比sensor輸出畫面的尺寸小
下圖是sensor輸出的原始照片,1600×1200。須要拍照的分辨率爲800×600,便可以做2X的digitalzoom
在這種情況下是不須要插值放大的,圖片的質量並無下降;但若是zoom的等級比較大,好比要4x的zoom,那麼光靠crop是不行的,仍是得再經過插值放大來完成。一般說來,若是拍照的分辨率比較小,zoom大均可以只經過crop的方式來完成。在上章節中介紹了digitalzoom的效果以及基本的實現原理,本章將着重介紹高通平臺上實現digitalzoom所涉及的相關模塊架構,由於digitalzoom是camera中的一個feature,分別須要在preview和snapshot中完成,
所涉及的相關模塊也都是和camera相關的,以下所示:
上圖是preview的時候,digitalzoom所涉及的相關模塊,各個模塊的用途以下(這裏主要介紹sensor、VFE和MDP):
一、 Sensor
雖然自己也有zoom的功能,但在這裏並未使用。Preview時若是作digitalzoom,只是正常的輸出frame而已,好比輸出30fps的VGA數據(YUV)。
二、 VFE
DSP的一部分,功能主要都是和圖像處理相關,在zoom的時候,它的用途主要就是Crop(剪裁),它會把sensor輸出的VGA數據crop成preview時所須要大小的數據,如CIF(352×288),這樣的話至關於已經作了一部分zoom(640/352),大概是1.8X,若是不夠,剩餘的zoom將由後面的MDP來完成。
Note:VFE只有crop的功能,沒有upscale(放大)的能力,因此VFE最多隻能完成有限的zoom。
三、 MDP
這是一個專門處理顯示數據的處理器,功能比較齊全,在zoom的時候主要的用處就是crop+upscale。由於VFE的zoom能力有限,因此當VFE不能知足要求的時候,MDP則繼續完成剩餘的zoom,好比:若是要求preview畫面的大小爲QVGA,如今要作4X的zoom,那麼VFE會從原始的VGA數據中crop出QVGA大小的數據,至關於已經作了2X的zoom,那麼剩下的2Xzoom怎麼作呢?MDP會從VFE輸出的QVGA(320×240)數據中crop出160×120大小的數據(從中間截取),而後再upscale成QVGA大小的數據送到LCD顯示,這樣至關於又作了2X的zoom,因此加起來一共作了4X的zoom。
Note:MDP最大能夠進行4X的upscale。
上面介紹了preview時zoom的實現,下面來看一下拍照時zoom是如何實現的?
Note:爲了知足所拍爲所看,即拍下來照片的景物範圍和preview時所看到的景物範圍要保持一致,preview時和snapshot時的zoomlevel必須保持一致。
一、 Sensor
輸出拍照須要的原始數據。在當前應用中,無論設置的拍照分辨率是多少,咱們要求sensor輸出的拍照數據是固定的,即最大3M(2048*1536,以ICE爲例)。
二、 VFE
功能和preview時候是一致的,只不過在拍照的時候,VFE會根據zoom的等級以及須要拍照的分辨率來自動crop出合適大小的數據。
例如選擇拍照的分辨率爲2048×1536,zoom的level爲4X,那麼VFE將從原始的2048×1536的數據中crop出512×384大小的數據,後面的zoom由Videocore中的jpegencoder完成。
還有一種情況,若是拍照的分辨率較小,那麼有可能只經過VFE的crop就能夠完成zoom功能,好比拍照的分辨率爲1024×768,這個時候若是作2X的zoom,那麼VFE只須要從原始的2048×1536的數據中間直接crop出1024×768的數據便可,後面就不須要再用jpegencoder來zoom了。但若是zoom的等級比較高,後面的2Xzoom仍是要經過jpegencoder來作了。
三、 Video core
負責把VFE輸出的數據encoder成jpeg文件,這裏的jpegencoder還有一個比較重要的功能,那就是upscale,經過這個功能,再搭配以前VFE的crop功能,zoom就能夠完成了。
Note:Jpeg encoder的upscale功能是有限的,最大能夠進行4X的放大,目前能夠知足ICE上的需求。
能夠看出,從HW架構來講,preview和snapshot只是在後面的upscale部分有所區別,前者是經過MDP來完成,後者則是經過jpegencoder(DSP)來完成。
本章將從軟件角度來分析一下高通Android平臺下digitalzoom的架構以及實現流程,下面先來看一下Android中camera部分的軟件架構。
Note:目前以Androiddonut版本爲例,高通在androidéclair版本上尚未導入
先來看一下Preview的流程:
一、VFEdriver會把從sensor傳送來的frame數據crop成上層須要的大小(具體若是crop要根據zoom的level),而後連同crop信息一塊兒把數據傳送到HAL。
二、HAL層不會對preview數據作任何處理,它會這些數據原封不動的callback到camera service,一樣包含cropinfo(下章節會詳細介紹crop info)。
三、Camera service在一開始的時候會在surfaceflinger中建立一個surface。當cameraservice收到preview數據的時候,2個主要接口會被調用:
1) zoomUpScale_callback
經過調用mSurface->updateCropRect接口把crop相關信息通知給surfaceflinger
2) previewCallback
經過調用mSurface->postBuffer接口把preview的數據傳遞給surfaceflinger。
四、Surfaceflinger收到數據和crop信息後會調用copybit的接口來驅動MDP去作相關的動做(crop&upscale),而後就去畫屏了。
再來看一下snapshot時的流程:
一、VFEdriver把從sensor傳遞來的原始拍照數據(最大分辨率:2048×1536)crop成zoom須要大小的數據,連同crop信息一塊兒傳遞給HAL。
二、HAL層收到snapshot的數據後會先去檢查crop info,判斷是否須要jpegencoder去作upscale的動做。若是不須要就直接encode成jpeg數據;若是須要,填好upscale的參數再作encode。
三、Jpeg encoder後的數據會從HAL callback到camera service,cameraservice會在通知上層去把數據寫成文件。
因而可知,在snapshot的時候,整個zoom在HAL就能夠完成了,而不像preview的時候,須要在surfaceflinger中配置MDP協助完成。具體的原理在第二章節中有詳細的敘述,這裏就不重複了。
本章將從代碼的層次來分析一下zoom的實現原理及流程。
Note:基於高通5110 release的code
首先來看一些配置參數(基於HAL):
#define MAX_ZOOM_LEVEL5//對於user來講能夠zoom的等級
static const int ZOOM_STEP =6;//每次zoom時的幅度,能夠修改
另外須要說明高通VFE中zoom的最大值爲60(和分辨率無關)。所在在ICE上咱們應該讓MAX_ZOOM_LEVEL×ZOOM_STEP=60。要麼增大MAX_ZOOM_LEVEL,要麼增大ZOOM_STEP。
下面再來看一下zoom等級的對應關係(高通能夠作到最大的就是zoom4X,這個是HW(MDP和jpegencoder)的限制):
下面看一下HAL層zoom的接口
HAL層的接口比較簡單,就是setZoom,上層傳遞一個zoom的level便可,執行時會判斷參數,若是沒有超出則通知VFE進行crop,以下:
因此surfaceflinger在更新畫面的時候就會根據這些參數來配置MDP,完成後續的操做了。
拍照的時候一樣也是這樣的原理,差異在於crop中的信息不須要傳遞給上層,而是直接傳遞給jpegencoder便可(寫到mDimension這個結構體中),以下(HAL中的receiveRawPicture函數):
Jpegencoder完成後,HAL只須要把zoom好的jpegdata callback給上層就OK了,因此拍照部分的zoom不須要上層額外的處理。
下面看看Camera service裏面是怎麼處理的?
Cameraservice收到callback後會把crop相關信息及標誌更新到preview所申請的surface中.
下面看一下VFE輸出數據的格式:
在Preview的時候,經過MSM_CAM_IOCTL_GETFRAME系統命令從底層獲得preview的數據,格式以下:
buffer爲數據地址,y_off和cbcr_off分辨爲Y的偏移和CBCR的偏移,經過y_off=0,cbcr_off=w*h,這裏和zoom相關的是cropinfo,比較重要,以下:
能夠看出有2個buffer的參數,其中1是preview的,2是snapshot的。若是沒有開啓zoom功能,這些參數都是空的;若是zoom的level比較低,VFE足以處理,那麼這些參數也是空的。
只有當VFE不足以處理所須要的zoom level時,這些參數的值纔有意義。具體含義以下:
out的值表明上層須要數據的寬和高,好比說上層設置的preview大小爲480×320,那麼out1_w=480;out1_h=320;而in的值則表明後端的MDP或是jpegencoder須要crop的大小,舉例來講明:
Sensor輸出VGApreview畫面,MMI設置HVGApreview大小,若是要作2X的zoom,VFE能力有限,只能作 640/480=1.3X,這個時候VFE輸出數據是crop後的HVGA數據,crop信息中的in1_w=320;out1_w=216,意思是後面 的MDP須要從HVGA的數據中crop出320×216大小的數據,而後在scale成HVGA,這樣總體算起來就是zoom2X了。
因此HAL只須要將preview數據以及crop info傳遞給上層便可,這裏是經過callback進行的.