camera2 簡(jiǎn)單總結(jié)

寫在開頭:本文為學(xué)習(xí) camera2 過程中的知識(shí)點(diǎn)歸納總結(jié)。

1. camera2 相機(jī)體系結(jié)構(gòu)

https://blog.csdn.net/u012596975/article/details/107136568

https://blog.csdn.net/u012596975/article/details/107138177
對(duì)于Camera Api v2的實(shí)現(xiàn),是通過Camera Framework來完成的,而該層也有著一次不小的演變,剛開始Framework層并不是直接通過AIDL接口與Camera Service進(jìn)行通信,而是通過一個(gè)JNI層來完成從Java到Native的轉(zhuǎn)換,而Native部分作為客戶端,保持對(duì)Service的通信。這種設(shè)計(jì),很顯然會(huì)比較臃腫,并且代碼難以維護(hù),所以之后由于AIDL接口的提出,谷歌直接將其加入到相機(jī)框架中,用于保持Framework與Service的通信,進(jìn)而擯棄了JNI層,進(jìn)一步減少了不必要的層級(jí)結(jié)構(gòu),保持了整個(gè)體系簡(jiǎn)潔性。

更多可參考 深入理解Android相機(jī)體系結(jié)構(gòu) 系列。

2. camera1和camera2的使用簡(jiǎn)單對(duì)比

先回顧一下,camera1和camera2的簡(jiǎn)單使用。
這兩篇camera1和camera2的預(yù)覽demo,十分簡(jiǎn)潔,功能單一,可供對(duì)比。
Android Camera1最簡(jiǎn)單的預(yù)覽框顯示
Android Camera2最簡(jiǎn)單的預(yù)覽框顯示

下面這兩張思維導(dǎo)圖,較為詳細(xì)得說明了camera的使用流程和API。這不是本篇的重點(diǎn)。


http://m.itdecent.cn/p/f63f296a920b
http://m.itdecent.cn/p/f63f296a920b

camera1 的 open 簡(jiǎn)單代碼流程可參考這篇:
Android Camera open 從上到下代碼流程
camera2 的 open 簡(jiǎn)單代碼流程可參考這篇:
Android CameraManager open 從上到下代碼流程

如果需要更詳細(xì)的demo,可參考官方的 demo:cameraview

camera1和camera2 的調(diào)用流程對(duì)比,可參考這張圖??梢钥吹?API V2是沒有通過JNI的api的,這里是直接調(diào)用的service。


https://source.android.google.cn/docs/core/camera

https://blog.csdn.net/u012596975/article/details/107137110

谷歌在Andorid 5.0(API Level 21)便重新對(duì)Camera進(jìn)行了設(shè)計(jì),摒棄了Camera Api v1的設(shè)計(jì)邏輯,提出了一個(gè)全新的API – camera2,引入了Session以及Request概念,將控制邏輯統(tǒng)一成一個(gè)視圖,因此在使用上更加復(fù)雜,同時(shí)也支持了更多特性,比如逐幀控制曝光、感光度以及支持Raw格式的輸出等。并且由于對(duì)控制邏輯的高度抽象化,使得該接口具有很高的靈活性,可以通過簡(jiǎn)單的操作實(shí)現(xiàn)30fps的全高清連拍的功能,總得來說,該接口極大地提高了對(duì)于相機(jī)框架的控制能力,同時(shí)也進(jìn)一步大幅度提升了其整體性能。
camera2的應(yīng)用層與framework層之間的流程如下:


https://blog.csdn.net/u012596975/article/details/107137110

簡(jiǎn)單來說就是,引入了Session以及Request,使用更加復(fù)雜,功能多,更加靈活了。

注意,雖然新增了camera2的api,camera1的代碼依然在android源碼中。分析的時(shí)候要注意。
frameworks/base/core/java/android/hardware/camera2/這個(gè)目錄下的是camera2的framework層代碼。

Camera整體架構(gòu)簡(jiǎn)述


https://blog.csdn.net/TaylorPotter/article/details/105387109

忽略掉驅(qū)動(dòng)層,就是這張圖。


https://source.android.google.cn/docs/core/camera

