1.7. 影片標準

影片裝置通常支援一種或多種不同的影片標準或其變體。每個影片輸入和輸出可能支援另一組標準。此集合由 ioctl VIDIOC_ENUMINPUTioctl VIDIOC_ENUMOUTPUT ioctl 分別返回的 struct v4l2_input 和 struct v4l2_outputstd 欄位報告。

V4L2 為目前全球使用的每種模擬影片標準定義了一個位,並預留了一些位用於驅動程式定義的標準,例如在 PAL 電視上觀看 NTSC 錄影帶的混合標準,反之亦然。應用程式可以使用預定義的位來選擇特定的標準,儘管更推薦向用戶呈現一個支援標準的選單。為了列舉和查詢支援標準的屬性,應用程式使用 ioctl VIDIOC_ENUMSTD, VIDIOC_SUBDEV_ENUMSTD ioctl。

許多定義的標準實際上只是少數幾個主要標準的變體。硬體實際上可能不區分它們,或者在內部進行區分並自動切換。因此,列舉的標準也包含一個或多個標準位的集合。

假設一個能夠解調 B/PAL、G/PAL 和 I/PAL 訊號的假設性調諧器。第一個列舉的標準是 B 和 G/PAL 的集合,根據 UHF 或 VHF 頻段中選擇的無線電頻率自動切換。列舉會提供“PAL-B/G”或“PAL-I”選項。類似地,複合輸入可能會合並標準,列舉“PAL-B/G/H/I”、“NTSC-M”和“SECAM-D/K”。[1]

要查詢和選擇當前影片輸入或輸出使用的標準,應用程式分別呼叫 VIDIOC_G_STDVIDIOC_S_STD ioctl。接收到的標準可以透過 ioctl VIDIOC_QUERYSTD, VIDIOC_SUBDEV_QUERYSTD ioctl 感知。

注意

所有這些 ioctl 的引數都是指向 v4l2_std_id 型別(一個標準集)的指標,而不是標準列舉的索引。當裝置有一個或多個影片輸入或輸出時,驅動程式必須實現所有影片標準 ioctl。

對於 USB 攝像頭等裝置,影片標準的概念意義不大,因此適用特殊規則。更普遍地,對於任何捕獲或輸出裝置,如果它

  • 無法以影片標準的標稱速率捕獲場或幀,或

  • 根本不支援影片標準格式。

在這種情況下,驅動程式應將 struct v4l2_input 和 struct v4l2_outputstd 欄位設定為零,並且 VIDIOC_G_STDVIDIOC_S_STDioctl VIDIOC_QUERYSTD, VIDIOC_SUBDEV_QUERYSTDioctl VIDIOC_ENUMSTD, VIDIOC_SUBDEV_ENUMSTD ioctl 應返回 ENOTTYEINVAL 錯誤程式碼。

應用程式可以利用 輸入功能輸出功能 標誌來確定影片標準 ioctl 是否可用於給定的輸入或輸出。

1.7.1. 示例:關於當前影片標準的資訊

v4l2_std_id std_id;
struct v4l2_standard standard;

if (-1 == ioctl(fd, VIDIOC_G_STD, &std_id)) {
    /* Note when VIDIOC_ENUMSTD always returns ENOTTY this
       is no video device or it falls under the USB exception,
       and VIDIOC_G_STD returning ENOTTY is no error. */

    perror("VIDIOC_G_STD");
    exit(EXIT_FAILURE);
}

memset(&standard, 0, sizeof(standard));
standard.index = 0;

while (0 == ioctl(fd, VIDIOC_ENUMSTD, &standard)) {
    if (standard.id & std_id) {
           printf("Current video standard: %s\\n", standard.name);
           exit(EXIT_SUCCESS);
    }

    standard.index++;
}

/* EINVAL indicates the end of the enumeration, which cannot be
   empty unless this device falls under the USB exception. */

if (errno == EINVAL || standard.index == 0) {
    perror("VIDIOC_ENUMSTD");
    exit(EXIT_FAILURE);
}

1.7.2. 示例:列出當前輸入支援的影片標準

struct v4l2_input input;
struct v4l2_standard standard;

memset(&input, 0, sizeof(input));

if (-1 == ioctl(fd, VIDIOC_G_INPUT, &input.index)) {
    perror("VIDIOC_G_INPUT");
    exit(EXIT_FAILURE);
}

if (-1 == ioctl(fd, VIDIOC_ENUMINPUT, &input)) {
    perror("VIDIOC_ENUM_INPUT");
    exit(EXIT_FAILURE);
}

printf("Current input %s supports:\\n", input.name);

memset(&standard, 0, sizeof(standard));
standard.index = 0;

while (0 == ioctl(fd, VIDIOC_ENUMSTD, &standard)) {
    if (standard.id & input.std)
        printf("%s\\n", standard.name);

    standard.index++;
}

/* EINVAL indicates the end of the enumeration, which cannot be
   empty unless this device falls under the USB exception. */

if (errno != EINVAL || standard.index == 0) {
    perror("VIDIOC_ENUMSTD");
    exit(EXIT_FAILURE);
}

1.7.3. 示例:選擇新的影片標準

struct v4l2_input input;
v4l2_std_id std_id;

memset(&input, 0, sizeof(input));

if (-1 == ioctl(fd, VIDIOC_G_INPUT, &input.index)) {
    perror("VIDIOC_G_INPUT");
    exit(EXIT_FAILURE);
}

if (-1 == ioctl(fd, VIDIOC_ENUMINPUT, &input)) {
    perror("VIDIOC_ENUM_INPUT");
    exit(EXIT_FAILURE);
}

if (0 == (input.std & V4L2_STD_PAL_BG)) {
    fprintf(stderr, "Oops. B/G PAL is not supported.\\n");
    exit(EXIT_FAILURE);
}

/* Note this is also supposed to work when only B
   or G/PAL is supported. */

std_id = V4L2_STD_PAL_BG;

if (-1 == ioctl(fd, VIDIOC_S_STD, &std_id)) {
    perror("VIDIOC_S_STD");
    exit(EXIT_FAILURE);
}