Привязка к реальному времени¶
media.source.realtime_aligner
Для live stream недостаточно знать порядок кадров и скорость воспроизведения. Стримеру нужно понимать, какому календарному времени соответствует каждый кадр: тогда его можно записать в DVR и позже найти нужный момент по дате и времени.
Источники дают разные основания для такого решения. У одних есть только относительная шкала, у других — собственные часы, которым не всегда можно доверять. Сеть может доставлять ровный по медиавремени поток рывками. Sapsan связывает эти шкалы с реальным временем, сохраняя интервалы между кадрами, и пересматривает привязку, когда поведение источника меняется.
Медиавремя, часы источника и время прибытия¶
У кадра есть временные метки: DTS задаёт момент декодирования, PTS — момент показа. Они определяют расположение кадра на медиашкале, но сами по себе не всегда содержат дату и время суток.
| Источник времени | Что известно стримеру | Задача |
|---|---|---|
| Относительные DTS/PTS, например в MPEG-TS | Порядок кадров и интервалы между ними | Выбрать положение этой шкалы на календаре стримера. |
| Календарные метки, например после привязки RTP через RTCP Sender Report | Абсолютное время по часам отправителя | Проверить, можно ли доверять этим часам. |
| Время фактического поступления | Когда кадр стал доступен серверному тракту | Учесть сетевые задержки и пакетную доставку, не превратив их в искажение медиашкалы. |
В одном стриме эти сведения могут появляться не одновременно. Например, RTSP-вход сначала принимает кадры по относительным RTP-меткам, а затем получает связь с абсолютным временем из RTCP. Переподключение камеры или переключение источника снова может изменить основание шкалы.
MPEG-TS без календарного времени¶
Временные метки MPEG-TS позволяют воспроизвести видео и звук в нужном темпе, но не сообщают, что кадр относится, например, к 14:00:00 сегодняшнего дня. Счётчик может начинаться с произвольного значения и переходить через границу своего диапазона.
Sapsan выбирает сдвиг между медиашкалой и часами стримера. Затем применяет его к DTS и PTS, сохраняя расстояния между метками:
calendar_time = source_time + offset
Например, кадр с относительным DTS 42,000 с привязывается к 14:00:00. Следующий кадр с DTS 42,040 с получает время 14:00:00,040. Его время не заменяется на момент выполнения очередного чтения сокета.
Так архив получает календарную шкалу, основанную на поступлении стрима в Sapsan. Для источника без абсолютных меток это серверная привязка: восстановить по ней неизвестное исходное время съёмки и задержку до стримера невозможно. При включённом входном буфере привязка происходит после его выдачи кадров, поэтому его задержка также влияет на положение шкалы.
RTSP и WebRTC: абсолютному времени нужна проверка¶
Входы на основе RTP, включая RTSP и WebRTC, могут получить абсолютное время через RTCP Sender Report. Но календарная метка не гарантирует правильных часов: камера могла потерять настройку времени, работать без синхронизации или передавать время далеко в прошлом либо будущем.
Для обычного пути выравнивания Sapsan различает календарные и относительные метки. Календарным считается масштаб Unix-времени не раньше 2000 года. Если такая метка отличается от часов стримера не больше чем на 60 секунд, она сохраняется: интервал доставки не превращается в повод заново назначить время источника.
Если расхождение превышает окно доверия, метка обрабатывается как шкала, требующая серверной привязки. Проверка симметрична для прошлого и будущего. Это предотвращает запись текущего эфира по явно неверному календарю камеры.
Окно доверия не является гарантией точной синхронизации: ошибка часов внутри него может сохраняться. Синхронизация времени на источнике и сервере остаётся необходимой для точного соответствия архивной записи реальному событию.
Решение принимается и для отдельных дорожек. Дорожка с достоверным календарным временем не получает повторно сдвиг, выбранный для относительной шкалы: иначе сервер мог бы прибавить эпоху Unix к уже абсолютной метке.
Импульсная подача: HLS → HTTP MPEG-TS¶
Промежуточный сервер может принять несколько секунд HLS, разобрать сегмент и отправить его содержимое по HTTP MPEG-TS почти одним залпом. Затем наступает пауза до следующего сегмента. Медиавремя внутри каждого залпа идёт равномерно, а время прибытия кадров резко колеблется.
Если назначать каждому кадру время по моменту прибытия, несколько секунд видео сожмутся до короткого сетевого залпа, а пауза между сегментами станет дырой в шкале. Если постоянно менять сдвиг по каждому колебанию, появятся повторные разрывы и перепривязки.
Sapsan обрабатывает такой вход последовательно:
- Входной буфер накапливает кадры и выпускает их в темпе DTS. Здесь тайминг внутри потока определяет интервалы выдачи, а импульсы сети поглощаются очередью.
- Выравниватель связывает полученную медиашкалу с календарём. Он сохраняет выбранный сдвиг, пока расхождение остаётся допустимым.
- Последующие компоненты получают привязанные метки для транскодирования, упаковки и записи.
У входа tshttp глубина буфера по умолчанию составляет 30 000 мс. Настройка передаётся через API central:
streams:
- name: tv1
inputs:
- tshttp:
url: http://origin.example/live/tv1.ts
source_options:
buffer_ms: 30000
buffer_ms задаётся в source_options конкретного входа. Это целевая глубина по медиавремени, а не число байтов. Явный 0 отключает буфер; положительное значение включает его и для других типов входов. У остальных типов он по умолчанию выключен. Увеличение глубины позволяет покрыть более длинные паузы ценой задержки и памяти.
Буфер не может компенсировать бесконечную остановку источника. После исчерпания накопленных кадров выдача приостанавливается. При избыточном накоплении старый материал может быть отброшен для сокращения отставания от live; эти события доступны в статистике.
Когда меняется привязка¶
Для шкалы, требующей серверного сдвига, выравниватель проверяет разницу между текущими часами и уже сдвинутым DTS. Если модуль разницы становится больше 5 секунд, выбирается новый сдвиг. Это позволяет реагировать на сброс меток, накопившееся расхождение темпа и изменение шкалы после переподключения.
Решение опирается на одну ведущую аудио- или видеодорожку. Видео получает приоритет перед аудио. Остальные дорожки с относительным временем получают общий сдвиг: они не должны поочерёдно перестраивать шкалу всего стрима из-за своих различий. Если ведущая дорожка не поступает более 5 секунд, другая поступающая аудио- или видеодорожка может стать ведущей.
Сдвиг применяется и к DTS, и к PTS. Выравниватель сохраняет их взаимное положение; он не исправляет уже существующую рассинхронизацию аудио и видео внутри источника.
При перепривязке в медиапайплайн передаётся событие изменения шкалы. Последующая упаковка может завершить текущие фрагменты и начать новые. Перепривязка может сдвинуть время как вперёд, так и назад: механизм восстанавливает связь с реальным временем, а не обещает скрыть любой скачок источника без разрыва.
Для источников с уже подготовленной календарной шкалой действует отдельный режим сохранения времени. Прямые входы HLS и DASH проходят без такой коррекции; их нормальное отставание на несколько сегментов не вызывает постоянных перепривязок. Поэтому непосредственный приём HLS и приём HTTP MPEG-TS, полученного промежуточным сервером из HLS, требуют разного поведения. Сохранение времени применяется также к внутренним путям передачи уже привязанных кадров, чтобы не менять шкалу повторно на каждом этапе.
Выравнивание встроено в live-пайплайн. Пороги 5 и 60 секунд описывают текущую реализацию; отдельные YAML-параметры для них в конфигурации стрима не предоставляются.
Что наблюдать¶
Запросите статистику у стримера, который принимает источник:
curl -fsS -u "$ADMIN_USER:$ADMIN_PASSWORD" \
http://streamer:8080/streamer/api-v4/streams/stats/tv1 \
| jq '{name, dts_source, source_timing_offset_ms,
source_timing_offset_min_ms, source_timing_offset_max_ms,
source_timing_jitter_ms, source_timing_input,
source_timing_window_started_at, input}'
Поле dts_source показывает основание шкалы:
realtime— время ведётся сдвигом к часам стримера.input— метки источника сохраняются: они прошли проверку календарного времени либо вход работает в режиме сохранения шкалы.
До поступления кадров и после длительного молчания поле может отсутствовать. При экспорте метрик stream_dts_source использует значения 1 для realtime и 2 для input.
source_timing_offset_ms показывает текущее смещение, измеряемое монитором времени. Границы source_timing_offset_min_ms / source_timing_offset_max_ms и source_timing_jitter_ms относятся к завершённому минутному окну; source_timing_input и source_timing_window_started_at обозначают источник и начало окна. Для относительной шкалы монитор выбирает собственную точку отсчёта, поэтому эти значения нельзя считать измерением неизвестной задержки от камеры до стримера.
Монитор находится перед выравнивателем, но после входного буфера. При включённом буфере его показатели уже отражают сглаженную подачу. Для оценки исходной неравномерности сопоставляйте их с состоянием буфера и его опустошениями, а не только с одним графиком джиттера.
В секции input доступны показатели буфера:
| Поле | Значение |
|---|---|
buffer_target_ms |
Целевая глубина в миллисекундах медиавремени. |
buffer_depth_ms |
Текущая глубина. |
buffer_underruns |
Накопленное число эпизодов исчерпания буфера. |
buffer_skips |
Накопленное число сокращений очереди при переполнении. |
buffer_skipped_ms |
Суммарное отброшенное медиавремя в миллисекундах. |
Нулевые поля могут отсутствовать в ответе. Сравнивайте прирост счётчиков за интервал; отсутствие всей секции статистики не означает, что проверка выполнена без ошибок.
Для эксплуатации полезно проверить три сценария:
- Ровный относительный поток — шкала архива следует часам стримера, а интервалы кадров сохраняются.
- Источник с неверными часами — явно недостоверный календарь заменяется серверной привязкой; после восстановления часов источник снова может вести собственное время.
- Поток, приходящий залпами — буфер сглаживает выдачу; длительные паузы и переполнения видны в статистике и не маскируются постоянным переназначением времени каждого кадра.