Skip to content

HLS

media.ingest.hls

Описание

Sapsan следует за чужим HLS-плейлистом в режиме клиента (pull): опрашивает плейлист, забирает сегменты и отдаёт кадры в тракт наравне с RTSP, SRT или MPEG-TS. Так отдаётся почти всякий агрегатор, всякая чужая CDN и всякий партнёр, которому не разрешили открыть UDP или SRT.

Настройка

Настройка выполняется через API central. Фрагмент конфигурации стрима:

streams:
  - name: chan1
    inputs:
    - hls:
        url: https://cdn.example.com/live/index.m3u8

Параметры

Параметр Умолчание Описание
url — адрес плейлиста ровно в том виде, как его записал оператор
headers нет заголовки ко всем запросам к источнику: плейлист, сегменты, ключи
variant_mode single single — один вариант мастера, ladder — вся лесенка
variant_bandwidth нет к какому битрейту подбирать вариант (ближайший снизу); без него берётся старший по BANDWIDTH
skew_threshold_ms 500 с какого расхождения рендишенов лесенка считается несинхронной
skew_policy report что делать при вердикте skewed: report — продолжать и показывать, fallback_to_single — откатиться на один вариант
connect_timeout_ms 5000 таймаут установления соединения
read_timeout_ms 15000 таймаут получения тела: плейлиста, сегмента, ключа
max_body_bytes 64 МиБ потолок размера одного ответа
peer_timeout_ms общий сколько ждать кадров, прежде чем считать источник потерянным

Аутентификация

Два способа, их можно сочетать:

  • заголовки — headers, например Authorization: Bearer <token>; уходят с плейлистом, вариантами, init-сегментами, сегментами и ключами того же origin и не уходят на чужой origin после редиректа;
  • учётные данные в самом URL — обычная Basic-аутентификация средствами HTTP-клиента.

Значения заголовков в логи не попадают: печатаются только имена. Адрес входа пишется в логи целиком и в ответах управляющего API отдаётся как есть — где именно в строке адреса секрет, знает только оператор, и маскировка наугад либо оставила бы токен в query, либо срезала бы то, по чему вход опознают в логе.

Варианты транспорта

HTTP или HTTPS; плейлист/манифест и медиасегменты загружаются отдельными запросами.

Поддерживаемые кодеки

Набор кодеков зависит от контейнера сегментов. MPEG-TS и fMP4 — контейнеры, а HLS — способ получения плейлистов и сегментов.

Сегменты MPEG-TS:

  • H.264
  • HEVC / H.265
  • AV1
  • JPEG 2000
  • MPEG-2 Video
  • AAC (ADTS)
  • AC-3
  • E-AC-3
  • MPEG Audio (Layer II / III)
  • SMPTE ST 302M

MPEG-TS — контейнер, а SRT, RIST, UDP и HTTP — способы его доставки. Перечень относится к извлечению кадров из MPEG-TS, а не к декодированию или поддержке этих кодеков плеером.

AV1 распознаётся по stream_type 0x06 и регистрационному дескриптору AV01 в PMT; один PES должен содержать целый temporal unit. MPEG-TS с AV1 без этой сигнализации не поддерживается. Для AAC реализован разбор ADTS; наличие stream_type 0x11 само по себе не означает поддержку LATM. Opus может быть распознан в PMT, но текущий PES-разборщик не выдаёт его кадры.

Сегменты fMP4:

  • H.264
  • HEVC / H.265
  • AV1
  • MPEG-2 Video
  • JPEG
  • AAC
  • AC-3
  • E-AC-3
  • MPEG Audio (Layer II / III)
  • Opus
  • G.711 A-law / μ-law

Это кодеки, которые вход извлекает из fMP4, а не список форматов декодирования. H.264 использует avc1/avc3, HEVC — hvc1/hev1, AV1 — av01 с av1C. Для MPEG-2 Video требуется mp4v с конфигурацией MPEG-2; это не обещание поддержки MPEG-4 Visual. JPEG передаётся дорожкой изображений. MPEG Audio определяется по esds или sample entry MP3; mp4a сам по себе не означает AAC. Для Opus используется Opus/dOps, для G.711 — alaw/ulaw. Контейнер и объявление дорожки должны соответствовать данным; наличие кодека в MPD не заменяет корректный init-сегмент.

Packed audio (отдельные ADTS или ID3+AAC без MPEG-TS/fMP4) этим входом не принимается.

Поведение при ошибках

Состояние входа и причина отказа доступны в статистике стрима. При обрыве или отсутствии кадров действует общий механизм повторных подключений и переключения на резерв.

Применение изменений

Перезапуска входа требует только смена url, headers и HTTP-настроек (connect_timeout_ms, read_timeout_ms, max_body_bytes): у нового источника своя нумерация дорожек, свой init и своя позиция в плейлисте. Остальное — режим варианта, порог и политика расхождения, peer_timeout_ms — применяется на лету, без разрыва вещания.

