Работа с usb видеокамерой в Linux. Часть 1

в 12:51, , рубрики: linux, linux kernel, programming, tutorial, video capture, видео, Работа с видео, метки: , , , , ,

   По популярности видеокамера, сегодня, стоит в одном ряду с микрофоном и наушниками. Она используется в различных направлениях, таких как распознавание объектов, дополненная реальность, видеоконференции и множество других. Но что же скрыто под капотом этих сложнейших программ? Как мы получаем картинку с видеокамеры? Этот цикл статей позволит взглянуть на простоту работы с видеокамерой на низком уровне, обработку полученного изображения.

   Для начала, немного информации о работе с устройствами в системе Linux. Устройства в nix системах представляют собой файл. С некоторыми файлами-устройств мы можем работать как с обычными файлами. Например:

~$ cat /dev/sda

эта команда выведет на экран весь диск sda.

Есть устройства с которыми нельзя работать напрямую, к ним относится видеокамера.При попытке это сделать мы получим такую реакцию системы:

~$ cat: /dev/video0: Недопустимый аргумент

*Где /dev/video0 это файл-устройство найшей видеокамеры.

Для работы с ней нам понадобится системная функция ioctl детальнее о ней можно ознакомится [1]. Попробуем это применить. Вот код позволяющий считать информации с устройства (альтернатива команде cat для видеоустройств):

Код тут

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <linux/videodev2.h>

int main (int argc,char* argv[])
{

/*Read Params*/
char *device_name;
if(argc > 1)
{
&nbsp&nbspdevice_name = argv[1];
} 
else
{
&nbsp&nbspdevice_name = "/dev/video0";
}

/*Open Device*/
int  file_device = open(device_name, O_RDWR, 0);

if (file_device == -1)
{
&nbsp&nbspprintf ("%s error %d, %sn",device_name, errno, strerror(errno));
&nbsp&nbspexit(EXIT_FAILURE);
}

/*Read Params From Device*/
struct v4l2_capability device_params;

if (ioctl(file_device, VIDIOC_QUERYCAP, &device_params) == -1)
{
&nbsp&nbspprintf (""VIDIOC_QUERYCAP" error %d, %sn", errno, strerror(errno));
&nbsp&nbspexit(EXIT_FAILURE);
}

printf("driver : %sn",device_params.driver);
printf("card : %sn",device_params.card);
printf("bus_info : %sn",device_params.bus_info);
printf("version : %d.%d.%dn",
&nbsp&nbsp&nbsp&nbsp&nbsp((device_params.version >> 16) & 0xFF),
&nbsp&nbsp&nbsp&nbsp&nbsp((device_params.version >> 8) & 0xFF),
&nbsp&nbsp&nbsp&nbsp&nbsp(device_params.version & 0xFF));
printf("capabilities: 0x%08xn", device_params.capabilities);
printf("device capabilities: 0x%08xn", device_params.device_caps);

/* Close Device */
if (-1 == close (file_device))
{
&nbsp&nbspprintf (""close" error %d, %sn", errno, strerror(errno));
&nbsp&nbspexit(EXIT_FAILURE);
}

file_device = -1;

return 0;
}

В первых строках кода считываются параметры с которой запущено приложение. Если параметров нету то device_name принимает стандартоне значение "/dev/video0".

В блоке «Open Device» происходит открытие устройства системной функцией open (нужно подключить header fcntl.h). Обязательный параметр O_RDWR отвечает за открытие устройства считывания/записи. Если при подключении возникла ошибка, то функция open вернет -1.

Блок «Read Params From Device» — это сердце нашей маленькой программы. Для его использования надо подключить билиотеку

<linux/videodev2.h>

возможно прийдется её установить, у каждого дистрибутива свой пакет под эту библиотеку
Системная функция ioctl имеет три параметра:
file_device — дескриптор нашего устройства
VIDIOC_QUERYCAP — функция ядра, которую применяем для нашего устройства.
device_params — область памяти куда будет сброшен результат функции «VIDIOC_QUERYCAP».

device_params это структура состоящая из таких полей:

struct v4l2_capability
{
&nbsp&nbsp__u8&nbsp&nbspdriver[16];    // имя модуля драйвера - который обслуживает видеоустройство
&nbsp&nbsp__u8&nbsp&nbspcard[32];      // имя видеоустройства
&nbsp&nbsp__u8&nbsp&nbspbus_info[32];  // шина к которой подключена камера (в нашем случае usb-порт)
&nbsp&nbsp__u32&nbspversion;       // версия ядра системы
&nbsp&nbsp__u32&nbspcapabilities;  // свойства(возможности/функции) физического устройства
&nbsp&nbsp__u32&nbspdevice_caps;   // функции доступные этому устройству
&nbsp&nbsp__u32&nbspreserved[3];   // резервное поле
};

если возникла ошибка ioctl вернет -1

Блок «Close Device» закрывает дескриптор устройства.

Посмотрим программу в действии.

скомпилируем

gcc catvd.c -o catdv

запустим

./catvd /dev/video0
/dev/video0 error 2, No such file or directory

устройство не определилось ядром либо не подключено уборщица опять ненужные провода дергала.
Подключаем и заново запуск. Получаем такую информацию:


./catvd /dev/video0
driver : uvcvideo
card : UVC Camera (046d:0804)
bus_info : usb-0000:00:12.2-3
version : 3.11.10
capabilities: 0x84000001
device capabilities: 0x04000001

поле capabilities и device capabilities можно расшифровать благодаря константам из файла videodev2.h:

V4L2_CAP_DEVICE_CAPS	0x80000000      // устроство содержит поля  для изменения параметров.
V4L2_CAP_STREAMING	0x04000000	// это потоковое устройство  i/o ioctls.
V4L2_CAP_VIDEO_CAPTURE	0x00000001      // устроство  имеет функцию видеозахвата.

На этом вводная статья заканчивается. В следующих обзорах будут затронуты, такие темы как memory-mapping, виодеформаты изображения, настройка камеры, вывод изображения в текстуру, работа с несколькими камерами.

Ресурсы используемые в статье:

  1. статья о работе ioctl
  2. о работе с video for linux (слегка устаревшая информация)

Исходник программы, используемой в статье.

Автор: svistkovr

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js