mirror of
https://github.com/bluenviron/mediamtx.git
synced 2025-12-20 02:00:05 -08:00
replace incoming absolute timestamps of any source (#5081)
Absolute timestamps are used to generate recording segments, so users should not be able to change them, unless explicitly allowed. Parameter useAbsoluteTimestamp allowed to re-enable absolute timestamps with RTSP and WebRTC, now it is extended to all protocols.
This commit is contained in:
parent
75420552b9
commit
ccaccc51b4
5 changed files with 27 additions and 9 deletions
|
|
@ -3,8 +3,8 @@
|
||||||
Some streaming protocols allow to route absolute timestamps, associated with each frame, that are useful for synchronizing several video or data streams together. In particular, _MediaMTX_ supports receiving absolute timestamps with the following protocols and devices:
|
Some streaming protocols allow to route absolute timestamps, associated with each frame, that are useful for synchronizing several video or data streams together. In particular, _MediaMTX_ supports receiving absolute timestamps with the following protocols and devices:
|
||||||
|
|
||||||
- HLS
|
- HLS
|
||||||
- RTSP (when the `useAbsoluteTimestamp` parameter is `true`)
|
- RTSP
|
||||||
- WebRTC (when the `useAbsoluteTimestamp` parameter is `true`)
|
- WebRTC
|
||||||
- Raspberry Pi Camera
|
- Raspberry Pi Camera
|
||||||
|
|
||||||
and supports sending absolute timestamps with the following protocols:
|
and supports sending absolute timestamps with the following protocols:
|
||||||
|
|
@ -13,6 +13,14 @@ and supports sending absolute timestamps with the following protocols:
|
||||||
- RTSP
|
- RTSP
|
||||||
- WebRTC
|
- WebRTC
|
||||||
|
|
||||||
|
By default, absolute timestamps of incoming frames are not used, instead they are replaced with the current timestamp. This prevents users from arbitrarily changing recording dates, and also allows to support sources that do not send absolute timestamps. It is possible to preserve original absolute timestamps by toggling the `useAbsoluteTimestamp` parameter:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
pathDefaults:
|
||||||
|
# Use absolute timestamp of frames, instead of replacing them with the current time.
|
||||||
|
useAbsoluteTimestamp: false
|
||||||
|
```
|
||||||
|
|
||||||
## Absolute timestamp in HLS
|
## Absolute timestamp in HLS
|
||||||
|
|
||||||
In the HLS protocol, absolute timestamps are routed by adding a `EXT-X-PROGRAM-DATE-TIME` tag before each segment:
|
In the HLS protocol, absolute timestamps are routed by adding a `EXT-X-PROGRAM-DATE-TIME` tag before each segment:
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/bluenviron/gohlslib/v2/pkg/codecs"
|
"github.com/bluenviron/gohlslib/v2/pkg/codecs"
|
||||||
"github.com/bluenviron/gortsplib/v5/pkg/description"
|
"github.com/bluenviron/gortsplib/v5/pkg/description"
|
||||||
"github.com/bluenviron/gortsplib/v5/pkg/format"
|
"github.com/bluenviron/gortsplib/v5/pkg/format"
|
||||||
|
"github.com/bluenviron/mediamtx/internal/conf"
|
||||||
"github.com/bluenviron/mediamtx/internal/logger"
|
"github.com/bluenviron/mediamtx/internal/logger"
|
||||||
"github.com/bluenviron/mediamtx/internal/ntpestimator"
|
"github.com/bluenviron/mediamtx/internal/ntpestimator"
|
||||||
"github.com/bluenviron/mediamtx/internal/stream"
|
"github.com/bluenviron/mediamtx/internal/stream"
|
||||||
|
|
@ -20,7 +21,7 @@ const (
|
||||||
ntpStateInitial ntpState = iota
|
ntpStateInitial ntpState = iota
|
||||||
ntpStateUnavailable
|
ntpStateUnavailable
|
||||||
ntpStateAvailable
|
ntpStateAvailable
|
||||||
ntpStateDegraded
|
ntpStateReplace
|
||||||
)
|
)
|
||||||
|
|
||||||
func multiplyAndDivide(v, m, d int64) int64 {
|
func multiplyAndDivide(v, m, d int64) int64 {
|
||||||
|
|
@ -33,11 +34,16 @@ func multiplyAndDivide(v, m, d int64) int64 {
|
||||||
func ToStream(
|
func ToStream(
|
||||||
c *gohlslib.Client,
|
c *gohlslib.Client,
|
||||||
tracks []*gohlslib.Track,
|
tracks []*gohlslib.Track,
|
||||||
|
pathConf *conf.Path,
|
||||||
strm **stream.Stream,
|
strm **stream.Stream,
|
||||||
) ([]*description.Media, error) {
|
) ([]*description.Media, error) {
|
||||||
var ntpStat ntpState
|
var ntpStat ntpState
|
||||||
var ntpStatMutex sync.Mutex
|
var ntpStatMutex sync.Mutex
|
||||||
|
|
||||||
|
if !pathConf.UseAbsoluteTimestamp {
|
||||||
|
ntpStat = ntpStateReplace
|
||||||
|
}
|
||||||
|
|
||||||
var medias []*description.Media //nolint:prealloc
|
var medias []*description.Media //nolint:prealloc
|
||||||
|
|
||||||
for _, track := range tracks {
|
for _, track := range tracks {
|
||||||
|
|
@ -69,11 +75,11 @@ func ToStream(
|
||||||
_, avail := c.AbsoluteTime(ctrack)
|
_, avail := c.AbsoluteTime(ctrack)
|
||||||
if avail {
|
if avail {
|
||||||
(*strm).Parent.Log(logger.Warn, "absolute timestamp appeared after stream started, we are not using it")
|
(*strm).Parent.Log(logger.Warn, "absolute timestamp appeared after stream started, we are not using it")
|
||||||
ntpStat = ntpStateDegraded
|
ntpStat = ntpStateReplace
|
||||||
}
|
}
|
||||||
return ntpEstimator.Estimate(pts)
|
return ntpEstimator.Estimate(pts)
|
||||||
|
|
||||||
default: // ntpStateDegraded
|
default: // ntpStateReplace
|
||||||
return ntpEstimator.Estimate(pts)
|
return ntpEstimator.Estimate(pts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/bluenviron/gortsplib/v5/pkg/description"
|
"github.com/bluenviron/gortsplib/v5/pkg/description"
|
||||||
"github.com/bluenviron/gortsplib/v5/pkg/format"
|
"github.com/bluenviron/gortsplib/v5/pkg/format"
|
||||||
"github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts"
|
"github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts"
|
||||||
|
"github.com/bluenviron/mediamtx/internal/conf"
|
||||||
"github.com/bluenviron/mediamtx/internal/stream"
|
"github.com/bluenviron/mediamtx/internal/stream"
|
||||||
"github.com/bluenviron/mediamtx/internal/test"
|
"github.com/bluenviron/mediamtx/internal/test"
|
||||||
"github.com/bluenviron/mediamtx/internal/unit"
|
"github.com/bluenviron/mediamtx/internal/unit"
|
||||||
|
|
@ -18,7 +19,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestToStreamNoSupportedCodecs(t *testing.T) {
|
func TestToStreamNoSupportedCodecs(t *testing.T) {
|
||||||
_, err := ToStream(nil, []*gohlslib.Track{}, nil)
|
_, err := ToStream(nil, []*gohlslib.Track{}, &conf.Path{}, nil)
|
||||||
require.Equal(t, ErrNoSupportedCodecs, err)
|
require.Equal(t, ErrNoSupportedCodecs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,8 +93,11 @@ func TestToStream(t *testing.T) {
|
||||||
c = &gohlslib.Client{
|
c = &gohlslib.Client{
|
||||||
URI: "http://localhost:5781/stream.m3u8",
|
URI: "http://localhost:5781/stream.m3u8",
|
||||||
OnTracks: func(tracks []*gohlslib.Track) error {
|
OnTracks: func(tracks []*gohlslib.Track) error {
|
||||||
medias, err2 := ToStream(c, tracks, &strm)
|
medias, err2 := ToStream(c, tracks, &conf.Path{
|
||||||
|
UseAbsoluteTimestamp: true,
|
||||||
|
}, &strm)
|
||||||
require.NoError(t, err2)
|
require.NoError(t, err2)
|
||||||
|
|
||||||
require.Equal(t, []*description.Media{{
|
require.Equal(t, []*description.Media{{
|
||||||
Type: description.MediaTypeVideo,
|
Type: description.MediaTypeVideo,
|
||||||
Formats: []format.Format{&format.H264{
|
Formats: []format.Format{&format.H264{
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ func (s *Source) Run(params defs.StaticSourceRunParams) error {
|
||||||
decodeErrors.Increase()
|
decodeErrors.Increase()
|
||||||
},
|
},
|
||||||
OnTracks: func(tracks []*gohlslib.Track) error {
|
OnTracks: func(tracks []*gohlslib.Track) error {
|
||||||
medias, err2 := hls.ToStream(c, tracks, &stream)
|
medias, err2 := hls.ToStream(c, tracks, params.Conf, &stream)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
return err2
|
return err2
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -482,7 +482,7 @@ pathDefaults:
|
||||||
# If the stream is not available, redirect readers to this path.
|
# If the stream is not available, redirect readers to this path.
|
||||||
# It can be can be a relative path (i.e. /otherstream) or an absolute RTSP URL.
|
# It can be can be a relative path (i.e. /otherstream) or an absolute RTSP URL.
|
||||||
fallback:
|
fallback:
|
||||||
# Route original absolute timestamps of RTSP and WebRTC frames, instead of replacing them.
|
# Use absolute timestamp of frames, instead of replacing them with the current time.
|
||||||
useAbsoluteTimestamp: false
|
useAbsoluteTimestamp: false
|
||||||
|
|
||||||
###############################################
|
###############################################
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue