Углубленное изучение программирования приложений камеры Linux v4l2.
Углубленное изучение программирования приложений камеры Linux v4l2.

Научно-исследовательский институт встраиваемых приложений |

Источник материала |CSDN

1. Что такое v4l2

vl42 — это аббревиатура видео для Linux 2. Это среда драйверов для видеоустройств ядра Linux. Структура драйверов обеспечивает унифицированный рабочий интерфейс (серия ioctl) для уровня приложений.

V4L2 предназначен для поддержки широкого спектра устройств. Лишь некоторые из них являются настоящими видеоустройствами и могут поддерживать различные устройства. Он может иметь следующие интерфейсы.

интерфейс захвата видео: интерфейс захвата видео, этот интерфейс используется в камерах, для этой функции использовалась версия v4l2 при ее первоначальной разработке.

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

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

Другие интерфейсы здесь представлены не будут. Давайте посмотрим на API v4l2.

2. Введение в API v4l2.

Программирование устройства V4L2 включает в себя следующие шаги.

  • Включите устройство
  • Изменить свойства устройства,Выберите видео и аудио вход,видеостандарты,Яркость изображения и т. д.
  • Установить формат данных
  • Установите методы ввода/вывода
  • Цикл ввода/вывода кэшочереди
  • Выключите устройство

Большинство операций реализуется путем вызова ioctl на уровне приложения. Эти ioctl можно разделить на следующие категории:

2.1 Запрос функции устройства

Поскольку V4L2 охватывает множество устройств, не все аспекты API применимы ко всем типам устройств. При использовании устройства v4l2 необходимо вызывать этот API, чтобы получить функции, поддерживаемые устройством (захват, вывод, наложение...). )

Примечание. Вы можете нажать на имя, чтобы просмотреть объяснение API.

2.2 Приоритет приложения

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

2.3 Устройства ввода и вывода
2.4 Стандарты видео
2.5 Атрибуты управления
2.6 Формат изображения

Изображения состоят из нескольких форматов, YUV, RGB, форматов сжатия и т. д. Каждый формат делится на несколько форматов, например RGB: RGB565, RGB888... Поэтому при использовании устройства необходимо задать формат.

2.7 Обрезка, вставка и масштабирование изображения
2.8 Ввод и вывод данных

Ядро использует очереди кэша для управления данными изображений. Существует два способа получения данных изображения из пользовательского пространства: один — чтение кэша пространства ядра посредством чтения и записи, а другой — сопоставление кэша пространства ядра с пользовательским пространством. . При работе с устройством v4l2 узнайте, какой метод поддерживает устройство, с помощью VIDIOC_QUERYCAP.

Сначала здесь представлен API ioctl. Существует множество интерфейсов, которые я не буду описывать здесь один за другим. Для получения подробной информации вы можете просмотреть Справочник по функциям V4L2. Давайте поговорим о том, как использовать эти интерфейсы.

3. Процесс работы устройства v4l2

V4L2 поддерживает несколько интерфейсов: захват (захват), вывод (вывод), наложение (предварительный просмотр) и т. д. Здесь мы объясним, как использовать функцию захвата, а процесс работы описан ниже.

  • step1:Включите устройство В Linux узлом видеоустройства является /dev/videox, используйте функцию open, чтобы открыть его.
Язык кода:javascript
копировать
int fd = open(name, flag);
if(fd < 0)
{
    printf("ERR(%s):failed to open %s\n", __func__, name);
    return -1;
}
return fd;
  • Шаг 2. Запрос функций устройства
Язык кода:javascript
копировать
if (ioctl(fd, VIDIOC_QUERYCAP, cap) < 0)
{
    printf("ERR(%s):VIDIOC_QUERYCAP failed\n", __func__);
    return -1;
}

Взгляните на v4l2_capability:

Язык кода:javascript
копировать
struct v4l2_capability {
 __u8 driver[16]; /* i.e. "bttv" */
 __u8 card[32]; /* i.e. "Hauppauge WinTV" */
 __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
 __u32   version;        /* should use KERNEL_VERSION() */
 __u32 capabilities; /* Device capabilities */
 __u32 reserved[4];
};

Самым важным из них является поле возможностей, которое отмечает функции устройства v4l2. Возможности имеют следующие биты маркировки:

О работе устройства можно судить по следующему:

  • шаг 3. Устройство может иметь несколько входов.,Например: на чипе,Контроллер камеры и интерфейс камеры разделены.,Какой интерфейс камеры необходимо выбрать в качестве источника входного сигнала контроллера камеры?

Конечно, не всем устройствам необходимо настраивать входы. Например: камеры UVC обычно имеют только один вход, который выбран по умолчанию и не требует настройки.

Вот как настроить устройство ввода

  • 1. Перечисление устройств ввода Следующая программа перечисляет все источники ввода устройства и печатает имена источников ввода:
Язык кода:javascript
копировать
struct v4l2_input input;

input.index = 0;
while (!ioctl(fd, VIDIOC_ENUMINPUT, &input))
{
    printf("input:%s\n", input.name);
    ++input.index;
}
  • 2. Настройте устройства ввода
Язык кода:javascript
копировать
struct v4l2_input input;
input.index = index; //Указываем устройство ввода

if (ioctl(fd, VIDIOC_S_INPUT, &input) < 0)
{
    printf("ERR(%s):VIDIOC_S_INPUT failed\n", __func__);
    return -1;
}
  • step 4: Настройка формата изображения некоторый Камера Поддерживает несколько форматов пикселей,Некоторые камеры поддерживают только один формат пикселей.,перед форматированием,Сначала необходимо перечислить все форматы,Проверьте, поддерживается ли формат, который вы хотите установить.,Затем выполните дальнейшие настройки
  • 1. Перечислите поддерживаемые форматы пикселей.
Язык кода:javascript
копировать
struct v4l2_fmtdesc fmtdesc;

fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmtdesc.index = 0;

while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
{
    printf("fmt:%s\n", fmtdesc.description);

    fmtdesc.index++;
}
  • 2. Установите формат пикселей.
Язык кода:javascript
копировать
struct v4l2_format v4l2_fmt;

memset(&v4l2_fmt, 0, sizeof(struct v4l2_format));
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
v4l2_fmt.fmt.pix.width = width; //ширина
v4l2_fmt.fmt.pix.height = height; //высокий
v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //Формат пикселей
v4l2_fmt.fmt.pix.field = V4L2_FIELD_ANY;

if (ioctl(fd, VIDIOC_S_FMT, &v4l2_fmt) < 0)
{
    printf("ERR(%s):VIDIOC_S_FMT failed\n", __func__);
    return -1;
}
  • step 5: Настройка кэша У устройств v4l2 есть два способа чтения данных: один — метод чтения, а другой — метод потоковой передачи. Для получения подробной информации необходимо просмотреть этот шаг. Поддерживает ли возвращаемый результат 2 V4L2_CAP_READWRITE или V4L2_CAP_STREAMING?

Метод чтения прост для понимания, то есть чтение через функцию чтения. Так что же означает потоковая передача?

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

Вот как подать заявку и сопоставить кэш:

  • 1. Применить кэш
Язык кода:javascript
копировать
struct v4l2_requestbuffers req;

req.count = nr_bufs; //кэш Количество
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;

if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0)
{
    printf("ERR(%s):VIDIOC_REQBUFS failed\n", __func__);
    return -1;
}
  • 2. Отображение кэша почемукартографированиекэш?

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

Для сопоставления кэша необходимо сначала запросить информацию о кэше, а затем использовать ее для сопоставления. Вот пример:

Язык кода:javascript
копировать
struct v4l2_buffer v4l2_buffer;
void* addr;

memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
v4l2_buffer.index = i; //Кэш, который вы хотите запросить
v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buffer.memory = V4L2_MEMORY_MMAP;

/* Запрос информации о кэше */
ret = ioctl(fd, VIDIOC_QUERYBUF, &v4l2_buffer);
if(ret < 0)
{
    printf("Unable to query buffer.\n");
    return -1;
}

/* картографирование */
addr = mmap(NULL /* start anywhere */ ,
            v4l2_buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED,
            fd, v4l2_buffer.m.offset);

Примечание. Все применяемые кэши необходимо сопоставить с использованием описанного выше метода.

  • 3. Ставим весь кэш в очередь
Язык кода:javascript
копировать
struct v4l2_buffer v4l2_buffer;

