AndroidCameraHAL3-MultiCamera-CameraX

CameraX 是一個 Jetpack 支持包之一,據官網介紹主要目的就是爲了編寫 camera APP 更加簡單高效,該模塊提供了一個一致的、高效的編程 API,可以在左右的 Android 設備上面使用,並且向後兼容到 Android 5.0(API 21)。雖然 CameraX 使用的還是 camera2 的接口,但是它通過封裝提供了一個更加簡單的、基於用例的生命週期追蹤的封裝接口。並且這層封裝還把設備相關的代碼隱藏了起來,這部分全部交給 CameraX 來完成,用戶就不用再去添加設備兼容性相關的代碼到自己的工程代碼裏面了,這可以減少很多的代碼量。

CameraX 可以提供和系統預裝相機類似的功能給到三方的 Camera APP,這個是一個非常大的提升了,據介紹兩行代碼就可以完成基本的功能了,怕不怕。此外還可以通過 CameraX Extensions 來添加一些設備支持的其它功能,比如說:人像模式、HDR、夜景模式、美顏等等。本文就簡單介紹下 CameraX 的一些概念性的東西。

文檔參考:

  1. https://developer.android.google.cn/training/camerax/architecture
  2. https://developer.android.google.cn/training/camerax
  3. https://source.android.google.cn/devices/camera/camerax-vendor-extensions

CameraX 帶來的主要提升

CameraX 使開發變得更加方便,CameraX 是基於用例的,也就是說可以不用過度注意細節,把更多的精力放在業務邏輯上面,而不是業務邏輯底層的東西,CameraX 區分了幾個基本的用例模式:

  1. Preview:用於預覽,也就是說這裏獲取到的圖片都是拿來預覽顯示的。
  2. Image analysis:可以讓算法模塊直接訪問到相關的 image buffer 並用於數據處理以及分析,比如可以直接傳遞給 MLkit 模塊進行處理。
  3. Image capture:高質量圖片抓取。

從 Android 5.0(API 21)往後的版本,CameraX 保證了其都擁有共同的 camera 行爲,所有的設備上面都可以保持一致。在不同的設備上面保持行爲一致是比較難得一件事情,和 IOS 設備不一樣,Android 設備歷史包袱太重了,市場上面硬件設備五花八門,下面的幾個點都是會影響到一致性的:圖像比例、原點、旋轉、預覽圖像寬高以及高分辨率圖片,在 CameraX 的加持下,這些都是可以搞定的,聽起來很厲害。

使用 CameraX Extension 可以獲得和 Native APP 差不多的相機能力,只需要兩句代碼即可完成,上面也提到過這部分可以支持的特性,這裏就不在贅述了。

CameraX 的基本架構

這部分涉及到甚多的 APP 層級代碼,本文不是非常關心這部分,所以就會抽出一點理論性的東西介紹,代碼什麼的就直接看官方文檔就可以了,在開頭也列出來了。

首先 CameraX 是用於更方便使用 Camera API2 的 JetPack 擴展,其將整個 Camera API2 整合成了:Preview、Image analysis、Image capture 三個大的類別。開發者可以使用其中一個或者同時使用多個功能組成自己的 APP 用例。要想使用這個 Lib,需要指定下面幾個項目類別:

  • 期望的 use case,這部分是可以配置的
  • 用指定的 listener 來表明自己用獲取到的輸出做什麼用途
  • 綁定到 Android Architecture Lifecycles 來實現自動化的生命週期管理

使用 set() 來配置一個 use case,然後使用 build() 完成構建,每一個用例都有一組特定的 API,比如對於 Image capture 來說就會提供 takePicture() API 來進行拍照動作。CameraX 使用生命週期管理框架來代替 onResumeonPause,使用 cameraProvider.bindToLifecycle 來綁定相應的 lifecycle 管理框架,一個示例代碼如下:

