天天看點

深入了解Camera 硬體抽象層

和你一起終身學習,這裡是程式員Android

經典好文推薦,通過閱讀本文,您将收獲以下知識點:

一、概覽

二、Camera HIDL 接口

三、Camera Provider 主程式

四、Camera HAL3 接口

一、概覽

始于谷歌的Treble開源項目,基于接口與實作的分離的設計原則,谷歌加入了Camera Provider這一抽象層,該層作為一個獨立程序存在于整個系統中,并且通過HIDL這一自定義語言成功地将Camera Hal Module從Camera Service中解耦出來,承擔起了對Camera HAL的封裝工作,縱觀整個Android系統,對于Camera Provider而言,對上是通過HIDL接口負責與Camera Service的跨程序通信,對下通過标準的HAL3接口下發針對Camera的實際操作,這俨然是一個中央樞紐般的調配中心的角色,而事實上正是如此,由此看來,對Camera Provider的梳理變得尤為重要,接下來就以我個人了解出發來簡單介紹下Camera Provider。

Camera Provider通過提供标準的HIDL接口給Camera Service進行調用,保持與Service的正常通信,其中谷歌将HIDL接口的定義直接暴露給平台廠商進行自定義實作,其中為了極大地減輕并降低開發者的工作量和開發難度,谷歌很好地封裝了其跨程序實作細節,同樣地,Camera Provider通過标準的HAL3接口,向下控制着具體的Camera HAL Module,而這個接口依然交由平台廠商負責去實作,而程序内部則通過簡單的函數調用,将HIDL接口與HAL3接口完美的銜接起來,由此構成了Provider整體架構。

深入了解Camera 硬體抽象層

image

由圖中可以看出Camera Provider程序由兩部分組成,一是運作在系統中的主程式通過提供了标準的HIDL接口保持了與Camera Service的跨程序通訊,二是為了進一步擴充其功能,通過dlopen方式加載了一系列So庫,而其中就包括了實作了Camera HAL3接口的So庫,而HAL3接口主要定義了主要用于實作圖像控制的功能,其實作主要交由平台廠商或者開發者來完成,是以Camera HAL3 So庫的實作各式各樣,在高通平台上,這裡的實作就是我們本文重點需要分析的CamX-CHI架構。

在開始梳理CamX-CHI之前,不防先從上到下,以接口為主線簡單梳理下Camera Provider的各個部分:

二、Camera HIDL 接口

首先需要明确一個概念,就是HIDL是一種自定義語言,其核心是接口的定義,而谷歌為了使開發者将注意力落在接口的定義上而不是機制的實作上,主動封裝了HIDL機制的實作細節,開發者隻需要通過*.hal檔案定義接口,填充接口内部實際的實作即可,接下來來看下具體定義的幾個主要接口:

深入了解Camera 硬體抽象層

在這裡插入圖檔描述

因為HIDL機制本身是跨程序通訊的,是以Camera Service本身通過HIDL接口擷取的對象都會有Bn端和Bp端,分别代表了Binder兩端,接下來為了友善了解,我們都省略掉Bn/Bp說法,直接用具體接口類代表,忽略跨程序兩端的差別。

ICameraProvider.hal源碼如下:

package [email protected];

import ICameraProviderCallback;
import [email protected]::types;
import [email protected]::ICameraDevice;
import [email protected]::ICameraDevice;

interface ICameraProvider {

    setCallback(ICameraProviderCallback callback) generates (Status status);

    getVendorTags() generates (Status status, vec<VendorTagSection> ps);

    getCameraIdList() generates (Status status, vec<string> cameraDeviceNames);

    isSetTorchModeSupported() generates (Status status, bool support);

    getCameraDeviceInterface_V1_x(string cameraDeviceName) generates (Status status, [email protected]::ICameraDevice device);

    getCameraDeviceInterface_V3_x(string cameraDeviceName) generates (Status status, [email protected]::ICameraDevice device);
};

           

該檔案中定義了ICameraProvider接口類,由CameraProvider繼承并實作,在Camera Provider啟動的時候被執行個體化,主要接口如下:

  • getCameraDeviceInterface_V3_x: 該方法主要用于Camera Service擷取ICameraDevice,通過該對象可以控制Camera 裝置的諸如配置資料流、下發request等具體行為。
  • setCallback:将Camera Service 實作的ICameraProviderCallback傳入Camera Provider,一旦Provider有事件産生時便可以通過該對象通知Camera Service。