了解完Android Camera工作大體流程后,來看看部分細(xì)節(jié)。

2. 源碼簡(jiǎn)單分析

本篇源碼分析,不會(huì)涉及驅(qū)動(dòng)層及以下(最多一點(diǎn)點(diǎn))。另由于MTK和高通camera,還有android原生的,在camera這塊差異很大,流程分析查找資料的時(shí)候要注意下。

Android Camera工作大體流程:


https://blog.csdn.net/TaylorPotter/article/details/105387109

出處: https://blog.csdn.net/TaylorPotter/article/details/105387109
綠色框中是應(yīng)用開發(fā)者需要做的操作,藍(lán)色為AOSP提供的API,黃色為Native Framework Service,紫色為HAL層Service.
描述一下步驟:

  • 1.App一般在MainActivity中使用SurfaceView或者SurfaceTexture + TextureView或者GLSurfaceView等控件作為顯示預(yù)覽界面的控件,共同點(diǎn)都是包含了一個(gè)單獨(dú)的Surface作為取相機(jī)數(shù)據(jù)的容器.
  • 2.在MainActivity onCreate的時(shí)候調(diào)用API 去通知Framework Native Service CameraServer去connect HAL繼而打開Camera硬件sensor.
  • 3.openCamera成功會(huì)有回調(diào)從CameraServer通知到App,在onOpenedCamera或類似回調(diào)中去調(diào)用類似startPreview的操作.此時(shí)會(huì)創(chuàng)建CameraCaptureSession,創(chuàng)建過程中會(huì)向CameraServer調(diào)用ConfigureStream的操作,ConfigureStream的參數(shù)中包含了第一步中空間中的Surface的引用,相當(dāng)于App將Surface容器給到了CameraServer,CameraServer包裝了下該Surface容器為stream,通過HIDL傳遞給HAL,繼而HAL也做configureStream操作
  • 4.ConfigureStream成功后CameraServer會(huì)給App回調(diào)通知ConfigStream成功,接下來App便會(huì)調(diào)用AOSP setRepeatingRequest接口給到CameraServer,CameraServer初始化時(shí)便起來了一個(gè)死循環(huán)線程等待來接收Request.
  • 5.CameraServer將request交到Hal層去處理,得到HAL處理結(jié)果后取出該Request的處理Result中的Buffer填到App給到的容器中,
    SetRepeatingRequest 為了預(yù)覽,則交給Preview的Surface容器,如果是Capture Request則將收到的Buffer交給ImageReader的Surface容器.
  • 6.Surface本質(zhì)上是BufferQueue的使用者和封裝者,當(dāng)CameraServer中App設(shè)置來的Surface容器被填滿了BufferQueue機(jī)制將會(huì)通知到應(yīng)用,此時(shí)App中控件取出各自容器中的內(nèi)容消費(fèi)掉,Preview控件中的Surface中的內(nèi)容將通過View提供到SurfaceFlinger中進(jìn)行合成最終顯示出來,即預(yù)覽;而ImageReader中的Surface被填了,則App將會(huì)取出保存成圖片文件消費(fèi)掉.

簡(jiǎn)單圖如下:


https://blog.csdn.net/TaylorPotter/article/details/105387109

https://blog.csdn.net/TaylorPotter/article/details/105387109
通過AIDL binder調(diào)用向Framework層的CameraServer進(jìn)程下指令,從CameraServer進(jìn)程中取的數(shù)據(jù).
基本過程都如下:

  • 1.openCamera:Sensor上電
  • 2.configureStream: 該步就是將控件如GLSurfaceView,ImageReader等中的Surface容器給到CameraServer.
  • 3.request: 預(yù)覽使用SetRepeatingRequest,拍一張可以使用Capture,本質(zhì)都是setRequest給到CameraServer
  • 4.CameraServer將Request的處理結(jié)果Buffer數(shù)據(jù)填到對(duì)應(yīng)的Surface容器中,填完后由BufferQueue機(jī)制回調(diào)到引用層對(duì)應(yīng)的Surface控件的CallBack處理函數(shù),接下來要顯示預(yù)覽或保圖片App中對(duì)應(yīng)的Surface中都有數(shù)據(jù)了