val preview = Preview.Builder().build()
val viewFinder: PreviewView = findViewById(R.id.previewView)

// The use case is bound to an Android Lifecycle with the following code
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// PreviewView creates a surface provider and is the recommended provider
preview.setSurfaceProvider(viewFinder.createSurfaceProvider(camera.cameraInfo))

關於更多生命週期相關的代碼以及使用介紹可以參考這裏:https://developer.android.google.cn/training/camerax/architecture#lifecycles。其餘還有併發 use case 等等的介紹,也可以參照鏈接裏面的頁面瞭解,這裏就不再多說了。並且對於每一種 use case 用例的實現,鏈接裏面也給出了相對應的子鏈接,可以參考其代碼實現。

CameraX Extension

CameraX 提供了 bokeh、HDR 以及其它的效果接口,這些如果手機硬件廠商有實現的話就可以套接到這個接口上面。對於想要支持 vendor extension 的設備來說,下面的幾個點是需要的(如果一個設備支持這些的話就可以優先啓用這些擴展來支持更加靈活強大的功能項):

  • OEM 設備提供了相關效果的庫包
  • OEM 庫在當前設備上面有安裝上去
  • OEM 庫也需要通過某種方式 report 出來,說我這個支持對應的效果擴展
  • 操作系統版本要對應,這裏安卓 5.0 以後的應該都是可以的

對於終端設備來講,也並不是一定得要提供這些特性,對於沒有實現的,會跳過這部分就當做不支持。有些設備可能別的都有,但是缺少 OTA 升級的庫包,或者是單純版本對不上,這些情況都是無法真正支持的。下面的圖片也展示了 CameraX 的擴展結構:
在這裏插入圖片描述
可以看到 OEM Vendor lib 連接了 Camera2 以及 Extensions 兩個模塊,最主要的 data flow 是在 OEM Vendor lib 和 Extension 之間以及 Extension 和 CameraX core 之間的。如果需要應用 vendor extension 的話,需要創建一個 Extender 對象,可以通過這個對象設置 Builder,並且可以配置相關效果的設置。在使用的時候也需要先通過接口查詢擴展項是否可用,因爲如果擴展項處於不可用狀態的話,enableExtension() 調用就是無效的,啥都不做。在 ImageCapture 模式下啓用擴展的時候可能會限制可選的 camera 數量,在這個用例下使用 bindToLifecycle() 來綁定生命週期管理框架的時候,如果沒有發現有支持這個擴展的 camera 的話,就會丟出一個異常。下面的代碼給了一個 image capture 用例的示範:

import androidx.camera.extensions.BokehExtender

fun onCreate() {
    // Create a Builder same as in normal workflow.
    val builder = ImageCapture.Builder()

    // Create a camera provider
    val cameraProvider : ProcessCameraProvider = ... // Get the provider instance

    // Create an Extender object which can be used to apply extension
    // configurations.
    val bokehImageCapture = BokehImageCaptureExtender.create(builder)

    // Select the camera
    val cameraSelector = CameraSelector.Builder()
                                       .requireLensFacing(CameraX.LensFacing.BACK)
                                       .build()

    // Query if extension is available (optional).
    if (bokehImageCapture.isExtensionAvailable()) {
        // Enable the extension if available.
        bokehImageCapture.enableExtension()
    }

    // Finish constructing configuration with the same flow as when not using
    // extensions.
    val useCase = ImageCapture.Builder().build()
    cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCase)
}

下面的圖是一個 Vendor 擴展結構圖:
在這裏插入圖片描述
三方的 APP 構建在 CameraX 擴展 lib 上面,通過 androidx.camera.extensions 接口 API 進行通信,再下層一點的 extensions-interface 也是由 CameraX 定義的,用於 CameraX 和 Vendor lib 進行交互,對於 Vendor 來說,必須要實現對應版本的接口。下面會通過人像模式的 Vendor 實現來進行一個簡介,其它的模式實現也都是可以通過這個來進行推導實現。對於 Vendor 來說,不必要每一個都要實現,對於沒有實現的效果來說,CameraX 會報告三方 APP 說我不支持就完事兒了,因爲三方 APP 使用的原因,Vendor 實現的 lib 不應該有任何特殊的權限控制,不然三方就直接用不了了。

