<menu id="ycqsw"></menu><nav id="ycqsw"><code id="ycqsw"></code></nav>
<dd id="ycqsw"><menu id="ycqsw"></menu></dd>
  • <nav id="ycqsw"></nav>
    <menu id="ycqsw"><strong id="ycqsw"></strong></menu>
    <xmp id="ycqsw"><nav id="ycqsw"></nav>
  • android網絡框架對比(自帶root權限的框架)


    這篇文章主要分下面幾點來展開講解:

    1) Android 最新Camera 整體框架;

    2) Android Camera2 和HAL3 的基本了解;

    3) Camera2 介紹;

    本文所寫的內容基于Android 9.0

    一、Android最新Camera 整體框架

    Android Camera整體框架主要包括三個進程: app進程 、 camera server進程hal進程(provider進程) 。進程之間的通信都是通過binder實現,其中app和camera server通信使用 AIDL (Android Interface Definition Language) ,camera server和hal(provider進程)通信使用 HIDL (HAL interface definition language) 。

    Android上面的框架分級,基本都是類似的,應用層-> framework層->Hal層,我們ps看下設備上實際的進程情況,如下圖所示,可以看到有cameraserver和provider進程。cameraservice是負責app和framework層的通信,而provider進程則是負責framework和hal層之間的通信。

    (附:

    Android 8.0重新設計了 Android 操作系統框架(在一個名為 “Treble” 的項目中),以便讓制造商能夠以更低的成本更輕松、更快速地將設備更新到新版 Android 系統。

    Android O之后使用Treble的架構,為了解決Android系統的碎片化問題和提高系統更新的效率,減少了framework 和HAL 的耦合性,進而引出了HIDL 的概念。

    HIDL 全稱為HAL interface definition language(發音為“hide-l”)是用于指定 HAL 和其用戶之間的接口的一種接口描述語言 (IDL)。

    HIDL 的目標是,框架可以在無需重新構建 HAL 的情況下進行替換。HAL 將由供應商或 SOC 制造商構建,放置在設備的 /vendor 分區中,這樣一來,框架就可以在其自己的分區中通過 OTA 進行替換,而無需重新編譯 HAL,這也是Project Treble框架設計而誕生的。)

    如下圖所示,展示了Android Camera的最新框架,我們先大概看下圖片流程,對整體框架有個基本了解。

    一篇文章帶你了解Android 最新Camera框架
    一篇文章帶你了解Android 最新Camera框架

    二、Android Camera2 和HAL3 的基本了解

    1) Camera2 接口什么時候開始引入的?

    Android 5.0 開始,Google 引入了一套全新的相機框架 Camera2(android.hardware.camera2)并且廢棄了舊的相機框架 Camera1(android.hardware.Camera) 。

    不了解的同學,可能會有疑問,為啥要廢棄Camera1接口?

    基本原因是,camera1接口過于簡單,沒法滿足更加復雜的相機應用場景。為了給應用層提供更多的相機控制權限,從而構建出更高質量的相機應用程序,Google才推出了Camera2 接口。

    下面可以看下和Camera1比較,Camera2有哪些高級特性。

    2)一些只有 Camera2 才支持的高級特性

    1. 在開啟相機之前檢查相機信息 出于某些原因,你可能需要先檢查相機信息再決定是否開啟相機,例如檢查閃光燈是否可用。在 Caemra1 上,你無法在開機相機之前檢查詳細的相機信息,因為這些信息都是通過一個已經開啟的相機實例提供的。在 Camera2 上,我們有了和相機實例完全剝離的 CameraCharacteristics 實例專門提供相機信息,所以我們可以在不開啟相機的前提下檢查幾乎所有的相機信息。 2. 在不開啟預覽的情況下拍照 在 Camera1 上,開啟預覽是一個很重要的環節,因為只有在開啟預覽之后才能進行拍照,因此即使顯示預覽畫面與實際業務需求相違背的時候,你也不得不開啟預覽。而 Camera2 則不強制要求你必須先開啟預覽才能拍照。 3. 一次拍攝多張不同格式和尺寸的圖片 在 Camera1 上,一次只能拍攝一張圖片,更不同談多張不同格式和尺寸的圖片了。而 Camera2 則支持一次拍攝多張圖片,甚至是多張格式和尺寸都不同的圖片。例如你可以同時拍攝一張 1440×1080 的 JPEG 圖片和一張全尺寸的 RAW 圖片。 4. 控制曝光時間 在暗環境下拍照的時候,如果能夠適當延長曝光時間,就可以讓圖像畫面的亮度得到提高。在 Camera2 上,你可以在規定的曝光時長范圍內配置拍照的曝光時間,從而實現拍攝長曝光圖片,你甚至可以延長每一幀預覽畫面的曝光時間讓整個預覽畫面在暗環境下也能保證一定的亮度。而在 Camera1 上你只能 YY 一下。 5. 連拍 連拍 30 張圖片這樣的功能在 Camera2 出現之前恐怕只有系統相機才能做到了(通過 OpenGL 截取預覽畫面的做法除外),也可能是出于這個原因,市面上的第三方相機無一例外都不支持連拍。有了 Camera2,你完全可以讓你的相機應用程序支持連拍功能,甚至是連續拍 30 張使用不同曝光時間的圖片。

    6. 靈活的 3A 控制 3A(AF、AE、AWB)的控制在 Camera2 上得到了最大化的放權,應用層可以根據業務需求靈活配置 3A 流程并且實時獲取 3A 狀態,而 Camera1 在 3A 的控制和監控方面提供的接口則要少了很多。例如你可以在拍照前進行 AE 操作,并且監聽本這次拍照是否點亮閃光燈。#####3)何為HAL3?為了配合Camera2 的使用,Android Hal層Camera框架也做了相對應的改動,也就是HAL3。Camera1接口對應的是調用的HAL1框架。

    3)一些概念

    關于Camera2 和Hal3,有些基本概念我們得了解下~

    我們先來看下Camera2 API涉及到哪些類,下面會對各個類的使用進行講解~~

    一篇文章帶你了解Android 最新Camera框架

    1) Pipeline

    Camera2 的 API 模型被設計成一個 Pipeline(管道),它按順序處理每一幀的請求并返回請求結果給客戶端。

    下面這張來自官方的圖展示了 Pipeline 的工作流程,我們會通過一個簡單的例子詳細解釋這張圖。

    一篇文章帶你了解Android 最新Camera框架

    為了解釋上面的示意圖,假設我們想要同時拍攝兩張不同尺寸的圖片,并且在拍攝的過程中閃光燈必須亮起來。整個拍攝流程如下:

    1.創建一個用于從 Pipeline 獲取圖片的 CaptureRequest。2.修改 CaptureRequest 的閃光燈配置,讓閃光燈在拍照過程中亮起來。3.創建兩個不同尺寸的 Surface 用于接收圖片數據,并且將它們添加到 CaptureRequest 中。4.發送配置好的 CaptureRequest 到 Pipeline 中等待它返回拍照結果。

    一個新的 CaptureRequest 會被放入一個被稱作 Pending Request Queue 的隊列中等待被執行,當 In-Flight Capture Queue 隊列空閑的時候就會從 Pending Request Queue 獲取若干個待處理的 CaptureRequest,并且根據每一個 CaptureRequest 的配置進行 Capture 操作。最后我們從不同尺寸的 Surface 中獲取圖片數據并且還會得到一個包含了很多與本次拍照相關的信息的 CaptureResult,流程結束。

    2 )Supported Hardware Level

    相機功能的強大與否和硬件息息相關,不同廠商對 Camera2 的支持程度也不同,所以 Camera2 定義了一個叫做 Supported Hardware Level 的重要概念,其作用是將不同設備上的 Camera2 根據功能的支持情況劃分成多個不同級別以便開發者能夠大概了解當前設備上 Camera2 的支持情況。

    截止到 Android P 為止,從低到高一共有 LEGACY、LIMITED、FULL 和 LEVEL_3 四個級別:

    1. LEGACY :向后兼容的級別,處于該級別的設備意味著它只支持 Camera1 的功能,不具備任何 Camera2 高級特性。2. LIMITED :除了支持 Camera1 的基礎功能之外,還支持部分 Camera2 高級特性的級別。3. FULL :支持所有 Camera2 的高級特性。4. LEVEL_3 :新增更多 Camera2 高級特性,例如 YUV 數據的后處理等。

    3 )Capture

    相機的所有操作和參數配置最終都是服務于圖像捕獲,例如對焦是為了讓某一個區域的圖像更加清晰,調節曝光補償是為了調節圖像的亮度。因此,在 Camera2 里面所有的相機操作和參數配置都被抽象成 Capture(捕獲),所以不要簡單的把 Capture 直接理解成是拍照,因為 Capture 操作可能僅僅是為了讓預覽畫面更清晰而進行對焦而已。如果你熟悉 Camera1,那你可能會問 setFlashMode() 在哪? setFocusMode() 在哪? takePicture() 在哪?

    告訴你,它們都是通過 Capture 來實現的。

    Capture 從執行方式上又被細分為 單次模式、多次模式 和 重復模式三種,我們來一一解釋下:

    ? 單次模式(One-shot) :指的是只執行一次的 Capture 操作,例如設置閃光燈模式、對焦模式和拍一張照片等。多個一次性模式的 Capture 會進入隊列按順序執行。 ? 多次模式(Burst) :指的是連續多次執行指定的 Capture 操作,該模式和多次執行單次模式的最大區別是連續多次 Capture 期間不允許插入其他任何 Capture 操作,例如連續拍攝 100 張照片,在拍攝這 100 張照片期間任何新的 Capture 請求都會排隊等待,直到拍完 100 張照片。多組多次模式的 Capture 會進入隊列按順序執行。 ? 重復模式(Repeating) :指的是不斷重復執行指定的 Capture 操作,當有其他模式的 Capture 提交時會暫停該模式,轉而執行其他被模式的 Capture,當其他模式的 Capture 執行完畢后又會自動恢復繼續執行該模式的 Capture,例如顯示預覽畫面就是不斷 Capture 獲取每一幀畫面。該模式的 Capture 是全局唯一的,也就是新提交的重復模式 Capture 會覆蓋舊的重復模式 Capture。

    我們舉個例子來進一步說明上面三種模式,假設我們的相機應用程序開啟了預覽,所以會提交一個重復模式的 Capture 用于不斷獲取預覽畫面,然后我們提交一個單次模式的 Capture,接著我們又提交了一組連續三次的多次模式的 Capture,這些不同模式的 Capture 會按照下圖所示被執行:

    一篇文章帶你了解Android 最新Camera框架

    下面是幾個重要的注意事項:

    1.無論 Capture 以何種模式被提交,它們都是按順序串行執行的,不存在并行執行的情況。2.重復模式是一個比較特殊的模式,因為它會保留我們提交的 CaptureRequest 對象用于不斷重復執行 Capture 操作,所以大多數情況下重復模式的 CaptureRequest 和其他模式的 CaptureRequest 是獨立的,這就會導致重復模式的參數和其他模式的參數會有一定的差異,例如重復模式不會配置
    CaptureRequest.AF_TRIGGER_START ,因為這會導致相機不斷觸發對焦的操作。3.如果某一次的 Capture 沒有配置預覽的 Surface,例如拍照的時候,就會導致本次 Capture 不會將畫面輸出到預覽的 Surface 上,進而導致預覽畫面卡頓的情況,所以大部分情況下我們都會將預覽的 Surface 添加到所有的 CaptureRequest 里。

    4) CameraManager

    CameraManager 是一個負責查詢和建立相機連接的系統服務,它的功能不多,這里列出幾個 CameraManager 的關鍵功能:

    1.將相機信息封裝到 CameraCharacteristics 中,并提獲取 CameraCharacteristics 實例的方式。2.根據指定的相機 ID 連接相機設備。3.提供將閃光燈設置成手電筒模式的快捷方式。

    5 )CameraCharacteristics

    CameraCharacteristics 是一個只讀的相機信息提供者,其內部攜帶大量的相機信息,包括代表相機朝向的 LENS_FACING ;判斷閃光燈是否可用的 FLASH_INFO_AVAILABLE ;獲取所有可用 AE 模式的
    CONTROL_AE_AVAILABLE_MODES 等等。

    如果你對 Camera1 比較熟悉,那么 CameraCharacteristics 有點像 Camera1 的 Camera.CameraInfo 或者 Camera.Parameters 。

    6 ) CameraDevice

    CameraDevice 代表當前連接的相機設備,它的職責有以下四個:

    1.根據指定的參數創建 CameraCaptureSession。2.根據指定的模板創建 CaptureRequest。3.關閉相機設備。4.監聽相機設備的狀態,例如斷開連接、開啟成功和開啟失敗等。

    熟悉 Camera1 的人可能會說 CameraDevice 就是 Camera1 的 Camera 類,實則不是,Camera 類幾乎負責了所有相機的操作,而 CameraDevice 的功能則十分的單一,就是只負責建立相機連接的事務,而更加細化的相機操作則交給了稍后會介紹的 CameraCaptureSession。

    7) Surface

    Surface 是一塊用于填充圖像數據的內存空間,例如你可以使用 SurfaceView 的 Surface 接收每一幀預覽數據用于顯示預覽畫面,也可以使用 ImageReader 的 Surface 接收 JPEG 或 YUV 數據。每一個 Surface 都可以有自己的尺寸和數據格式,你可以從 CameraCharacteristics 獲取某一個數據格式支持的尺寸列表。

    8) CameraCaptureSession

    CameraCaptureSession 實際上就是配置了目標 Surface 的 Pipeline 實例,我們在使用相機功能之前必須先創建 CameraCaptureSession 實例。一個 CameraDevice 一次只能開啟一個 CameraCaptureSession,絕大部分的相機操作都是通過向 CameraCaptureSession 提交一個 Capture 請求實現的,例如拍照、連拍、設置閃光燈模式、觸摸對焦、顯示預覽畫面等等。

    9 ) CaptureRequest

    CaptureRequest 是向 CameraCaptureSession 提交 Capture 請求時的信息載體,其內部包括了本次 Capture 的參數配置和接收圖像數據的 Surface。CaptureRequest 可以配置的信息非常多,包括圖像格式、圖像分辨率、傳感器控制、閃光燈控制、3A 控制等等,可以說絕大部分的相機參數都是通過 CaptureRequest 配置的。

    值得注意的是每一個 CaptureRequest 表示一幀畫面的操作,這意味著你可以精確控制每一幀的 Capture 操作。

    10) CaptureResult

    CaptureResult 是每一次 Capture 操作的結果,里面包括了很多狀態信息,包括閃光燈狀態、對焦狀態、時間戳等等。

    例如你可以在拍照完成的時候,通過 CaptureResult 獲取本次拍照時的對焦狀態和時間戳。

    需要注意的是,CaptureResult 并不包含任何圖像數據,前面我們在介紹 Surface 的時候說了,圖像數據都是從 Surface 獲取的。

    11) Request的整體處理流程

    一篇文章帶你了解Android 最新Camera框架

    三、 代碼實戰:如何拍攝單張照片

    拍攝單張照片是最簡單的拍照模式,它使用的就是 單次模式 的 Capture,我們會使用 ImageReader 創建一個接收照片的 Surface,并且把它添加到 CaptureRequest 里提交給相機進行拍照,最后通過 ImageReader 的回調獲取 Image 對象,進而獲取 JPEG 圖像數據進行保存。

    1) 定義回調接口

    當拍照完成的時候我們會得到兩個數據對象,一個是通過 onImageAvailable() 回調給我們的存儲圖像數據的 Image,一個是通過 onCaptureCompleted() 回調給我們的存儲拍照信息的 CaptureResult,它們是一一對應的,所以我們定義了如下兩個回調接口:

    private val captureResults: BlockingQueue<CaptureResult> = LinkedBlockingDeque()
    
    
    private inner class CaptureImageStateCallback : CameraCaptureSession.CaptureCallback() {
        @MainThread
        override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) {
            super.onCaptureCompleted(session, request, result)
            captureResults.put(result)
        }
    }
    
    
    private inner class OnJpegImageAvailableListener : ImageReader.OnImageAvailableListener {
        @WorkerThread
        override fun onImageAvailable(imageReader: ImageReader) {
            val image = imageReader.acquireNextImage()
            val captureResult = captureResults.take()
            if (image != null && captureResult != null) {
                // Save image into sdcard.
            }
        }
    }
    
    
    

    2) 創建 ImageReader

    創建 ImageReader 需要我們指定照片的大小,所以首先我們要獲取支持的照片尺寸列表,并且從中篩選出合適的尺寸,假設我們要求照片的尺寸最大不能超過 4032×3024,并且比例必須是 4:3,所以會有如下篩選尺寸的代碼片段:

    @WorkerThread
    private fun getOptimalSize(cameraCharacteristics: CameraCharacteristics, clazz: Class<*>, maxWidth: Int, maxHeight: Int): Size? {
        val streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
        val supportedSizes = streamConfigurationMap?.getOutputSizes(clazz)
        return getOptimalSize(supportedSizes, maxWidth, maxHeight)
    }
    
    
    @AnyThread
    private fun getOptimalSize(supportedSizes: Array<Size>?, maxWidth: Int, maxHeight: Int): Size? {
        val aspectRatio = maxWidth.toFloat() / maxHeight
        if (supportedSizes != null) {
            for (size in supportedSizes) {
                if (size.width.toFloat() / size.height == aspectRatio && size.height <= maxHeight && size.width <= maxWidth) {
                    return size
                }
            }
        }
        return null
    }
    

    接著我們就可以篩選出合適的尺寸,然后創建一個圖像格式是 JPEG 的 ImageReader 對象,并且獲取它的 Surface:

    val imageSize = getOptimalSize(cameraCharacteristics, ImageReader::class.java, maxWidth, maxHeight)!!
    jpegImageReader = ImageReader.newInstance(imageSize.width, imageSize.height, ImageFormat.JPEG, 5)
    jpegImageReader?.setOnImageAvailableListener(OnJpegImageAvailableListener(), cameraHandler)
    jpegSurface = jpegImageReader?.surface
    
    
    

    3) 創建 CaptureRequest

    接下來我們使用 TEMPLATE_STILL_CAPTURE 模板創建一個用于拍照的 CaptureRequest.Builder 對象,并且添加拍照的 Surface 和預覽的 Surface 到其中:

    captureImageRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
    captureImageRequestBuilder.addTarget(previewDataSurface)
    captureImageRequestBuilder.addTarget(jpegSurface)
    
    
    

    版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。

    發表評論

    登錄后才能評論
    国产精品区一区二区免费