Android Camera HAL V3 Vendor Tag及V1,V3參數轉換

   轉眼一看,上一次發博文都快是三年之前了,慚愧 ! 主要是三年前找的這份工作,雖然是世界500強的技術大牛公司,但是工作可一點都不高大上,非常的忙,一天不但要處理各種camera的bug,還要開發camera的各種feature和sensor驅動,還要和內部、外部的人各種扯皮,你懂的。忙的三年了纔有閒心來發表這片博文。

       牢騷已完,言歸正傳。

       在Android 5.0上,Google正式的將Camera HAL 3.0作爲一個標準配置進行了發行,當然Camera HAL V1也是作爲兼容標準是可以用的。但是很多有實力的芯片廠商都第一時間切換到了HAL V3。 HAL V3與V1最大的本質區別,我認爲就是把幀的參數和幀的圖像數據綁定到了一起,比如V1的時候一張preview上來的YUV幀,APP是不知道這個YUV幀採用的Gain和曝光時間究竟是多少。但是在V3裏面,每一幀都有一個數據結構來描述,其中包括了幀的參數和幀的數據,當APP發送一個request的時候是需要指定使用什麼樣的參數,到request返回的時候,返回數據中就有圖像數據和相關的參數配置。

        在V1裏面,如果想增加一些廠商特定的參數,比如增加Saturation的設置,最簡單的方法就是直接使用CameraParameters.set來實現,即在APP中,

        Camera.Parameters mParameters = mCamera.getParameters();

        mParameters.set("saturation", 10);

        mCamera.setParameters(parameters);

        由於HAL V1的參數傳遞是通過字符串來完成的,也就是最後傳到HAL的字符串裏面會有“saturation=10”  這樣的字符串,在HAL直接解析這些字符串就OK了。

但是到了HAL V3,從framework到hal的參數傳遞都是通過metadata的方式來傳遞,簡單的說就是每一個設置現在都變成了一個參數對,比如假設要設置AE mode爲auto,以前V1可能是“AE mode=auto”這樣的字符串,在V3就是比如AE mode的功能序號是10,參數auto爲1,傳下來的其實是類似(10,1)這樣的參數對。在HAL裏面需要通過10這個參數,去獲取設置值1。因此比如原來在V1裏面有saturation這種設置的話,在V3就需要添加新的處理來實現。

        Google 考慮到各大芯片廠商都可能有自己的特定參數需要設置,因此在metadata裏面定義了vendor tag的數據範圍來讓vendor可以添加自己的特定操作。比如上面說到的saturation由於不是google的標準參數,就可以通過vendor tag來實現。

         首先,需要在camera_metadata_tags.h裏面定義自己的vendor tag序號值,比如

typedef enum camera_metadata_tag {
             ANDROID_SYNC_START,
     ANDROID_SYNC_MAX_LATENCY,                         // enum         | public
     ANDROID_SYNC_END,

+    VENDOR_TAG_SATURATION =
+    VENDOR_SECTION_START,

        ..............................................

 } camera_metadata_tag_t;

        Google規定,Vendor Tag都需要在VENDOR_SECTION_START後面添加,此處添加了VENDOR_TAG_SATURATION。在HAL裏面如果需要處理Vendor Tag,一個是需要camera module的版本是2.2以上,因爲Google在這個版本之後才穩定支持vendor tag。一個是需要vendor tag的的operations函數。如下面所述。