著重看看以下幾點(diǎn)

  • CameraService和CameraProvider服務(wù)啟動(dòng)
  • open
  • configure
  • request

2.1 CameraService和CameraProvider服務(wù)啟動(dòng)

層級(jí)架構(gòu)概覽


https://blog.csdn.net/weixin_41678668/article/details/88620265

總體邏輯順序計(jì)
(1) CameraProvider進(jìn)程啟動(dòng)、注冊(cè)
(2) CameraServer進(jìn)程啟動(dòng)、注冊(cè)、初始化
(3) CameraServer初始化過程中通過HIDL通信獲取CameraProvider,并對(duì) CameraProvider進(jìn)行初始化

CameraService和CameraProvider初始化


https://blog.csdn.net/qq_16775897/article/details/81240600

CameraServer初始化


https://blog.csdn.net/TaylorPotter/article/details/105387109

具體代碼流程可參考:
Android 8.1 Camera2架構(gòu)解析(1) CameraService和CameraProvider服務(wù)啟動(dòng)流程
[Android O] Camera 服務(wù)啟動(dòng)流程簡(jiǎn)析

2.2 open

可直接參考這篇:

camera framework open流程
有道筆記上排版更好。
camera2 open流程

最后來張時(shí)序圖加深下印象。


https://blog.csdn.net/TaylorPotter/article/details/105387109

2.3 configure

以下代碼出自這篇Android Camera2最簡(jiǎn)單的預(yù)覽框顯示

/**
     * 打開相機(jī),預(yù)覽是在回調(diào)里面執(zhí)行的。
     */
    private void openCamera() {
        try {
            // 4.權(quán)限檢查
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                    != PackageManager.PERMISSION_GRANTED) {
                requestCameraPermission();
                return;
            }

            // 5.真正打開相機(jī)
            Log.i(TAG, "openCamera");
            mCameraManager.openCamera(mCameraId, mStateCallback, null);
        } catch (CameraAccessException e) {
            Log.e(TAG, "openCamera error = " + e.getMessage());
        }

     /**
     * 相機(jī)狀態(tài)監(jiān)聽對(duì)象
     */
    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice camera) {
            Log.i(TAG, "StateCallback! onOpened");
            mCameraDevice = camera; // 打開成功,保存代表相機(jī)的CameraDevice實(shí)例
            SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
            surfaceTexture.setDefaultBufferSize(mTextureView.getWidth(), mTextureView.getHeight());
            Surface surface = new Surface(surfaceTexture);
            ArrayList<Surface> previewList = new ArrayList<>();
            previewList.add(surface);
            try {
                // 6.將TextureView的surface傳遞給CameraDevice
                mCameraDevice.createCaptureSession(previewList, new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession session) {
                        try {
                            CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                            builder.addTarget(surface); // 必須設(shè)置才能正常預(yù)覽
                            CaptureRequest captureRequest = builder.build();

                            // 7.CameraCaptureSession與CaptureRequest綁定(這是最后一步,已可顯示相機(jī)預(yù)覽)
                            session.setRepeatingRequest(captureRequest, mSessionCaptureCallback, null);
                        } catch (CameraAccessException e) {
                            Log.e(TAG, "createCaptureRequest error = " + e.getMessage());
                        }
                    }

                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                        Log.e(TAG, "onConfigureFailed");
                    }
                }, null);
            } catch (CameraAccessException e) {
                Log.e(TAG, "createCaptureSession error = " + e.getMessage());
            }
        }


應(yīng)用層在openCamera之后,會(huì)調(diào)用createCaptureSession。


image.png

createCaptureSession之后的流程可參考這篇:
camera framework configure流程分析

涉及到的主要類:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java#632

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

出處:https://blog.csdn.net/haodada1226/article/details/121719939

總結(jié)一下:

① configure為app傳入的surface配置相應(yīng)的stream,然后將gbp、streamid、surfaceid進(jìn)行綁定,以便于發(fā)送request請(qǐng)求的時(shí)候去獲取;
② 告訴hal層,需要從camera中獲取什么樣格式的buffer

簡(jiǎn)單版時(shí)序圖


http://m.itdecent.cn/p/26d4b781a14d

復(fù)雜版時(shí)序圖


https://blog.csdn.net/TaylorPotter/article/details/105387109

2.4 request

在 Android Camera2最簡(jiǎn)單的預(yù)覽框顯示 這篇文的代碼中可以看到,
調(diào)用createCaptureRequest之后通過build創(chuàng)建CaptureRequest,然后session.setRepeatingRequest,然后就可以預(yù)覽了。

https://blog.csdn.net/TaylorPotter/article/details/105387109

然后接下來的流程可直接參考這篇:
camera framework request流程

涉及到的主要類如下:
http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/base/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java#121

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java#submitCaptureRequest

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/hardware/interfaces/camera/device/3.4/default/ExternalCameraDeviceSession.cpp#400

出處: https://blog.csdn.net/haodada1226/article/details/121848769

這里總結(jié)一下:

configure的時(shí)候?yàn)槊總€(gè)surface創(chuàng)建相應(yīng)的Camera3OutputStream,然后將相應(yīng)的信息保存起來(注意CameraDeviceClient中的mStreamMap、mConfiguredOutputs以及Camera3Device中的mOutputStreams等),然后告訴hal層需要配置什么格式、分辨率等的流。request中會(huì)將上述的surfaces和outputStreams填充進(jìn)request請(qǐng)求中,然后在Camera3Device中起一個(gè)thread,一直向hal層發(fā)送request請(qǐng)求。

最后來張時(shí)序圖


https://blog.csdn.net/TaylorPotter/article/details/105387109

3.camera中的BufferQueue

http://m.itdecent.cn/p/05a8d6f5b4df
BufferQueue可以理解為一個(gè)生產(chǎn)者-消費(fèi)者”模型,對(duì)GraphicBuffer管理的一種機(jī)制。
需注意的是,可以將BufferQueue當(dāng)作是一個(gè)算法結(jié)構(gòu),并不是只有Surfaceflinger會(huì)使用到,其他進(jìn)程只要有GraphicBuffer的消費(fèi)地方都會(huì)使用到。

BufferQueue結(jié)構(gòu)


http://m.itdecent.cn/p/05a8d6f5b4df

http://m.itdecent.cn/p/05a8d6f5b4df

http://m.itdecent.cn/p/05a8d6f5b4df
圖形生產(chǎn)者(如相機(jī),View繪制等)先向BufferQueue申請(qǐng)GraphicBuffer,填充完GraphicBuffer后,將GraphicBuffer移交給BufferQueue,BufferQueue會(huì)通知圖形消費(fèi)者(如Surfaceflinger,ImageReader,GLConsumer等)
相機(jī)中preview使用到的TextureView中的成員SurfaceTexture就是個(gè)自帶BufferQueue的組件。

http://m.itdecent.cn/p/05a8d6f5b4df

框架流程匯總


http://m.itdecent.cn/p/26d4b781a14d

參考鏈接:
深入理解Android相機(jī)體系結(jié)構(gòu)之二
深入理解Android相機(jī)體系結(jié)構(gòu)之三
深入理解Android相機(jī)體系結(jié)構(gòu)之十

官方文檔

Android Camera簡(jiǎn)單整理(一)-Camera Android架構(gòu)(基于Q)
Android Camera簡(jiǎn)單整理(三)-Mtk Camera MtkCam3架構(gòu)學(xué)習(xí)

[Android O] Camera 服務(wù)啟動(dòng)流程簡(jiǎn)析

CameraService啟動(dòng)流程
Android 8.1 Camera2架構(gòu)解析(1) CameraService和CameraProvider服務(wù)啟動(dòng)流程
Camera service服務(wù)啟動(dòng)流程

BufferQueue詳解 原理
Android-Fk:BufferQueue學(xué)習(xí)整理
Android Camera2 Framwork+Hal+Surface整體數(shù)據(jù)流程

Android Camera 打開預(yù)覽流程分析(三)-- Camera 連接到CameraService 過程分析
camera framework configure流程分析
Camera2 API -- OutputConfiguration
camera framework configure流程分析

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容