轉眼一看,上一次發博文都快是三年之前了,慚愧 ! 主要是三年前找的這份工作,雖然是世界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]);
+ }