camera_module_t HAL_MODULE_INFO_SYM = {
     NAMED_FIELD_INITIALIZER(common) {
         NAMED_FIELD_INITIALIZER(tag) HARDWARE_MODULE_TAG,
-        NAMED_FIELD_INITIALIZER(module_api_version) CAMERA_MODULE_API_VERSION_2_0,
+        NAMED_FIELD_INITIALIZER(module_api_version) CAMERA_MODULE_API_VERSION_2_2,
        ...............................................
-    NAMED_FIELD_INITIALIZER(get_vendor_tag_ops) NULL,
+    NAMED_FIELD_INITIALIZER(get_vendor_tag_ops) get_vendor_tag_ops,
       ................................................
 };

        get_vendor_tag_ops是需要自己實現的,其中主要有以下幾個接口,可以參照hardware/libhardware/modules/camera下面的VendorTags.cpp和VendorTags.h來實現。主要的功能如以下描述

static void get_vendor_tag_ops(vendor_tag_ops_t* ops)
+{
+    ALOGE("%s : ops=%p", __func__, ops);
+    ops->get_tag_count      = get_tag_count;  
+    ops->get_all_tags       = get_all_tags;  
+    ops->get_section_name   = get_section_name;
+    ops->get_tag_name       = get_tag_name;
+    ops->get_tag_type       = get_tag_type;
+}

get_tag_count;  //返回vendor tag的個數,有多少個返回多少個

get_all_tags;  //把所有vendor tag挨個放在service傳下來的uint32_t * tag_array裏面,這樣上層就知道每一個tag對應的序號值了

 get_section_name;//獲取vendor tag的section對應的section名稱,比如可以把某幾個tag放在一個section裏面,其它的放在其它的section裏面. 查看metadata.h裏面的定義很好理解,如果你想增加自己的section,就可以在VENDOR_SECTION = 0x8000後面添加自己的section。本人由於參數較少,也沒有分類的必要,所以就使用默認的VENDOR_SECTION.

typedef enum camera_metadata_section {
    ANDROID_COLOR_CORRECTION,
   ......................
    ANDROID_SECTION_COUNT,
    VENDOR_SECTION = 0x8000
} camera_metadata_section_t;

typedef enum camera_metadata_section_start {
    ANDROID_COLOR_CORRECTION_START = ANDROID_COLOR_CORRECTION  << 16,
........................
    VENDOR_SECTION_START           = VENDOR_SECTION            << 16
} camera_metadata_section_start_t;
 get_tag_name用於獲取每一個tag的名稱,比如我這個地方返回“saturation”就可以了

get_tag_type這個函數返回tag對應的設置數據的類型,可以用TYPE_INT32, TYPE_FLOAT等多種數據格式,取決於需求,我這個只要是INT32就行了。

       這樣CameraService.cpp在啓動的時候就會調用onFirstRef裏面的下面代碼來加載我們所寫的vendor tag

       if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_2) {
            ALOGE("yangsy CameraService %s %d", __FUNCTION__, __LINE__);
            setUpVendorTags();
        }

       那vendor tag如何設置,在HAL裏面如何處理呢?由於我這個saturation設置是在以前V1的APP裏面需要使用,因此首先需要實現V1和V3參數的轉換,Google在services/camera/libcameraservice/api1/client2/Parameters.cpp實現相應的轉換,因此

首先需要在status_t Parameters::set(const String8& paramString)裏面獲取V1 APP傳下來的saturation的值,其中的paramString就是V1的參數設置的字符串

       mSaturation = newParams.getInt("saturation"); 

       由於V3的參數都是在request frame的時候一起下發的,因此需要講mSaturation的值在Parameters::updateRequest(CameraMetadata *request)裏面下發到HAL,即

+    res = request->update(VENDOR_TAG_SATURATION, &mSaturation, 1);
+    ALOGE("yangsy request update saturation result:%d", res);

       這樣就將saturation的vendor tag和其設置值發送到了HAL V3。

       那在HAL V3裏面如何獲得saturation的值呢?這個就比較簡單了,使用CameraMetadata::find(uint32_t tag)的find函數,在處理request的metadata的代碼裏面添加就OK了

+    tag = VENDOR_TAG_SATURATION; //需要查找的tag
+    ALOGE("yangsy HAL  settings effect setting");
+    entry = settings.find(tag);//調用metada.find
+    if (entry.count == 1) { //找到了tag
+        ALOGE("yangsy HAL try saturation %d", entry.data.i32[0]);//entry.data.i32[0]就是相應的設置值
+    mSensor->setSaturation(entry.data.i32[0]); 
+    }


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