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

寫(xiě)在開(kāi)頭:本文為學(xué)習(xí) camera2 過(guò)程中的知識(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),是通過(guò)Camera Framework來(lái)完成的藤为,而該層也有著一次不小的演變,剛開(kāi)始Framework層并不是直接通過(guò)AIDL接口與Camera Service進(jìn)行通信藏雏,而是通過(guò)一個(gè)JNI層來(lái)完成從Java到Native的轉(zhuǎn)換鹤啡,而Native部分作為客戶(hù)端,保持對(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ì)得說(shuō)明了camera的使用流程和API携添。這不是本篇的重點(diǎn)嫁盲。


http://www.reibang.com/p/f63f296a920b
http://www.reibang.com/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是沒(méi)有通過(guò)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ì)控制邏輯的高度抽象化,使得該接口具有很高的靈活性孽鸡,可以通過(guò)簡(jiǎn)單的操作實(shí)現(xiàn)30fps的全高清連拍的功能蹂午,總得來(lái)說(shuō),該接口極大地提高了對(duì)于相機(jī)框架的控制能力彬碱,同時(shí)也進(jìn)一步大幅度提升了其整體性能画侣。
camera2的應(yīng)用層與framework層之間的流程如下:


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

簡(jiǎn)單來(lái)說(shuō)就是,引入了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工作大體流程后沙咏,來(lái)看看部分細(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)用開(kāi)發(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繼而打開(kāi)Camera硬件sensor.
  • 3.openCamera成功會(huì)有回調(diào)從CameraServer通知到App,在onOpenedCamera或類(lèi)似回調(diào)中去調(diào)用類(lèi)似startPreview的操作.此時(shí)會(huì)創(chuàng)建CameraCaptureSession,創(chuàng)建過(guò)程中會(huì)向CameraServer調(diào)用ConfigureStream的操作,ConfigureStream的參數(shù)中包含了第一步中空間中的Surface的引用,相當(dāng)于App將Surface容器給到了CameraServer,CameraServer包裝了下該Surface容器為stream,通過(guò)HIDL傳遞給HAL,繼而HAL也做configureStream操作
  • 4.ConfigureStream成功后CameraServer會(huì)給App回調(diào)通知ConfigStream成功,接下來(lái)App便會(huì)調(diào)用AOSP setRepeatingRequest接口給到CameraServer,CameraServer初始化時(shí)便起來(lái)了一個(gè)死循環(huán)線(xiàn)程等待來(lái)接收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è)置來(lái)的Surface容器被填滿(mǎn)了BufferQueue機(jī)制將會(huì)通知到應(yīng)用,此時(shí)App中控件取出各自容器中的內(nèi)容消費(fèi)掉,Preview控件中的Surface中的內(nèi)容將通過(guò)View提供到SurfaceFlinger中進(jìn)行合成最終顯示出來(lái),即預(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
通過(guò)AIDL binder調(diào)用向Framework層的CameraServer進(jìn)程下指令,從CameraServer進(jìn)程中取的數(shù)據(jù).
基本過(guò)程都如下:

  • 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ù),接下來(lái)要顯示預(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初始化過(guò)程中通過(guò)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流程

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


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

2.3 configure

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

/**
     * 打開(kāi)相機(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.真正打開(kāi)相機(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)聽(tīng)對(duì)象
     */
    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice camera) {
            Log.i(TAG, "StateCallback哼勇! onOpened");
            mCameraDevice = camera; // 打開(kāi)成功都伪,保存代表相機(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流程分析

涉及到的主要類(lèi):
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://www.reibang.com/p/26d4b781a14d

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


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

2.4 request

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

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

然后接下來(lái)的流程可直接參考這篇:
camera framework request流程

涉及到的主要類(lèi)如下:
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)的信息保存起來(lái)(注意CameraDeviceClient中的mStreamMap、mConfiguredOutputs以及Camera3Device中的mOutputStreams等)耸弄,然后告訴hal層需要配置什么格式咧虎、分辨率等的流。request中會(huì)將上述的surfaces和outputStreams填充進(jìn)request請(qǐng)求中计呈,然后在Camera3Device中起一個(gè)thread砰诵,一直向hal層發(fā)送request請(qǐng)求征唬。

最后來(lái)張時(shí)序圖


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

3.camera中的BufferQueue

http://www.reibang.com/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://www.reibang.com/p/05a8d6f5b4df

http://www.reibang.com/p/05a8d6f5b4df

http://www.reibang.com/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://www.reibang.com/p/05a8d6f5b4df

框架流程匯總


http://www.reibang.com/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 打開(kāi)預(yù)覽流程分析(三)-- Camera 連接到CameraService 過(guò)程分析
camera framework configure流程分析
Camera2 API -- OutputConfiguration
camera framework configure流程分析

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末囱怕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子毫别,更是在濱河造成了極大的恐慌,老刑警劉巖岛宦,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砾肺,死亡現(xiàn)場(chǎng)離奇詭異变汪,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)实胸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)童芹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)假褪,“玉大人近顷,你說(shuō)我怎么就攤上這事∽罕椋” “怎么了域醇?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵譬挚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我盐须,道長(zhǎng)贼邓,這世上最難降的妖魔是什么闷尿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任填具,我火速辦了婚禮灌旧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘描融。我一直安慰自己衡蚂,他們只是感情好毛甲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布玻募。 她就那樣靜靜地躺著,像睡著了一般跃惫。 火紅的嫁衣襯著肌膚如雪爆存。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音曾棕,去河邊找鬼霉翔。 笑死债朵,一個(gè)胖子當(dāng)著我的面吹牛瀑凝,可吹牛的內(nèi)容都是我干的粤咪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼某筐!你這毒婦竟也來(lái)了冠跷?” 一聲冷哼從身側(cè)響起蜜托,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤橄务,失蹤者是張志新(化名)和其女友劉穎蜂挪,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體攒驰,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隅津,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年伦仍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了充蓝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谓苟。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涝焙,死狀恐怖孕暇,靈堂內(nèi)的尸體忽然破棺而出妖滔,到底是詐尸還是另有隱情座舍,我是刑警寧澤簸州,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布搏存,位于F島的核電站矢洲,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏袁滥。R本人自食惡果不足惜灾螃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一腰鬼、第九天 我趴在偏房一處隱蔽的房頂上張望熄赡。 院中可真熱鬧彼硫,春花似錦拧篮、人聲如沸他托。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)韧掩。三九已至窖铡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間费彼,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留关划,地道東北人贮折。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像臼疫,于是被迫代替她去往敵國(guó)和親烫堤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鸽斟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容