1.2Camera Preview流程及源碼分析

Camera API2的預覽實現在網上有非常多的代碼可以參考,包括Google官方提供的Demo。直接看代碼,模仿、改寫當然是最快的實現方式,但如果其中的邏輯關係可能沒有捋順清楚,在沒有參考代碼的情況下,能否同樣實現相關功能就值得商榷了。

 

1API2架構圖

這個圖是一個常見的用於展示API2架構的圖,但事實上這個圖並不能對架構和開發起到很好的幫助。這個圖的主要問題是無法搞清楚Camera APP與Camera Device之間到底是什麼邏輯關係。本文中,我將從類邏輯出發,逐步串起preview的全過程。

PS:想直接看結論的可以到最後看總結的部分,跳過中間的實現環節,和代碼分析。

一、Camera Manager類和open camera的方法

我們在上一節中說過,CameraManager是一個System Service,也就是Camera Service,Camera的軟件行爲都是發生在這個Service中的。所以當我們想要使用Camera、想要獲取Camera信息時,首先要獲取到CameraManager對象。2CameraManager類

Kotlin代碼

val manager = activity!!.getSystemService(Context.CAMERA_SERVICE) as CameraManager

此時,我們來詳細的看一下CameraManager類的屬性和方法,在圖2中可以看到有4個方法以openCamera開頭,區別僅僅是參數不同。此處選擇

方法,這個方法應該時使用頻率最高的一個open方法。

Kotlin代碼

manager.openCamera(mCameraId!!, mStateCallback, mBackgroundHandler)

源碼:

可以看到對內部直接調用了openCameraForUid方法,並且出現了CameraDeviceImpl類,這個類前面提到過是非公開API暫時不管,繼續查看該方法源碼。


 
該方法在進行了非空和異常處理之後調用了openCameraDeviceUserAsync方法。如果我們查看剩下的一個open方法,會發現也是調用的openCameraForUid方法。換言之,Camera的真正open方法只有一個,就是openCameraDeviceUserAsync()方法。

 
該方法的核心部分進行了一次API support的判斷,如果支持將進入HAL3.2以上通道;如果不支持將進入legacy HAL1通道。至此Camera open已    經完成,方法返回CameraDevice對象。
我們回溯到最初的方法。可以看到三個需要傳入的參數,除了第一個Camera id,還需要傳入一個CameraDevice.StateCallback對象。
如前所述,StateCallback是表示CameraDevice狀態的回調,分別對應已打開、已關閉、失去連接、出錯四種狀態。對於預覽來說,需要在onOpened方法中進行處理,並獲得CameraDevice對象。
二、CameraDevice類和創建會話
CameraDevice對象可以理解爲設備本身。

 

從提供的公開方法可以看出,CameraDevice的主要行爲就是創建不同作用的session,會話機制作爲API2中引入的新機制,是區別於API1的主要特點,關於session機制將在下一節專門進行分析。

首選我們選擇方法作爲創建session方法。

之所以選擇這個方法是因爲這個方法的第一個參數是Surface的List,而我們知道SurfaceVIew/TextureView/GLSurfaceView等都是我們通常用來顯示Preview的載體,很容易纔想到二者之間存在某種關係

Kotlin代碼

所以這個List的第一個值代表的就是SurfaceVIew的surface。這裏再多提一句第二個值是ImageReader的surface,第三個值一般是縮略圖的surface。

方法的第二個參數是StateCallback,不用於openCamera方法中的StateCallback,這裏是CameraCaptureSession的狀態回調。

內部的方法代表了會話的各種狀態,方法名一目瞭然不多做解釋了。

其中onConfigured()方法,即Camera配置完成的回調無疑就是我們處理後續邏輯的方法,在這個方法中我們將得到CameraDevice建立的session對象。

至此,在整個邏輯上就只有最後一步生成預覽。

三、生成預覽

在上一步我們得到了CameraCaptureSession對象。

可以看到用於拍照的capture方法,以及用於連續捕捉的方法。對於preview無疑是連續捕捉畫面,所以setRepeatingRequest方法就是我們所需要的方法。
Kotlin代碼

mCaptureSession!!.setRepeatingRequest(

mPreviewRequest!!,

mCaptureCallback, mBackgroundHandler
)

   方法中的第一個參數CaptureRequest就是用來表述要捕獲的單幅圖像的,所以通過配置CaptureRequest的參數,就完成了對preview畫面的配置,包括對焦、白平衡等配置,具體的配置將在後續章節中展開講解。

四、總結

在實現Camera Preview功能的過程中,通過層層推進的方式,我們可以看到API2的邏輯是:

  1. CameraManager管理CameraDevice
  2. CameraDevice管理CameraCaptureSession
  3. CameraDeviceCameraCaptureSession的狀態反饋到各自的StateCallback回調中,用戶需要實現的部分都在這些回調中。

https://upload-images.jianshu.io/upload_images/11656926-13401a0dbd6c039b.png?imageMogr2/auto-orient/

這裏給出一個完整的流程圖例。

 

經過分析後,再回頭看圖一,就會發現這個圖很有迷惑性,左側的APP是指實現了全部API的整個相機實現,而右側的Device是指實體硬件。

 

下一節將詳細分析API2 session機制。

附一:相機模型

https://source.android.google.cn/devices/camera/images/camera_model.png

附二:API 用途摘要

  1. 監聽和枚舉相機設備。
  2. 打開設備並連接監聽器。
  3. 配置目標使用情形的輸出(如靜態捕獲、錄製等)。
  4. 爲目標使用情形創建請求。
  5. 捕獲/重複請求和連拍。
  6. 接收結果元數據和圖片數據。
  7. 切換使用情形時,返回到第 3 步。

 

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