Запись архива (DVR)
Как включить непрерывную запись потока на диск, задать глубину архива и убедиться, что запись действительно идёт.
Архив (DVR) — непрерывная запись живого потока на диск с возможностью потом отмотать назад, посмотреть любой момент и выгрузить фрагмент файлом. Запись ведётся из того же кольцевого буфера, из которого идёт раздача: поток разбирается один раз, отдельного разбора «для архива» нет.
Запись — это факт конфигурации, а не команда#
Начать и остановить запись через API нельзя, и такого эндпоинта нет. Поток пишется, потому что в
его блоке есть строка dvr, и перестаёт писаться, когда эту строку убирают, когда поток помечен
disabled;, либо когда служба останавливается.
Следствия, которые стоит принять сразу:
- Чтобы включить или выключить запись — правьте конфигурацию (файл, панель управления или
PATCH /api/v1/streams/{id}) и применяйте изменения. - Изменение строки
dvrперезапускает только этот поток; остальные потоки продолжают работать и не теряют зрителей. Подробнее — Применение изменений. - Директива
on_demandна пишущем потоке игнорируется. Запись означает «тянуть источник всегда»: «писать только когда смотрят» дало бы архив с дырами.
Как включить запись одному потоку#
Шаг 1. Объявите хранилище#
Хранилище — это именованный каталог на диске, куда складываются записи. Один раз на весь сервер:
storage archive /var/lib/hastreamer/dvr;
Каталог должен существовать и быть доступен на запись пользователю, от имени которого запущена
служба hastreamer.service. Полный набор параметров хранилища, вытеснение по заполнению диска и
холодный ярус S3 — на странице Хранилища и S3.
Шаг 2. Добавьте строку dvr в поток#
stream cam1 { input rtsp://admin:пароль@10.0.0.10:554/Streaming/Channels/101; dvr archive 14d 500G; }
Читается так: «писать в хранилище archive, хранить 14 дней или 500 ГиБ — что наступит раньше».
Шаг 3. Примените изменения#
# разобрать файл, ничего не запуская: при ошибке печатается строка с её номером hastreamer --validate /etc/hastreamer/hastreamer.conf # применить: перезапустится только изменённый поток systemctl reload hastreamer
Запись начинается сразу после перезапуска потока — ждать чего-либо не нужно.
Синтаксис директивы dvr#
dvr <хранилище> [<глубина>] [<объём>] [copy=<ссылка-s3> [<глубина-s3>] [<объём-s3>]];
Аргументы позиционные, но распознаются по форме, а не по месту: сервер смотрит на вид слова и
понимает, что это. Поэтому dvr archive 500G 14d; и dvr archive 14d 500G; — одно и то же.
| Параметр | Тип и допустимые значения | По умолчанию | Применение |
|---|---|---|---|
<хранилище> |
имя объявленного локального дискового хранилища | — (обязателен) | горячее |
<глубина> |
число + s · m · h · d · w · mo · y |
без ограничения | горячее |
<объём> |
число + K · M · G · T (двоичные, только заглавные) |
без ограничения | горячее |
copy= |
s3://<бакет>@<аккаунт> либо s3s://<бакет>@<аккаунт> (TLS) |
нет копии | горячее |
mode= |
async · cross — режим репликации кластера |
— | горячее |
<узел>/<том> |
цель репликации в кластере | — | горячее |
Хранилище обязательно всегда, когда запись включена. Без него конфигурация не примется:
stream "cam1": record needs a known local DISK storage (got "archiv"); use copy= for an s3 cold tier
Аргументы mode= и <узел>/<том> относятся к работе нескольких серверов; на одиночном сервере они
не действуют.
dvr archive fast 14d; — это не «пиши в оба хранилища». Второе имя просто перетирает первое, и
запись пойдёт в fast без единого предупреждения. Один поток пишется ровно в одно локальное
хранилище (плюс, при желании, одна копия в S3 через copy=).
Единственное место, где порядок значим, — copy=: глубина и объём до него относятся к диску,
после — к архиву в S3.
dvr fast 2h 3G copy=s3s://cam-archive@coldtier 30d 100G;
Здесь на диске держатся последние 2 часа (не более 3 ГиБ), а в S3 — 30 дней (не более 100 ГиБ). Настройка холодного яруса разобрана на странице Хранилища и S3.
Единицы глубины#
| Суффикс | Значение |
|---|---|
s |
секунды |
m |
минуты |
h |
часы |
d |
сутки |
w |
недели |
mo |
месяцы — фиксированные 30 суток, не календарный месяц |
y |
годы — фиксированные 365 суток |
m — это минуты, а не месяцыdvr archive 30m; хранит тридцать минут видео, а не тридцать месяцев. Ошибка не даёт ни
предупреждения при разборе, ни сообщения в журнале: конфигурация полностью корректна, просто архив
оказывается короче ожидаемого в десятки тысяч раз — и это выясняется в тот день, когда запись
понадобилась.
Месяцы пишутся mo: dvr archive 30mo;.
Объём задаётся суффиксами K, M, G, T — двоичные (×1024) и только заглавные.
500g, 500GB и 500Gi — ошибки разбора:
stream "cam1": bad retention_size "500GB" (K/M/G/T) stream "cam1": bad retention_time "14days" (s/m/h/d/w/mo/y)
Пропущенное значение (или 0) означает «без ограничения по этому измерению». Оставлять без
ограничений оба измерения можно, но тогда за место на диске отвечает только вытеснение по
заполнению — см. ниже.
Как глубина и объём работают вместе#
Ограничения не выбирают между собой — они применяются подряд, в фиксированном порядке:
- Удаляются все записи, чей конец старше
<глубина>. - Из того, что осталось, удаляются самые старые, пока суммарный размер превышает
<объём>.
На практике это значит «сработает то ограничение, которое наступит раньше». Полезный приём: задайте глубину по требованиям регламента, а объём — как страховку от неожиданно выросшего битрейта.
Самая свежая завершённая запись потока не удаляется ни по возрасту, ни по размеру. Поток нельзя
вычистить до полной пустоты — даже если глубина 1s, а объём 1K.
Длительность записи и что лежит на диске#
Записи режутся на файлы фиксированной целевой длительности, которая задаётся на хранилище, а не
на потоке, — параметром segment_secs. Допустимы только три значения: 900 (по умолчанию), 1800
и 3600 секунд.
Рез всегда происходит по ключевому кадру, поэтому реальный файл получается чуть длиннее целевой
величины: при segment_secs 900; фактическая длина обычно около 900–905 с. Досрочный рез
происходит при смене параметров кодирования и при разрыве непрерывности потока.
Раскладка на диске:
<путь-хранилища>/<поток>/ГГГГ/ММ/ДД/ЧЧ-ММ-СС-мкс_d<мс>.mp4 <путь-хранилища>/<поток>/ГГГГ/ММ/ДД/ЧЧ-ММ-СС-мкс_d<мс>.mp4.idx
Время в имени — UTC, с точностью до микросекунды. Рядом с каждым файлом лежит .idx — индекс,
благодаря которому перемотка по архиву мгновенна. Файл, в который прямо сейчас идёт запись, не
имеет суффикса _d: суффикс появляется в момент, когда запись закрыта, проверена и внесена в
каталог. Поэтому незавершённая запись физически не может попасть ни в выдачу, ни под удаление.
Каталог архива — не просто набор .mp4. Удаление файла без его .idx (или наоборот) оставляет
запись, которую сервер не сможет ни отдать, ни корректно вычистить. Для очистки архива потока
используйте DELETE /api/v1/dvr-archive/{поток} или уменьшите глубину и дождитесь прохода
обслуживания.
Что происходит при исчерпании места#
Защита эшелонирована — на потоке и на хранилище:
- Ретенция потока. Записи
cam1вытесняются по его собственным<глубина>/<объём>. Один разросшийся поток не трогает соседей. - Вытеснение по заполнению хранилища. Если файловая система пересекла порог
evict_at_percent(по умолчанию 90 %), проход обслуживания удаляет самые старые записи по всем потокам этого хранилища, пока заполнение не опустится на 2 процентных пункта ниже порога. Подробнее — Хранилища и S3. - Реакция на «диск полон». Если запись упёрлась в
ENOSPC, проход обслуживания просыпается досрочно (в пределах ~2 с) и первым делом освобождает место.
Запись никогда не тормозит приём потока: медленный или полный диск не создаёт обратного давления на источник. Если запись не поспевает, в архиве возникает видимый разрыв непрерывности — при просмотре он выглядит как стык между записями, а не как порча файла.
Задержка очистки#
Удаление устаревших записей выполняет фоновый проход обслуживания. Его период задаётся глобально:
| Параметр | Тип и допустимые значения | По умолчанию | Применение |
|---|---|---|---|
dvr_cleanup_secs |
целое, секунды | 600 |
рестарт |
dvr_cleanup_secs 600;
Отсюда практическое следствие: архив может отставать от заданной глубины на один такт. При
значениях по умолчанию поток с dvr archive 6h; какое-то время держит 6 часов и ещё до 10 минут
сверху. Это нормально и не считается ошибкой. Уменьшать период ради «точности» не нужно — проход
сканирует каталоги всех хранилищ, и частые проходы стоят дороже, чем несколько лишних минут видео.
Проход выполняется на отдельном системном потоке, вне ядер, обслуживающих зрителей, поэтому на раздачу он не влияет.
Проверка: запись действительно идёт#
Сводка по хранилищу — в поле streams тройки [поток, число записей, байт]:
curl -sS "http://media.example.com:8080/api/v1/storages" \ -H "Authorization: Bearer $TOKEN"
[{"name":"archive","path":"/var/lib/hastreamer/dvr","identity":"","identity_healthy":true, "maintenance_healthy":true,"total_bytes":84444717056,"used_bytes":31178297344, "avail_bytes":53266419712,"evict_at_percent":90, "streams":[["cam1",21,21012998324]], "write_bps":1441369,"tier_backlog_bytes":0,"s3_healthy":true}]
Календарь записанных суток (UTC):
curl -sS "http://media.example.com:8080/cam1/dvr/api/days"
{"days":["2026-08-19"]}
Покрытие за последний час — если запись идёт, end_ms растёт от вызова к вызову:
curl -sS "http://media.example.com:8080/cam1/dvr/api/timeline"
{"from":1787139386390,"to":1787142986390, "ranges":[{"start_ms":1787139151495,"end_ms":1787142986427, "segment_count":5,"bytes":4348353497,"tier":"local"}]}
Если запись не включена, тот же запрос отвечает 404 с телом stream is not recorded — это
однозначный ответ «в конфигурации потока нет строки dvr», а не «архив пуст».
Примеры выше показаны без токена — так они работают на сервере без auth_backend { }. Когда
авторизация просмотра настроена, запросам к /<поток>/dvr/… нужен токен с правом dvr; API
/api/v1/… всегда требует Authorization: Bearer $TOKEN. См.
Авторизация просмотра.
В панели управления те же факты видны без командной строки: страница Storage показывает заполнение и крупнейшие записи, а на карточке потока вкладка DVR — покрытие, число записей и календарь. Вкладка появляется только у пишущих потоков.
Куда двигаться дальше#
- Хранилища и S3 — параметры хранилища, вытеснение, холодный ярус.
- Просмотр и экспорт — как отмотать архив и выгрузить фрагмент файлом.
- VoD — видео по запросу — раздача готовых файлов, если запись вам не нужна.