◆ ForgeVis
Skip to content

Воспроизведение архива ​

Сервер воспроизведения отвечает на один вопрос: что снимала эта камера в этот момент? Запрос называет камеру и момент времени, а запись начинается с него.

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

Включение ​

yaml
playback:
  enabled: true
  # Адрес слушателя.
  address: :9996
  # Значение заголовка Access-Control-Allow-Origin, чтобы страница с другого
  # адреса могла проигрывать записи.
  allowOrigin: '*'

За тем же правом read, что и HLS: кто может смотреть камеру, тот может смотреть и её записи. Управляющий API и его учётные данные сюда не попадают — у браузера не должно быть ключей, которыми перенастраивают рекордер.

Нужен фрагментированный формат записи

Воспроизведению требуется record.format: fmp4. Прогрессивная запись хранит заголовок в конце файла и пишет его при закрытии, поэтому в начале нет ничего, что подсказало бы, как добраться до нужного момента. Начать с произвольного места означало бы собрать этот заголовок заново — это ремукс, а не перемотка. При record.format: mp4 сервер прямо об этом и отвечает; пользуйтесь экспортом.

Запрос момента ​

GET /playback/get?path=<камера>&start=<RFC 3339>&duration=<секунды>&format=<mp4|fmp4>
ПараметрЗначение
pathидентификатор камеры — папка архива, в которую пишет рекордер
startс какого момента, RFC 3339 (2026-08-21T14:23:05+03:00)
durationсколько отдать, в секундах. Без него — до конца записи
formatmp4 для браузера, fmp4 для инструментов. По умолчанию fmp4
bash
curl -o clip.mp4 \
  'http://recorder:9996/playback/get?path=cam001&start=2026-08-21T14:23:05Z&duration=60&format=mp4'

Ответ несёт заголовок X-Playback-Start — момент, с которого он на самом деле начинается. Это редко совпадает с запрошенным: воспроизведение откатывается к ближайшему ключевому кадру, а запрос, попавший в разрыв записи, получает следующую существующую. Поэтому сервер говорит об этом прямо, а не оставляет вызывающего в уверенности, что курсор на шкале стоит верно.

Почему форматов два ​

format=mp4 — обычный файл: один заголовок, описывающий каждый сэмпл, и дальше медиа. Это то, что играет элемент <video>. Ничего не декодируется и не перекодируется: байты копируются как есть, заново собирается только описание перед ними — из таблиц, которые фрагменты и так несут.

format=fmp4 — собственные фрагменты записи, потоком. Дешевле в сборке и привычнее инструментам вроде ffplay. Но браузер, получивший фрагменты напрямую, читает весь ответ до конца, прежде чем показать кадр: в потоке нет индекса, по которому можно перематывать, и он ищет конец. Отданный именно потоком — chunked, без длины и без диапазонов — он проигрывается по мере прихода: так это делает Chrome, а Safari от такого отказывается.

Коротко: mp4 — для браузера и плееров, fmp4 — для скриптов и утилит.

Как работает перемотка ​

Перемотка происходит на узле, который держит файл. Каждый архивный файл начинается с Segment Index Box, который рекордер заполняет при закрытии: на каждый фрагмент смещение, размер, длительность и признак ключевого кадра. Поэтому ответ на «начни с 14:23:05» — это несколько килобайт из головы файла, поиск по таблице и переход. Сама запись не сканируется, ничего не декодируется.

Клиент, делающий то же самое через HTTP-диапазоны, нуждался бы в той же таблице, но ему пришлось бы сначала её скачать и самому посчитать смещения, прежде чем попросить нужные байты.

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

С чего начинается ответ ​

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

Момент, на который ничего не записано — клик в разрыв или время раньше начала архива, — получает следующую существующую запись, а не ошибку. Так полезнее: если запись возобновляется минутой позже, зритель попадёт на неё, а не упрётся в пустой ответ. Куда он попал на самом деле, говорит X-Playback-Start.

Чего он не делает ​

Один файл на запрос. Окно, попавшее сразу на две записи, отдаётся из первой; за следующей вызывающий приходит отдельно. Сшивание их в один непрерывный поток — отдельная возможность.

Не отдаёт эфир. Сервер воспроизведения отдаёт записанное. Для того, что происходит сейчас, есть HLS-стриминг.

Proprietary software.