用戶控制
設備通常有一些用戶可設置的控制器,如亮度和飽和度等等一些會展示在圖形用戶界面的東西。但不同設備會有不同的可用設置,而且此外其可設置值範圍、默認值在不同設備上也不盡相同。控制ioctl提供創造一個良好用戶界面的信息和機制,這會讓這些控制器在任何設備上都能正確的工作。
所有控制器都需通過ID值進行訪問。V4L2定義了一些用於特殊目的的ID。驅動也可以使用V4L2CID_PRIVATE_BASE和更大的值聲明其自定義控制器。預定義的ID帶有前綴V4L2_CID,在Table 1.1. Control IDs中列出http://linuxtv.org/downloads/v4l-dvb-apis/control.html#control-id
這些ID用來查詢一個控制器的屬性、用來獲取或設定當前的設置值。
通常應用程序應當明確提出關於他們的目標的一些控制器。每個控制器的名字應該便於理解,如果目標不便理解,驅動開發者應該提供用戶文檔,用戶可用以涉入驅動或開發盤控制程序。預定義ID應介紹一點控制編程,如在通道切換期間使設備靜音。
當進行了視頻輸入輸出切換、調製器和調諧器切換、聲音輸入輸出切換後驅動也許會列舉出一些不同的控制。不同場景中有不同的默認值、當前值、步進值以及菜單項。擁有自定義ID的控制可以更改自己的名字和類型。控制值是被全局保存的,不會因爲切換而改變,甚至當設備打開或關閉時,比如一個調諧radio頻率改變,不再外部應用請求的情況下。因爲V4L2沒有事件機制,所以如果一個panel程序想和其他的panel程序合作的話,就需要有規律的獲取控制值來更新用戶接口。
附帶:色溫表(來自http://en.wikipedia.org/wiki/Color_temperature)
溫度 | 光源 |
---|---|
1700K | 火柴 |
1850K | 燭光、日出、日落 |
2700-3300K | 白熾燈 |
3000K | 柔(暖)光燈、日光燈 |
3200K | 畫室燈光 |
3350K | 製作室燈光 |
4100-4150K | 月光 |
5000K | 水平的日光、管燈、冷光燈 |
5500-6000K | 豎向日光,電子閃光 |
6200K | 氙氣閃光燈 |
6500K | 陰天 |
6500-10500K | LCD CRT屏幕 |
15000-27000 | 清純的藍色極光 |
應用程序可以通過VIDIOC_QUERYCTRL和VIDIOC_QUERYMENU ioctl來列舉有效的控制,通過VIDIOC_G_CTRL和VIDIOC_S_CTRL來獲取和設置控制值。當設備擁有一個或以上的設置時,驅動必須聲明VIDIOC_QUERYCTRL、VIDIOC_G_CTRL、VIDIOC_S_CTRL。當有一個或以上的菜單類型控制時還必須其對應驅動還必須聲明VIDIOC_QUERYMENU。
例1.8 列舉所有控制
struct v4l2_queryctrl queryctrl;
struct v4l2_querymenu querymenu;
static void
enumerate_menu (void)
{
printf (" Menu items:\n");
memset (&querymenu, 0, sizeof (querymenu));
querymenu.id = queryctrl.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));
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 ();
} 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 ();
} else {
if (errno == EINVAL)
break;
perror ("VIDIOC_QUERYCTRL");
exit (EXIT_FAILURE);
}
}
例1.9 更改控制
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 = TRUE; /* silence */
/* Errors ignored */
ioctl (fd, VIDIOC_S_CTRL, &control);