Загрузка 0
ПОДЕЛИТЬСЯ

Мой блог

Листай вниз

Как построить real-time конвейер видеоаналитики на C++20, Clang и ONNX Runtime

Как построить real-time конвейер видеоаналитики на C++20, Clang и ONNX Runtime

Когда модель YOLO обрабатывает кадр значительно дольше, чем камера транслирует новый материал, классические FIFO-очереди быстро приводят к катастрофическому отставанию от эфира. Я, Сергей Багров, детально изучил опыт построения отказоустойчивого видеосервера на C++20, где для сохранения актуальности трансляции вместо бесконечных буферов применяются слоты последнего значения.

В основе архитектуры лежит практическая концепция: в системах реального времени кадровая свежесть критически важнее скрупулезной полноты обработки. Ознакомиться с первоисточником можно, изучив материал на Хабре, а ниже я подробно разберу ключевые инженерные решения и устройство конвейера.

Архитектурная схема потоков видеоаналитики на сервере
Общая схема движения кадров и задач внутри многопоточного конвейера видеоаналитики.
Графики производительности и распределения времени inference
Графики времени выполнения задач нейросети и распределения нагрузки на CPU.

Постановка задачи и специфика RTSP-потоков

Современный сервер видеоаналитики должен решать комплекс взаимосвязанных задач в режиме 24/7. Помимо беспрерывного чтения и декодирования входящего потока от камеры, программный комплекс обязан фиксировать движение, сопровождать целевые объекты, запускать полнокадровый инференс, производить детекцию в мини-областях, генерировать превью для HLS, сохранять события в базе данных и оперативно отдавать актуальную информацию по REST API.

Реклама

Практические тесты показывают суровую математику: камера транслирует около 14 кадров в секунду, тогда как один тяжелый проход YOLO на CPU занимает порядка 1,7 секунды. За это время устройство успевает получить более двух десятков новых изображений. Попытка складывать их в стандартную очередь неминуемо приведет к исчерпанию оперативной памяти и росту задержки. Поэтому был принят жесткий архитектурный контракт: захват видео не ждет аналитику, а устаревшие кадры заменяются самыми свежими экземплярами.

Архитектурные особенности и организация потоков

Сетевую часть серверной инфраструктуры обслуживает фреймворк Drogon, а обработка видеокадров распределена по специализированным постоянным потокам. Создавать новые потоки динамически под каждый кадр нецелесообразно из-за огромных накладных издержек и сложностей с управлением сессиями ONNX Runtime.

Внутри программного конвейера постоянно функционируют строго выделенные исполнители. Главный поток захвата единолично владеет объектом дешифрации, координатор распределяет задачи и агрегирует итоги, отдельные воркеры выполняют детектирование движения и трекинг, а вспомогательный контур готовит графические данные для трансляций.

Почему слот эффективнее классической очереди

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

Реклама

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

Управление нагрузкой и механизмы backpressure

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

Такой подход гарантирует предсказуемое потребление ресурсов. Общий объем выделенной памяти остается стабильным и не зависит от времени непрерывной работы программного обеспечения.

Реализация воркеров на базе современных средств C++20

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

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

Границы применимости механизма stop_token

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

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

Реклама

Защита от устаревших результатов вычислений

Асинхронный характер конвейера порождает проблему невалидных ответов: если пользователь переключает камеру или меняет настройки модели, тяжелый воркер может вернуть результат для уже неактуального источника. Для исключения подобных ошибок внедрена двухуровневая система поколений.

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

Метрики и диагностические счетчики

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

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

Результаты ночного нагрузочного тестирования

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

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

Принципиальные основы спроектированной системы

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

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

Ограничения архитектуры слота последнего кадра

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

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

Итоги разработки

Эффективный real-time конвейер — это не система, которая пытается успеть обработать абсолютно всё, а архитектура с четко запрограммированным и безопасным поведением в условиях аппаратных перегрузок.

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

01.