for(i = 0; i < nr_bufs; i++)
{
 memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
 v4l2_buffer.index = i; //Кэш, который вы хотите поставить в очереди
 v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 v4l2_buffer.memory = V4L2_MEMORY_MMAP; 

    ret = ioctl(fd, VIDIOC_QBUF, &v4l2_buffer);
    if(ret < 0)
    {
        printf("Unable to queue buffer.\n");
        return -1;
    }
}
  • step 6:Включите устройство
Язык кода:javascript
копировать
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (ioctl(fd, VIDIOC_STREAMON, &type) < 0)
{
    printf("ERR(%s):VIDIOC_STREAMON failed\n", __func__);
    return -1;
}
  • Шаг 7: Чтение данных Получение данных изображения на самом деле представляет собой непрерывный процесс входа и выхода из очереди.,Перед выходом необходимо вызвать опрос и дождаться завершения подготовки данных.
  • 1.poll
Язык кода:javascript
копировать
struct pollfd poll_fds[1];

poll_fds[0].fd = fd;
poll_fds[0].events = POLLIN; //ждём, пока его можно будет прочитать

poll(poll_fds, 1, 10000);
  • 2.внеочередь
Язык кода:javascript
копировать
struct v4l2_buffer buffer;

buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory = V4L2_MEMORY_MMAP;

if (ioctl(fd, VIDIOC_DQBUF, &buffer) < 0)
{
    printf("ERR(%s):VIDIOC_DQBUF failed, dropped frame\n", __func__);
    return -1;
}

После удаления из очереди получается индекс кэша buffer.index, а затем находится соответствующий кэш и данные считываются через сопоставленный адрес.

  • 3. Введите очередь. После завершения чтения данных буф необходимо поставить обратно в очередь:
Язык кода:javascript
копировать
struct v4l2_buffer v4l2_buf;

v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buf.memory = V4L2_MEMORY_MMAP;
v4l2_buf.index = i; //указанный буфер

if (ioctl(fd, VIDIOC_QBUF, &v4l2_buf) < 0)
{
    printf("ERR(%s):VIDIOC_QBUF failed\n", __func__);
    return -1;
}

Чтение данных заключается в непрерывном циклическом выполнении трех вышеуказанных шагов.

  • step 8:Выключите устройство
  • 1.Выключите устройство
Язык кода:javascript
копировать
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0)
{
    printf("ERR(%s):VIDIOC_STREAMOFF failed\n", __func__);
    return -1;
}
  • 2. Отменить карту
Язык кода:javascript
копировать
for(i = 0; i < nr_bufs; ++i)
    munmap(buf[i].addr, buf[i]->length);
  • закрыть дескриптор файла
Язык кода:javascript
копировать
close(fd);
  • libv4l2 Устройство v4l2 довольно сложно в работе. По этой причине я инкапсулировал его и написал набор библиотек, чтобы сделать его более удобным в использовании. Вы можете получить его из libv4l2 здесь.

В комплекте идет пример example_cature, который запускает программу через capture /dev/video0 для сбора картинки в формате YUYV. После сбора получается pic.yuv, который можно просмотреть через ffplay ffplay -pixel_format yuyv422 -f rawvideo -video_size. 640x480 pic.yuv, рендеры следующие

4. v4l2 захватывает изображения и отображает их в буфере кадров.

Как отобразить собранное изображение на баффе кадра?

  • 1. Конвертировать формат изображения, конвертировать формат yuv в рамку формат RGB, который может получить бафф
  • 2. Управляйте усилением кадров, сопоставляйте видеопамять усиления кадров с пользовательским пространством и напрямую записывайте в видеопамять для отображения изображения.

Конкретный процесс реализации здесь подробно описываться не будет. Ниже приведен пример для получения ссылки:

Язык кода:javascript
копировать
https://github.com/ImSjt/libv4l2

После выполнения команды make для компиляции вы можете получить video2lcd, выполните video2lcd /dev/video0

Эффект от бега следующий:

5. v4l2 собирает изображения и отображает их с помощью Qt

Как использовать qt display, принцип тот же, что и при отображении на фрейме. Все они представляют собой сбор, формат преобразования и отображение. Вот пример для получения ссылки:

Язык кода:javascript
копировать
https://github.com/ImSjt/libv4l2

Эффект от операции следующий.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose