Перейти к основному содержимому

06-04-01 Мультивью: мозаика из нескольких RTSP-источников

06-04-01

В современных видеокомплексах — будь то студийный пульт, система видеонаблюдения или видеостена — часто возникает необходимость одновременно отображать изображение с нескольких камер. Одним из наиболее эффективных и технически доступных решений для этого является создание мозаики (multiview mosaic) с использованием FFMPEG. Этот подход позволяет объединить несколько видеопотоков в одно выходное видео, где каждый источник занимает выделенную область кадра, например, в виде сетки 2×2.

Такой формат особенно полезен для:

  • Оперативных пультов, где требуется обзор с нескольких точек;
  • Студийных preview, чтобы контролировать сцену с разных ракурсов;
  • Видеостен, где важно визуально компактно представить множество источников.

Рассмотрим, как реализуется такая задача на практике с помощью FFMPEG, и какие технические нюансы при этом необходимо учитывать.


Команда FFMPEG для создания мозаики 2×2

Приведённая ниже команда демонстрирует типичный сценарий создания мозаики из четырёх RTSP-источников:

ffmpeg -i rtsp://cam1 -i rtsp://cam2 -i rtsp://cam3 -i rtsp://cam4 \
-filter_complex "\
[0:v]setpts=PTS-STARTPTS,scale=640x360[cam1];\
[1:v]setpts=PTS-STARTPTS,scale=640x360[cam2];\
[2:v]setpts=PTS-STARTPTS,scale=640x360[cam3];\
[3:v]setpts=PTS-STARTPTS,scale=640x360[cam4];\
[cam1][cam2][cam3][cam4]xstack=inputs=4:layout=0_0|640_0|0_360|640_360[out]" \
-map "[out]" -c:v libx264 -f flv rtmp://server/app/mosaic

Разберём её по частям, чтобы понять логику работы.


Этапы обработки: от источников к финальному кадру

1. Подключение к RTSP-источникам

Каждый из четырёх -i rtsp://... указывает FFMPEG на отдельный видеопоток с IP-камеры. FFMPEG одновременно инициирует подключение к каждому источнику, начинает приём RTP-пакетов и их демультиплексацию. Это требует от системы:

  • стабильного сетевого соединения с каждой камерой;
  • достаточной пропускной способности канала;
  • устойчивости к возможным флуктуациям задержки (jitter) в сети.

⚠️ Важно: если одна из камер не отвечает или теряет соединение, FFMPEG по умолчанию может остановить всю команду. В реальных системах это решается обёртыванием в скрипты с перезапуском или использованием опций вроде -timeout и -reconnect.


2. Обработка каждого видеопотока: выравнивание времени и масштабирование

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

[0:v]setpts=PTS-STARTPTS,scale=640x360[cam1]

Разберём этот фрагмент:

  • [0:v] — ссылка на видеопоток первого входа (камера 1);
  • setpts=PTS-STARTPTSсбрасывает временную метку (PTS), чтобы отсчёт шёл с нуля. Это критически важно, потому что разные камеры могут иметь разную начальную задержку, и их временные шкалы не синхронизированы;
  • scale=640x360 — изменяет разрешение кадра до нужного размера, чтобы все потоки занимали одинаковую площадь в мозаике;
  • [cam1] — присваивает результат метке, чтобы использовать её далее в цепочке.

То же самое повторяется для остальных трёх источников. Без setpts возможна рассинхронизация — один поток может "прыгать" во времени относительно других, что приведёт к визуальным артефактам или ошибкам при кодировании.


3. Объединение потоков: фильтр xstack

После подготовки всех четырёх видеопотоков они объединяются с помощью фильтра xstack:

[cam1][cam2][cam3][cam4]xstack=inputs=4:layout=0_0|640_0|0_360|640_360[out]

Здесь:

  • inputs=4 — указывает, что объединяется четыре входа;
  • layout задаёт расположение каждого источника в финальном кадре:
    • 0_0 — левый верхний угол (камера 1);
    • 640_0 — правый верхний (камера 2);
    • 0_360 — левый нижний (камера 3);
    • 640_360 — правый нижний (камера 4).

Финальное изображение будет иметь размер 1280×720 (640×2 на ширину, 360×2 на высоту), что соответствует стандартному HD-формату.

