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_BASE

V4L2_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_GAINV4L2_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_DISABLED

0

V4L2_CID_POWER_LINE_FREQUENCY_50HZ

1

V4L2_CID_POWER_LINE_FREQUENCY_60HZ

2

V4L2_CID_POWER_LINE_FREQUENCY_AUTO

3

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)

選擇一種顏色效果。定義了以下值

V4L2_COLORFX_NONE

顏色效果已停用。

V4L2_COLORFX_ANTIQUE

一種老舊(老照片)效果。

V4L2_COLORFX_ART_FREEZE

霜凍顏色效果。

V4L2_COLORFX_AQUA

水彩,冷色調。

V4L2_COLORFX_BW

黑白。

V4L2_COLORFX_EMBOSS

浮雕,高光和陰影取代明暗邊界,低對比度區域設定為灰色背景。

V4L2_COLORFX_GRASS_GREEN

草綠色。

V4L2_COLORFX_NEGATIVE

負片。

V4L2_COLORFX_SEPIA

棕褐色調。

V4L2_COLORFX_SKETCH

素描。

V4L2_COLORFX_SKIN_WHITEN

皮膚美白。

V4L2_COLORFX_SKY_BLUE

天藍色。

V4L2_COLORFX_SOLARIZATION

反轉,影像色調部分反轉,只有高於或低於某個閾值的顏色值被反轉。

V4L2_COLORFX_SILHOUETTE

剪影(輪廓)。

V4L2_COLORFX_VIVID

鮮豔色彩。

V4L2_COLORFX_SET_CBCR

Cb 和 Cr 色度分量被 V4L2_CID_COLORFX_CBCR 控制項確定的固定係數替換。

V4L2_COLORFX_SET_RGB

RGB 分量被 V4L2_CID_COLORFX_RGB 控制項確定的固定 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_CTRLVIDIOC_S_CTRL ioctls 獲取和設定控制值。當裝置有一個或多個控制項時,驅動程式必須實現 VIDIOC_QUERYCTRLVIDIOC_G_CTRLVIDIOC_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);