ICameraProviderCallback.hal源碼如下:

package [email protected];

import a[email protected]::types;

interface ICameraProviderCallback {

    cameraDeviceStatusChange(string cameraDeviceName, CameraDeviceStatus newStatus);

    torchModeStatusChange(string cameraDeviceName, TorchModeStatus newStatus);
};

           

該檔案中定義了ICameraProviderCallback回調接口類,該接口由Camera Service 中的CameraProviderManager::ProviderInfo繼承并實作,在Camera Service 啟動的時候被執行個體化,通過調用ICameraProvider::setCallback接口注冊到Camera Provider中,其主要接口如下:

  • cameraDeviceStatusChange:将Camera 裝置狀态上傳至Camera Service,狀态由CameraDeviceStatus定義

ICameraDevice.hal源碼如下:

package [email protected];

import [email protected]::types;
import ICameraDeviceSession;
import ICameraDeviceCallback;

interface ICameraDevice {

    getResourceCost() generates (Status status, CameraResourceCost resourceCost);

    getCameraCharacteristics() generates (Status status, CameraMetadata cameraCharacteristics);

    setTorchMode(TorchMode mode) generates (Status status);

    open(ICameraDeviceCallback callback) generates (Status status, ICameraDeviceSession session);

    dumpState(handle fd);
 };

           

該檔案中定義了ICameraDevice接口類,由CameraDevice::TrampolineDeviceInterface_3_2實作,其主要接口如下:

  • open:用于建立一個Camera裝置,并且将Camera Service中繼承ICameraDeviceCallback并實作了相應接口的Camera3Device作為參數傳入Provider中,供Provider上傳事件或者圖像資料。
  • getCameraCharacteristics:用于擷取Camera裝置的屬性。

ICameraDeviceCallback.hal源碼如下:

package [email protected];

import [email protected]::types;

interface ICameraDeviceCallback {
    processCaptureResult(vec<CaptureResult> results);
    notify(vec<NotifyMsg> msgs);
};

           

該檔案中定義了ICameraDeviceCallback接口類,由Camera Service中的Camera3Device繼承并實作,通過調用ICameraDevice::open方法注冊到Provider中,其主要接口如下:

  • processCaptureResult_3_4: 一旦有圖像資料産生會通過調用該方法将資料以及meta data上傳至Camera Service。
  • notify: 通過該方法上傳事件至Camera Service中,比如shutter事件等。

ICameraDeviceSession.hal源碼如下:

package [email protected];

import [email protected]::types;

interface ICameraDeviceSession {

    constructDefaultRequestSettings(RequestTemplate type) generates (Status status, CameraMetadata requestTemplate);

    configureStreams(StreamConfiguration requestedConfiguration) generates (Status status, HalStreamConfiguration halConfiguration);

    processCaptureRequest(vec<CaptureRequest> requests, vec<BufferCache> cachesToRemove) generates (Status status, uint32_t numRequestProcessed);

    getCaptureRequestMetadataQueue() generates (fmq_sync<uint8_t> queue);

    getCaptureResultMetadataQueue() generates (fmq_sync<uint8_t> queue);

    flush() generates (Status status); close();
};

           

該檔案中定義了ICameraDeviceSession接口類,由CameraDeviceSession::TrampolineSessionInterface_3_2繼承并實作,其主要接口如下:

  • constructDefaultRequestSettings:用于建立預設的Request配置項。
  • configureStreams_3_5:用于配置資料流,其中包括了output buffer/Surface/圖像格式大小等屬性。
  • processCaptureRequest_3_4:下發request到Provider中,一個request對應着一次圖像需求。
  • close: 關閉目前會話。

三 、Camera Provider 主程式

接下來進入到Provider内部去看看,整個程序是如何運轉的,以下圖為例進行分析:

深入了解Camera 硬體抽象層

在這裡插入圖檔描述

在系統初始化的時候,系統會去運作[email protected]_64程式啟動Provider程序,并加入HW Service Manager中接受統一管理,在該過程中執行個體化了一個LegacyCameraProviderImpl_2_4對象,并在其構造函數中通過hw_get_module标準方法擷取HAL的camera_module_t結構體,并将其存入CameraModule對象中,之後通過調用該camera_modult_t結構體的init方法初始化HAL Module,緊接着調用其get_number_of_camera方法擷取目前HAL支援的Camera數量,最後通過調用其set_callbacks方法将LegcyCameraProviderImpl_2_4(LegcyCameraProviderImpl_2_4繼承了camera_modult_callback_t)作為參數傳入CamX-CHI中,接受來自CamX-CHI中的資料以及事件,當這一系列動作完成了之後,Camera Provider程序便一直便存在于系統中,監聽着來自Camera Service的調用。

深入了解Camera 硬體抽象層

在這裡插入圖檔描述

接下來以上圖為例簡單介紹下Provider中幾個重要流程:

  • Camera Service通過調用ICameraProvider的getCameraDeviceInterface_v3_x接口擷取ICameraDevice,在此過程中,Provider會去執行個體化一個CameraDevice對象,并且将之前存有camera_modult_t結構體的CameraModule對象傳入CameraDevice中,這樣就可以在CameraDevice内部通過CameraModule通路到camera_module_t的相關資源,然後将CameraDevice内部類TrampolineDeviceInterface_3_2(該類繼承并實作了ICameraDevice接口)傳回給Camera Service。
  • Camera Service通過之前擷取的ICameraDevice,調用其open方法來打開Camera裝置,接着在Provider中會去調用CameraDevice對象的open方法,在該方法内部會去調用camera_module_t結構體的open方法,進而擷取到HAL部分的camera3_device_t結構體,緊接着Provider會執行個體化一個CameraDeviceSession對象,并且将剛才擷取到的camera3_device_t結構體以參數的方式傳入CameraDeviceSession中,在CameraDeviceSession的構造方法中又會調用CameraDeviceSession的initialize方法,在該方法内部又會去調用camera3_device_t結構體的ops内的initialize方法開始HAL部分的初始化工作,最後CameraDeviceSession對象被作為camera3_callback_ops的實作傳入HAL,接收來自HAL的資料或者具體事件,當一切動作都完成後,Provider會将CameraDeviceSession::TrampolineSessionInterface_3_2(該類繼承并實作了ICameraDeviceSession接口)對象通過HIDL回調的方法傳回給Camera Service中。
  • Camera Service通過調用ICameraDevcieSession的configureStreams_3_5接口進行資料流的配置,在Provider中,最終會通過調用之前擷取的camera3_device_t結構體内ops的configure_streams方法下發到HAL中進行處理。
  • Camera Service通過調用ICameraDevcieSession的processCaptureRequest_3_4接口下發request請求到Provider中,在Provider中,最終依然會通過調用擷取的camera3_device_t結構體内ops中的process_capture_request方法将此次請求下發到HAL中進行處理。

從整個流程不難看出,這幾個接口最終對應的是HAL3的接口,并且Provider并沒有經過太多複雜的額外的處理。

四、Camera HAL3 接口

HAL硬體抽象層(Hardware Abstraction Layer),是谷歌開發的用于屏蔽底層硬體抽象出來的一個軟體層, 每一個平台廠商可以将不開源的代碼封裝在這一層,僅僅提供二進制檔案。

該層定義了自己的一套通用标準接口,平台廠商務必按照以下規則定義自己的Module:

  • 每一個硬體子產品都通過hw_module_t來描述,具有固定的名字HMI
  • 每一個硬體子產品都必須實作hw_module_t裡面的open方法,用于打開硬體裝置,并傳回對應的操作接口集合
  • 硬體的操作接口集合使用hw_device_t 來描述,并可以通過自定義一個更大的包含hw_device_t的結構體來拓展硬體操作集合

其中代表硬體子產品的是hw_module_t,對應的裝置是通過hw_device_t來描述,這兩者的定義如下:

hw_module_t/hw_device_t源碼如下:

typedef struct hw_module_t {
    uint32_t tag; //HMI
    struct hw_module_methods_t* methods;
} hw_module_t;

typedef struct hw_module_methods_t {
    int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device);
} hw_module_methods_t;

typedef struct hw_device_t {
    struct hw_module_t* module;
    int (*close)(struct hw_device_t* device);
} hw_device_t;

           

