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

HLS и DASH: сегментированный стриминг и вопросы задержки

06-02-04

В этом разделе мы рассмотрим, как FFMPEG используется для генерации потоков по протоколам HLS (HTTP Live Streaming) и DASH (Dynamic Adaptive Streaming over HTTP) — двух ключевых технологий сегментированного стриминга. Основное внимание будет уделено HLS, так как он наиболее распространён и наглядно демонстрирует особенности такого подхода к передаче видео. Мы разберём, как FFMPEG режет поток на сегменты, формирует плейлисты, и почему этот подход по своей природе связан с большой задержкой. Также обсудим, где такие решения уместны, а где — нет.


Как FFMPEG создаёт HLS-поток​

HLS — это протокол, разработанный Apple, который передаёт видео не как непрерывный поток, а как последовательность коротких файлов (сегментов), загружаемых по HTTP. FFMPEG может выступать в роли генератора HLS, принимая входной поток (например, с камеры или файла) и преобразуя его в набор сегментов и управляющего файла-плейлиста.

Рассмотрим типичную команду:

ffmpeg -i input -c:v libx264 -c:a aac -f hls -hls_time 4 -hls_list_size 5 stream.m3u8

Разберём её по частям:

  • -i input — входной источник (может быть файлом, RTSP-потоком, камерой и т.д.).
  • -c:v libx264 — кодирование видео в H.264.
  • -c:a aac — кодирование аудио в AAC.
  • -f hls — указывает FFMPEG использовать формат вывода HLS.
  • -hls_time 4 — длительность каждого сегмента в секундах (здесь — 4 секунды).
  • -hls_list_size 5 — количество сегментов, отображаемых в плейлисте .m3u8.
  • stream.m3u8 — имя основного плейлиста.

Что происходит при выполнении команды?​

FFMPEG делает следующее:

  1. Принимает входной поток и транскодирует его (если нужно) в H.264 + AAC.
  2. Режет видео на сегменты по 4 секунды каждый. Каждый сегмент сохраняется как отдельный файл, например: stream0.ts, stream1.ts, stream2.ts и т.д.
  3. Формирует плейлист stream.m3u8 — текстовый файл в формате M3U8, содержащий список активных сегментов и их метаданные.

Пример содержимого stream.m3u8:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:2
#EXTINF:4.000,
stream2.ts
#EXTINF:4.000,
stream3.ts
#EXTINF:4.000,
stream4.ts
#EXT-X-ENDLIST

Примечание: В режиме live-трансляции тег #EXT-X-ENDLIST отсутствует, так как трансляция продолжается.

Каждый новый сегмент добавляется в конец плейлиста, а старые — удаляются, если размер списка ограничен (например, -hls_list_size 5 оставляет только 5 последних сегментов).


Почему HLS по определению имеет большую задержку​

Задержка (латентность) в HLS не является ошибкой или недоработкой — она заложена в самой архитектуре протокола. Ниже мы разберём ключевые причины.

1. Необходимость накопления нескольких сегментов​

Клиент (например, браузер или плеер) не может начать воспроизведение, пока не загрузит хотя бы один сегмент. Но на практике плееры ждут 2–3 сегмента, чтобы сформировать буфер и избежать обрывов при скачках сети.

Если каждый сегмент длится 4 секунды, а плеер ждёт 3 сегмента, минимальная задержка уже составляет 12 секунд.

🔹 Пример:
Сегмент A (0–4 с) — загружен.
Сегмент B (4–8 с) — загружен.
Сегмент C (8–12 с) — загружен.
Только теперь плеер начинает воспроизведение с начала сегмента A.
Реальное время: 12 сек, но видео показывает 0 сек → задержка = 12 с.

2. Кэширование на уровне CDN и прокси​

HLS использует HTTP, что позволяет задействовать CDN (Content Delivery Network) и промежуточные кэши. Это повышает масштабируемость, но добавляет задержку:

  • CDN может кэшировать сегменты на несколько секунд.
  • Промежуточные прокси (например, корпоративные или провайдерские) также могут задерживать доставку файлов.
  • Некоторые CDN принудительно кэшируют .ts-файлы, что делает невозможным «мгновенное» обновление.

3. Период обновления плейлиста​

Клиент периодически запрашивает обновлённый stream.m3u8, чтобы узнать, появились ли новые сегменты. Интервал обновления зависит от реализации, но обычно составляет от 1 до 3 секунд.

