DVR / Архив¶
С версии 1.13 в Perfect Streamer доступен встроенный DVR — постоянный архив стрима на диске, который работает параллельно с обычной OTT-выдачей (HLS / DASH). Архив пишется автоматически, без отдельного процесса, и воспроизводится через те же URL OTT, что и live-вещание — отличие только в query-параметре.
Возможности:
Запись каждого OTT-стрима в архив на выбранном хранилище.
HLS, DASH и Low-Latency HLS воспроизведение архива (VOD) на тех же URL, что и live (DASH и LL-HLS — на CMAF, в режиме OTT/HLS/LL-HLS/LL-Dash).
Поддержка субтитров (WebVTT) — пишутся вместе с TS-чанками.
Несколько хранилищ — стрим привязывается к одному, разные стримы могут писать на разные диски.
Автоматическая очистка по времени удержания и по заполнению диска.
EPG-aligned VOD — выдача архива по указанию EPG-события.
Адаптивный VOD — поддерживается для адаптивных групп.
DVR не требует отдельной лицензии. Включается на уровне стрима добавлением привязки к хранилищу.
DVR не заменяет live-вещание. Если у стрима есть архив — клиент получает live-плейлист с тем же поведением, что и без DVR. Архив начинает воспроизводиться только тогда, когда клиент явно запросил VOD-режим через query-параметр URL (см. ниже).
Конфигурация хранилища¶
Хранилище — это запись в разделе Configuration / DVR Storage. Каждая запись описывает одну директорию на диске, в которую PSS пишет файлы архива. Стрим использует одно хранилище.
При добавлении хранилища настраиваются:
Name — отображаемое имя.
Dir Path — путь к директории на диске. После создания записи путь изменить нельзя — чтобы перенести архив на другой диск, нужно удалить запись и добавить новую с новым путём. Существующие файлы при удалении записи на диске не трогаются.
Max Usage, % — порог заполнения диска (по умолчанию 90 %). При превышении начинает работать size-based очистка (см. ниже). Минимум 1 %, максимум 100 %.
Cleanup Interval, сек — период работы задачи очистки (по умолчанию 10 сек). На каждом тике сначала срезается всё старше глубины хранения стрима, затем — при превышении Max Usage — старые чанки.
Disk Pressure Grace, сек — сколько секунд Used % должен непрерывно превышать Max Usage, прежде чем начнётся Size-based cleanup (по умолчанию 60 сек). Фильтрует короткие пики.
Disk Pressure Cut, сек — верхний предел для одного тика очистки: сколько секунд видео на один стрим может быть удалено за раз (по умолчанию 300 сек). Остальное переносится на следующий тик.
Disk Emergency Bytes — порог свободного места, ниже которого хранилище переходит в состояние Error и запись останавливается (по умолчанию 2 ГиБ). Автоматическое восстановление — при свободном месте ≥ 2 × этого значения.
Alarm Disk-Full Hysteresis, % — запас ниже Max Usage, до которого size-based очистка опускает заполнение, чтобы Used % не колебался у самого порога (по умолчанию 2 %).
Большинство значений по умолчанию подходят для типовых установок; коррекция требуется обычно только для Max Usage и Dir Path.
На один диск имеет смысл создавать одно хранилище. Если на одном диске указать несколько записей с разными подкаталогами, они будут конкурировать за свободное место — диск общий, а очистка у каждого хранилища своя.
Привязка стрима к хранилищу¶
В настройках Stream / OTT появляется секция DVR:
Storage — выпадающий список доступных хранилищ; 0 означает «архив выключен для этого стрима».
Storage Hours — глубина архива для этого стрима в часах, от 1 до 2160 (до 90 суток). Чанки старше этого значения удаляются на каждом тике задачи очистки (Rolling cleanup).
Storage Min Hour — нижний порог защиты (часы). Задача очистки никогда не удаляет чанки моложе этого значения, даже под давлением Max Usage. Используйте, если бизнес-логика требует гарантированной свежей записи, например «последние 2 часа всегда есть».
Изменение Storage на лету:
выставление 0 — отключает архив; чанки на диске сохраняются, новые не пишутся. VOD-сессии по этому стриму начинают отвечать 404;
выбор другого хранилища — стрим отвязывается от старого и начинает писать в новое. Файлы со старого диска не переносятся.
Изменение Storage Hours и Storage Min Hour применяется мгновенно — на следующем тике задача очистки увидит новое значение.
После настройки стрим начинает писать архив автоматически, как только перейдёт в состояние Running.
VOD: воспроизведение архива¶
Архив воспроизводится через те же URL, что и live-вещание HLS / DASH (см. раздел OTT сервис) — отличается только query-параметр.
URL и параметры¶
URL для HLS, DASH и Low-Latency HLS (DASH и LL-HLS — на CMAF, требуют режима OTT/HLS/LL-HLS/LL-Dash):
Без query-параметров — обычный live с скользящим окном. При наличии параметра t — VOD режим.
Параметр |
Назначение |
|---|---|
|
Время начала VOD (Unix epoch, сек). t=0 — от начала архива. Наличие t (даже t=0) включает VOD-режим. |
|
Длительность VOD-окна, сек. d=0 или параметр отсутствует — «до текущего момента». Имеет смысл только вместе с t. |
|
EPG-aligned VOD: сервер сам находит EPG-событие, активное в указанный момент, и берёт его start и duration как границы окна. Несовместим с t и d (server-side замена). См. ниже. |
|
Стандартные параметры live (см. OTT сервис); |
Поведение по t и d:
t |
d |
Окно |
Условие 404 |
|---|---|---|---|
нет |
— |
live (скользящее окно) |
— |
0 |
нет / 0 |
[начало архива, сейчас] |
DVR не привязан |
0 |
> 0 |
[начало архива, +d] |
DVR не привязан |
> 0 |
нет / 0 |
[t, сейчас] |
DVR не привязан |
> 0 |
> 0 |
[t, t+d] |
DVR не привязан |
Нормализация границ:
t раньше начала архива — start автоматически подтягивается к первому доступному чанку (cleanup мог уже срезать). Это не 404, просто покажем то, что осталось.
t в будущем или окно полностью раньше архива — пустой, но валидный плейлист (HLS: только header +
EXT-X-ENDLIST; DASH:@type="static",mediaPresentationDuration="PT0S").Чанки выбираются строго по моменту начала чанка, попадающему в полусегмент [t, t+d) — частичных сегментов нет.
VOD на стриме без архива (или у которого хранилище в Error) — 404 сразу на master playlist / MPD. Сессия не создаётся.
Текст ошибок в теле 404 (видны в логах сервера и в HTTP body):
VOD: stream not running— стрим есть в конфиге, но не в Running.VOD: no DVR archive— у стрима не задано хранилище или хранилище в Error.VOD: DVR detached— стрим был отвязан от хранилища между запросами.VOD: EPG event not found— для?epg=событие не найдено.
VOD HLS плейлист — закрытый (плеер видит длительность и может перематывать):
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:5.000,
...
#EXT-X-ENDLIST
В live-плейлисте этих маркеров нет — это и есть единственное отличие.
VOD DASH MPD — статический: @type="static", фиксированный mediaPresentationDuration, явные <SegmentURL>. Live-DASH остаётся @type="dynamic".
Если в выбранном интервале есть разрывы в архиве (например, был перезапуск записи или cleanup срезал часть посередине), DASH MPD автоматически разбивается на несколько <Period> — по одному на каждую сплошную дорожку. Плееры (VLC, dashjs, Shaka) перематывают через границу периода без специальных настроек.
EPG-aligned VOD¶
Если стрим связан с EPG-источником (поля EPG Source и EPG Channel в настройках стрима), клиент может запросить архив по моменту времени, попадающему в EPG-событие:
http://host:port/hls/stream/login/password/index.m3u8?epg=1778500000
http://host:port/dash/stream/login/password/index.mpd?epg=1778500000
Сервер находит EPG-событие, активное в указанный epoch, и сам подставляет его start и duration как границы VOD-окна. Это удобно для каталога передач: UI знает время события, но не обязан вычислять точные сек./мс. границы.
Если стрим к EPG не привязан или в этот момент нет события — 404 ``VOD: EPG event not found``. Параметры t и d при наличии epg игнорируются.
Адаптивные потоки¶
Адаптивные группы (см. HLS Adaptive Multistream) поддерживают те же VOD-параметры:
http://host:port/hls/adaptive/group/login/password/index.m3u8?t=0
http://host:port/dash/adaptive/group/login/password/index.mpd?t=0
В master playlist (HLS) попадают только те варианты, у которых задано хранилище DVR. Варианты без DVR пропускаются (в логе появляется VOD: variant N has no DVR), сборка из оставшихся вариантов работает.
В DASH-варианте каждое качество становится отдельным <Representation> внутри общих <Period>; плеер может переключаться между качествами без переоткрытия манифеста.
Поведение проигрывателя¶
VOD HLS / DASH с архива играют стандартные плееры: VLC, hls.js, dashjs, Shaka, ffmpeg. Перемотка по таймлайну работает.
Если плеер запросил сегмент, который к этому моменту уже удалил cleanup, сервер вернёт 404 на этот сегмент (не 500). VLC, hls.js, dashjs пропускают такой сегмент и продолжают воспроизведение со следующего.
Дополнительные возможности:
Защита активных сессий: пока VOD-сессия открыта, cleanup не удаляет чанки в её окне (см. ниже).
Live-edge bridge: если клиент в VOD-сессии запросил сегмент за правой границей VOD-окна — например, при достижении конца архива пошёл вперёд по таймлайну — сервер автоматически отдаёт сегмент из live-памяти. Никаких переадресаций и повторной авторизации.
Кеш плейлиста: на повторные запросы того же VOD
index.m3u8/index.mpdсервер отдаёт байт в байт идентичный ответ — без повторного построения. Подходит для CDN перед PSS.
Субтитры в архиве¶
Если у стрима в потоке есть субтитры (DVB Subtitling, Teletext или WebVTT) и включена опция OTT WebVTT в настройках стрима, субтитры архивируются параллельно с TS-чанками — в файлы .vtt рядом с .ts.
В live-режиме master playlist содержит EXT-X-MEDIA:TYPE=SUBTITLES; в VOD-режиме сервер отдаёт VOD-плейлист субтитров (с ENDLIST) и .vtt сегменты на тех же URL.
Особенности:
HLS: сохраняется заголовок
X-TIMESTAMP-MAPв начале каждого.vtt(обязательно по спецификации HLS).DASH: заголовок
X-TIMESTAMP-MAPудаляется на лету (он привязан к абсолютному PCR и конфликтует с DASH-якорем; иначе VLC показывает пустые субтитры).В адаптивной группе: если активный sub-stream не пишет субтитры — VTT-сегменты вернут 404. На следующем варианте плеер может снова получить субтитры.
Отключить субтитры можно либо опцией OTT WebVTT в стриме, либо вообще не включая HLS в режиме OTT/HLS.
Очистка и retention¶
PSS использует четыре стратегии очистки, работающие на каждом тике задачи очистки (по умолчанию каждые 10 сек):
Rolling cleanup (per-stream): для каждого стрима удаляются чанки старше Storage Hours. Работает всегда, даже если диск полупустой.
Size-based cleanup (общий по хранилищу): когда Used % на диске непрерывно превышает Max Usage в течение Disk Pressure Grace секунд, начинают срезаться самые старые чанки пропорционально по всем стримам, привязанным к хранилищу. Очистка идёт порциями по Disk Pressure Cut сек видео на стрим за тик. Никогда не удаляет чанки моложе Storage Min Hour.
Emergency disk-full cut: когда свободное место упало ниже Disk Emergency Bytes, очистка работает агрессивно, может удалять даже защищённые сессией чанки. Запись останавливается до тех пор, пока свободное место не восстановится с гистерезисом × 2.
Orphan scan: на диске могут остаться файлы, не учтённые в индексе (после внезапной остановки PSS). Сборщик проходит по подкаталогам стримов и удаляет такие «забытые» файлы — первый прогон вскоре после старта сервиса, далее раз в час и при срабатывании disk pressure. Защита от гонки с записью — пропускаются файлы моложе 60 сек.
Замечание. Задачи очистки запускаются в фоне; пользователю обычно не нужно ничего делать. Если архив растёт быстрее, чем срезается — снижайте Storage Hours на стримах или повышайте Disk Pressure Cut.
Защита активных VOD-сессий¶
Когда клиент открывает VOD-сессию, на каждом хранилище, участвующем в её окне, регистрируется «защитный слот» с моментом начала окна. Rolling и size-based очистка не трогают чанки в окне открытой сессии. Слот снимается автоматически, когда сессия закрывается (FIN, таймаут).
Это значит:
Если клиент держит VOD-сессию долго, он гарантированно может перемотать на любой момент внутри своего окна — чанки не «исчезнут под ним».
Очистка по Max Usage может временно не доводить Used % до желаемого порога, пока сессия активна; как только клиент уйдёт — очистка догонит.
Emergency disk-full cut и Storage Min Hour обходят защиту: если диск близок к нулю свободного места, чанки удаляются, и клиент получит 404 на затронутые сегменты (плеер пропустит).
После перезапуска PSS защитные слоты исчезают — очистка возобновляется сразу.
Несколько хранилищ¶
Можно создать любое количество записей DVR Storage — каждая для своей директории / своего диска. Стримы привязываются к разным хранилищам независимо. Очистка и пороги (Max Usage, Disk Pressure) работают per-storage.
Сценарии применения:
Разделение по уровням ценности: хранилище на быстрой SSD для премиум-каналов с большой глубиной, хранилище на ёмком HDD для остальных.
Отдельный диск под архив: чтобы запись DVR не конкурировала с системным диском или с временными файлами.
Разделение проектов: один диск под комплект каналов №1, другой под №2 — упрощает миграцию и аудит.
Изменение привязки стрима (поле Storage в Stream / OTT) переключает запись на лету. Старые файлы остаются на прежнем диске нетронутыми — их можно либо удалить вручную, либо снова подключить запись, переставив стрим обратно.
Состояние хранилища и мониторинг¶
В разделе Data / DVR Storage List (а также через API GET /data/dvr-storage-list) отображаются по каждому хранилищу:
State — Ready / Error (плюс промежуточное Not Ready у только что добавленного хранилища).
Total / Free / Used Bytes — свободное и занятое место на диске.
Used % — текущий процент заполнения.
Archived Bytes — суммарный размер чанков, учтённых в индексе всех привязанных стримов (без orphan-файлов).
Pressure Since Sec — момент (epoch), когда Used % впервые превысил Max Usage в текущем эпизоде давления; 0 означает «давления нет сейчас».
Active Task — фоновая операция обслуживания, идущая прямо сейчас: gc-orphans (удаление осиротевших файлов), disk-pressure-trim (срезание под давлением диска) или none, и сколько секунд она уже выполняется. Кратковременные (< 2 сек) операции в UI не мерцают.
Last cleanup — сводка по последним прогонам очисток: сколько времени назад был предыдущий сбор осиротевших файлов (и сколько их удалено) и последнее срезание под давлением диска (сколько места освобождено).
Attached streams — список привязанных стримов; по каждому показаны имя, признак идущей записи (active), заданная глубина архива (retention-hours) и фактическое наполнение (archived-sec и archived-bytes). Сумма archived-bytes по стримам равна Archived Bytes всего хранилища.
Состояния:
Ready — каталог доступен, запись и очистка идут штатным образом.
Error — каталог хранилища недоступен (размонтирован, нет прав, ошибка файловой системы) либо на диске критически мало места; запись остановлена. Восстановление автоматическое — как только каталог снова доступен и появляется достаточно свободного места.
Если хранилище ушло в Error, проверьте, смонтирован ли каталог архива и есть ли на диске свободное место — PSS сам не выходит из этого состояния, пока проблема не устранена физически.
Заполненность архива во времени:
На уровне стрима (Data / Stream) доступна метрика storage-gap-percent — доля пропусков по времени в накопленном архиве: 0 % — запись сплошная, выше — в архиве есть разрывы (перезапуски источника, срезанные очисткой участки).
Endpoint
GET /data/dvrstatотдаёт гистограмму заполнения архива по интервалам времени с разметкой событий записи (старт/останов источника, смена PMT, переключения скремблирования, перестройка индекса, прогон очистки) и активности субтитров — для отрисовки шкалы DVR-архива в админ-интерфейсе.
Защита от случайных потерь данных¶
Несколько операций админ-интерфейса приводят к потере записанного архива или к прекращению выдачи VOD. Перед их выполнением админский UI показывает модальное подтверждение:
Удаление DVR Storage — все привязанные стримы теряют доступ к VOD; файлы на диске остаются, но без записи о хранилище они недостижимы через PSS.
Переключение стрима на другое хранилище — VOD по старому архиву перестаёт работать.
Отвязка стрима от хранилища (Storage = 0) — то же самое.
Уменьшение Max Usage — может спровоцировать size-based очистку и удалить старые чанки.
Уменьшение Storage Hours / Storage Min Hour — может вывести часть архива за rolling-окно.
Это сознательное решение продукта: операция выполнима, но требует подтверждения, и удалённые файлы остаются на диске (их можно вернуть из бэкапа). Размещение архива на отдельном файловом сервере / RAID существенно снижает риск необратимой потери.
Ограничения текущей версии¶
VOD-сессия, открытая клиентом, не следит за live edge — если за время сессии в архив добавились новые чанки, клиент должен перезапросить плейлист (стандартное поведение всех HLS / DASH плееров).
На один диск имеет смысл назначать одно хранилище — несколько записей с разными подкаталогами на одном диске будут конкурировать за свободное место.
Сегменты адресуются хешем (HLS на MPEG-TS) или шаблоном
$Number$.m4sс общимinit.mp4(live DASH на CMAF) / явными<SegmentURL>на.m4s(VOD DASH). Изменение размеров чанка между live и VOD не требует переоткрытия URL.Orphan-scanner запускается раз в час; чтобы ускорить — достаточно перезапустить PSS.