從上面的定義可以看出,主要是通過hw_module_t 代表了子產品,通過其open方法用來打開一個裝置,而該裝置是用hw_device_t來表示,其中除了用來關閉裝置的close方法外,并無其它方法,由此可見谷歌定義的HAL接口,并不能滿足絕大部分HAL子產品的需要,是以谷歌想出了一個比較好的解決方式,那便是将這兩個基本結構嵌入到更大的結構體内部,同時在更大的結構内部定義了各自子產品特有的方法,用于實作子產品的功能,這樣,一來對上保持了HAL的統一規範,二來也擴充了子產品的功能。

基于上面的方式,谷歌便針對Camera 提出了HAL3接口,其中主要包括了用于代表一系列操作主體的結構體以及具體操作函數,接下來我們分别進行詳細介紹:

1. 核心結構體解析

HAL3中主要定義了camera_module_t/camera3_device_t/camera3_stream_configuration/camera3_stream以及camera3_stream_buffer幾個主要結構體。

其中camera_module_t以及camera3_device_t代碼定義如下:

typedef struct camera_module {
    hw_module_t common;
    int (*get_number_of_cameras)(void);
    int (*get_camera_info)(int camera_id, struct camera_info *info);
    nt (*set_callbacks)(const camera_module_callbacks_t *callbacks);
    void (*get_vendor_tag_ops)(vendor_tag_ops_t* ops);
    int (*open_legacy)(const struct hw_module_t* module, const char* id, uint32_t halVersion, struct hw_device_t** device);
    int (*set_torch_mode)(const char* camera_id, bool enabled);
    int (*init)();
    int (*get_physical_camera_info)(int physical_camera_id, int (*is_stream_combination_supported)(int camera_id,const camera_stream_combination_t *streams);
    int (*is_stream_combination_supported)(int camera_id, const camera_stream_combination_t *streams);
    void (*notify_device_state_change)(uint64_t deviceState);
} camera_module_t;

typedef struct camera3_device {
    hw_device_t common;
    camera3_device_ops_t *ops; //拓展接口,Camera HAL3定義的标準接口
    void *priv;
} camera3_device_t;

           

由定義不難發現,camera_module_t包含了hw_module_t,主要用于表示Camera子產品,其中定義了諸如get_number_of_cameras以及set_callbacks等擴充方法,而camera3_device_t包含了hw_device_t,主要用來表示Camera裝置,其中定義了camera3_device_ops操作方法集合,用來實作正常擷取圖像資料以及控制Camera的功能。

結構體camera3_stream_configuration代碼定義如下:

typedef struct camera3_stream_configuration {
    uint32_t num_streams;
    camera3_stream_t **streams;
    uint32_t operation_mode;
    const camera_metadata_t *session_parameters;
} camera3_stream_configuration_t;

           

該結構體主要用來代表配置的資料流清單,内部裝有上層需要進行配置的資料流的指針,内部的定義簡單介紹下:

  • num_streams: 代表了來自上層的資料流的數量,其中包括了output以及input stream。
  • streams: 是streams的指針數組,包括了至少一條output stream以及至多一條input stream。
  • operation_mode: 目前資料流的操作模式,該模式在camera3_stream_configuration_mode_t中被定義,HAL通過這個參數可以針對streams做不同的設定。
  • session_parameters: 該參數可以作為預設參數,直接設定為NULL即可,CAMERA_DEVICE_API_VERSION_3_5以上的版本才支援。

結構體camera3_stream_t的代碼定義如下:

typedef struct camera3_stream {
    int stream_type;
    uint32_t width;
    uint32_t height;
    int format;
    uint32_t usage;
    uint32_t max_buffers;
    void *priv;
    android_dataspace_t data_space;
    int rotation;
    const char* physical_camera_id;
}camera3_stream_t;

           

該結構體主要用來代表具體的資料流實體,在整個的配置過程中,需要在上層進行填充,當下發到HAL中後,HAL會針對其中的各項屬性進行配置,這裡便簡單介紹下其内部的各個元素的意義:

  • stream_type: 表示資料流的類型,類型在camera3_stream_type_t中被定義。
  • width:表示目前資料流中的buffer的寬度。
  • height: 表示目前資料流中buffer的高度。
  • format: 表示目前資料流中buffer的格式,該格式是在system/core/include/system/graphics.h中被定義。
  • usage:表示目前資料流的gralloc用法,其用法定義在gralloc.h中。
  • max_buffers:指定了目前資料流中可能支援的最大資料buffer數量。
  • data_space: 指定了目前資料流buffer中存儲的圖像資料的顔色空間。
  • rotation:指定了目前資料流的輸出buffer的旋轉角度,其角度的定義在camera3_stream_rotation_t中,該參數由Camera Service進行設定,必須在HAL中進行設定,該參數對于input stream并沒有效果。
  • physical_camera_id:指定了目前資料流從屬的實體camera Id。

結構體camera3_stream_buffer_t定義如下:

typedef struct camera3_stream_buffer {
    camera3_stream_t *stream;
    buffer_handle_t *buffer
    int status;
    int acquire_fence;
    int release_fence;
} camera3_stream_buffer_t;

           

該結構體主要用來代表具體的buffer對象,其中重要元素如下:

  • stream: 代表了從屬的資料流
  • buffer:buffer句柄

2. 核心接口函數解析

HAL3的核心接口都是在camera3_device_ops中被定義,代碼定義如下:

typedef struct camera3_device_ops {
    int (*initialize)(const struct camera3_device *, const camera3_callback_ops_t *callback_ops);
    int (*configure_streams)(const struct camera3_device *, camera3_stream_configuration_t *stream_list);
    int (*register_stream_buffers)(const struct camera3_device *,const camera3_stream_buffer_set_t *buffer_set);
    const camera_metadata_t* (*construct_default_request_settings)(const struct camera3_device *, int type);
    int (*process_capture_request)(const struct camera3_device *, camera3_capture_request_t *request);
    void (*get_metadata_vendor_tag_ops)(const struct camera3_device*, vendor_tag_query_ops_t* ops);
    void (*dump)(const struct camera3_device *, int fd);
    int (*flush)(const struct camera3_device *);
    void (*signal_stream_flush)(const struct camera3_device*, uint32_t num_streams, const camera3_stream_t* const* streams);
    int (*is_reconfiguration_required)(const struct camera3_device*, const camera_metadata_t* old_session_params, const camera_metadata_t* new_session_params);
} camera3_device_ops_t;

           

從代碼中可以看見,該結構體定義了一系列的函數指針,用來指向平台廠商實際的實作方法,接下來就其中幾個方法簡單介紹下:

a) initialize

