Skip to content

Add rtspRequire and rtspRateControl to RTSP sources - #6047

Open
nlsrchtr wants to merge 1 commit into
bluenviron:mainfrom
nlsrchtr:feat/onvif-replay-headers
Open

Add rtspRequire and rtspRateControl to RTSP sources#6047
nlsrchtr wants to merge 1 commit into
bluenviron:mainfrom
nlsrchtr:feat/onvif-replay-headers

Conversation

@nlsrchtr

@nlsrchtr nlsrchtr commented Aug 6, 2026

Copy link
Copy Markdown

mediamtx can already pull ONVIF Profile G recordings: rtspRangeType/rtspRangeStart produce the "Range: clock=" header on PLAY, and rtspScale accelerates delivery beyond real time. Two headers from the ONVIF Streaming Specification are still unreachable, and both matter for replay.

"Rate-Control: no" (section 6.5.2) asks for a recording as fast as the transport allows rather than in real time. It matters because rtspScale is not an equivalent: section 6.5 says a device MAY accept Scale values other than 1.0/-1.0, while section 6.5.2 says an ONVIF compliant server SHALL support Rate-Control=no for playback. So today's only fast-replay option rests on an optional feature while the mandatory one cannot be sent. The two are also mutually exclusive: with Rate-Control=no, section 6.5 requires Scale to be 1.0 or -1.0, since the client rather than the server then paces the stream.

"Require: onvif-replay" (section 6.4) declares that the client understands the replay extensions. Without it a device that does not implement them does not fail, it streams something else -- live, or the recording from its start -- so a request for a specific past window can silently return different footage. With the tag the same device answers 551 (Option not supported), which is a much better outcome than plausible-looking wrong data.

Both follow the rtspScale pattern exactly: a per-path string, applied to PLAY through OnRequest. Require is APPENDED rather than assigned, because gortsplib already sets that header when the client is reading a back channel and both feature tags have to survive.

Tested with TestRequireAndRateControl, alongside the existing TestScale.

mediamtx can already pull ONVIF Profile G recordings: rtspRangeType/rtspRangeStart produce the
"Range: clock=" header on PLAY, and rtspScale accelerates delivery beyond real time. Two headers
from the ONVIF Streaming Specification are still unreachable, and both matter for replay.

"Rate-Control: no" (section 6.5.2) asks for a recording as fast as the transport allows rather
than in real time. It matters because rtspScale is not an equivalent: section 6.5 says a device
MAY accept Scale values other than 1.0/-1.0, while section 6.5.2 says an ONVIF compliant server
SHALL support Rate-Control=no for playback. So today's only fast-replay option rests on an
optional feature while the mandatory one cannot be sent. The two are also mutually exclusive:
with Rate-Control=no, section 6.5 requires Scale to be 1.0 or -1.0, since the client rather than
the server then paces the stream.

"Require: onvif-replay" (section 6.4) declares that the client understands the replay
extensions. Without it a device that does not implement them does not fail, it streams something
else -- live, or the recording from its start -- so a request for a specific past window can
silently return different footage. With the tag the same device answers 551 (Option not
supported), which is a much better outcome than plausible-looking wrong data.

Both follow the rtspScale pattern exactly: a per-path string, applied to PLAY through OnRequest.
Require is APPENDED rather than assigned, because gortsplib already sets that header when the
client is reading a back channel and both feature tags have to survive.

Tested with TestRequireAndRateControl, alongside the existing TestScale.
Copilot AI lite review requested due to automatic review settings August 6, 2026 10:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends RTSP static sources configuration to support ONVIF Profile G replay by allowing additional RTSP headers to be sent on PLAY, improving correctness for replay requests and enabling transport-paced playback.

Changes:

  • Add new per-path config options rtspRequire and rtspRateControl (docs + config struct fields).
  • Inject Require (appended) and Rate-Control headers into RTSP PLAY requests.
  • Add a unit test verifying the new headers are sent on PLAY, and expose the options in the OpenAPI schema.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
mediamtx.yml Documents new rtspRequire / rtspRateControl path defaults.
internal/staticsources/rtsp/source.go Adds header injection on RTSP PLAY via client OnRequest.
internal/staticsources/rtsp/source_test.go Adds a test that asserts Require and Rate-Control are present on PLAY.
internal/conf/path.go Adds config fields for the new options to the Path struct.
api/openapi.yaml Exposes the new fields in the API schema.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +142 to +146
if req.Method == base.Play {
if params.Conf.RTSPScale != "" {
if req.Header == nil {
req.Header = base.Header{}
}
Comment thread mediamtx.yml
# Negative values play in reverse, values > 1 fast-forward,
# values 0 < x < 1 play slow motion.
rtspScale:
# Require header value to send to the source, in order to declare support for a RTSP feature.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants