Android Camera架構淺析

1、Camera成像原理介紹

Camera工作流程圖

image

Camera的成像原理可以簡單概括如下:

景物(SCENE)通過鏡頭(LENS)生成的光學圖像投射到圖像傳感器(Sensor)表面上,然後轉爲電信號,經過A/D(模數轉換)轉換後變爲數字圖像信號,再送到數字信號處理芯片(DSP)中加工處理,再通過IO接口傳輸到CPU中處理,通過DISPLAY就可以看到圖像了。

電荷耦合器件(CCD)互補金屬氧化物半導體(CMOS)接收光學鏡頭傳遞來的影像,經模/數轉換器(A/D)轉換成數字信號,經過編碼後存儲。

流程如下: 
1、CCD/CMOS將被攝體的光信號轉變爲電信號—電子圖像(模擬信號) 
2、由模/數轉換器(ADC)芯片來將模擬信號轉化爲數字信號 
3、數字信號形成後,由DSP或編碼庫對信號進行壓縮並轉化爲特定的圖像文件格式儲存

數碼相機的光學鏡頭與傳統相機相同,將影像聚到感光器件上,即(光)電荷耦合器件(CCD) 。CCD替代了傳統相機中的感光膠片的位置,其功能是將光信號轉換成電信號,與電視攝像相同。

CCD是半導體器件,是數碼相機的核心,其內含器件的單元數量決定了數碼相機的成像質量——像素,單元越多,即像素數高,成像質量越好,通常情況下像素的高低代表了數碼相機的檔次和技術指標。

2、Android Camera框架

Android的Camera子系統提供一個拍照和錄製視頻的框架。

它將Camera的上層應用與Application Framework、用戶庫串接起來,而正是這個用戶庫來與Camera的硬件層通信,從而實現操作camera硬件。

image

3、Android Camera的代碼結構

Android的Camera代碼主要在以下的目錄中: 
Camera的JAVA部分 
packages/apps/Camera/。其中Camera.java是主要實現的文件。這部分內容編譯成爲目標是Camera.apk 
com.android.camera這個包,幾個主要的類文件如下: 
PhotoViewer:GalleryPicker.java(所有圖片集)--->ImageGallery.java(某個Folder下圖片列表)--->ViewImage.java(看某張具體圖片) 
VideoPlayer:GalleryPicker.java(所有視頻集) --->MovieView.java(看某一個視頻) 
Camera:Camera.java(Camera取景及拍照) 
VideoCamera:VideoCamera.java(VideoCamera取景及攝像)

 

Camera的framework供上層應用調用的部分

 

base/core/java/android/hardware/Camera.java

這部分目標是framework.jar

 

Camera的JNI部分 
frameworks/base/core/jni/android_hardware_Camera.cpp 
這部分內容編譯成爲目標是libandroid_runtime.so。

Camera UI庫部分 
frameworks/base/libs/ui/camera 
這部分的內容被編譯成庫libcamera_client.so。

Camera服務部分 
frameworks/base/camera/libcameraservice/ 
這部分內容被編譯成庫libcameraservice.so。

Camera HAL層部分 
hardware/msm7k/libcamera 
或 
vendor/qcom/android-open/libcamera2 
爲了實現一個具體功能的Camera,在HAL層需要一個硬件相關的Camera庫(例如通過調用video for linux驅動程序和Jpeg編碼程序實現或者直接用各個chip廠商實現的私有庫來實現,比如Qualcomm實現的libcamera.so和libqcamera.so),實現CameraHardwareInterface規定的接口,來調用相關的庫,驅動相關的driver,實現對camera硬件的操作。這個庫將被Camera的服務庫libcameraservice.so調用。

未完待續

在下一篇中,我會以兩條路徑來詳細介紹Camera HAL的實現:自己依據V4l2規範來實現CameraHardwareInterface; Qualcomm的Camera架構(QualcommCameraHardware和mm-camera/mm-still)。當然,在涉及到Qualcomm私有庫部分,爲避免不必要的麻煩,我會一筆帶過。敬請見諒!



高通Android平臺硬件調試之Camera

 

高通android平臺上調試2款camera sensor,一款是OV的5M YUV sensor,支持jpeg out,同時也支持AF,調試比較比較簡單,因爲別的項目已經在使用了,只是把相關的驅動移植過來就好;另一款是Samsung的一款比較新的3M YUV FF sensor,在最新項目中要使用的,本文以調試該sensor爲例,從底層驅動的角度分享一下高通android平臺下調試camera的經驗,而對於高通平臺camera部分的架構以及原理不做過多的介紹。
一、準備工作
從項目中看,在硬件(板子)ready前,軟件部分是要準備好的。單獨從底層驅動來看,軟件部分可以分爲2個部分,一個是高通平臺相關的,再一個就是sensor部分的,通常的做法就是把sensor相關的設定移植到高通平臺的框架之中。這樣就需要先拿到sensor的spec以及廠商提供的sensor register setting file。Spec的用途是清楚高通平臺和sensor通訊(讀寫寄存器)的時序以及相關參數設定;而廠商提供的setting file則是在使用camera各個功能(preview、snapshot...)時候需要寫入到sensor中的.
本項目中,高通平臺爲MSM7X27,camera爲Samsung 5CA。從spec中知道,該sensor的I2C ID爲0x78,I2C的通信採用雙字節方式,另外也弄清楚了讀寫sensor寄存器的規則,從調試角度看這些基本上夠用了。另外廠商提供的setting file,其實就是寄存器列表,告訴我們再什麼時候將哪些寄存器寫入什麼值,通常是一個寄存器地址再加上一個寄存器的值,不過Samsung提供的是PC上調試使用的文本,需要自己轉換成c語言中的二維數組。從文件中看,寄存器數據可以分爲幾個部分:初始化、IQ設定(tuning相關)、clk設定、preview設定、snapshot設定,基本上有這幾個就夠了,其他的比如調節亮度啦、設定特殊效果啦、設置白平衡啦等等都可以自己通過spec來完成。
Sensor部分的東西搞定後,接下來就是修改高通camera部分的驅動了,主要有:
Kernal部分:
1、檢查Sensor的電源配置,並修改軟件中的設定。本項目中使用2.8/1.8/1.5共3個電源。
2、檢查並修改sensor reset設置。注意reset的時間設定,務必和spec中一致,否則會導致sensor無法工作。
3、修改I2C驅動,使用雙字節讀寫的接口,並完成讀取sensor ID的接口。這個用來檢驗I2C通訊是否OK
4、導入寄存器設定,分別在初始化、preview、snapshot等幾個部分寫入對應的寄存器值。
注意:reset以及寫寄存器部分一定要按照spec的規定加入一些delay,否則會導致sensor工作異常

User空間部分:
這個部分主要是根據硬件的規格來配置VFE,如sensor輸出數據的格式,接口方式、分辨率大小、同步信號模式等,比較簡單,但一定要檢查仔細,任何一個地方不對都會導致調試失敗。
到這裏爲止,軟件部分的準備已經告一段落了。

二、調試環境準備(板子出來了,但sensor sample還沒到位)
首先,測試點的準備。
調試前就需要想好,如果sensor無法工作,要怎麼去debug,這就需要去測量一些信號,比如power、reset、I2C、M/P CLK、H/V同步信號、數據信號等,要確保這些信號都可以測量到。
其次要選擇軟件的調試環境,這裏選擇在ADB環境中執行高通的mm-qcamera-test程序來調試,相關的trace都可以打印出來。
這樣就萬事俱備,只欠sensor了。

三、調試(sensor終於拿到了)
將sensor接到板子上,開機後,ADB中運行調試程序,preview畫面並沒有出來,失敗,有點小失望,本來覺得可以一氣呵成的,但畢竟這是一個全新的sensor,任何一個地方沒有想到位做到位都會導致失敗。那就找原因吧。
1、首先從trace得知,I2C已經讀到了sensor的ID:0x05CA,這可以說明I2C通訊是沒有問題的
2、接着檢查Sensor的電源配置,測量了供給sensor的3個電源,都是OK的。
3、測量MCLK,這個是提供給sensor使用的,正常(24MHZ)
4、測量PCLK,這個是sensor輸出的,正常(58MHZ,高通上限爲96MHZ),和寄存器中配置的一致。
5、測量H/V同步信號,這個是sensor輸出的,正常。和FPS和分辨率一致。
6、測量數據信號,這個是sensor輸出的,正常。(數據信號,示波器上可以看到)
這樣看來,sensor已經在正常工作了,但爲何preview畫面沒有出來呢?繼續檢查高通這邊的設定。
從trace看,高通的VFE已經reset並且start了,但一直接沒有輸出preview數據,這就奇怪了,sensor明明已經輸出了,爲什麼VFE接收後並沒有把數據吐出來呢,難道這個sensor輸出的數據VFE無法識別?爲了驗證這個問題,我在另一塊板子上測量了OV sensor輸出數據的波形,主要是M/P clk、H/V同步信號,然後再拿來對比,不過並沒有發現異常,只是H/V同步信號有所不同,主要高低的佔空比不太一致,會不會是這樣信號的問題呢?爲了進一步驗證,我同時測量了H/V 信號和數據信號,這時發現OV sensor輸出的數據信號是包在V幀同步信號的低電平中;而Samsung 5CA輸出的數據信號是包在V幀同步信號的高電平中,會不會是因爲V信號極性設置不對導致VFE沒有讀取到sensor輸出的數據呢?重新檢查了一下高通VFE的設定,果然有一個參數是用來設定V信號極性的,這個參數默認是Active Low的,我這邊並沒有去修改它。接着把這個參數修改爲Active High,重新build、download後,開機運行,Ok了,preview畫面可以正常顯示了。到這裏爲止sensor的硬件調試可以算作完成了,後續的其他功能也可以慢慢完善了。

 

 

FSL調試之Camera

fsl的camera hal層沒有實現上層到下層的設置參數的接口,所以需要自己實現。好在從應用到hal層的參數已經弄好,否則工作量就更大了。
參數設置在hal層調用的函數是status_t CameraHal::setParameters(const CameraParameters& params)。在這個函數裏實現對每個參數的設置。參數設置主要通過 CameraParameters這個類實現的。通過觀察這個類發現,裏面有個get()函數,可以分別得到各個參數。如
const char *white_balance = params.get(CameraParameters::KEY_WHITE_BALANCE);這個可以得到目前白平衡的參數即返回值。然後根據返回值判斷是哪種情況,如
if (strcmp(white_balance, CameraParameters::WHITE_BALANCE_AUTO) == 0) { //判斷爲自動白平衡
LOGV("white_balance to ioctl is auto !/n");
ctl.id = V4L2_CID_AUTO_WHITE_BALANCE; //自動白平衡命令,ctl爲v4l2_control結構,該結構很有用
ctl.value = 1;
if (ioctl(camera_device, VIDIOC_S_CTRL, &ctl) < 0){ //通過 VIDIOC_S_CTRL把ctl結構體傳下去
LOGE("set control failed/n");
//return -1;
}
}else if(strcmp(white_balance, CameraParameters::WHITE_BALANCE_INCANDESCENT) == 0){ //白熾燈模式
LOGV("white_balance to ioctl is incandescent !/n");
ctl.id = V4L2_CID_DO_WHITE_BALANCE; //其它白平衡情況都用該命令
ctl.value = 2; //根據用戶自己定義的白平衡模式數目排列
if (ioctl(camera_device, VIDIOC_S_CTRL, &ctl) < 0){ //同樣通過 VIDIOC_S_CTRL把ctl結構體傳下去,然後在根據value值分情況討論
LOGE("set control failed/n");
//return -1;
}
}

傳到驅動的mxc_v4l2_capture.c文件的mxc_v4l_ioctl中,mxc_v4l_ioctl調用mxc_v4l_do_ioctl,mxc_v4l_do_ioctl對命令的解釋如下
/*!
* V4l2 VIDIOC_S_CTRL ioctl
*/
case VIDIOC_S_CTRL: {
pr_debug(" case VIDIOC_S_CTRL/n");
retval = mxc_v4l2_s_ctrl(cam, arg);
break;
}
這樣就到了mxc_v4l2_s_ctrl。在mxc_v4l2_s_ctrl通過對ctl.id分情況調用
switch (c->id) {
......
case V4L2_CID_AUTO_WHITE_BALANCE:
ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true);
ret = vidioc_int_s_ctrl(cam->sensor, c); //該函數是v4l2對應ov7670驅動中的s_ctl
ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false);
break;
case V4L2_CID_DO_WHITE_BALANCE:
ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, true, true);
ret = vidioc_int_s_ctrl(cam->sensor, c);
ipu_csi_enable_mclk_if(CSI_MCLK_I2C, cam->csi, false, false);
break;
......
其中vidioc_int_s_ctrl()是v4l2對應ov7670驅動中的 ioctl_s_ctrl,具體代碼怎麼對應由於篇幅原因就不貼出來。
根據ctl結構體的id分情況去實現即可。
switch (vc->id) {
.....
case V4L2_CID_AUTO_WHITE_BALANCE:
retval = ov7670_autowhitebalance(vc->value);
break;
case V4L2_CID_DO_WHITE_BALANCE:
retval = ov7670_dowhitebalance(vc->value);
break;
......
下面是whitebalance函數的實現
static int ov7670_autowhitebalance(int value)
{
unsigned char v = 0;
int ret;
printk("0v7670_autowhitebalance called/n");
ret = ov7670_read(ov7670_data.i2c_client, REG_COM8, &v);
if (value)
v |= COM8_AWB; //自動白平衡

msleep(10); /* FIXME */
ret += ov7670_write(ov7670_data.i2c_client, 0x01, 0x56);
ret += ov7670_write(ov7670_data.i2c_client, 0x02, 0x44);
ret += ov7670_write(ov7670_data.i2c_client, REG_COM8, v);

return ret; 
}

static int ov7670_dowhitebalance(int value)
{
unsigned char v = 0;
int ret;
printk("0v7670_dowhitebalance called value:%d/n",value);
ret = ov7670_read(ov7670_data.i2c_client, REG_COM8, &v);
if (value)
v &= ~COM8_AWB; //關閉自動白平衡

msleep(10); /* FIXME */
ret += ov7670_write(ov7670_data.i2c_client, REG_COM8, v);
if(value == 2) //INCANDESCENCE //這個值就是ctl的value值
{
ret += ov7670_write(ov7670_data.i2c_client, 0x01, 0x8c);
ret += ov7670_write(ov7670_data.i2c_client, 0x02, 0x59);
}else if(value == 3) //FLUORESCENT
{
ret += ov7670_write(ov7670_data.i2c_client, 0x01, 0x7e);
ret += ov7670_write(ov7670_data.i2c_client, 0x02, 0x49); 
}else if(value == 4) //DAYLIGHT
{
ret += ov7670_write(ov7670_data.i2c_client, 0x01, 0x52);
ret += ov7670_write(ov7670_data.i2c_client, 0x02, 0x66);
}

return ret; 
}
其中函數中ox01、0x02分別是藍紅通道的增益的寄存器。

上面是白平衡從hal層最終到sensor的參數設置過程。其它如色彩效果、取景模式等都是同樣的過程。
取景模式根據具體的情況如夜間模式等設定具體的寄存器即可
色彩效果主要通過設置uv的值實現的


轉自:http://blog.csdn.net/linphusen/article/details/6385236


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章