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

06-06-01 Откуда берётся задержка: разбор по этапам

При работе с потоковым видео в реальном времени, особенно при использовании таких инструментов, как FFMPEG, важно понимать, что задержка (латентность) — это не единичный эффект, а суммарный результат накопления временных задержек на каждом этапе обработки медиапотока. Даже при идеальной скорости передачи данных по сети, конечная задержка между моментом захвата кадра на камере и его отображением на экране получателя может составлять от нескольких сотен миллисекунд до нескольких секунд.

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


1. Сетевой уровень: буферы и сглаживание джиттера

На входе в систему, когда FFMPEG принимает поток по сети (например, с IP-камеры по RTSP или через SRT), задержка уже начинается. Основные источники:

Буферы сокетов (socket buffers)

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

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

🔹 Пример: если буфер сокета рассчитан на 100 мс потока, FFMPEG начнёт обработку только после того, как в буфере накопится достаточно данных. Это вносит минимальную задержку в 100 мс, даже если сеть идеальна.

Сглаживание джиттера (jitter buffering)

Особенно актуально при использовании UDP/RTP и SRT, где пакеты могут приходить не по порядку или с переменной задержкой (джиттер).

FFMPEG (через библиотеку libavformat) использует внутренний джиттер-буфер, чтобы:

  • переставить пакеты в правильном порядке;
  • дождаться пропущенных фрагментов (если есть механизм восстановления, как в SRT);
  • избежать разрывов в воспроизведении.

🔹 Визуализация: представьте, что вы получаете кадры 1, 3, 2, 5, 4. Чтобы отобразить их корректно, нужно подождать, пока придут кадры 2 и 4. Это ожидание — и есть задержка.

Чем нестабильнее сеть, тем больше буфер джиттера, и тем выше латентность.
SRT, например, позволяет задать параметр latency, который напрямую управляет размером этого буфера (в миллисекундах). Увеличение латентности повышает надёжность, но снижает «живость» потока.


2. Демультиплексор: ожидание ключевого кадра

После получения потока из сети FFMPEG передаёт его в демультиплексор — компонент, который «распаковывает» контейнер (например, RTP, RTMP, TS) и выделяет отдельные видеопотоки, аудиопотоки и метаданные.

На этом этапе возникает задержка по следующей причине:

Необходимость дождаться I-кадра (ключевого кадра)

Видео в современных кодеках (H.264, H.265) строится по принципу предиктивного кодирования:

  • I-кадры (ключевые) содержат полную информацию о кадре;
  • P- и B-кадры хранят только изменения относительно других кадров.

Чтобы начать декодирование, декодер должен получить I-кадр. Если поток начат не с него (например, FFMPEG подключился к уже идущей трансляции), демультиплексор должен ждать появления ближайшего I-кадра.

🔹 Пример: если GOP (группа кадров) имеет длину 2 секунды (например, при 30 кадрах/сек и I-кадре каждые 60 кадров), и вы подключились в середине GOP, задержка может составить до 2 секунд, пока не придёт следующий I-кадр.

Это особенно заметно при работе с RTSP-потоками с камер, где перекодирование не производится, и GOP остаётся длинным.


3. Декодер: внутренние буферы и B-кадры

После демультиплексации данные поступают в декодер (libavcodec). Здесь задержка возникает из-за особенностей архитектуры видеокодеков.

Обработка B-кадров

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

В результате:

  • декодер накапливает кадры во внутреннем буфере;
  • выдаёт их в порядке отображения, а не поступления.

🔹 Пример: последовательность кадров: I → B → P → B → B → I
Чтобы правильно декодировать первый B-кадр (между I и P), нужно сначала получить P-кадр.
Чтобы декодировать следующие B-кадры, нужно дождаться следующего I-кадра.
Это создаёт буфер на 2–3 кадра, что добавляет задержку в 60–100 мс при 30 кадрах/сек.

Чем больше B-кадров в GOP, тем выше потенциальная задержка на стороне декодера.


4. Фильтры: накопление кадров для обработки

После декодирования видео может пройти через цепочку фильтров (filtergraph), где применяются:

  • масштабирование (scale);
  • деинтерлейсинг (yadif);
  • шумоподавление (hqdn3d);
  • наложение оверлеев (overlay, drawtext);
  • композитинг (мозайка, PIP).

Почему фильтры добавляют задержку?

Многие фильтры работают не по одному кадру, а требуют:

  • анализа нескольких кадров (например, для временного шумоподавления);
  • синхронизации нескольких источников (в случае PIP или мозайки);
  • накопления кадров для корректной работы (например, fps или minterpolate).

