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的邏輯是:
- CameraManager管理CameraDevice
- CameraDevice管理CameraCaptureSession
- CameraDevice、CameraCaptureSession的狀態反饋到各自的StateCallback回調中,用戶需要實現的部分都在這些回調中。
這裏給出一個完整的流程圖例。
經過分析後,再回頭看圖一,就會發現這個圖很有迷惑性,左側的APP是指實現了全部API的整個相機實現,而右側的Device是指實體硬件。
下一節將詳細分析API2 session機制。
附一:相機模型
附二:API 用途摘要
- 監聽和枚舉相機設備。
- 打開設備並連接監聽器。
- 配置目標使用情形的輸出(如靜態捕獲、錄製等)。
- 爲目標使用情形創建請求。
- 捕獲/重複請求和連拍。
- 接收結果元數據和圖片數據。
- 切換使用情形時,返回到第 3 步。