1.7. 影片標準¶
影片裝置通常支援一種或多種不同的影片標準或其變體。每個影片輸入和輸出可能支援另一組標準。此集合由 ioctl VIDIOC_ENUMINPUT 和 ioctl VIDIOC_ENUMOUTPUT ioctl 分別返回的 struct v4l2_input 和 struct v4l2_output 的 std 欄位報告。
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_STD 和 VIDIOC_S_STD ioctl。接收到的標準可以透過 ioctl VIDIOC_QUERYSTD, VIDIOC_SUBDEV_QUERYSTD ioctl 感知。
注意
所有這些 ioctl 的引數都是指向 v4l2_std_id 型別(一個標準集)的指標,而不是標準列舉的索引。當裝置有一個或多個影片輸入或輸出時,驅動程式必須實現所有影片標準 ioctl。
對於 USB 攝像頭等裝置,影片標準的概念意義不大,因此適用特殊規則。更普遍地,對於任何捕獲或輸出裝置,如果它
無法以影片標準的標稱速率捕獲場或幀,或
根本不支援影片標準格式。
在這種情況下,驅動程式應將 struct v4l2_input 和 struct v4l2_output 的 std 欄位設定為零,並且 VIDIOC_G_STD、VIDIOC_S_STD、ioctl VIDIOC_QUERYSTD, VIDIOC_SUBDEV_QUERYSTD 和 ioctl VIDIOC_ENUMSTD, VIDIOC_SUBDEV_ENUMSTD ioctl 應返回 ENOTTY 或 EINVAL 錯誤程式碼。
應用程式可以利用 輸入功能 和 輸出功能 標誌來確定影片標準 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);
}