Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: playback can skip gap between segments #3816

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions internal/conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,14 @@ type Conf struct {
PPROFTrustedProxies IPNetworks `json:"pprofTrustedProxies"`

// Playback
Playback bool `json:"playback"`
PlaybackAddress string `json:"playbackAddress"`
PlaybackEncryption bool `json:"playbackEncryption"`
PlaybackServerKey string `json:"playbackServerKey"`
PlaybackServerCert string `json:"playbackServerCert"`
PlaybackAllowOrigin string `json:"playbackAllowOrigin"`
PlaybackTrustedProxies IPNetworks `json:"playbackTrustedProxies"`
Playback bool `json:"playback"`
PlaybackAddress string `json:"playbackAddress"`
PlaybackEncryption bool `json:"playbackEncryption"`
PlaybackServerKey string `json:"playbackServerKey"`
PlaybackServerCert string `json:"playbackServerCert"`
PlaybackAllowOrigin string `json:"playbackAllowOrigin"`
PlaybackTrustedProxies IPNetworks `json:"playbackTrustedProxies"`
PlaybackSegmentAlwaysConcatenation bool `json:"playbackSegmentAlwaysConcatenation"`

// RTSP server
RTSP bool `json:"rtsp"`
Expand Down Expand Up @@ -349,6 +350,7 @@ func (conf *Conf) setDefaults() {
conf.PlaybackServerKey = "server.key"
conf.PlaybackServerCert = "server.crt"
conf.PlaybackAllowOrigin = "*"
conf.PlaybackSegmentAlwaysConcatenation = false

// RTSP server
conf.RTSP = true
Expand Down
22 changes: 12 additions & 10 deletions internal/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,16 +311,17 @@ func (p *Core) createResources(initial bool) error {
if p.conf.Playback &&
p.playbackServer == nil {
i := &playback.Server{
Address: p.conf.PlaybackAddress,
Encryption: p.conf.PlaybackEncryption,
ServerKey: p.conf.PlaybackServerKey,
ServerCert: p.conf.PlaybackServerCert,
AllowOrigin: p.conf.PlaybackAllowOrigin,
TrustedProxies: p.conf.PlaybackTrustedProxies,
ReadTimeout: p.conf.ReadTimeout,
PathConfs: p.conf.Paths,
AuthManager: p.authManager,
Parent: p,
Address: p.conf.PlaybackAddress,
Encryption: p.conf.PlaybackEncryption,
ServerKey: p.conf.PlaybackServerKey,
ServerCert: p.conf.PlaybackServerCert,
AllowOrigin: p.conf.PlaybackAllowOrigin,
TrustedProxies: p.conf.PlaybackTrustedProxies,
SegmentAlwaysConcatenation: p.conf.PlaybackSegmentAlwaysConcatenation,
ReadTimeout: p.conf.ReadTimeout,
PathConfs: p.conf.Paths,
AuthManager: p.authManager,
Parent: p,
}
err = i.Initialize()
if err != nil {
Expand Down Expand Up @@ -685,6 +686,7 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
newConf.PlaybackServerCert != p.conf.PlaybackServerCert ||
newConf.PlaybackAllowOrigin != p.conf.PlaybackAllowOrigin ||
!reflect.DeepEqual(newConf.PlaybackTrustedProxies, p.conf.PlaybackTrustedProxies) ||
newConf.PlaybackSegmentAlwaysConcatenation != p.conf.PlaybackSegmentAlwaysConcatenation ||
newConf.ReadTimeout != p.conf.ReadTimeout ||
closeAuthManager ||
closeLogger
Expand Down
5 changes: 3 additions & 2 deletions internal/playback/on_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func seekAndMux(
start time.Time,
duration time.Duration,
m muxer,
alwaysConcatenation bool,
) error {
if recordFormat == conf.RecordFormatFMP4 {
var firstInit *fmp4.Init
Expand Down Expand Up @@ -86,7 +87,7 @@ func seekAndMux(
return err
}

if !segmentFMP4CanBeConcatenated(firstInit, segmentEnd, init, seg.Start) {
if !segmentFMP4CanBeConcatenated(firstInit, segmentEnd, init, seg.Start, alwaysConcatenation) {
break
}

Expand Down Expand Up @@ -163,7 +164,7 @@ func (s *Server) onGet(ctx *gin.Context) {
return
}

err = seekAndMux(pathConf.RecordFormat, segments, start, duration, m)
err = seekAndMux(pathConf.RecordFormat, segments, start, duration, m, s.SegmentAlwaysConcatenation)
if err != nil {
// user aborted the download
var neterr *net.OpError
Expand Down
3 changes: 2 additions & 1 deletion internal/playback/on_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ func computeDurationAndConcatenate(
prevInit,
out[len(out)-1].Start.Add(time.Duration(out[len(out)-1].Duration)),
init,
seg.Start) {
seg.Start,
false) {
prevStart := out[len(out)-1].Start
curEnd := seg.Start.Add(maxDuration)
out[len(out)-1].Duration = listEntryDuration(curEnd.Sub(prevStart))
Expand Down
6 changes: 4 additions & 2 deletions internal/playback/segment_fmp4.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ func segmentFMP4CanBeConcatenated(
prevEnd time.Time,
curInit *fmp4.Init,
curStart time.Time,
alwaysConcatenation bool,
) bool {
return reflect.DeepEqual(prevInit, curInit) &&
!curStart.Before(prevEnd.Add(-concatenationTolerance)) &&
!curStart.After(prevEnd.Add(concatenationTolerance))
(alwaysConcatenation ||
(!curStart.Before(prevEnd.Add(-concatenationTolerance)) &&
!curStart.After(prevEnd.Add(concatenationTolerance))))
}

func segmentFMP4ReadInit(r io.ReadSeeker) (*fmp4.Init, error) {
Expand Down
21 changes: 11 additions & 10 deletions internal/playback/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,17 @@ type serverAuthManager interface {

// Server is the playback server.
type Server struct {
Address string
Encryption bool
ServerKey string
ServerCert string
AllowOrigin string
TrustedProxies conf.IPNetworks
ReadTimeout conf.StringDuration
PathConfs map[string]*conf.Path
AuthManager serverAuthManager
Parent logger.Writer
Address string
Encryption bool
ServerKey string
ServerCert string
AllowOrigin string
TrustedProxies conf.IPNetworks
ReadTimeout conf.StringDuration
PathConfs map[string]*conf.Path
AuthManager serverAuthManager
SegmentAlwaysConcatenation bool
Parent logger.Writer

httpServer *httpp.WrappedServer
mutex sync.RWMutex
Expand Down
2 changes: 2 additions & 0 deletions mediamtx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ playbackAllowOrigin: '*'
# If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header.
playbackTrustedProxies: []
# Whether playback segments always concatenation
playbackSegmentAlwaysConcatenation: no

###############################################
# Global settings -> RTSP server
Expand Down