RTSP DVR¶
media.play.rtsp_dvr
Sapsan выдаёт записанный архив по RTSP. Клиент получает список доступных периодов записи, выбирает время по UTC и управляет воспроизведением в одной сессии. Чтение существующего архива не требует работающего входного источника.
Транспорт¶
RTSP 1.0 и RTP/RTCP interleaved в одном TCP-соединении. UDP не поддерживается: SETUP с UDP возвращает 461.
Поддерживаемые кодеки¶
- H.264
- HEVC / H.265
- AV1
- AAC
- Opus
- PCMA
- PCMU
Список относится к пакетизации RTSP; клиент должен поддерживать выбранные кодеки.
AAC передаётся как MPEG4-GENERIC с AU-заголовками; AV1 — с RTP-фрагментацией и sequence header. Для MP4A-LATM и MPEG Audio (MPA, MP2/MP3) есть объявления в SDP, но полноценная соответствующая RTP-упаковка текущим выходным трактом не обеспечивается; они не включены в список выше. При необходимости преобразуйте звук в AAC или Opus. Наличие имени кодека в SDP само по себе не гарантирует совместимость.
Протокол и адрес¶
Управление использует RTSP 1.0: RFC 2326. Описание дорожек передаётся в SDP: RFC 4566. Медиа передаётся по RTP/RTCP: RFC 3550. Для H.264 применяется формат RTP из RFC 6184.
Список архивных периодов в одном атрибуте SDP и параметр position — расширения архивного интерфейса Sapsan. Их формат описан ниже. Поддерживаемый набор возможностей и известные расхождения приведены явно; наличие RTSP 1.0 само по себе не означает поддержки всех режимов этих RFC.
Для доступа нужны записанный архив DVR, настроенный RTSP listener и разрешённая лицензией функция media.play.rtsp_dvr.
rtsp://sapsan.example.com:554/camera?dvr=true
Адрес статичен: время передаётся в заголовке Range, а не в URL. Значение dvr=true обязательно; другие значения параметра отклоняются. Обычная ссылка без этого параметра предназначена для эфира и не принимает архивный Range: clock=.... Если требуется авторизация токеном, добавьте &token=<token>.
Лицензия¶
Функция media.play.rtsp_dvr использует отдельный лицензионный лимит media_play_rtsp_dvr. Обычный эфир по RTSP использует media_play_rtsp; разрешение эфира не даёт доступа к архиву.
Допуск проверяется до чтения архива, в том числе при прямом PLAY без предварительного DESCRIBE. Нулевой лимит запрещает доступ, а исчерпанный числовой лимит запрещает создание новых сессий: сервер отвечает 453 Not Enough Bandwidth.
Архивная сессия сохраняет свой лицензионный допуск после конца выбранного диапазона. Следующий PLAY в том же соединении использует ту же сессию. Освобождайте её через TEARDOWN или закрытие соединения; EOF сам по себе не освобождает занятый слот. Подробнее — лицензирование.
Доступные периоды записи¶
Клиент начинает с DESCRIBE:
DESCRIBE rtsp://sapsan.example.com:554/camera?dvr=true RTSP/1.0
CSeq: 1
Accept: application/sdp
В ответе 200 OK тело имеет тип application/sdp. На уровне сессии, до описаний дорожек m=, передаётся атрибут:
a=range:clock=20261019T080000Z-20261019T093000Z;clock=20261019T100000Z-
Это пример двух периодов записи с разрывом между ними. Формат времени — YYYYMMDDThhmmssZ, целые секунды UTC. Отсутствие времени после дефиса у последнего периода означает продолжающуюся запись.
- Порядок. Периоды перечисляются по возрастанию времени.
- Объединение. Соседние периоды объединяются; при построении списка также объединяются разрывы длительностью до 10 секунд включительно. Такой список не гарантирует наличие кадров в каждой секунде объединённого периода.
- Количество. Передаётся не более 100 последних периодов. Более старую сохранившуюся запись можно запросить явным
PLAY, даже если её нет в этом списке. - Пустой архив. Атрибут
a=rangeотсутствует. Для описания дорожек сервер может использовать доступный эфир.
При наличии записи описание дорожек берётся из архива. Поэтому DESCRIBE и воспроизведение возможны после отключения входного источника.
Подготовка транспорта¶
Для каждой нужной дорожки выполните SETUP, используя её идентификатор из SDP. Поддерживается RTP/RTCP внутри того же TCP-соединения, что и RTSP — interleaved TCP. В примере <track-url> обозначает URL выбранной дорожки:
SETUP <track-url> RTSP/1.0
CSeq: 2
Transport: RTP/AVP/TCP;unicast;interleaved=0-1
Существенные заголовки ответа:
RTSP/1.0 200 OK
CSeq: 2
Session: example-session;timeout=60
Transport: RTP/AVP/TCP;unicast;interleaved=0-1
В дальнейших запросах используйте полученный Session. Для следующей дорожки выбирайте другую пару interleaved-каналов. Транспорт UDP отклоняется кодом 461.
Примеры показывают существенные поля обмена. В сети строки заканчиваются CRLF, заголовки отделяются от тела пустой строкой, а Content-Length содержит длину тела в байтах.
Выбор времени и перемотка¶
Для воспроизведения интервала отправьте PLAY на адрес всей сессии:
PLAY rtsp://sapsan.example.com:554/camera?dvr=true RTSP/1.0
CSeq: 3
Session: example-session
Range: clock=20261019T081000Z-20261019T081500Z
Scale: 1
Существенные поля ответа:
RTSP/1.0 200 OK
CSeq: 3
Session: example-session;timeout=60
Range: clock=20261019T081000Z-20261019T081500Z
Scale: 1
В ответе RTP-Info содержит seq и rtptime для выдаваемых подготовленных дорожек, включая первый архивный запуск и перемотку. При продолжении после паузы rtptime соответствует фактическому следующему кадру, в том числе после разрыва записи.
Запрос PLAY |
Поведение Sapsan |
|---|---|
Range: clock=<from>-<to> |
Начать с независимого фрагмента и выдавать кадры с DTS меньше <to> |
Range: clock=<from>- |
Выбрать существующие фрагменты начиная с указанного времени без верхней границы |
Новый Range: clock=... в той же сессии |
Сразу перемотать; повторный SETUP не нужен |
Range: npt=now- |
Переключиться на эфир |
Без Range, источник уже выбран |
Продолжить выдачу, в том числе после PAUSE |
Без Range, первый запуск |
Выбрать эфир |
Открытый числовой NPT, например npt=10- |
451 Parameter Not Understood; текущая выдача продолжается |
Ответный Range сообщает выбранные границы. Если <from> находится внутри независимого фрагмента, воспроизведение начинается с его начала, которое может быть раньше запроса. Поиск назад ограничен 60 секундами; если подходящего начала нет, выбирается следующий независимый фрагмент. Конец ограничивается запрошенным <to> и доступной записью. Кадры с DTS, равным <to> или больше него, не выдаются.
Дефис сохраняется и при открытом конце. Запрос принимает UTC с целыми секундами, но фактическая граница в ответе может содержать миллисекунды, например clock=20261019T081000.250Z-20261019T081500Z.
Скорость — обычная вперёд. Scale можно не передавать или указать 1; на Scale: 1 сервер возвращает Scale: 1. Другие скорости и обратная форма clock=-<to> возвращают 451 Parameter Not Understood, сохраняя текущую выдачу.
Если между выбранными фрагментами есть разрыв записи, сервер переходит к следующему доступному фрагменту без ожидания всей длительности разрыва. Медиавременные метки перескакивают через пропуск.
Открытый диапазон читает выборку фрагментов на момент PLAY и завершается на её конце. Новые фрагменты не подхватываются, автоматического перехода к эфиру нет. Для эфира нужен явный PLAY с npt=now-.
Текущая позиция¶
Чтобы получить позицию выдачи, отправьте GET_PARAMETER с телом position:
GET_PARAMETER rtsp://sapsan.example.com:554/camera?dvr=true RTSP/1.0
CSeq: 4
Session: example-session
Content-Type: text/parameters
Content-Length: 10
position
Здесь тело — position с завершающим CRLF, всего 10 байт. Ответ:
RTSP/1.0 200 OK
CSeq: 4
Session: example-session;timeout=60
Range: clock=20261019T081012Z
Supported: position
Время находится в заголовке, а не в теле ответа. Это одна метка без дефиса, в отличие от диапазона в ответе PLAY. Значение соответствует DTS последнего выданного кадра с точностью до секунды, а не моменту его показа на экране клиента.
До первого выданного кадра выбранного источника, в том числе после перемотки, position возвращает 503 Service Unavailable без Range, с Supported: position. Во время паузы и после конца архива возвращаются 200 OK и последняя подтверждённая позиция. По одному коду 200 нельзя определить, продолжается ли передача кадров. Неизвестный параметр в непустом теле даёт 200 OK и Supported: position, без Range.
Пауза и завершение сессии¶
PAUSE на адрес сессии приостанавливает выдачу с сохранением позиции внутри фрагмента. Следующий PLAY без Range продолжает с оставшихся кадров. Новый Range: clock=... задаёт немедленную перемотку, в том числе при конвейерной отправке нескольких PLAY; очередь интервалов не создаётся.
Во время паузы поддерживайте сессию пустым GET_PARAMETER. Сервер объявляет timeout=60; отправляйте keepalive чаще этого интервала. Входящие RTSP-запросы и RTCP-пакеты учитываются как активность.
При нормальном исчерпании диапазона, по которому уже передавалось RTP-медиа, сервер отправляет RTCP BYE по подготовленным дорожкам и завершает текущую выдачу. Соединение и сессия остаются открытыми: можно запросить другой диапазон без повторного SETUP.
Для освобождения сессии отправьте TEARDOWN с её Session. После ответа 200 OK соединение закрывается и лицензионный слот освобождается.
Медиа и границы совместимости¶
Для H.264 параметры декодера передаются в SDP, а недостающие SPS/PPS добавляются перед ключевыми кадрами. При смене конфигурации архивных фрагментов параметры обновляются. RTP timestamp формируется из архивного DTS; RTCP Sender Report связывает его со временем NTP.
RTCP Sender Report содержит накопленные количества RTP-пакетов и октетов полезной нагрузки. Заголовки RTP и обёртка interleaved в октеты не входят. Перемотка с тем же SSRC не сбрасывает счётчики.
Поддерживаемый профиль имеет следующие ограничения:
- Транспорт. Только interleaved TCP; UDP возвращает
461. - Скорость. Только обычное воспроизведение вперёд; другие значения
Scaleвозвращают451. - Шкала времени. Для архивного позиционирования используйте
clockс целыми секундами UTC. Числовой NPT и SMPTE не поддерживаются. Дробные секунды допустимы только в ответе. - Последовательность диапазонов. Каждый новый архивный
PLAYсразу перематывает; очереди интервалов нет. - Продолжающаяся запись. Открытый диапазон не читает фрагменты, появившиеся после его запуска.
Коды ответов¶
| Код | Причина |
|---|---|
400 Bad Request |
Некорректный dvr или URL; отсутствует Transport в SETUP |
403 Forbidden |
Отказ авторизации либо зашифрованный поток, недоступный для RTSP-выдачи |
404 Not Found |
Не найден стрим, архив или дорожка |
451 Parameter Not Understood |
Неподдержанный Range или Scale; запрос архива через обычную live-ссылку |
453 Not Enough Bandwidth |
Функция запрещена лицензией или исчерпан лимит сессий |
454 Session Not Found |
Нет контекста сессии, необходимого для запроса |
457 Invalid Range |
Пустое или обратное окно; нет подходящих архивных фрагментов |
461 Unsupported Transport |
Запрошен транспорт, отличный от interleaved TCP |
503 Service Unavailable |
Источник недоступен; position запрошен до первого кадра выбранного источника. EOF архива сам по себе не даёт 503 для position |
Проверка клиента¶
Проверяйте интеграцию на записи с известными временными границами и разрывом:
- Получите SDP и сопоставьте
a=rangeс периодами записи с учётом объединения коротких разрывов. - Выполните
SETUPдля нужных дорожек. Проверьте пары interleaved-каналов и идентификатор сессии. - Запросите
positionдо первого кадра: ожидается503безRange. - Запустите
PLAYс началом внутри фрагмента иScale: 1. Проверьте выбранныйRange, ответныйScaleи соответствиеrtptime/seqпервому RTP-пакету. Кадров с DTS >=<to>быть не должно. - Сделайте паузу посреди фрагмента и продолжите через
PLAYбезRange. Проверьте сохранение оставшихся кадров и позиции. - Проверьте
451для неподдержанной скорости и числового NPT: текущая выдача должна продолжаться. - Дождитесь EOF и RTCP BYE, затем запросите другой диапазон в том же соединении. Проверьте позицию после EOF и накопленные счётчики Sender Report.
- Проверьте лицензионный отказ
453при нулевом или исчерпанном лимите и завершите сессию черезTEARDOWN.