1.9. 使用者控制¶
裝置通常具有許多使用者可設定的控制項,例如亮度、飽和度等,這些控制項將在圖形使用者介面上呈現給使用者。但是,不同的裝置將具有不同的可用控制項,並且可能值的範圍和預設值也會因裝置而異。控制 ioctls 提供資訊和一種機制,用於為這些控制項建立友好的使用者介面,該介面將與任何裝置正確工作。
所有控制項都透過一個 ID 值訪問。V4L2 為特定目的定義了幾個 ID。驅動程式還可以使用 V4L2_CID_PRIVATE_BASE [1] 及更高的值實現自己的自定義控制項。預定義的控制 ID 具有字首 V4L2_CID_,並列在 控制 ID 中。ID 用於查詢控制項的屬性,以及獲取或設定當前值。
通常,應用程式應向用戶呈現控制項,而不對其目的進行假設。每個控制項都附帶一個使用者應該理解的名稱字串。當目的不直觀時,驅動程式編寫者應提供使用者手冊、使用者介面外掛或驅動程式特定的面板應用程式。引入預定義 ID 是為了以程式設計方式更改一些控制項,例如在頻道切換期間使裝置靜音。
驅動程式在切換當前影片輸入或輸出、調諧器或調製器、或音訊輸入或輸出後,可能會列舉不同的控制項。不同之處在於界限、預設值和當前值、步長或選單項可能不同。具有某個自定義 ID 的控制項也可以更改名稱和型別。
如果某個控制項不適用於裝置的當前配置(例如,它不適用於當前影片輸入),則驅動程式會設定 V4L2_CTRL_FLAG_INACTIVE 標誌。
控制值是全域性儲存的,它們在切換時不會改變,除非是為了保持在報告的界限內。它們也不會在裝置開啟或關閉時,或調諧器無線電頻率改變時,或一般情況下未經應用程式請求而改變。
V4L2 指定了一種事件機制,用於在控制項值改變時通知應用程式(參見 ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT,事件 V4L2_EVENT_CTRL),面板應用程式可能希望利用此機制來始終反映正確的控制值。
所有控制項都使用機器位元組序。
1.9.1. 控制 ID¶
V4L2_CID_BASE第一個預定義 ID,等同於
V4L2_CID_BRIGHTNESS。V4L2_CID_USER_BASEV4L2_CID_BASE的同義詞。V4L2_CID_BRIGHTNESS(integer)影像亮度,更確切地說,是黑電平。
V4L2_CID_CONTRAST(integer)影像對比度或亮度增益。
V4L2_CID_SATURATION(integer)影像色彩飽和度或色度增益。
V4L2_CID_HUE(integer)色調或色彩平衡。
V4L2_CID_AUDIO_VOLUME(integer)整體音量。請注意,一些驅動程式也提供 OSS 或 ALSA 混音器介面。
V4L2_CID_AUDIO_BALANCE(integer)音訊立體聲平衡。最小值對應於完全向左,最大值對應於完全向右。
V4L2_CID_AUDIO_BASS(integer)音訊低音調整。
V4L2_CID_AUDIO_TREBLE(integer)音訊高音調整。
V4L2_CID_AUDIO_MUTE(boolean)靜音音訊,即,將音量設定為零,但不影響
V4L2_CID_AUDIO_VOLUME。與 ALSA 驅動程式一樣,V4L2 驅動程式在載入時必須靜音以避免過多的噪音。實際上,整個裝置應重置為低功耗狀態。V4L2_CID_AUDIO_LOUDNESS(boolean)響度模式(低音增強)。
V4L2_CID_BLACK_LEVEL(integer)亮度的另一個名稱(不是
V4L2_CID_BRIGHTNESS的同義詞)。此控制項已棄用,不應在新驅動程式和應用程式中使用。V4L2_CID_AUTO_WHITE_BALANCE(boolean)自動白平衡(相機)。
V4L2_CID_DO_WHITE_BALANCE(button)這是一個動作控制項。設定時(值被忽略),裝置將進行白平衡,然後保持當前設定。這與布林型的
V4L2_CID_AUTO_WHITE_BALANCE形成對比,後者在啟用時會持續調整白平衡。V4L2_CID_RED_BALANCE(integer)紅色色度平衡。
V4L2_CID_BLUE_BALANCE(integer)藍色色度平衡。
V4L2_CID_GAMMA(integer)伽馬調整。
V4L2_CID_WHITENESS(integer)灰度裝置的白度。這是
V4L2_CID_GAMMA的同義詞。此控制項已棄用,不應在新驅動程式和應用程式中使用。V4L2_CID_EXPOSURE(integer)曝光(相機)。[單位?]
V4L2_CID_AUTOGAIN(boolean)自動增益/曝光控制。
V4L2_CID_GAIN(integer)增益控制。
主要用於控制例如電視調諧器和網路攝像頭的增益。大多數裝置只用此控制項控制數字增益,但某些裝置也可能包括模擬增益。區分數字增益和模擬增益的裝置使用控制項
V4L2_CID_DIGITAL_GAIN和V4L2_CID_ANALOGUE_GAIN。
V4L2_CID_HFLIP(boolean)水平翻轉影像。
V4L2_CID_VFLIP(boolean)垂直翻轉影像。
V4L2_CID_POWER_LINE_FREQUENCY(enum)啟用電源線頻率濾波器以避免閃爍。
enum v4l2_power_line_frequency的可能值有V4L2_CID_POWER_LINE_FREQUENCY_DISABLED0
V4L2_CID_POWER_LINE_FREQUENCY_50HZ1
V4L2_CID_POWER_LINE_FREQUENCY_60HZ2
V4L2_CID_POWER_LINE_FREQUENCY_AUTO3
V4L2_CID_HUE_AUTO(boolean)啟用裝置的自動色調控制。在自動色調控制啟用時設定
V4L2_CID_HUE的效果未定義,驅動程式應忽略此類請求。V4L2_CID_WHITE_BALANCE_TEMPERATURE(integer)此控制項以開爾文為單位指定白平衡設定(色溫)。驅動程式應具有至少 2800(白熾燈)到 6500(日光)的範圍。有關色溫的更多資訊,請參閱 維基百科。
V4L2_CID_SHARPNESS(integer)調整相機中的銳度濾鏡。最小值停用濾鏡,更高值可提供更銳利的影像。
V4L2_CID_BACKLIGHT_COMPENSATION(integer)調整相機中的背光補償。最小值停用背光補償。
V4L2_CID_CHROMA_AGC(boolean)色度自動增益控制。
V4L2_CID_CHROMA_GAIN(integer)調整色度增益控制(在色度 AGC 停用時使用)。
V4L2_CID_COLOR_KILLER(boolean)啟用色殺(即,在影片訊號弱時強制生成黑白影像)。
V4L2_CID_COLORFX(enum)選擇一種顏色效果。定義了以下值
|
顏色效果已停用。 |
|
一種老舊(老照片)效果。 |
|
霜凍顏色效果。 |
|
水彩,冷色調。 |
|
黑白。 |
|
浮雕,高光和陰影取代明暗邊界,低對比度區域設定為灰色背景。 |
|
草綠色。 |
|
負片。 |
|
棕褐色調。 |
|
素描。 |
|
皮膚美白。 |
|
天藍色。 |
|
反轉,影像色調部分反轉,只有高於或低於某個閾值的顏色值被反轉。 |
|
剪影(輪廓)。 |
|
鮮豔色彩。 |
|
Cb 和 Cr 色度分量被 |
|
RGB 分量被 |
V4L2_CID_COLORFX_RGB(integer)確定
V4L2_COLORFX_SET_RGB顏色效果的紅色、綠色和藍色系數。提供的 32 位值中,[7:0] 位被解釋為藍色分量,[15:8] 位為綠色分量,[23:16] 位為紅色分量,[31:24] 位必須為零。V4L2_CID_COLORFX_CBCR(integer)確定
V4L2_COLORFX_SET_CBCR顏色效果的 Cb 和 Cr 係數。提供的 32 位值中,[7:0] 位被解釋為 Cr 分量,[15:8] 位為 Cb 分量,[31:16] 位必須為零。V4L2_CID_AUTOBRIGHTNESS(boolean)啟用自動亮度。
V4L2_CID_ROTATE(integer)將影像旋轉指定角度。常見角度為 90、270 和 180 度。將影像旋轉 90 度和 270 度將反轉顯示視窗的高度和寬度。需要使用 VIDIOC_S_FMT ioctl 根據所選旋轉角度設定影像的新高度和寬度。
V4L2_CID_BG_COLOR(integer)設定當前輸出裝置的背景顏色。背景顏色需要以 RGB24 格式指定。提供的 32 位值中,0-7 位解釋為紅色顏色資訊,8-15 位為綠色顏色資訊,16-23 位為藍色顏色資訊,24-31 位必須為零。
V4L2_CID_ILLUMINATORS_1 V4L2_CID_ILLUMINATORS_2(boolean)開啟或關閉裝置(通常是顯微鏡)的照明器 1 或 2。
V4L2_CID_MIN_BUFFERS_FOR_CAPTURE(integer)這是一個只讀控制項,應用程式可以讀取並用作提示,以確定傳遞給 REQBUFS 的 CAPTURE 緩衝區的數量。該值是硬體工作所需的最小 CAPTURE 緩衝區數量。狀態解碼器需要此控制項。
V4L2_CID_MIN_BUFFERS_FOR_OUTPUT(integer)這是一個只讀控制項,應用程式可以讀取並用作提示,以確定傳遞給 REQBUFS 的 OUTPUT 緩衝區的數量。該值是硬體工作所需的最小 OUTPUT 緩衝區數量。狀態編碼器需要此控制項。
V4L2_CID_ALPHA_COMPONENT(integer)設定 Alpha 顏色分量。當捕獲裝置(或記憶體到記憶體裝置的捕獲佇列)生成包含 Alpha 分量的幀格式(例如 打包 RGB 影像格式),並且 Alpha 值未由裝置或記憶體到記憶體輸入資料定義時,此控制項允許您選擇所有畫素的 Alpha 分量值。當輸出裝置(或記憶體到記憶體裝置的輸出佇列)消耗不包含 Alpha 分量的幀格式,並且裝置支援 Alpha 通道處理時,此控制項允許您設定所有畫素的 Alpha 分量值以供裝置中進一步處理。
V4L2_CID_LASTP1預定義控制 ID 的結尾(當前為
V4L2_CID_ALPHA_COMPONENT+ 1)。V4L2_CID_PRIVATE_BASE第一個自定義(驅動程式特定)控制項的 ID。依賴特定自定義控制項的應用程式應檢查驅動程式名稱和版本,參見 查詢功能。
應用程式可以使用 ioctls VIDIOC_QUERYCTRL、VIDIOC_QUERY_EXT_CTRL 和 VIDIOC_QUERYMENU 以及 VIDIOC_QUERYMENU ioctls 列舉可用控制項,並使用 VIDIOC_G_CTRL 和 VIDIOC_S_CTRL ioctls 獲取和設定控制值。當裝置有一個或多個控制項時,驅動程式必須實現 VIDIOC_QUERYCTRL、VIDIOC_G_CTRL 和 VIDIOC_S_CTRL;當裝置有一個或多個選單型別控制項時,必須實現 VIDIOC_QUERYMENU。
1.9.2. 示例:列舉所有控制項¶
struct v4l2_queryctrl queryctrl;
struct v4l2_querymenu querymenu;
static void enumerate_menu(__u32 id)
{
printf(" Menu items:\\n");
memset(&querymenu, 0, sizeof(querymenu));
querymenu.id = id;
for (querymenu.index = queryctrl.minimum;
querymenu.index <= queryctrl.maximum;
querymenu.index++) {
if (0 == ioctl(fd, VIDIOC_QUERYMENU, &querymenu)) {
printf(" %s\\n", querymenu.name);
}
}
}
memset(&queryctrl, 0, sizeof(queryctrl));
queryctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
while (0 == ioctl(fd, VIDIOC_QUERYCTRL, &queryctrl)) {
if (!(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)) {
printf("Control %s\\n", queryctrl.name);
if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
enumerate_menu(queryctrl.id);
}
queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
}
if (errno != EINVAL) {
perror("VIDIOC_QUERYCTRL");
exit(EXIT_FAILURE);
}
1.9.3. 示例:列舉所有控制項,包括複合控制項¶
struct v4l2_query_ext_ctrl query_ext_ctrl;
memset(&query_ext_ctrl, 0, sizeof(query_ext_ctrl));
query_ext_ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
while (0 == ioctl(fd, VIDIOC_QUERY_EXT_CTRL, &query_ext_ctrl)) {
if (!(query_ext_ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) {
printf("Control %s\\n", query_ext_ctrl.name);
if (query_ext_ctrl.type == V4L2_CTRL_TYPE_MENU)
enumerate_menu(query_ext_ctrl.id);
}
query_ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
}
if (errno != EINVAL) {
perror("VIDIOC_QUERY_EXT_CTRL");
exit(EXIT_FAILURE);
}
1.9.4. 示例:列舉所有使用者控制項(舊式)¶
memset(&queryctrl, 0, sizeof(queryctrl));
for (queryctrl.id = V4L2_CID_BASE;
queryctrl.id < V4L2_CID_LASTP1;
queryctrl.id++) {
if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &queryctrl)) {
if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
continue;
printf("Control %s\\n", queryctrl.name);
if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
enumerate_menu(queryctrl.id);
} else {
if (errno == EINVAL)
continue;
perror("VIDIOC_QUERYCTRL");
exit(EXIT_FAILURE);
}
}
for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
queryctrl.id++) {
if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &queryctrl)) {
if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
continue;
printf("Control %s\\n", queryctrl.name);
if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
enumerate_menu(queryctrl.id);
} else {
if (errno == EINVAL)
break;
perror("VIDIOC_QUERYCTRL");
exit(EXIT_FAILURE);
}
}
1.9.5. 示例:更改控制項¶
struct v4l2_queryctrl queryctrl;
struct v4l2_control control;
memset(&queryctrl, 0, sizeof(queryctrl));
queryctrl.id = V4L2_CID_BRIGHTNESS;
if (-1 == ioctl(fd, VIDIOC_QUERYCTRL, &queryctrl)) {
if (errno != EINVAL) {
perror("VIDIOC_QUERYCTRL");
exit(EXIT_FAILURE);
} else {
printf("V4L2_CID_BRIGHTNESS is not supported\n");
}
} else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
printf("V4L2_CID_BRIGHTNESS is not supported\n");
} else {
memset(&control, 0, sizeof (control));
control.id = V4L2_CID_BRIGHTNESS;
control.value = queryctrl.default_value;
if (-1 == ioctl(fd, VIDIOC_S_CTRL, &control)) {
perror("VIDIOC_S_CTRL");
exit(EXIT_FAILURE);
}
}
memset(&control, 0, sizeof(control));
control.id = V4L2_CID_CONTRAST;
if (0 == ioctl(fd, VIDIOC_G_CTRL, &control)) {
control.value += 1;
/* The driver may clamp the value or return ERANGE, ignored here */
if (-1 == ioctl(fd, VIDIOC_S_CTRL, &control)
&& errno != ERANGE) {
perror("VIDIOC_S_CTRL");
exit(EXIT_FAILURE);
}
/* Ignore if V4L2_CID_CONTRAST is unsupported */
} else if (errno != EINVAL) {
perror("VIDIOC_G_CTRL");
exit(EXIT_FAILURE);
}
control.id = V4L2_CID_AUDIO_MUTE;
control.value = 1; /* silence */
/* Errors ignored */
ioctl(fd, VIDIOC_S_CTRL, &control);