Счётчики

Ниже — точные имена полей протокольной статистики. counter накапливает события, gauge показывает текущее значение; список включает оба вида. Нулевые поля могут отсутствовать в ответе. API и Prometheus используют разные проекции: весь список не следует ожидать в одном ответе Admin API. Доступ к детализации зависит от лицензии на счётчики.

Общие показатели входа: bytes, frames, errors, warnings. Они суммируют данные протокола, поэтому складывать их с протокольными счётчиками повторно не нужно.

Hls

Поле Тип
segments counter
bytes counter
frames counter
playlist_reloads counter
discontinuities counter
segments_skipped counter
segments_gone counter
segments_cancelled counter
segments_gap counter
errors_playlist counter
errors_segment_network counter
errors_segment_status counter
errors_segment_decode counter
errors_decrypt counter
fragment_gaps counter
fragment_overlaps counter
fragment_seam_error_ms counter
edge_distance_ms counter
playlist_updated_at gauge
frames_emitted_at gauge
memory_bytes gauge
ad_marks counter
errors_ad_marks_dropped counter
warning_ad_mark_descriptors_dropped counter

Прочее

Правило старта

Всё, что лежало в плейлисте на момент подключения, — история. Захват начинается с первого сегмента, появившегося после подключения; так же он ведёт себя и на реконнекте.

Глубины старта в настройках нет намеренно: иначе на каждом обрыве связи стрим вместо вещания разгребал бы накопленное окно, вылитое в тракт за секунды.

Лесенка и расхождение рендишенов

При variant_mode: ladder захватываются все варианты мастера. Опорным берётся старший по BANDWIDTH вариант, остальные сравниваются с ним посегментно — по номеру медиа-последовательности. Вердикт виден в статистике входа, поле hls_ladder:

  • synced — рендишены идут вместе, переключение между ними безопасно;
  • skewed — расхождение превысило порог либо сломана структура: переключение даст рывок или рассинхрон;
  • unmeasurable — сравнивать не с чем, нет пар сегментов с общим номером.

Расхождение меряется двумя способами сразу. Заявленное — разница EXT-X-PROGRAM-DATE-TIME в разметке, фактическое — разница медиавремени первых кадров. Разошлись они между собой — болен не поток, а разметка, и чинить это владельцу источника.

Note

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

Политика fallback_to_single откатывает захват на один вариант при вердикте skewed — для части источников это единственный рабочий режим. Откат живёт до перезапуска входа.

Шифрование

Поддержаны AES-128 (сегмент целиком) и SAMPLE-AES (покадрово, для H.264 и AAC). Ключ забирается тем же клиентом и с теми же заголовками, что и остальное, и кэшируется по адресу, поэтому ротация ключа посреди плейлиста работает сама собой — у нового ключа другой адрес.

Молчащий сервер ключей — это ошибка входа с адресом ключа и кодом ответа; тело сегмента при этом не качается вовсе, расшифровать его всё равно нечем.

CENC/DRM (Widevine, PlayReady, FairPlay) не поддерживается и отклоняется по имени KEYFORMAT.

Что поддержано

Возможность Состояние
Медиа-плейлист: EXT-X-MEDIA-SEQUENCE, EXTINF, EXT-X-ENDLIST есть
Мастер-плейлист: выбор варианта, рендишены EXT-X-MEDIA есть
Сегменты fMP4 (EXT-X-MAP) и MPEG-TS есть
EXT-X-BYTERANGE есть
EXT-X-DISCONTINUITY, пересоздание плейлиста, отставание от окна есть
EXT-X-GAP есть, пропуск без ошибки
EXT-X-PROGRAM-DATE-TIME — привязка медиавремени к UTC есть
Шифрование AES-128 и SAMPLE-AES (H.264, AAC) есть
Лесенка: приём всех вариантов, измерение расхождения есть
LL-HLS: EXT-X-PART, blocking reload нет, части игнорируются
CENC/DRM нет
«Упакованный звук»: голый ADTS или ID3+AAC вместо контейнера нет, формат называется в ошибке
Субтитры TTML и WebVTT-сегменты нет, дорожка распознаётся и пропускается
Захват MPEG-DASH нет

Проверка

Откройте http://server/streaming/v/chan1/index.m3u8 в плеере или запросите скриншот http://server/streaming/live-preview-jpeg/chan1.

Смотреть стоит не только «кадры пошли», а три вещи:

  • отставание выдачи от края плейлиста — без него жалоба «поток отстаёт» неотличима от «источник отстаёт», а лечатся они в разных местах;
  • пропуски сегментов и их разбивку: вымыло из окна, отменён на лету, объявлен EXT-X-GAP. Последнее — не ошибка источника, а его честное заявление;
  • стык соседних фрагментов — дефект тихий: сегменты скачаны все, ошибок разбора нет, а медиа внутри них не стыкуется, и в архиве останется провал.

Что дальше