🔹 Пример: фильтр hqdn3d (высококачественное шумоподавление) использует временное усреднение — он смотрит на соседние кадры, чтобы решить, какой пиксель «настоящий». Это требует буферизации нескольких кадров, что добавляет задержку.

Даже простой overlay (наложение логотипа) требует, чтобы оба потока (основной и логотип) были декодированы и синхронизированы по времени. Если один из источников «отстаёт», FFMPEG будет ждать, чтобы не нарушить синхронизацию.


5. Кодер: look-ahead, VBV и структура GOP

После фильтрации видео поступает в кодер, где оно может быть перекодировано (например, в H.264 для RTMP-трансляции). Это один из самых задержкоёмких этапов.

Look-ahead (предпросмотр кадров)

Некоторые кодеры (например, libx264) используют look-ahead — анализируют будущие кадры, чтобы:

  • оптимизировать распределение битрейта;
  • выбирать лучшие точки для I-кадров;
  • улучшить сжатие.

Но для этого нужно накопить несколько кадров в буфере, прежде чем начать кодирование.

🔹 Пример: при --look-ahead-frames 20 кодер ждёт 20 кадров, прежде чем закодировать первый. При 30 кадрах/сек это 666 мс задержки только на этапе кодера.

VBV-буфер (Video Buffering Verifier)

VBV — это модель буфера получателя, используемая для контроля битрейта. Кодер моделирует, как будет заполняться буфер на стороне клиента, чтобы:

  • избежать переполнения (buffer overflow);
  • обеспечить плавное воспроизведение.

Для этого он сглаживает битрейт, что требует:

  • накопления кадров;
  • отложенной выдачи данных.

Чем больше bufsize (размер VBV-буфера), тем сильнее сглаживание и выше задержка.

Структура GOP

Как уже обсуждалось, длинный GOP увеличивает задержку:

  • I-кадры реже — дольше ждать при подключении;
  • больше B- и P-кадров — больше буферизации в декодере и кодере.

Но короткий GOP снижает эффективность сжатия. Это — классический компромисс между качеством, битрейтом и задержкой.


6. Мультиплексор и протокол вывода: буферы перед отправкой

На финальном этапе закодированный поток передаётся в мультиплексор, который упаковывает его в контейнер (например, FLV для RTMP, TS для SRT) и отправляет по сети.

Буферы вывода

FFMPEG использует выходные буферы, чтобы:

  • сгладить всплески битрейта;
  • компенсировать неравномерную скорость кодирования;
  • избежать перегрузки сети.

Но эти буферы задерживают отправку кадров.

Особенности протоколов

ПротоколОсобенность задержки
RTMPИспользует внутренние буферы на сервере; типичная задержка — 1–3 сек.
SRTПараметр latency явно задаёт размер буфера восстановления (по умолчанию 120 мс).
HLSПо определению высокозадержечный: нужно несколько сегментов (обычно 3–6), каждый по 2–6 сек.
UDP/TSМинимальная задержка, но нет защиты от потерь — подходит только для надёжных сетей.

🔹 Пример: при HLS-трансляции с -hls_time 4 и -hls_list_size 5, клиент должен загрузить минимум 2–3 сегмента, прежде чем начать воспроизведение. Это автоматически даёт задержку 8–12 секунд.


Итоговая карта задержек: суммарный эффект

Ниже представлена сводная таблица источников задержки в типичном FFMPEG-пайплайне:

ЭтапИсточник задержкиТипичное значениеМожно ли уменьшить?
СетьДжиттер-буфер, сокет50–200 мсДа (настройка latency, UDP)
ДемультиплексорОжидание I-кадрадо 2 секДа (короткий GOP на источнике)
ДекодерB-кадры, буферизация50–150 мсДа (отключить B-кадры)
ФильтрыНакопление кадров30–200 мсДа (упростить граф)
КодерLook-ahead, VBV, GOP100–1000 мсДа (настройки кодека)
Мультиплексор/выводБуферы, сегментация100 мс – 10 секДа (выбор протокола)

⚠️ Важно: общая задержка — это сумма всех этапов. Даже если каждый вносит по 100 мс, итог может быть более 1 секунды.


Связь с предыдущими знаниями

Студенты, изучавшие структуру видео и кодеков, могут связать эти источники задержки с уже известными концепциями:

  • GOP — влияет на задержку при подключении и в кодере/декодере;
  • B-кадры — требуют буферизации;
  • битрейт-контроль (CBR/VBR) — связан с VBV и look-ahead;
  • RTP/RTCP — механизм джиттера и синхронизации.

Таким образом, задержка в FFMPEG — не «ошибка», а следствие применения стандартных механизмов сжатия, сетевой доставки и обработки, направленных на качество и стабильность.
Понимание этих этапов позволяет осознанно выбирать компромиссы при проектировании видеосистем.


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