Camera HAL3學習: Android Camera System

Android Camera硬件抽象層(HAL,Hardware Abstraction Layer)主要用於把底層camera drive與硬件和位於android.hardware中的framework APIs連接起來。Camera子系統主要包含了camera pipeline components 的各種實現,而camera HAL提供了這些組件的使用接口。

注:camera HAL起着承上啓下的作用。在camera HAL層實現中,芯片廠商一般將camera HAL層的實現分爲兩層:interface層和OEM層。OEM層爲下層,它用於屏蔽不同的camera硬件。不同的camera硬件必須支持OEM層提供的對外接口。Interface層爲上層,它調用OEM層的對外接口來實現camera HAL所定義的接口。對於Interface層,它並不知道底層camera硬件到底是哪一個版本。同時,interface層完成了屏蔽camera HAL版本的作用。對於OEM層,它也不知道上層是哪一個camera HAL版本,及android版本。兩層分離架構,可以很容易地實現不同芯片支持同一個android版本和同一款芯片支持不同android版本(前提條件是該款芯片能夠支持這些android版本的各個需求)。

  1. Camera System Architecture

下圖所示爲Android官方給出的Camera System架構。

圖 1 Android Camera System Architecture

從圖 1中可以看出,Camera System主要包含如下幾個重要組成部分:

  1. Application Framework