💡 Примечание: xstack — более современная и гибкая альтернатива устаревшему tile. Он поддерживает произвольные позиции и даже перекрытия, в отличие от строгой сетки.


4. Вывод результата

-map "[out]" -c:v libx264 -f flv rtmp://server/app/mosaic
  • -map "[out]" — указывает, что выходной видеопоток берётся из результата фильтра xstack;
  • -c:v libx264 — кодирует объединённое видео в H.264;
  • -f flv — упаковывает поток в контейнер FLV, совместимый с RTMP;
  • rtmp://server/app/mosaic — адрес назначения, например, медиасервер (Wowza, Nginx-RTMP, OBS).

Ключевые технические аспекты

1. Выравнивание временных меток (setpts)

Разные камеры могут:

  • иметь разную начальную задержку;
  • использовать разные часы (clock drift);
  • передавать поток с разным буфером на стороне камеры.

Без setpts=PTS-STARTPTS FFMPEG будет пытаться обрабатывать кадры в их "оригинальной" временной шкале, что может привести к:

  • пропуску кадров;
  • ошибкам синхронизации;
  • "зависанию" потока.

setpts устраняет этот эффект, начиная отсчёт времени с нуля для каждого источника, что делает их временно совместимыми.


2. Влияние сетевой задержки и джиттера

Каждый RTSP-источник может идти по разному сетевому пути:

  • одна камера — по Wi-Fi, другая — по кабелю;
  • разные маршрутизаторы, разная загрузка каналов.

Это приводит к разной задержке (latency) и вариации задержки (jitter). FFMPEG использует входные буферы, чтобы компенсировать эти колебания, но:

  • слишком большой буфер — увеличивает общую задержку;
  • слишком маленький — вызывает обрывы и потери кадров.

В реальных системах можно использовать опции вроде:

  • -rtbufsize 100M — ограничение размера буфера приёма;
  • -fflags nobuffer — уменьшение буферизации (но с риском потерь).

3. Нагрузка на CPU

Одновременная работа с четырьмя RTSP-потоками — это серьёзная нагрузка:

  • 4 декодера — каждый поток нужно декодировать (H.264/H.265);
  • 4 масштабирования — каждый кадр преобразуется в нужное разрешение;
  • 1 композитинг — объединение в мозайку;
  • 1 кодирование — финальный поток перекодируется.

Примерная нагрузка на CPU:

ОперацияНагрузка (примерно)
Декодирование 1 потока10–25% CPU
Масштабирование5–10% CPU
Композитинг (xstack)5–15% CPU
Кодирование (libx264)20–40% CPU

Итого: для 4 камер может потребоваться 60–100% одного ядра (в зависимости от разрешения, битрейта, настроек кодирования).

💡 Рекомендация: для масштабных систем (8+ камер) стоит рассмотреть:

  • аппаратное декодирование (h264_cuvid, h264_qsv);
  • использование GPU для масштабирования и композитинга;
  • распределение нагрузки по нескольким серверам.

Практические сценарии использования

СценарийПример применения
ВидеонаблюдениеОператор видит 4 зоны одновременно на одном экране
Студийная съёмкаРежиссёр контролирует основную камеру, дублирующую, презентацию и гостя
Спортивная трансляцияОбзор с разных ракурсов: трибун, поле, судья, замены
Видеостена16 камер в сетке 4×4 на большой экран в ЦОДе или транспортном узле

Возможные модификации команды

Мозаика 3×3 (9 камер)

-layout 0_0|640_0|1280_0|0_360|640_360|1280_360|0_720|640_720|1280_720

Финальное разрешение: 1920×1080.

Другие фильтры вместо xstack

  • tile=3x3 — упрощённая сетка, но без гибкости позиционирования;
  • hstack, vstack — горизонтальное или вертикальное объединение;
  • overlay — для PIP (картинка в картинке), а не мозаики.

Итоги

Создание мозаики из нескольких RTSP-источников — типичная задача для FFMPEG, демонстрирующая его силу как универсального медиа-композитора. Однако за простотой команды скрывается сложная техническая реализация, включающая:

  • синхронизацию временных шкал;
  • компенсацию сетевой нестабильности;
  • значительную вычислительную нагрузку.

Понимание этих аспектов позволяет:

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

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