CameraX 在最開始的時候會檢查 Vendor lib 的版本號看是否兼容,檢查只包括主版本號和次版本號,比如 1.1,再後面的就當做是補丁號了,僅僅做一些 bug fix,不會改變接口。CameraX 會通過 ExtensionVersionImpl 接口來進行版本號校驗。當 CameraX 決定好使用的版本號之後,InitializerImpl.init 方法就會被調用表明 APP 想要進行一些初始化動作,並且會一直等到 OnExtensionsInitializedCallback 返回成功之後纔會進行其它的調用。

有關於 CameraX 擴展的這部分在:https://source.android.google.cn/devices/camera/camerax-vendor-extensions 這裏可以找到相關的實現描述,由於這部分是與 framework 相關性較大,這裏也就不做深入探索了,目前來講對我來說知道有這麼一個玩意兒就行了,用到時再去細究,不然記了也是白記,很快就忘掉了。

End

這裏爲止,Android Camera 的大概結構介紹就告一段落了,我覺得基本上差不多該提及的都有提到了,本系列也不是入門系列,有一定基礎的話看起來會更加順暢一點,零基礎的我這個就很不適合看,會有一臉懵的感覺。接下來如果還更新 Android Camera 的話可能就會更新一些與內部設計結構相關的東西,這部分短時間內並不打算寫出來,因爲我覺得這部分比較抽象理論,而且很進階,不好寫,就算寫出來大概率也是一個月一篇的樣子,emmm,恰逢公衆號和 CSDN 博客都有新開了付費閱讀功能,這麼老大勁寫出來的估計會試用一波付費閱讀。

後面應該會寫一寫 C++ 語言相關的東西,比較接近基礎,這部分其實大部分都可以找到通用學習文章,但是我並不打算因此不寫這部分內容,我就權當做自己學習 C++ 所做的筆記吧,當然會融入一些自我的思考,不然就是流水賬,顯得毫毫毫毫無技術含量了,穿插着應該會有一些數據結構與算法的內容,再夯實一下基礎吧。目前個人的技能點就分了下面幾個大的方面:

  1. 基礎數據結構與算法
  2. 基礎語言 C/C++ 編程(這個與上面一個都是比較通用的玩意兒,基本上網絡上面的文章都是鋪天蓋地的,當然極度硬核的還是不是特別的多)
  3. 視頻流數據管理、處理、分發框架(這部分有很多很多很多可以說的細節,算是比較硬核的一個點了,屬於你網上都找不到太多資料的那種)
  4. 基本嵌入式視覺處理(視頻防抖相關的技術族,包括但不限於圖像插值、二維數據濾波、圖像的投影變換、線性代數在圖像幾何的應用等等等等)

不得不說,現在工程細分的太深入了,當然也是因爲產品質量的不斷提高與客戶需求的不斷提升導致的,以前都是囫圇圇差不多做出來就完事兒了,現在不行,你不僅要做出來,還得穩定、效果好,這就使得越來越多的細節加入到具體的模塊處理當中,導致不斷的模塊細分。咱就說防抖這一個,裏面就能分出一個 10~20 人左右的團隊來,每個人專門去做具體的某一塊。這麼龐大的技術細節,讓我也不知道如何取捨,目前就希望不斷地夯實上面四個技術點,然後有機會的話再去延伸其它的點感覺技術生涯前 8~10 年差不多就可以僵在這幾個點上面了,後面可能不用再去關注那麼多細節了,更多地會是注重整體結構性設計,不過走着看着吧,太遠的未來終歸是無法確定。


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