Application framework層主要是應用代碼(app's code),這個代碼主要利用android.hardware.Camera API與Camera硬件進行交互。這些代碼調用相關的JNI類來訪問與Camera進行交互的原生代碼(native code)。

  1. JNI

與android.hardware.Camera有關的JNI代碼主要frameworks/base/core/jni/ android_hardware_Camera.cpp。這些代碼調用下一層的原生代碼以獲得物理camera的訪問權,然後返回用於在framework層創建android.hardware.Camera對象的數據。

  1. Native framework

Native framework的定義位於 frameworks/av/camera/Camera.cpp中,它提供了android.hardware.Camera類在本地的實現。這些類調用IPC binder來獲得camera service。

  1. Binder IPC proxies

IPC binder代理可以現實進程間通信。在frameworks/av/camera目錄下有三個camera binder類的定義。ICameraService是cameraservice的接口,ICamera是被打開的camera設備的接口,ICameraClient是camera設備返回給application framework層的接口。

  1. Camera Service

Camera service位於frameworks/av/services/camera/libcameraservice/CameraService.cpp,它是與HAL直接進行交互的真正代碼。

  1. HAL

硬件抽象層定義了一套標準接口,你必須實現這些接口,以保證你的APP能夠與你的Camera硬件正確的協調工作,從而使保證你的Camera的所有功能能夠正常進行工作。以下是google原文:

The hardware abstraction layer defines the standard interface that the camera service calls into and that you must implement to have your camera hardware function correctly.

  1. Kernel Driver

Camera驅動向下與真實的camera硬件進行交互,向上與HAL實現進行交互。Camera硬件和驅動必須能夠提供YV12和NV21格式的圖像數據,以支持camera圖像數據在顯示屏上的預覽和視頻錄製。

注:YV12是YUV420P,三個plane,即Y,V,U三個plane依次存儲,如:YYYYYYYY VV UU;NV21是YUV420SP,兩plane,即Y,VU作爲兩個plane存儲,且VU交織,即一個V,一個U,依次存儲,如:YYYYYYYY VUVU。

  1. HAL的實現

  2. Implementation of HAL

HAL層位於camera驅動和上層Android framework層之間,它定義了一些標準接口,你必須正確地實現這些接口,以保證你的APP能夠正確的操作你的camera硬件進行正常工作。HAL接口定義位於hardware/libhardware/include/hardware/camera.h 和hardware/libhardware/include/hardware/camera_common.h頭文件中。

camera_common.h文件定義了一個重要的struct——camera_module。camera_module定義了一套標準結構以獲取與camera相關的基本信息,比如ID和一些camera的基本屬性等,如是否爲前置或後置camera等。

Camera.h則包含了與android.hardware.Camera相關的代碼。該頭文件聲明瞭camera_device結構體,camera_device結構體包含一個camera_device_ops結構體,camera_device_ops結構體包含了指向HAL接口實現函數的函數指針。開發者可以查看frameworks/av/include/camera/CameraParameters.h 文件以瞭解更多不同類型的camera參數的相關文檔。這些參數都通過HAL中的 int (*set_parameters)(struct camera_device *, const char *parms) 函數指針進行設置。

關於HAL實現的一個例子,可以查看Galaxy Nexus HAL的實現,它位於hardware/ti/omap4xxx/camera。

  1. Configuring the Shared Library

你必須設置Android的build system以保證將自己的HAL實現打包進一個共享庫(shared library),然後通過創建一個android.mk文件來將其複製到一個合適的目錄中,這主要包含如下幾個步驟:

  1. 創建一個包含你的library源代碼的目錄:device/<company_name>/<device_name>/camera。

  2. 創建一個Android.mk文件來build你的library。確保該Makefild文件包含如下幾行:

LOCAL_MODULE := camera.<device_name>

LOCAL_MODULE_RELATIVE_PATH := hw

注意,你的library必須按如下格式進行命名:camera.<device_camera>(.so會自動添加)。這樣Android纔可以正確的加載你的library。可以查看Galaxy Nexus camera的例子瞭解具體情況,例子位於hardware/ti/omap4xxx/Android.mk。

  1. 通過從目錄frameworks/native/data/etc下拷貝必要功能XML文件,在你的設備的Makefile文件中明確指出你的設備有哪些功能。例如,明確指出你的設備有閃光燈,而且能自動聚焦,那就需要在你的設備所對應的<device>/<company_name>/<device_name> /device.mk Makefile文件中增加下面幾行:

PRODUCT_COPY_FILES := \ ...

 

PRODUCT_COPY_FILES += \

frameworks/native/data/etc/android.hardware.camera.flash-autofocus.xml:system/etc/permissions/android.hardware.camera.flash-autofocus.xml \

可以查看device/samsung/tuna/device.mk這個例子。

  1. 在device/<company_name>/<device_name>/media_profiles.xml和device/<company_name> /<device_name>/media_codecs.xml兩個XML文件中,聲明你的camera設備支持的多媒體編解碼器,格式和分辨率。

  2. 在你的設備的device/<company_name>/<device_name>/device.mk文件中添加如下幾行,將media_profiles.xml 和 media_codecs.xml複製到合適的位置。

# media config xml file

PRODUCT_COPY_FILES += \

<device>/<company_name>/<device_name>/media_profiles.xml:system/etc/media_profiles.xml

 

# media codec config xml file

PRODUCT_COPY_FILES += \

<device>/<company_name>/<device_name>/media_codecs.xml:system/etc/media_codecs.xml

  1. 通過在你的設備device/<company_name>/<device_name>/device.mk Makefile中的PRODUCT_PACKAGES變量裏添加app名稱,聲明你想將哪些camera app添加到你的設備的系統image中:

PRODUCT_PACKAGES := \

Gallery2 \

...

  1. Camera HAL v3概述

Android硬件抽象層(Hardware Abstraction Layer,HAL)向上連接camera framework 層APIs,向下連接底層Camera驅動和硬件。最新版的Android引進了一種全新的camera stack底層實現方案。如果你有之前開發的適用於老版本Android的camera HAL module和驅動,那麼注意了,因爲新版本與老版本在camera pipeline的實現上面有非常大的改動。

由於很多設備仍然依賴於老版本的camera HAL,因此,未來的Android發佈版本依然會支持第一版的camera HAL。Android camera service也支持同時實現兩種HAL,這種設計有一定的好處,比如你想使用HAL v1支持一個能力比較有限的前置camera,同時使用HAL v3支持一個具有強大功能的後置camera,此時這種設計就有了用武之地。HAL v2是v1向v3的一個過渡版本,將不在支持。

系統中只會有一個camera HAL module(這個module擁有自己的版本號,當前是1、2或2.1),該module可以維護多個獨立的camera device,每個device都會有自己的版本號。Camera module v2或更新版本的module會支持device v2及更新的版本,這個 camera module可以支持多個不同版本的camera device。這也就是我們爲什麼說Android支持兩個HAL的實現。

注意:新的camera HAL仍然處於開發過程中,以後隨時有可能改變,本文只是從一個比較高的層面來介紹camera 子系統的設計和結構,忽略了很多細節的東西。

  1. 概述

第1版的camera subsystem被設計成由頂層控制黑箱結構。簡單的說,老的camera子系統有3種操作模式:

  • 預覽

  • 視頻錄製

  • 繼續拍照

    每種模式都有所不同,也有一定的功能重疊。這使得很以後在功能擴展方面變得比較困難,比如說burst mode,它屬於上面三種中的兩種。

圖 2 Camera components

  1. 第3版的改進

重新設計Camera API的目的是從本質是提升Android應用對Android設備上Camera Subsystem的控制能力,同時確保Camera API的可維護性。

加強控制能力主要爲了在Android設備上爲開發出更高質量的camera應用,儘可能地利用設備最大性能,提升應用的使用效果與用戶體驗。

第3版的camera子系統將所有的操作模式都歸一成一個單一的視圖,這種視圖可以實現之前的斜體一種模式,也可以方便地進行模式擴展。這樣做的好處是用戶可以更加靈活的控制對焦、曝光和一些後續的處理,如降噪、對比度和銳化等。此外,簡化的視圖使得應用開發者可以使用camera的不同功能。新的API將camera子系統建立成一種pipeline,將捕獲幀的輸入請求轉換爲幀,以1:1的方式。該請求封裝了所有關於捕獲和處理一幀的配置信息,主要包括:分辨率、像素格式,手動控制sensor、lens和flash,3A製作模型,RAW轉YUV處理控制等等。

舉個簡單的例子,application framework向camera subsystem請求一幀,camera subsystem返回一個輸出流作爲結果。另外,metadata包含了如顏色空間、鏡頭陰影等信息,每一個返回結果都會包含這些信息,下面的圖表會詳細介紹每個一個組件。

你可以將Camera v3想象成一個pipeline,它將每一個拍照請求轉化爲sensor捕獲的一幀圖像,其處理如下:

  • 返回一個拍照相關的擁有元數據的對象。

  • 一個或者多個圖像數據buffer,每個都有自己的目標surface。

可能的輸出surface被預先配置:

  • 每一個surface是固定分辨率的多個圖像buffer的目標。

  • 只有很少數量的surface可以被配置爲立即輸出。

一個請求包含了所有拍照的配置,輸出surface的列表被添加到圖像buffer中(所有被配置的單元的輸出)。一個請求可能只發送一次,也有可能會被多次發送。拍照優先於被重複發送的請求。

圖 3 Camera core operation model

  1. Supported Version

支持camera HAL v3版本的camera設備,在camera_device_t.common.version和camera_info_t.device_version (來自於camera_module_t.get_camera_info)中,必須返回CAMERA_DEVICE_API_VERSION_3_1。包含v3.1設備的camera模塊至少需要實現camera模塊接口的v2.0版本(由camera_module_t.common.module_api_version定義)。

  1. HAL Subsystem

  2. Requests

Application framework層向camera子系統發出一系列捕獲數據的請求。一個請求對應於結果中的一個單元。請求封裝了這些結果關於捕獲數據和處理數據的所有配置信息。這些信息包括:分辨率,像素格式,sensor調整,鏡頭和閃光燈控制,3A操作模式,RAW轉YUV處理,統計信息產生,等等。這裏考慮了很多關於對結果數據的輸出和處理的控制。多個請求可以一次性發出,提交請求是非阻塞模式。這些請求總是按照被接收到的順序來處理。

圖 4 Camera model

  1. The HAL and camera subsystem

Camera子系統包括camera流水線上各個組件的實現,比如3A算法及其處理控制。Camera HAL層爲你實現這些組件提供了接口。爲了保持對多個設備製造商和圖像信號處理器(ISP,或者camera sensor)供應商之間的跨平臺兼容性,camera流水線模塊是虛擬的,並沒有直接對應任何真實的ISP。但是,它與真實的處理流水線很相似,以便你能夠高效地將它映射到你的硬件。另外,它很抽象,在質量,性能或者跨設備兼容性方面,不需要任何妥協就可以支持多個不同算法和操作指令。

The camera pipeline also supports triggersthat the app framework can initiate to turn on things such as auto-focus. Italso sends notifications back to the app framework, notifying apps of eventssuch as an auto-focus lock or errors.

Camera流水線也支持觸發器,app framework能夠初始化並打開它,比如自動聚焦。它也能向app framework發送通知,通知app關於自動聚焦被鎖或者錯誤的事件。

圖 5 Camera pipeline

請注意,在最初發布的版本中,上述圖表中的一些圖像處理模塊並沒有被很好地定義。Camera pipeline做了如下的假設:

  • 輸出的RAW Bayer數據在ISP內部沒有經過任何處理;

  • 生成的統計數據是基於raw sensor的輸出數據;

  • ISP中,將raw sensor的輸出數據轉換爲YUV格式的各個處理模塊沒有嚴格的先後次序;

  • 雖然展示了多個縮放和裁剪單元,但是所有的縮放單元共用一個輸出區域控制(比如數字變焦)。但是每個單元可以有不同的輸出分辨率和像素格式。

注:數字變焦是根據變焦倍數,從原始圖像中裁剪一部分,然後放大到原始分辨率。由於是使用縮放算法直接放大的,所以其圖像質量會降低。上圖有三個縮放/裁剪單元,但它們共用一個輸出控制器,即request control,由它來決定輸出到外部緩衝區。根據application framework層的需求,最上面的縮放/裁剪單元會對從raw sensor採集的數據進行裁剪和縮放,最後輸出到外邊緩衝區。中間和下面的縮放/裁剪單元都是對ISP處理之後的YUV數據進行處理。中間的單元對YUV進行裁剪並縮放後,調用JPEG編碼器對其進行編碼,輸出JPEG圖像。下面的單元對YUV進行裁剪並縮放後,輸出不同分辨率的YUV數據。這三個縮放/裁剪單元對輸入數據也可以不進行裁剪和縮放處理。

API使用總結

這是android camera API使用步驟的簡單總結。查看" Startup and expected operation sequence"可以獲得這些步驟的詳細分解,以及API的調用。

  1. 監聽並枚舉所有camera設備;

  2. 打開設備並連接監聽器;

  3. 配置目標用例所需的輸出信息(比如靜態圖片,視頻錄製等)

  4. 根據目標用例創建請求;

  5. 發送或者重複發送這些請求;

  6. 接收輸出的元數據和圖像數據;

  7. 切換用例,則跳轉到第3步;

HAL層操作總結

  • Framework層發送捕獲數據的異步請求。

  • HAL層設備必須按照次序處理請求。對於每個請求,HAL層需要輸出元數據和一個或者多個圖像數據。

  • 對於請求和結果都需要遵循先進先出的原則;這個數據流將被後續的請求所參考。

  • 對於同一個請求,所有輸出數據的時間戳必須相同,以便framework層同步輸出數據,如果需要的話。

  • 在請求和結果數據總,所有捕獲數據的配置和狀態(除了3A處理),都需要封裝起來。

圖 6 Camera HAL overview

  1. Startup and expected operation sequence

這段描述了使用camera API的詳細步驟。其中涉及到的結構體和函數請參考文件:platform/hardware/libhardware/include/hardware/camera3.h

  1. Framework層調用函數camera_module_t->common.open(),將返回一個hardware_device_t類型的結構體。

  2. Framework層檢查字段hardware_device_t->version,根據版本信息,實例化一個適合這個版本的camera硬件設備的句柄。例如版本號是CAMERA_DEVICE_API_VERSION_3_0,則這個設備將被轉化爲camera3_device_t。

  3. Framework層調用函數camera3_device_t->ops->initialize(),並傳遞了framework層的回調函數指針。這個函數只能被調用一次,且在調用函數open()之後,在其他函數被調用之前。

  4. Framework層調用函數camera3_device_t->ops->configure_streams(),向這個HAL層設備傳遞了輸入輸出的流信息。

  5. Framework層分配grallocbuffer;調用函數camera3_device_t->ops->register_stream_buffers(),至少使用一個configure_streams中列舉的輸出流。同一個流只能被註冊一次。

  6. Framework層通過調用camera3_device_t->ops->construct_default_request_settings()獲取用例的默認設置。這個在第三步之後任意地方進行調用。

  7. Framework層使用默認設置集合中某一套設置,且保證之前註冊了至少一個輸出流,創建並向HAL層發第一個捕獲請求。這個請求將通過調用函數camera3_device_t->ops->process_capture_request()發送到HAL層。HAL必須阻止函數返回,直到HAL準備好接收下一個請求。

  8. Framework層連續地提交請求。可能會調用函數register_stream_buffers()來註冊沒有註冊過的流,調用函數construct_default_request_settings獲取其他用例所需的默認設置。

  9. 當一個請求的捕獲開始時(sensor開始曝光),HAL層將調用函數camera3_callback_ops_t->notify()通知上層SHUTTER事件,其中包括sensor開始曝光的幀號和時間戳。調用函數process_capture_result()處理這個幀號對應的數據之前,HAL層必鬚髮出SHUTTER通知。

  10. 流水線持續一些時間後,HAL層開始使用函數camera3_callback_ops_t->process_capture_result()向framework層返回處理完的圖像數據。返回結果的次序與提交請求的次序完全一致。多個請求可以被一次提交,但這取決於camera HAL層設備的流水線深度。

  11. 工作一段時間之後,framework層可能會停止提交新的請求,等待其他請求被完成(所有buffer被填充,所有結果被返回),然後再次調用函數configure_streams()。這是爲一組新的輸入輸出流重啓camera硬件和流水線。前面配置的一些流可能會被重複使用;如果流的buffer已經註冊到了HAL層,它們將不再被註冊。如果有一個被註冊的輸出流還存在,則framework層將從第七步重新開始(否則,將從第五步開始)。

  12. Framework層將調用函數camera3_device_t->common->close()結束camera會話。當framework層沒有其他調用時,可以在任何時間調用這個函數,儘管這個調用會阻塞,直到所有正在處理的捕獲被完成(所有結果被返回,所有buffer被填充)。函數close()返回之後,不允許HAL調用camera3_callback_ops_t的任何函數。一旦函數close()被調用,framework層將不能調用其他任何HAL層設備函數。

  13. 如果發生錯誤或者其他異步事件,HAL層必須調用函數camera3_callback_ops_t->notify()告知上層對應的錯誤或者事件信息。一個與設備相關的致命錯誤被通知上層後,HAL應該像被調用了函數close()一樣。但是,在調用函數notify()之前,HAL必須取消或者完成所有未結束的數據捕獲操作,以便致命錯誤被上報之後,framework不會收到設備的任何回調函數。除了函數close(),致命錯誤信息發出後,其他函數只能返回-ENODEV或者NULL。

圖 7 Camera operational flow

  1. Operational modes

Camera HAL層v3版本的設備實現兩種可能的操作模式之一:limited模式和full模式。新的高端設備預計會支持full模式。Limited模式與camera HAL層v1版本一樣,對硬件需求很低,用於舊的或者低價設備。Full模式是limited模式的超集,如上面所述,它們有着基本上一樣的操作流程。

Camera HAL層必須使用靜態元數據android.info.supportedHardwareLevel指明其所支持的模式。0表示支持limited模式,1表示支持full模式。

簡單來講,limited模式設備不允許應用程序控制捕獲數據信息的設置(3A控制除外),大分辨率圖像的高幀率捕獲,raw數據的獲取,或者上面所說的最大視頻分辨率的YUV輸出流(對於大圖像只支持JPEG)。
Limited模式行爲的細節如下:

  • Limited模式的設備不需要實現請求配置與實際捕獲圖像數據的完全匹配。相反,將來有時改變配置將更高效,可能也不需要一個配置必須對應一個同樣的輸出幀。快速改變配置可能會使得某些配置從來沒有被使用過。但是,有高分辨率(大於1080P)輸出buffer的捕獲必須使用指定的配置(處理速度的描述如下)。

  • 在limited模式下,有高分辨率(大於1080P)輸出buffer的捕獲在函數process_capture_request()中會阻塞,直到所有輸出buffer都被填充。Full模式HAL層設備必須按照靜態元數據中指定的速率,處理相應像素格式的高分辨率請求的序列。HAL層調用函數process_capture_result()產生輸出結果;framework層需要爲函數process_capture_request()做好準備,然後阻塞,直到limited模式設備的高分辨率捕獲請求被函數process_capture_result()執行完畢。

  •  Limited設備不需要支持大多數的配置、結果、靜態信息。只有下面的配置期待被limited模式HAL層設備所支持:

    • android.control.aeAntibandingMode (controls)
    • android.control.aeExposureCompensation (controls)
    • android.control.aeLock (controls)
    • android.control.aeMode (controls)
    • [OFF means ON_FLASH_TORCH]
    • android.control.aeRegions (controls)
    • android.control.aeTargetFpsRange (controls)
    • android.control.afMode (controls)
    • [OFF means infinity focus]
    • android.control.afRegions (controls)
    • android.control.awbLock (controls)
    • android.control.awbMode (controls)
    • [OFF not supported]
    • android.control.awbRegions (controls)
    • android.control.captureIntent (controls)
    • android.control.effectMode (controls)
    • android.control.mode (controls)
    • [OFF not supported]
    • android.control.sceneMode (controls)
    • android.control.videoStabilizationMode (controls)
    • android.control.aeAvailableAntibandingModes (static)
    • android.control.aeAvailableModes (static)
    • android.control.aeAvailableTargetFpsRanges (static)
    • android.control.aeCompensationRange (static)
    • android.control.aeCompensationStep (static)
    • android.control.afAvailableModes (static)
    • android.control.availableEffects (static)
    • android.control.availableSceneModes (static)
    • android.control.availableVideoStabilizationModes (static)
    • android.control.awbAvailableModes (static)
    • android.control.maxRegions (static)
    • android.control.sceneModeOverrides (static)
    • android.control.aeRegions (dynamic)
    • android.control.aeState (dynamic)
    • android.control.afMode (dynamic)
    • android.control.afRegions (dynamic)
    • android.control.afState (dynamic)
    • android.control.awbMode (dynamic)
    • android.control.awbRegions (dynamic)
    • android.control.awbState (dynamic)
    • android.control.mode (dynamic)
    • android.flash.info.available (static)
    • android.info.supportedHardwareLevel (static)
    • android.jpeg.gpsCoordinates (controls)
    • android.jpeg.gpsProcessingMethod (controls)
    • android.jpeg.gpsTimestamp (controls)
    • android.jpeg.orientation (controls)
    • android.jpeg.quality (controls)
    • android.jpeg.thumbnailQuality (controls)
    • android.jpeg.thumbnailSize (controls)
    • android.jpeg.availableThumbnailSizes (static)
    • android.jpeg.maxSize (static)
    • android.jpeg.gpsCoordinates (dynamic)
    • android.jpeg.gpsProcessingMethod (dynamic)
    • android.jpeg.gpsTimestamp (dynamic)
    • android.jpeg.orientation (dynamic)
    • android.jpeg.quality (dynamic)
    • android.jpeg.size (dynamic)
    • android.jpeg.thumbnailQuality (dynamic)
    • android.jpeg.thumbnailSize (dynamic)
    • android.lens.info.minimumFocusDistance (static)
    • android.request.id (controls)
    • android.request.id (dynamic)
    • android.scaler.cropRegion (controls)
    • [ignores (x,y), assumes center-zoom]
    • android.scaler.availableFormats (static)
    • [RAW not supported]
    • android.scaler.availableJpegMinDurations (static)
    • android.scaler.availableJpegSizes (static)
    • android.scaler.availableMaxDigitalZoom (static)
    • android.scaler.availableProcessedMinDurations (static)
    • android.scaler.availableProcessedSizes (static)
    • [full resolution not supported]
    • android.scaler.maxDigitalZoom (static)
    • android.scaler.cropRegion (dynamic)
    • android.sensor.orientation (static)
    • android.sensor.timestamp (dynamic)
    • android.statistics.faceDetectMode (controls)
    • android.statistics.info.availableFaceDetectModes (static)
    • android.statistics.faceDetectMode (dynamic)
    • android.statistics.faceIds (dynamic)
    • android.statistics.faceLandmarks (dynamic)
    • android.statistics.faceRectangles (dynamic)
    • android.statistics.faceScores (dynamic)
  1. Interaction between the application capture request, 3A control, and the processing pipeline

根據3A控制模塊的配置,camera流水線會忽略應用程序請求中的一些參數,而使用3A控制模塊提供的值代替。例如,當自動曝光開啓時,曝光時間,幀率,sensor的敏感參數都由3A算法控制,應用程序提供的值全被忽略。3A事務爲幀所設置的參數值必須包含在輸出的元數據中。下面的表格描述了3A模塊的不同模式和被這些模式所控制的屬性。屬性的定義見文件platform/system/media/camera/docs/docs.html

Parameter

State

Properties controlled

android.control.aeMode

OFF

None

 

ON

android.sensor.exposureTime android.sensor.frameDuration android.sensor.sensitivity android.lens.aperture (if supported) android.lens.filterDensity (if supported)

 

ON_AUTO_FLASH

Everything is ON, plus android.flash.firingPower, android.flash.firingTime, and android.flash.mode

 

ON_ALWAYS_FLASH

Same as ON_AUTO_FLASH

 

ON_AUTO_FLASH_RED_EYE

Same as ON_AUTO_FLASH

android.control.awbMode

OFF

None

 

WHITE_BALANCE_*

android.colorCorrection.transform. Platform-specific adjustments if android.colorCorrection.mode is FAST or HIGH_QUALITY.

android.control.afMode

OFF

None

 

FOCUS_MODE_*

android.lens.focusDistance

android.control.videoStabilization

OFF

None

 

ON

Can adjust android.scaler.cropRegion to implement video stabilization

android.control.mode

OFF

AE, AWB, and AF are disabled

 

AUTO

Individual AE, AWB, and AF settings are used

 

SCENE_MODE_*

Can override all parameters listed above. Individual 3A controls are disabled.

 

所列的3A算法的控制大部分都是與舊的API參數一一匹配(例如曝光補償,場景模式,或者白平衡模式)。

圖2中的圖像處理模塊的控制都是基於一個相似的原則,通常每個模塊有三中模式:

  • OFF:這個處理模塊不使能。去馬賽克,顏色校正和tone曲線調整模塊必須使能。

  • FAST:在這種模式,與off模式相比,處理模塊不會降低輸出幀率,但是對於產生高質量輸出時就不受這個限制了。典型地,它被用於預覽或者視頻錄製模式,或者靜態圖片的快速捕獲。在一些設備中,這種模式與OFF模式一樣(不工作就不會降低幀率);在一些設備中,它與HIGH_QUALITY模式一樣(高質量處理也不會降低幀率)。

  • HIGHQUALITY:在這種模式中,處理模塊產生最高質量的結果,如果需要會降低輸出幀率。典型地,它被用於高質量靜態圖片的捕獲。一些包括手動控制的模塊,可以替代FAST或者HIGHQUALITY。例如,圖像校正模塊支持一個顏色轉換矩陣,而tone曲線調整支持一個任意全局tone映射曲線。

一個camera子系統能夠支持的最大幀率是多個元素的函數:

  • 輸出圖像流所需要的分辨率

  • Imager對binning / skipping模式的支持

  • imager接口的帶寬

  • 各個ISP處理模塊的帶寬

因爲對於不同的ISP和sensor,這些因子有很大的變化,camera HAL層接口想要抽象一個儘可能簡單的帶寬限制模型。這個模型有如下特性:

  • Sensor總是輸出能滿足應用程序請求的輸出流大小的最小分辨率圖像數據。這個最小分辨率至少與被請求的最大輸出流大小一樣大。

  • 因爲任何情況可能會用到被配置的輸出流的幾個或者所有,所以sensor和ISP必須被配置爲能夠將一個圖像同時縮放到所有輸出流中。

  • JPEG流就像請求的被處理的YUV流;在請求中,它們直接被當作JPEG流來引用。

  • JPEG處理器能夠同時處理camera流水線的剩餘部分,但不能在同一個時刻處理多於一張的圖片。

  1. Metadata and Controls

  2. Metadata support

Android framework層爲了支持保存raw圖像文件,增加了大量關於sensor特性的元數據。這些元數據包括大量信息,例如顏色空間和lens shading。

在camera子系統中,大多數元數據信息都是以靜態屬性的方式存在,因此在配置輸出流水線或者提交請求之前獲取這些元數據。在新的camera API中,通過getCameraInfo()方法向application極大地擴展了這些元數據信息。

另外,camera子系統的手動控制需要各類設備提供關於設備當前狀態和捕獲當前幀時所用的參數的反饋。硬件所使用的實際參數值(曝光時間,幀週期,敏感度)必須包括在輸出的元數據中。這些信息對application是必須的,它可以知道clamping 或rounding何時發生,修正圖像捕獲的配置。

例如,如果application在某個請求中設置的幀週期是0,HAL層必須將那個請求中的幀週期強制爲真正的最小幀週期,然後將這個最小週期添加到輸出結果的元數據中。

如果一個application要實現定製的3A事例(例如,HDR burst的某些檢測),它需要知道所返回的結果中最新一幀的配置信息,以更新下一個請求的配置。因此,新的camera API爲每一個捕獲的幀添加了大量動態元數據。這些元數據包括這次捕獲時設置的和實際使用的參數值,也包括每幀其他的元數據,比如時間戳和統計數據。

  1. Per-setting control

對於大多數設置,期望它們能夠在每一幀都被改變,對輸出幀數據流不會引入明顯的卡頓或者延遲。理想情況下,輸出幀率只受請求中幀週期字段的控制,不依賴於處理模塊配置的改變。實際上,一些特殊控制可以使其變慢;這些控制包括camera流水線的輸出分辨率和輸出格式,以及影響物理設備的控制,例如鏡頭焦距。對於每個控制,精確的需求如下描述。 

  1. Raw sensor data support

除了舊API所支持的像素格式,新的API增加了對raw sensor數據(Bayer RAW)的支持,高級camera application還支持raw圖像文件的保存。

  1. 3A Modes and State Transition

雖然HAL層負責實現3A算法,但HAL interface定義了一個高層次的狀態機描述,允許HAL層設備和framework層交流3A當前狀態和3A事件的觸發情況。

當設備被打開時,所有3A狀態都應該是STATE_INACTIVE。碼流配置不需重置3A。例如,需要通過調用configure()來修改固定焦點。

要觸發3A行爲,需要爲下一個請求簡單地設置相關觸發器實體,以引導觸發器的啓動。例如,啓動自動聚焦的觸發器需要在一個請求中將ANDROID_CONTROL_AF_TRIGGER設置爲ANDROID_CONTROL_AF_TRIGGER_START。停止自動聚焦需要將ANDROID_ CONTROL_AF_TRIGGER設置爲ANDROID_CONTRL_AF_TRIGGER_CANCEL。否則,實體不存在或者被設置爲ANDROID_CONTROL_AF_TRIGGER_IDLE。每個請求對觸發器設置一個非IDLE的值,都會引發一個獨立的觸發器事件。

在頂層,通過設置ANDROID_CONTROL_MODE控制3A。可以選擇沒有3A(ANDROID_CONTROL_MODE_OFF),自動模式(ANDROID_CONTROL_MODE_AUTO)和場景模式(ANDROID_CONTROL_USE_SCENE_MODE)。

  • 在OFF模式下,自動聚焦(AF),自動曝光(AE)和自動白平衡(AEB)模式都被關閉。3A事例不會重置捕獲控制中的任何設置。

  • 在AUTO模式下,AF,AE和AWB模式運行各自的獨立算法,它們有自己的模式,狀態和觸發器元數據實體,如下段描述。

  • 在USE_SCENE_MODE模式下,ANDROID_CONTROL_SCENE_MODE的值決定3A事例的行爲。在除了FACE_PRIORITY的SCENE_MODE中,HAL層必須將ANDROID_CONTROL_AE/AWB/AF_MODE的值重置爲更適合被選擇的SCENE_MODE的模式。例如,HAL層喜歡在SCENE_MODE_NIGHT場景中使用AF的CONTINUOUS_FOCUS模式。當這些場景模式被忽略時,將使用用戶對AE/AWB/AF_MODE的選擇。

  • 對SCENE_MODE_FACE_PRIORITY的場景,AE/AWB/AFMODE工作在ANDROID_CONTROL_MODE_AUTO模式下。但是3A算法需要側重對場景中檢測出來的臉進行測光和聚焦。

  1. Auto-focus settings and result entries

Main metadata entries:

  • ANDROID_CONTROL_AF_MODE:控制當前自動聚焦模式的選擇。通過framework層在請求中設置。
    AF_MODE_OFF:AF關閉;framework/app直接控制鏡頭的位置。
    AF_MODE_AUTO:Single-sweep自動聚焦。只有AF被觸發,鏡頭纔會移動。

  • AF_MODE_MACRO:Single-sweep微距自動聚焦。只有AF被觸發,鏡頭纔會移動。

  • AF_MODE_CONTINUOUS_VIDEO:平滑的持續聚焦,用於視頻錄製。觸發則立即在當前位置鎖住焦點。取消而繼續持續聚焦。

  • AF_MODE_CONTINUOUS_PICTURE:快速持續聚焦,用於靜態圖片的ZSL捕獲。一旦達到掃描目標,觸發則立即鎖住焦點。取消而繼續持續聚焦。

  • AF_MODE_EDOF:高級的景深聚焦。沒有自動聚焦的瀏覽,觸發和取消沒有意義。通過HAL層控制圖像的聚集。

  • ANDROID_CONTROL_AF_STATE:描述當前AF算法狀態的動態元數據,HAL層在結果的元數據中報告該信息。

  • AF_STATE_INACTIVE:不做聚焦,或者算法被重置。鏡頭不移動。這個狀態總是用於MODE_OFF或者MODE_EDOF。當設備剛被打開時,必須處於這個狀態。

  • AF_STATE_PASSIVE_SCAN:一個持續聚焦的算法正在做掃描。鏡頭正在移動中。

  • AF_STATE_PASSIVE_FOCUSED:一個持續聚焦的算法認爲已經聚焦成功。鏡頭不在移動。HAL層會自動地離開這個狀態。

  • AF_STATE_PASSIVE_UNFOCUSED:一個持續聚焦的算法認爲聚焦失敗。鏡頭不在移動。HAL層會自動地離開這個狀態。

  • AF_STATE_ACTIVE_SCAN:用戶觸發的掃描正在進行中。

  • AF_STATE_FOCUSED_LOCKED:AF算法認爲聚焦結束。鏡頭不再移動。

  • AF_STATE_NOT_FOCUSED_LOCKED:AF算法沒能完成聚焦。鏡頭不再移動。

  • ANDROID_CONTROL_AFTRIGGER:控制啓動自動聚集掃描,其意義由所選擇的模式和狀態決定。Framework層在請求中設置該值。

  • AF_TRIGGER_IDLE:沒有觸發器。

  • AF_TRIGGER_START:觸發AF掃描。其作用取決於模式和狀態。

  • AF_TRIGGER_CANCEL:停止當前的AF掃描,重置算法到默認狀態。

  • 其他元數據實體:

  • ANDROID_CONTROL_AF_REGIONS:控制視角區域的選擇,用於檢測好的聚焦點。用於所有可進行聚焦掃描的AF模式。Framework層在請求中設置該值。

  1. Auto-exposure settings and result entries

Main metadata entries:

  • ANDROID_CONTROL_AE_MODE:控制當前自動曝光模式的選擇。Framework層在請求中設置該值。

  • AE_MODE_OFF:關閉自動曝光;用戶控制曝光,增益,幀週期和閃光燈。

  • AE_MODE_ON:標準的自動聚焦,閃光燈關閉。用戶設置閃光燈啓動或者手電筒模式。

  • AE_MODE_ON_AUTO_FLASH:標準自動曝光,開啓閃光燈。HAL層精確控制捕獲前和捕獲靜態圖片時閃光。用戶可控制閃光燈關閉。

  • AE_MODE_ON_ALWAYS_FLASH:標準自動曝光,拍照時閃光燈一直開啓。HAL層精確控制捕獲前閃光。用戶可控制閃光燈關閉。

  • AE_MODE_ON_AUTO_FLASH_REDEYE:標準自動曝光。HAL層精確控制預閃和捕獲靜態圖片時閃光。在前面捕獲序列的最後一幀啓動一次閃光燈,以減少後面圖片中的紅眼現象。用戶可控制閃光燈關閉。

  • ANDROID_CONTROL_AE_STATE:描述當前AE算法狀態的動態元數據,HAL層在結果的元數據中報告該信息。

  • AE_STATE_INACTIVE:模式切換後AE初始狀態。當設備剛打開時,AE必須處於這個狀態。

  • AE_STATE_SEARCHING:AE沒有達到曝光目標,正在調整曝光參數。

  • AE_STATE_CONVERGED:AE已經找到當前場景的正確的曝光值,曝光參數不再改變。HAL層會自動離開這個狀態,尋找更好的解決方案。

  • AE_STATE_LOCKED:使用AE_LOCK已經鎖住了AE。曝光值不再改變。

  • AE_STATE_FLASH_REQUIRED:HAL層已經曝光成功,但爲了獲取更亮的圖片,需要開啓閃光燈。用於ZSL模式。

  • AE_STATE_PRECAPTURE:HAL在捕獲序列中間進行控制。根據AE模式,這種模式採用啓動閃光燈測光或者瞬間開啓關閉閃光燈預防紅眼。

  • ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER:在捕獲一張高質量圖像之前,控制啓動一個測光序列。Framework層在請求中設置該值。

  • PRECAPTURE_TRIGGER_IDLE:沒有觸發器。

  • PRECAPTURE_TRIGGER_START:啓動一個捕獲序列。HAL層使用後續的請求爲獲取高分辨率圖像決定理想的曝光/白平衡。

Additional metadata entries:

  • ANDROID_CONTROL_AE_LOCK:控制鎖住AE當前的值。

  • ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION:控制調整AE算法目標亮度點。

  • ANDROID_CONTROL_AE_TARGET_FPS_RANGE:控制選擇AE算法的目標幀率區間。AE事例不能使用這個區間之外的幀率值。

  • ANDROID_CONTROL_AE_REGIONS:控制視角區域的選擇,用於檢測好的曝光值。用於所有除了OOF的AE模式。

  1. Auto-whitebalance settings and resultentries

Main metadata entries:

  • ANDROID_CONTROL_AWB_MODE:控制當前白平衡模式的選擇。

  • AWB_MODE_OFF:關閉自動白平衡。用戶控制顏色矩陣。

  • AWB_MODE_AUTO:使能自動白平衡;3A控制顏色轉換,可能會使用比簡單矩陣更復雜的轉換。

  • AWB_MODE_INCANDESCENT:用於室內白zhi燈的白平衡設置,色溫大概2700K。

  • AWB_MODE_FLUORESCENT:用於熒光燈的白平衡設置,色溫大概5000K。

  • AWB_MODE_WARM_FLUORESCENT:用於熒光燈的白平衡設置,色溫大概3000K。

  • AWB_MODE_DAYLIGHT:用於晴天的白平衡設置,色溫大概5500K。

  • AWB_MODE_CLOUDY_DAYLIGHT:用於陰天的白平衡設置,色溫大概6500K。

  • AWB_MODE_TWILIGHT:用於日出/日落的白平衡設置,色溫大概15000K。

  • AWB_MODE_SHADE:用於陰影處的白平衡設置,色溫大概7500K。

  • ANDROID_CONTROL_AWB_STATE:描述當前AWB算法狀態的動態元數據,HAL層在結果的元數據中報告該信息。

  • AWB_STATE_INACTIVE:切換模式後AWB的初始狀態。當設備剛打開時,AWB必須處於這個狀態。

  • AWB_STATE_SEARCHING:AWB沒有收斂到目標值,在改變顏色調整參數。

  • AWB_STATE_CONVERGED:AWB爲當前場景已經找到了理想的顏色調整值,這些參數不再改變。HAL層會自動離開該狀態去尋找更好的解決方案。

  • AWB_STATE_LOCKED:使用AWB_LOCK鎖住了AWB。顏色調整值不再改變。

Additional metadata entries:

  • ANDROID_CONTROL_AWB_LOCK:控制鎖住當前AWB的值。

  • ANDROID_CONTROL_AWB_REGIONS:控制視角區域的選擇,用於檢測好的顏色平衡值。只用於自動白平衡模式。

  1. General state machine transition notes

在切換AF,AE和AWB的不同模式是總會將算法的狀態重置爲INACTIVE。同樣地,在CONTROL_MODE和CONTROL_SCENE_MODE(CONTROL_MODE == USE_SCENE_ MODE)之間切換時,也需要將算法的狀態重置爲INACTIVE。

  1. AF state machines

 

mode = AF_MODE_OFF or AF_MODE_EDOF

     

State

Transformation cause

New state

Notes

INACTIVE

   

AF is disabled

mode = AF_MODE_AUTO or AF_MODE_MACRO

     

State

Transformation cause

New state

Notes

INACTIVE

AF_TRIGGER

ACTIVE_SCAN

Start AF sweep Lens now moving

ACTIVE_SCAN

AF sweep done

FOCUSED_LOCKED

If AF successful Lens now locked

ACTIVE_SCAN

AF sweep done

NOT_FOCUSED_LOCKED

If AF successful Lens now locked

ACTIVE_SCAN

AF_CANCEL

INACTIVE

Cancel/reset AF Lens now locked

FOCUSED_LOCKED

AF_CANCEL

INACTIVE

Cancel/reset AF

FOCUSED_LOCKED

AF_TRIGGER

ACTIVE_SCAN

Start new sweep Lens now moving

NOT_FOCUSED_LOCKED

AF_CANCEL

INACTIVE

Cancel/reset AF

NOT_FOCUSED_LOCKED

AF_TRIGGER

ACTIVE_SCAN

Start new sweep Lens now moving

All states

mode change

INACTIVE

 

mode = AF_MODE_CONTINUOUS_VIDEO

     

State

Transformation cause

New state

Notes

INACTIVE

HAL initiates new scan

PASSIVE_SCAN

Start AF sweep Lens now moving

INACTIVE

AF_TRIGGER

NOT_FOCUSED_LOCKED

AF state query Lens now locked

PASSIVE_SCAN

HAL completes current scan

PASSIVE_FOCUSED

End AF scan Lens now locked

PASSIVE_SCAN

AF_TRIGGER

FOCUSED_LOCKED

Immediate transformation if focus is good Lens now locked

PASSIVE_SCAN

AF_TRIGGER

NOT_FOCUSED_LOCKED

Immediate transformation if focus is bad Lens now locked

PASSIVE_SCAN

AF_CANCEL

INACTIVE

Reset lens position Lens now locked

PASSIVE_FOCUSED

HAL initiates new scan

PASSIVE_SCAN

Start AF scan Lens now moving

PASSIVE_FOCUSED

AF_TRIGGER

FOCUSED_LOCKED

Immediate transformation if focus is good Lens now locked

PASSIVE_FOCUSED

AF_TRIGGER

NOT_FOCUSED_LOCKED

Immediate transformation if focus is bad Lens now locked

FOCUSED_LOCKED

AF_TRIGGER

FOCUSED_LOCKED

No effect

FOCUSED_LOCKED

AF_CANCEL

INACTIVE

Restart AF scan

NOT_FOCUSED_LOCKED

AF_TRIGGER

NOT_FOCUSED_LOCKED

No effect

NOT_FOCUSED_LOCKED

AF_CANCEL

INACTIVE

Restart AF scan

mode = AF_MODE_CONTINUOUS_PICTURE

     

State

Transformation cause

New state

Notes

INACTIVE

HAL initiates new scan

PASSIVE_SCAN

Start AF scan Lens now moving

INACTIVE

AF_TRIGGER

NOT_FOCUSED_LOCKED

AF state query Lens now locked

PASSIVE_SCAN

HAL completes current scan

PASSIVE_FOCUSED

End AF scan Lens now locked

PASSIVE_SCAN

AF_TRIGGER

FOCUSED_LOCKED

Eventual transformation once focus good Lens now locked

PASSIVE_SCAN

AF_TRIGGER

NOT_FOCUSED_LOCKED

Eventual transformation if cannot focus Lens now locked

PASSIVE_SCAN

AF_CANCEL

INACTIVE

Reset lens position Lens now locked

PASSIVE_FOCUSED

HAL initiates new scan

PASSIVE_SCAN

Start AF scan Lens now moving

PASSIVE_FOCUSED

AF_TRIGGER

FOCUSED_LOCKED

Immediate transformation if focus is good Lens now locked

PASSIVE_FOCUSED

AF_TRIGGER

NOT_FOCUSED_LOCKED

Immediate transformation if focus is bad Lens now locked

FOCUSED_LOCKED

AF_TRIGGER

FOCUSED_LOCKED

No effect

FOCUSED_LOCKED

AF_CANCEL

INACTIVE

Restart AF scan

NOT_FOCUSED_LOCKED

AF_TRIGGER

NOT_FOCUSED_LOCKED

No effect

NOT_FOCUSED_LOCKED

AF_CANCEL

INACTIVE

Restart AF scan

 

  1. AE and AWB state machines

AE和AWB的狀態機基本上是完全相同的。AE有額外的FLASH_REQUIRED和PRECAPTURE狀態。所以下面行中涉及這兩個狀態時,AWB狀態機忽略之。

mode = AE_MODE_OFF / AWB mode not AUTO

     

State

Transformation cause

New state

Notes

INACTIVE

   

AE/AWB disabled

mode = AE_MODE_ON_* / AWB_MODE_AUTO

     

State

Transformation cause

New state

Notes

INACTIVE

HAL initiates AE/AWB scan

SEARCHING

 

INACTIVE

AE/AWB_LOCK on

LOCKED

Values locked

SEARCHING

HAL finishes AE/AWB scan

CONVERGED

Good values, not changing

SEARCHING

HAL finishes AE scan

FLASH_REQUIRED

Converged but too dark without flash

SEARCHING

AE/AWB_LOCK on

LOCKED

Values locked

CONVERGED

HAL initiates AE/AWB scan

SEARCHING

Values locked

CONVERGED

AE/AWB_LOCK on

LOCKED

Values locked

FLASH_REQUIRED

HAL initiates AE/AWB scan

SEARCHING

Values locked

FLASH_REQUIRED

AE/AWB_LOCK on

LOCKED

Values locked

LOCKED

AE/AWB_LOCK off

SEARCHING

Values not good after unlock

LOCKED

AE/AWB_LOCK off

CONVERGED

Values good after unlock

LOCKED

AE_LOCK off

FLASH_REQUIRED

Exposure good, but too dark

All AE states

PRECAPTURE_START

PRECAPTURE

Start precapture sequence

PRECAPTURE

Sequence done, AE_LOCK off

CONVERGED

Ready for high-quality capture

PRECAPTURE

Sequence done, AE_LOCK on

LOCKED

Ready for high-quality capture

 

  1. Enabling manual control

在配置3A模塊中所涉及的一些控制,允許application直接控制。

對於每個請求,HAL層負責3A控制的模塊會檢查3A控制字段的狀態。如果有3A事例使能,這些事例可能會重置該事例相關的控制變量,重置的值會放置於此次捕獲的結果元數據中。例如,如果在一個請求中自動曝光使能,HAL層會重置這個請求中的曝光值,增益和幀週期字段(和潛在的閃光燈字段,依賴於AE模式)。相關控制如下

Control name

Unit

Notes

android.control.mode

enum: OFF, AUTO, USE_SCENE_MODE

High-level 3A control. When set to OFF, all 3A control by the HAL is disabled. The application must set the fields for capture parameters itself. When set to AUTO, the individual algorithm controls in android.control.* are in effect, such as android.control.afMode. When set to USE_SCENE_MODE, the individual controls in android.control.* are mostly disabled, and the HAL implements one of the scene mode settings (such as ACTION, SUNSET, or PARTY) as it wishes.

android.control.afMode

enum

OFF means manual control of lens focusing through android.lens.focusDistance.

android.control.aeMode

enum

OFF means manual control of exposure/gain/frame duration through android.sensor.exposureTime / .sensitivity / .frameDuration

android.control.awbMode

enum

OFF means manual control of white balance.

 

  1. Output streams and cropping

  2. Output streams

與老的Camera子系統不同,老系統從camera輸出的數據有3~4種不同的類型(ANativeWindow-based preview operations, preview callbacks, video callbacks, and takePicture callbacks),而在新的camera子系統中,對於所有解決方案和輸出數據格式,系統只輸出ANativeWindow-based preview operations。可以一次配置多個這樣的數據流,發送單幀給多個不同的目標,如GPU、視頻編碼器、渲染腳本(RenderScript)或應用程序的可見緩衝區(RAE Bayer、YUV buffer、或JPEG-encoded buffers)。

    爲了優化處理,所有輸出流都必須提前配置,一次只能配置有限的數量。這樣做的好處,就是允許提前分配內存緩衝區和配置camera硬件。於是,當一次提交多個請求或輸出到多個不同pipeline時,就不會有請求延時。

爲了實現新版Camera API的向後兼容,必須至少同時支持3路輸出流,外加一路JPEG流。這是支持視頻快拍的必須條件。

  • One stream to the GPU/SurfaceView (opaque YUV format) for preview

  • One stream to the video encoder (opaque YUV format) for recording

  • One stream to the application (known YUV format) for preview frame callbacks

  • One stream to the application (JPEG) for video snapshots.

    具體的需求仍然處於商定之中,還沒有最終確定。

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