Urządzenia video, takie jak: karty telewizyjne, kamerki internetowe, karty DVB, tunery radiowe itp. działają w oparciu o jeden wspólny interfejs - Video4Linux. Począwszy od jąder 2.6 mamy do dyspozycji dwie wersje Video4Linux. Przejście z starego standardu na nowy wymaga jednak trochę czasu i dlatego wciąż istnieje możliwość wyboru pomiędzy nimi. Zaleca się jednak używanie Video4Linux2 (V4L2) i odchodzenie od Video4Linux (V4L). W artykule przedstawiam sposób programowania w oparciu o oba interfejsy, by pokazać różnice, wady i zalety nowych rozwiązań.
8.9.2004 14:00 | Paweł Pustelnik | přečteno 29021×
Urządzenia video, takie jak: karty telewizyjne, kamerki internetowe, karty DVB, tunery radiowe itp. działają w oparciu o jeden wspólny interfejs - Video4Linux. Począwszy od jąder 2.6 mamy do dyspozycji dwie wersje Video4Linux. Przejście z starego standardu na nowy wymaga jednak trochę czasu i dlatego wciąż istnieje możliwość wyboru pomiędzy nimi. Zaleca się jednak używanie Video4Linux2 (V4L2) i odchodzenie od Video4Linux (V4L). W artykule przedstawiam sposób programowania w oparciu o oba interfejsy, by pokazać różnice, wady i zalety nowych rozwiązań. Często nie tłumaczę tekstu, gdyż mogłoby to niepotrzebnie utrudnić zrozumienie, a czasem po prostu niełatwo rozsądnie przetłumaczyć pewne techniczne czynności na język polski.
W systemie urządzenia video/radio mają liczbę major = 81, natomiast minory to wartości od 0 do 255 i mogą wyglądać jak poniżej:
Nazwa | Wartości minorów | Typ |
/dev/video | 0-63 | Video Capture Interface |
/dev/radio | 64-127 | AM/FM Radio Devices |
/dev/vtx | 192-223 | Teletext Interface Chips |
/dev/vbi | 224-255 | Raw VBI Data (Intercast/teletext) |
Podane rozwiązanie jest pewnym przyjętym standardem, by nie powodować niepotrzebnego zamieszania, niemniej jednak, jest to sprawa administratora systemu.
Uwaga: podane wartości dotyczą urządzeń Video4Linux i nie są tożsame z Linux DVB, które mają major = 212.
Jeżeli w naszym Linuksie nie mamy utworzonych odpowiednich plików urządzeń, to możemy to zrobić ręcznie. Przykładowo, by utworzyć urządzenie video:
mknod /dev/video0 c 81 0
chmod 666 /dev/video0
ln -s /dev/video0 /dev/video
Teraz Video4Linux widzi pod /dev/video nasz pierwszy odbiornik video (np. z karty TV bądź kamerki).
Analogicznie możemy utworzyć urządzenia dla radia:
mknod /dev/radio0 c 81 64
chmod 666 /dev/radio0
ln -s /dev/radio0 /dev/radio
Drugi sposób, to wykorzystanie gotowego skryptu. Możemy go znaleźć w źródłach jądra w katalogu: /Documentation/video4linux/bttv. Plik nazywa się MAKEDEV. Być może trzeba będzie go uczynić wykonywalnym.
V4L2 w przeciwieństwie do V4L udostępnia wielokrotne otwieranie tego samego urządzenia w tym samym czasie. Pozwala to na równoległe wykonywanie różnych czynności, np. jeden program działa jako prosty aplet do zmiany jasności obrazu, a w tym samym czasie inny program nagrywa obraz z kamery. Należy jednak pamiętać, iż to od sterownika zależy, czy i w jakim stopniu możemy wykorzystać te możliwości. Co więcej, sterowniki nie powinny pozwalać na jednoczesne czytanie/zapisywanie danych na urządzeniu poprzez kopiowanie buforów itp.
Otwieranie, zamykanie, wywoływanie odpowiednich funkcji odbywa się tak samo dla obu interfejsów. Otwieramy urządzenie przy użyciu funkcji open(), zamykamy przez close(), a do urządzenia odwołujemy się poprzez ioctl().
Aby móc korzystać z Video4Linux, należy załączać plik nagłówkowy <linux/videodev.h>.
Poniżej prezentuję przykład otwarcia i zamknięcia urządzenia video.
Przykład 1. Otwieranie/Zamykanie urządzenia video:
Pierwszą czynnością jaką należy wykonać po otwarciu urządzenia jest sprawdzenie jego możliwości. Wiele urządzeń tego samego typu różni się bowiem między sobą, jedne karty TV mają tuner radiowy, drugie tuner radiowy i telewizyjny itp.
Test ten pozwoli nam także wykryć, którego interfejsu używa nasze urządzenie - który interfejs musimy stosować, by móc odwoływać się do tego urządzenia.
W V4L należy użyć wywołania VIDIOCGCAP (get capabilities - pobierz informacje o możliwościach naszego urządzenia) . Następnie sprawdzamy wartości poszczególnych danych w strukturze video_capability.
Struktura video_capability:
name[32] | nazwa kanoniczna interfejsu |
type | typ interfejsu |
channels | liczba kanałów (nie kanałów telewizyjnych,ale wejść) radio/tv |
audios | liczba urządzeń audio |
maxwidth | maksymalna przechwytywana szerokość obrazu w pikselach |
maxheight | maksymalna przechwytywana wysokość obrazu w pikselach |
minwidth | minimalna przechwytywana szerokość obrazu w pikselach |
minheight | minimalna przechwytywana wysokość obrazu w pikselach |
Pole type zawiera informacje o flagach:
VID_TYPE_CAPTURE | może przechwytywać |
VID_TYPE_TUNER | posiada tuner |
VID_TYPE_TELETEXT | posiada teletext |
VID_TYPE_OVERLAY | Can overlay its image onto the frame buffer |
VID_TYPE_CHROMAKEY | Overlay is Chromakeyed |
VID_TYPE_CLIPPING | Overlay clipping is supported |
VID_TYPE_FRAMERAM | Overlay overwrites frame buffer memory |
VID_TYPE_SCALES | obraz jest skalowalny |
VID_TYPE_MONOCHROME | tyko w skali szarości |
VID_TYPE_SUBCAPTURE | przechwycony obraz może być tylko częścią całego obrazu |
Poniżej podaję przykład zapytania o możliwości urządzenia i wyświetlenie wyników.
Przykład 2. V4L - Zapytanie o możliwości urządzenia:
W V4L2 musimy użyć wywołania VIDIOC_QUERYCAP. Następnie sprawdzamy strukturę v4l2_capability.
Struktura v4l2_capability:
__u8 driver[16] | nazwa sterownika |
__u8 card[32] | nazwa urządzenia |
__u8 bus_info[32] | lokalizacja urządzenia |
__u32 version | numer wersji sterownika |
__u32 capabilities flagi urządzenia, | patrz niżej |
__u32 reserved[4] | pole zarezerwowane na przyszłe rozwiązania |
Pole capabilities:
V4L2_CAP_VIDEO_CAPTURE | 0x00000001 | The device supports the video capture interface. |
V4L2_CAP_VIDEO_OUTPUT | 0x00000002 | The device supports the video output interface. |
V4L2_CAP_VIDEO_OVERLAY | 0x00000004 | The device supports the video overlay interface. |
V4L2_CAP_VBI_CAPTURE | 0x00000010 | The device supports the VBI capture interface |
V4L2_CAP_VBI_OUTPUT | 0x00000020 | The device supports the VBI output interface |
V4L2_CAP_RDS_CAPTURE | 0x00000100 | |
V4L2_CAP_TUNER | 0x00010000 | |
V4L2_CAP_AUDIO | 0x00020000 | |
V4L2_CAP_READWRITE | 0x01000000 | The device supports the read() and/or write() I/O methods. |
V4L2_CAP_ASYNCIO | 0x02000000 | The device supports the asynchronous I/O methods. |
V4L2_CAP_STREAMING | 0x04000000 | The device supports the streaming I/O method. |
Poniżej podaję przykład zapytania o możliwości urządzenia wyświetlenie wyników:
Przykład 3. V4L2 - Zapytanie o możliwości urządzenia:
V4L udostępnia wywołania VIDIOCGCHAN (get channel) oraz VIDIOCSCHAN (set channel), używając struktury video_channel, by otrzymać dostęp do poszczególnych wejść/wyjść urządzenia. Przykładowo możemy odbierać obraz z tunera telewizyjnego, z wejścia S-VIDEO lub też COMPOSITE.
Struktura video_channel składa się z:
channel | The channel number |
name | The input name - preferably reflecting the label on the card input itself |
tuners | Number of tuners for this input |
flags | Properties the tuner has |
type | Input type (if known) |
norm | The norm for this channel |
Mamy następujące flagi (flags):
VIDEO_VC_TUNER | Channel has tuners |
VIDEO_VC_AUDIO | Channel has audio |
VIDEO_VC_NORM | Channel has norm setting |
Mamy następujące typy (type):
VIDEO_TYPE_TV | The input is a TV input |
VIDEO_TYPE_CAMERA | The input is a camera |
Poniżej podaję przykłady sprawdzenia informacji o aktualnie używanym wejściu oraz zmiany wejścia.
Przykład 4. V4L - Informacje o wejściu urządzenia:
Przykład 5. V4L2 - Zmiana wejścia urządzenia:
W przypadku V4L2 sprawa wygląda nieco inaczej. Najpierw poprzez wywołanie VIDIOC_ENUMINPUT (jeśli interesują nas wejścia urządzenia) lub VIDIOC_ENUMOUTPUT (jeśli interesują nas wyjścia urządzenia) zapełniamy informacjami strukturę v4l2_input. Struktura ta zawiera dane o konkretnym wejściu/wyjściu. Jeśli chcemy jednak uzyskać numer wejścia/wyjścia bądź też je zmienić, to należy zastosować wywołania systemowe takie jak: VIDIOC_G_INPUT (get input), VIDIOC_S_INPUT (set input), VIDIOC_G_OUTPUT (get output), VIDIOC_S_OUTPUT (set output).
Struktura v4l2_input:
__u32 index | Identyfikator wejścia |
__u8 name[32] | Nazwa wejścia video (np. Composite 1) |
__u32 type | Typ wejścia (TUNER, CAMERA) |
__u32 audioset | Wejście audio |
__u32 tuner | Identyfikator tunera,jeśli urządzenia posiada takowy |
v4l2_std_id std | Struktura standardu video (nie omawiana w tym artykule) |
__u32 status | Informacje o aktualnym stanie wejścia |
__u32 reserved[4] | Zarezerwowane na przyszłe funkcje |
__u32 type:
V4L2_INPUT_TYPE_TUNER | 1 | Wejście używane przez tuner |
V4L2_INPUT_TYPE_CAMERA | 2 | Wejście analogowe, np. CVBS / Composite Video, S-Video, RGB |
__u32 status:
Podstawowe: | ||
V4L2_IN_ST_NO_POWER | 0x00000001 | Attached device is off |
V4L2_IN_ST_NO_SIGNAL | 0x00000002 | |
V4L2_IN_ST_NO_COLOR | 0x00000004 | |
Analogowe video: | ||
V4L2_IN_ST_NO_H_LOCK | 0x00000100 | No horizontal sync lock |
V4L2_IN_ST_COLOR_KILL | 0x00000200 | The color killer is enabled |
V4L2_IN_ST_NO_COLOR | 0x00000004 | No color is detected |
Cyfrowe video: | ||
V4L2_IN_ST_NO_SYNC | 0x00010000 | No synchronization lock |
V4L2_IN_ST_NO_EQU | 0x00020000 | No equalizer lock |
V4L2_IN_ST_NO_CARRIER | 0x00040000 | Carrier recovery failed |
VCR and Set-Top Box : | ||
V4L2_IN_ST_MACROVISION | 0x01000000 | Macrovision protection has been detected |
V4L2_IN_ST_NO_ACCESS | 0x02000000 | Conditional access denied |
V4L2_IN_ST_VTR | 0x04000000 | VTR time constant |
Poniżej prezentuję, podobnie jak dla V4L, przykłady sprawdzenia numeru wejścia + informacje o wejściu oraz zmiany wejścia na pierwsze w urządzeniu.
Przykład 6. V4L2 - Informacje o wejściu urządzenia:
Przykład 7. V4L2 - Zmiana wejścia urządzenia:
Przechwytywany obraz może nie być takiej jakości, jakiej oczekujemy. Często trzeba poprawić kontrast, balans kolorów itp. W V4L zmian tych można dokonać poprzez wywołanie VIDIOCGPICT (pobranie informacji o aktualnych ustawieniach) oraz VIDIOCSPICT (przekazanie nowych ustawień do urządzenia). W obu przypadkach dane znajdują się w strukturze video_picture.
Struktura video_picture:
brightness | Picture brightness |
hue | Picture hue (colour only) |
colour | Picture colour (colour only) |
contrast | Picture contrast |
whiteness | The whiteness (greyscale only) |
depth | The capture depth (may need to match the frame buffer depth) |
palette | Reports the palette that should be used for this image |
Następujące wartości dla palette są zdefiniowane:
VIDEO_PALETTE_GREY | Skala szarości (0-255) |
VIDEO_PALETTE_HI240 | |
VIDEO_PALETTE_RGB565 | |
VIDEO_PALETTE_RGB555 | |
VIDEO_PALETTE_RGB24 | |
VIDEO_PALETTE_RGB32 | |
VIDEO_PALETTE_YUV422 | |
VIDEO_PALETTE_YUYV | |
VIDEO_PALETTE_UYVY | |
VIDEO_PALETTE_YUV420 | |
VIDEO_PALETTE_YUV411 | |
VIDEO_PALETTE_RAW | |
VIDEO_PALETTE_YUV422P | |
VIDEO_PALETTE_YUV411P |
Zmiana wartości pola w palette oznacza zmianę formatu otrzymywanych danych. Możemy zatem otrzymywać obraz tylko w skali szarości, mimo iż nasze urządzenie obsługuje kolory i może nam podawać dane w formacie RGB24 lub RGB32.
Przykład 8. V4L - Uzyskanie informacji o aktualnej wartości kontrastu:
Przykład 9. V4L2 - Zmiana aktualnej wartości jasności i palety:
V4L2 używa specjalnych, zdefiniowanych identyfikatorów (ID). Niektóre sterowniki mogą nawet zawierać swoje własne, typowe tylko dla danego urządzenia właściwości, do których możemy się odwoływać przez V4L2_CID_PRIVATE_BASE. Każdy identyfikator jest poprzedzony przedrostkiem V4L2_CID_ .
Poniżej lista wszystkich identyfikatorów:
ID | Typ | Opis |
V4L2_CID_BASE | Pierwszy zdefiniowany ID = V4L2_CID_BRIGHTNESS | |
V4L2_CID_BRIGHTNESS
|
integer | |
V4L2_CID_CONTRAST | integer | |
V4L2_CID_SATURATION | integer | |
V4L2_CID_HUE |
integer | |
V4L2_CID_AUDIO_VOLUME | integer | |
V4L2_CID_AUDIO_BALANCE
|
integer | |
V4L2_CID_AUDIO_BASS | integer | |
V4L2_CID_AUDIO_TREBLE | integer | |
V4L2_CID_AUDIO_MUTE
|
boolean | |
V4L2_CID_AUDIO_LOUDNESS
|
boolean | |
V4L2_CID_BLACK_LEVEL
|
integer | |
V4L2_CID_AUTO_WHITE_BALANCE
|
boolean | |
V4L2_CID_DO_WHITE_BALANCE
|
button | |
V4L2_CID_RED_BALANCE
|
integer | |
V4L2_CID_BLUE_BALANCE | integer | |
V4L2_CID_GAMMA | integer | |
V4L2_CID_WHITENESS | integer | |
V4L2_CID_EXPOSURE | integer | |
V4L2_CID_AUTOGAIN
|
boolean | |
V4L2_CID_GAIN | integer | |
V4L2_CID_HFLIP
|
boolean | |
V4L2_CID_VFLIP
|
boolean | |
V4L2_CID_HCENTER | integer | |
V4L2_CID_VCENTER | integer | |
V4L2_CID_LASTP1
|
Ostatni ID = 1 + V4L2_CID_VCENTER | |
V4L2_CID_PRIVATE_BASE
|
Zdefiniowany przez sterownik |
Sprawdzenie, czy dany identyfikator jest dostępny w naszym urządzeniu oraz jakie może przyjmować wartości, wymaga użycia kilku wywołań. VIDIOC_QUERYCTRL oraz IDIOC_QUERYMENU pozwalają na sprawdzenie poszczególnych właściwości. Zależność między nimi jest następująca: poprzez wywołanie VIDIOC_QUERYCTRL wypełniamy strukturę v4l2_queryctrl. Następnie sprawdzamy, czy wartość pola v4l2_ctrl_type jest równa V4L2_CTRL_TYPE_MENU. Jeżeli tak, to możemy się odwoływać do wartości pól tej struktury.
Operacje zmiany bądź odczytania aktualnej wartości dokonujemy wywołaniami VIDIOC_S_CTRL (set control) oraz VIDIOC_G_CTRL (get control), które zapisują/odczytują dane z struktury v4l2_format.
Struktura v4l2_format:
enum v4l2_buf_type type | Typ strumienia danych | ||
union fmt : | |||
struct v4l2_pix_format pix | format danych - patrz niżej | ||
struct v4l2_window win | Definition of an overlaid image | ||
struct v4l2_vbi_format vbi | Raw VBI capture or output parameters | ||
__u8 raw_data[200] | Przyszłe funkcje |
Przykład 10. V4L2 - Uzyskanie informacji o wszystkich dostępnych identyfikatorach:
Przykład 11. V4L2 - Uzyskanie informacji o aktualnej wartości kontrastu:
Przykład 12. V4L2 - Zmiana aktualnej wartości jasności:
W V4L mieliśmy w strukturze video_picture pole palette, które określało rodzaj palety kolorów - sposób w jaki otrzymujemy przechwytywane dane, np. jako ciąg bajtów RBGRBGRGB... (RGB24). Jednak wspomniane powyżej metody dla V4L2 nie udostępniają nam możliwości zmian palety. V4L2 udostępnia nam strukturę v4l2_pix_format oraz wywołania VIDIOC_S_FMT (set format) czy VIDIOC_G_FMT (get format). Jednak nie odwołujemy się bezpośrednio do v4l2_pix_format, ale poprzez v4l2_format - tabela powyżej.
Struktura v4l2_pix_format:
__u32 width | szerokość w pikselach |
__u32 height | wysokość w pikselach |
__u32 pixelformat | format danych (paleta) - patrz niżej |
enum v4l2_field field | patrz niżej |
__u32 bytesperline | liczba bajtów w linii |
__u32 sizeimage | rozmiar obrazu |
enum v4l2_colorspace colorspace | patrz niżej |
__u32 priv | zastrzeżone na przyszłe funkcje |
__u32 pixelformat - to właśnie zmiana tego pola pozwoli (jak dla V4L) zmienić paletę. Jednak w V4L2 mamy nieco inne nazwy niektórych pól, dokonano podziału na formaty RGB oraz YUV. Poniżej przedstawiam formaty używane przez V4l2:
RGB formats:
V4L2_PIX_FMT_RGB332 |
V4L2_PIX_FMT_RGB555 |
V4L2_PIX_FMT_RGB565b1 |
V4L2_PIX_FMT_RGB555X |
V4L2_PIX_FMT_RGB565X |
V4L2_PIX_FMT_BGR24 |
V4L2_PIX_FMT_RGB24 |
V4L2_PIX_FMT_BGR32 |
V4L2_PIX_FMT_RGB3 |
YUV formats:
V4L2_PIX_FMT_GREY |
V4L2_PIX_FMT_YUYV |
V4L2_PIX_FMT_UYVY |
V4L2_PIX_FMT_Y41P |
V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV420 |
V4L2_PIX_FMT_YVU410, V4L2_PIX_FMT_YUV410 |
V4L2_PIX_FMT_YUV422P |
V4L2_PIX_FMT_YUV411P |
V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV21 |
enum v4l2_field field - obrazy video są bardzo często pełne interlace'u. Tutaj możemy określić sposób otrzymywania obu pól składających się na ramkę. Problem interlace'u nie jest celem tego artykułu. Na końcu wśród ciekawych linków można znaleźć informacje na ten temat. enum v4l2_colorspace colorspace - pole ustawiane przez sterownik. Więcej w API V4L2.
Wśród pól struktury v4l2_pix_format widzimy width oraz height. Pozwalają one na zmianę szerokości i wysokości obrazu.
Poniżej podaję przykłady dla wspomnianych wcześniej metod.
Przykład 13. V4L2 - Zmiana wysokości i szerokości obrazu:
Przykład 14. V4L2 - Uzyskanie informacji o aktualnej wysokości,szerokości oraz palecie obrazu:
Przykład 15. V4L2 - Zmiana palety na RGB24:
Zmianę wysokości, szerokości w V4L dokonujemy wywołaniem VIDIOCGWIN oraz VIDIOCSWIN, które wypełniają pola width oraz height w strukturze video_window.
Struktura video_windowskłada się z następujących pól:
x |
y |
width |
height |
chromakey |
flags |
clips |
clipcount |
Przykład 16. V4L - Zmiana wysokości i szerokości obrazu:
Przykład 17. V4L - Odczyt wysokości i szerokości obrazu:
Celem niniejszego artykułu było przedstawienie podstaw V4L oraz V4L2. Oba interfejsy mają znacznie większe możliwości aniżeli pokazane przez autora. Być może - jeśli będzie taka potrzeba - powstanie seria artykułów, które będą prezentować pozostałe funkcje obu interfejsów. Polecam przeanalizowanie pliku videodev.h.
Użyteczne linki:
Paweł Pustelnik, 31-08-2004. [pawelpus@wp.pl]