Это означает, что даже если сегмент уже готов, клиент может не узнать о нём сразу.


Сравнение задержки: HLS vs другие протоколы​

ПротоколТипичная задержкаПричина задержки
HLS10–30 секСегментация, буферизация, кэширование
RTMP3–8 секTCP, буферы сервера, отсутствие сегментации
SRT0.5–2 секАдаптивное управление буферами, FEC, низкоуровневая передача
WebRTC0.2–1 секP2P, UDP, минимальные буферы, эфемерная передача

✅ Вывод: HLS — самый медленный из распространённых протоколов, но это компенсируется его масштабируемостью и надёжностью.


Где уместно использовать HLS?​

Несмотря на высокую задержку, HLS остаётся одним из самых популярных протоколов для потокового видео. Вот где он работает лучше всего:

✅ Уместные сценарии​

СценарийПочему подходит
Массовые трансляции (концерты, спортивные события)Тысячи зрителей → нужна масштабируемость через CDN. Задержка не критична.
Видеокурсы и вебинары (по записи)Важно качество и стабильность, а не интерактивность.
ТВ-вещание через интернетАрхитектура HLS совместима с традиционным ТВ-опытом (зритель смотрит "эфир", а не общается).
Архивные стримы и VOD (Video on Demand)Плейлисты легко кэшируются, поддерживаются все браузеры.

❌ Неуместные сценарии​

СценарийПочему не подходит
Вебинары с обратной связьюЗадержка 15 секунд делает диалог невозможным.
Видеонаблюдение в реальном времениОператору нужно видеть "сейчас", а не "15 секунд назад".
Интерактивные трансляции (опросы, игры)Зритель отвечает с задержкой — система не успевает реагировать.
WebRTC-интеграцииТребуется синхронность, HLS несовместим по задержке.

DASH: аналог HLS с похожими ограничениями​

DASH (Dynamic Adaptive Streaming over HTTP) — это открытый стандарт, аналогичный HLS, но не привязанный к Apple. Он также использует сегментацию и HTTP-доставку, поэтому страдает от тех же проблем с задержкой.

Различия незначительны с точки зрения латентности:

  • DASH может использовать короткие сегменты (даже <1 сек), но это требует частых запросов и не всегда поддерживается CDN.
  • Формат описания — MPD (Media Presentation Description) вместо .m3u8.
  • Поддержка более сложных сценариев адаптации, но архитектура буферизации остаётся похожей.

🔹 FFMPEG также поддерживает DASH, но реже используется для него, чем для HLS.


Вывод: FFMPEG — удобный генератор HLS, но не для ультранизкой задержки​

FFMPEG отлично справляется с ролью HLS-генератора:

  • Простая команда → готовый поток.
  • Поддержка транскодирования, сегментации, настройки размера сегментов.
  • Интеграция с любыми входами (RTSP, файлы, UDP и т.д.).

Однако важно понимать:

❗ HLS — это технология для масштабируемых, но не интерактивных трансляций.

Если в вашем сценарии критична задержка, стоит рассмотреть другие решения:

  • SRT — для межстудийных линий.
  • WebRTC — для интерактивных приложений.
  • RTMP (с короткими буферами) — как компромисс.

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


Практический совет: как уменьшить задержку в HLS (ограниченно)​

Хотя полностью устранить задержку в HLS невозможно, можно частично её снизить:

НастройкаЭффект
-hls_time 1Сегменты по 1 секунде → быстрее появляются в плейлисте
-hls_list_size 3Меньше сегментов в буфере → клиент начинает раньше
Использование LL-HLS (Low-Latency HLS)Экспериментальный режим Apple с частичной загрузкой сегментов и push-обновлениями плейлиста
Отказ от CDN / кэшированияПрямая доставка с сервера, но теряется масштабируемость

⚠️ Важно: LL-HLS поддерживается не всеми плеерами и требует специальной настройки сервера. FFMPEG частично поддерживает его через флаги, но реализация сложнее.


Итог​

  • HLS — это сегментированный протокол, основанный на HTTP.
  • FFMPEG легко генерирует HLS-потоки через опции -f hls и настройки сегментации.
  • Задержка неизбежна из-за архитектуры: накопление сегментов, кэширование, обновление плейлиста.
  • HLS уместен для массовых, неинтерактивных трансляций, где важна стабильность и масштабируемость.
  • Для низколатентных сценариев (видеосвязь, мониторинг) HLS не подходит — нужны другие протоколы и инструменты.