該方法必須在camera_module_t中的open方法之後,其它camera3_device_ops中方法之前被調用,主要用來将上層實作的回調方法注冊到HAL中,并且根據需要在該方法中加入自定義的一些初始化操作,另外,谷歌針對該方法在性能方面也有嚴格的限制,該方法需要在5ms内傳回,最長不能超過10ms。

b) configure_streams

該方法在完成initialize方法之後,在調用process_capture_request方法之前被調用,主要用于重設目前正在運作的Pipeline以及設定新的輸入輸出流,其中它會将stream_list中的新的資料流替換之前配置的資料流。在調用該方法之前必須確定沒有新的request下發并且目前request的動作已經完成,否則會引起無法預測的錯誤。一旦HAL調用了該方法,則必須在内部配置好滿足目前資料流配置的幀率,確定這個流程的運作的順暢性。

其中包含了兩個參數,分别是camera3_device以及stream_list(camera3_stream_configuration_t ),其中第二個參數是上層傳入的資料流配置清單,該清單中必須包含至少一個output stream,同時至多包含一個input stream。

另外,谷歌針對該方法有着嚴格的性能要求,平台廠商在實作該方法的時候,需要在500ms内傳回,最長不能超過1000ms。

c) construct_default_request_settings

該方法主要用于建構一系列預設的Camera Usecase的capture 設定項,通過camera_metadata_t來進行描述,其中傳回值是一個camera_metadata_t指針,其指向的記憶體位址是由HAL來進行維護的,同樣地,該方法需要在1ms内傳回,最長不能超過5ms。

d) process_capture_request

該方法用于下發單次新的capture request到HAL中, 上層必須保證該方法的調用都是在一個線程中完成,而且該方法是異步的,同時其結果并不是通過傳回值給到上層,而是通過HAL調用另一個接口process_capture_result()來将結果傳回給上層的,在使用的過程中,通過in-flight機制,保證短時間内下發足夠多的request,進而滿足幀率要求。

該方法的性能依然受到谷歌的嚴格要求,規定其需要在一幀圖像處理完的時長内傳回,最長不超過4幀圖像處理完成的時長,比如目前預覽幀率是30幀,則該方法的操作耗時最長不能超過120ms,否則便會引起明顯的幀抖動,進而影響使用者體驗。

e) dump

該方法用于列印目前Camera裝置的狀态,一般是由上層通過dumpsys工具輸出debug dump資訊或者主動抓取bugreport的時候被調用,該方法必須是非阻塞實作,同時需要保證在1ms内傳回,最長不能超過10ms。

f) flush

當上層需要執行新的configure_streams的時候,需要調用該方法去盡可能快地清除掉目前已經在進行中的或者即将處理的任務,為配置資料流提供一個相對穩定的環境,其具體工作如下:

  • 所有的還在流轉的request會盡可能快的傳回
  • 并未開始進行流轉的request會直接傳回,并攜帶錯誤資訊
  • 任何可以打斷的硬體操作會立即被停止
  • 任何無法進行打斷的硬體操作會在目前狀态下進行休眠

flush會在所有的buffer都得以釋放,所有request都成功傳回後才真正傳回,該方法需要在100ms内傳回,最長不能超過1000ms。

上面的一系列方法是上層直接對下控制Camera Hal,而一旦Camera Hal産生了資料或者事件的時候,可以通過camera3_callback_ops中定義的回調方法将資料或者事件傳回至上層,該結構體定義如下:

typedef struct camera3_callback_ops {

    void (*process_capture_result)(const struct camera3_callback_ops *, const camera3_capture_result_t *result);
    void (*notify)(const struct camera3_callback_ops *, const camera3_notify_msg_t *msg);

    camera3_buffer_request_status_t (*request_stream_buffers)(
        const struct camera3_callback_ops *,
        uint32_t num_buffer_reqs,
        const camera3_buffer_request_t *buffer_reqs,
        /*out*/uint32_t *num_returned_buf_reqs,
        /*out*/camera3_stream_buffer_ret_t *returned_buf_reqs);

    void (*return_stream_buffers)( const struct camera3_callback_ops *, uint32_t num_buffers, const camera3_stream_buffer_t* const* buffers);
} camera3_callback_ops_t;

           

其中常用的回調方法主要有兩個:用于傳回資料的process_capture_result以及用于傳回事件的notify,接下來分别介紹下:

a) process_capture_result

該方法用于傳回HAL部分産生的metadata和image buffers,它與request是多對一的關系,同一個request,可能會對應到多個result,比如可以通過調用一次該方法用于傳回metadata以及低分辨率的圖像資料,再調用一次該方法用于傳回jpeg格式的拍照資料,而這兩次調用時對應于同一個process_capture_request動作。

同一個Request的Metadata以及Image Buffers的先後順序無關緊要,但是同一個資料流的不同Request之間的Result必須嚴格按照Request的下發先後順序進行依次傳回的,如若不然,會導緻圖像資料顯示出現順序錯亂的情況。

該方法是非阻塞的,而且并且必須要在5ms内傳回。

b) notify

該方法用于異步傳回HAL事件到上層,必須非阻塞實作,而且要在5ms内傳回。

谷歌為了将系統架構和平台廠商的自定義部分相分離,在Android上推出了Treble項目,該項目直接将平台廠商的實作部分放入vendor分區中進行管理,進而與system分區保持隔離,這樣便可以在互相獨立的空間中進行各自的疊代更新,而互不幹擾,而在相機架構體系中,便将Camera HAL Module從Camera Service中解耦出來,放入獨立程序Camera Provider中進行管理,而為了更好的進行跨程序通路,谷歌針對Provider提出了HIDL機制用于Camera Servic對于Camera Provier的通路,而HIDL接口的實作是在Camera Provider中實作,針對Camera HAL Module的控制又是通過谷歌制定的Camera HAL3接口來完成,是以由此看來,Provider的職責也比較簡單,通過HIDL機制保持與Camera Service的通信,通過HAL3接口控制着Camera HAL Module。

原文連結:https://blog.csdn.net/u012596975/article/details/107137523

相關文章友情推薦 

1. Android開發幹貨分享

至此,本篇已結束。轉載網絡的文章,小編覺得很優秀,歡迎點選閱讀原文,支援原創作者,如有侵權,懇請聯系小編删除,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

深入了解Camera 硬體抽象層

點個在看,友善您使用時快速檢視!