diff --git a/examples/client-read-codec-h264-convert-to-jpeg/main.go b/examples/client-read-codec-h264-convert-to-jpeg/main.go index 4cfcc408..971c8e4d 100644 --- a/examples/client-read-codec-h264-convert-to-jpeg/main.go +++ b/examples/client-read-codec-h264-convert-to-jpeg/main.go @@ -9,7 +9,6 @@ import ( "time" "github.com/aler9/gortsplib" - "github.com/aler9/gortsplib/pkg/rtph264" "github.com/aler9/gortsplib/pkg/url" ) @@ -75,10 +74,7 @@ func main() { } // setup RTP/H264->H264 decoder - rtpDec := &rtph264.Decoder{ - PacketizationMode: track.PacketizationMode, - } - rtpDec.Init() + rtpDec := track.CreateDecoder() // setup H264->raw frames decoder h264RawDec, err := newH264Decoder() diff --git a/examples/client-read-codec-h264-save-to-disk/main.go b/examples/client-read-codec-h264-save-to-disk/main.go index c918adee..b53ffdbb 100644 --- a/examples/client-read-codec-h264-save-to-disk/main.go +++ b/examples/client-read-codec-h264-save-to-disk/main.go @@ -2,7 +2,6 @@ package main import ( "github.com/aler9/gortsplib" - "github.com/aler9/gortsplib/pkg/rtph264" "github.com/aler9/gortsplib/pkg/url" ) @@ -47,10 +46,7 @@ func main() { } // setup RTP/H264->H264 decoder - rtpDec := &rtph264.Decoder{ - PacketizationMode: track.PacketizationMode, - } - rtpDec.Init() + rtpDec := track.CreateDecoder() // setup H264->MPEGTS muxer mpegtsMuxer, err := newMPEGTSMuxer(track.SafeSPS(), track.SafePPS()) diff --git a/examples/client-read-codec-h264/main.go b/examples/client-read-codec-h264/main.go index 5fac2ca7..73cc0434 100644 --- a/examples/client-read-codec-h264/main.go +++ b/examples/client-read-codec-h264/main.go @@ -4,7 +4,6 @@ import ( "log" "github.com/aler9/gortsplib" - "github.com/aler9/gortsplib/pkg/rtph264" "github.com/aler9/gortsplib/pkg/url" ) @@ -52,10 +51,7 @@ func main() { } // setup RTP/H264->H264 decoder - rtpDec := &rtph264.Decoder{ - PacketizationMode: track.PacketizationMode, - } - rtpDec.Init() + rtpDec := track.CreateDecoder() // setup H264->raw frames decoder h264RawDec, err := newH264Decoder() diff --git a/examples/client-read-codec-mpeg4audio/main.go b/examples/client-read-codec-mpeg4audio/main.go index 4afd7eaa..d13f11ce 100644 --- a/examples/client-read-codec-mpeg4audio/main.go +++ b/examples/client-read-codec-mpeg4audio/main.go @@ -4,7 +4,6 @@ import ( "log" "github.com/aler9/gortsplib" - "github.com/aler9/gortsplib/pkg/rtpmpeg4audio" "github.com/aler9/gortsplib/pkg/url" ) @@ -49,13 +48,7 @@ func main() { } // setup decoder - dec := &rtpmpeg4audio.Decoder{ - SampleRate: track.Config.SampleRate, - SizeLength: track.SizeLength, - IndexLength: track.IndexLength, - IndexDeltaLength: track.IndexDeltaLength, - } - dec.Init() + dec := track.CreateDecoder() // called when a RTP packet arrives c.OnPacketRTP = func(ctx *gortsplib.ClientOnPacketRTPCtx) { diff --git a/examples/client-read-codec-opus/main.go b/examples/client-read-codec-opus/main.go index 998bb14d..bca1370f 100644 --- a/examples/client-read-codec-opus/main.go +++ b/examples/client-read-codec-opus/main.go @@ -4,7 +4,6 @@ import ( "log" "github.com/aler9/gortsplib" - "github.com/aler9/gortsplib/pkg/rtpopus" "github.com/aler9/gortsplib/pkg/url" ) @@ -49,10 +48,7 @@ func main() { } // setup decoder - dec := &rtpopus.Decoder{ - SampleRate: track.SampleRate, - } - dec.Init() + dec := track.CreateDecoder() // called when a RTP packet arrives c.OnPacketRTP = func(ctx *gortsplib.ClientOnPacketRTPCtx) { diff --git a/examples/client-read-codec-vp8/main.go b/examples/client-read-codec-vp8/main.go index 8d393768..98910437 100644 --- a/examples/client-read-codec-vp8/main.go +++ b/examples/client-read-codec-vp8/main.go @@ -4,7 +4,6 @@ import ( "log" "github.com/aler9/gortsplib" - "github.com/aler9/gortsplib/pkg/rtpvp8" "github.com/aler9/gortsplib/pkg/url" ) @@ -49,8 +48,7 @@ func main() { } // setup decoder - dec := &rtpvp8.Decoder{} - dec.Init() + dec := track.CreateDecoder() // called when a RTP packet arrives c.OnPacketRTP = func(ctx *gortsplib.ClientOnPacketRTPCtx) { diff --git a/examples/client-read-codec-vp9/main.go b/examples/client-read-codec-vp9/main.go index e47bc894..28c1b392 100644 --- a/examples/client-read-codec-vp9/main.go +++ b/examples/client-read-codec-vp9/main.go @@ -4,7 +4,6 @@ import ( "log" "github.com/aler9/gortsplib" - "github.com/aler9/gortsplib/pkg/rtpvp9" "github.com/aler9/gortsplib/pkg/url" ) @@ -49,8 +48,7 @@ func main() { } // setup decoder - dec := &rtpvp9.Decoder{} - dec.Init() + dec := track.CreateDecoder() // called when a RTP packet arrives c.OnPacketRTP = func(ctx *gortsplib.ClientOnPacketRTPCtx) { diff --git a/track_generic.go b/track_generic.go index c2ce47e7..e8b47016 100644 --- a/track_generic.go +++ b/track_generic.go @@ -124,15 +124,6 @@ func (t *TrackGeneric) ClockRate() int { return t.clockRate } -func (t *TrackGeneric) clone() Track { - return &TrackGeneric{ - Media: t.Media, - Payloads: append([]TrackGenericPayload(nil), t.Payloads...), - trackBase: t.trackBase, - clockRate: t.clockRate, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackGeneric) MediaDescription() *psdp.MediaDescription { formats := make([]string, len(t.Payloads)) @@ -171,3 +162,12 @@ func (t *TrackGeneric) MediaDescription() *psdp.MediaDescription { Attributes: attributes, } } + +func (t *TrackGeneric) clone() Track { + return &TrackGeneric{ + Media: t.Media, + Payloads: append([]TrackGenericPayload(nil), t.Payloads...), + trackBase: t.trackBase, + clockRate: t.clockRate, + } +} diff --git a/track_h264.go b/track_h264.go index 13b97561..d0f2f2d2 100644 --- a/track_h264.go +++ b/track_h264.go @@ -9,6 +9,8 @@ import ( "sync" psdp "github.com/pion/sdp/v3" + + "github.com/aler9/gortsplib/pkg/rtph264" ) // TrackH264 is a H264 track. @@ -100,44 +102,6 @@ func (t *TrackH264) ClockRate() int { return 90000 } -func (t *TrackH264) clone() Track { - return &TrackH264{ - PayloadType: t.PayloadType, - SPS: t.SPS, - PPS: t.PPS, - PacketizationMode: t.PacketizationMode, - trackBase: t.trackBase, - } -} - -// SafeSPS returns the track SPS. -func (t *TrackH264) SafeSPS() []byte { - t.mutex.RLock() - defer t.mutex.RUnlock() - return t.SPS -} - -// SafePPS returns the track PPS. -func (t *TrackH264) SafePPS() []byte { - t.mutex.RLock() - defer t.mutex.RUnlock() - return t.PPS -} - -// SafeSetSPS sets the track SPS. -func (t *TrackH264) SafeSetSPS(v []byte) { - t.mutex.Lock() - defer t.mutex.Unlock() - t.SPS = v -} - -// SafeSetPPS sets the track PPS. -func (t *TrackH264) SafeSetPPS(v []byte) { - t.mutex.Lock() - defer t.mutex.Unlock() - t.PPS = v -} - // MediaDescription returns the track media description in SDP format. func (t *TrackH264) MediaDescription() *psdp.MediaDescription { t.mutex.RLock() @@ -190,3 +154,50 @@ func (t *TrackH264) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackH264) clone() Track { + return &TrackH264{ + PayloadType: t.PayloadType, + SPS: t.SPS, + PPS: t.PPS, + PacketizationMode: t.PacketizationMode, + trackBase: t.trackBase, + } +} + +// CreateDecoder creates a decoder able to decode the content of the track. +func (t *TrackH264) CreateDecoder() *rtph264.Decoder { + d := &rtph264.Decoder{ + PacketizationMode: t.PacketizationMode, + } + d.Init() + return d +} + +// SafeSPS returns the track SPS. +func (t *TrackH264) SafeSPS() []byte { + t.mutex.RLock() + defer t.mutex.RUnlock() + return t.SPS +} + +// SafePPS returns the track PPS. +func (t *TrackH264) SafePPS() []byte { + t.mutex.RLock() + defer t.mutex.RUnlock() + return t.PPS +} + +// SafeSetSPS sets the track SPS. +func (t *TrackH264) SafeSetSPS(v []byte) { + t.mutex.Lock() + defer t.mutex.Unlock() + t.SPS = v +} + +// SafeSetPPS sets the track PPS. +func (t *TrackH264) SafeSetPPS(v []byte) { + t.mutex.Lock() + defer t.mutex.Unlock() + t.PPS = v +} diff --git a/track_h265.go b/track_h265.go index 50fd1e06..684170f6 100644 --- a/track_h265.go +++ b/track_h265.go @@ -93,6 +93,52 @@ func (t *TrackH265) ClockRate() int { return 90000 } +// MediaDescription returns the track media description in SDP format. +func (t *TrackH265) MediaDescription() *psdp.MediaDescription { + t.mutex.RLock() + defer t.mutex.RUnlock() + + typ := strconv.FormatInt(int64(t.PayloadType), 10) + + fmtp := typ + + var tmp []string + if t.VPS != nil { + tmp = append(tmp, "sprop-vps="+base64.StdEncoding.EncodeToString(t.VPS)) + } + if t.SPS != nil { + tmp = append(tmp, "sprop-sps="+base64.StdEncoding.EncodeToString(t.SPS)) + } + if t.PPS != nil { + tmp = append(tmp, "sprop-pps="+base64.StdEncoding.EncodeToString(t.PPS)) + } + if tmp != nil { + fmtp += " " + strings.Join(tmp, "; ") + } + + return &psdp.MediaDescription{ + MediaName: psdp.MediaName{ + Media: "video", + Protos: []string{"RTP", "AVP"}, + Formats: []string{typ}, + }, + Attributes: []psdp.Attribute{ + { + Key: "rtpmap", + Value: typ + " H265/90000", + }, + { + Key: "fmtp", + Value: fmtp, + }, + { + Key: "control", + Value: t.control, + }, + }, + } +} + func (t *TrackH265) clone() Track { return &TrackH265{ PayloadType: t.PayloadType, @@ -144,49 +190,3 @@ func (t *TrackH265) SafeSetPPS(v []byte) { defer t.mutex.Unlock() t.PPS = v } - -// MediaDescription returns the track media description in SDP format. -func (t *TrackH265) MediaDescription() *psdp.MediaDescription { - t.mutex.RLock() - defer t.mutex.RUnlock() - - typ := strconv.FormatInt(int64(t.PayloadType), 10) - - fmtp := typ - - var tmp []string - if t.VPS != nil { - tmp = append(tmp, "sprop-vps="+base64.StdEncoding.EncodeToString(t.VPS)) - } - if t.SPS != nil { - tmp = append(tmp, "sprop-sps="+base64.StdEncoding.EncodeToString(t.SPS)) - } - if t.PPS != nil { - tmp = append(tmp, "sprop-pps="+base64.StdEncoding.EncodeToString(t.PPS)) - } - if tmp != nil { - fmtp += " " + strings.Join(tmp, "; ") - } - - return &psdp.MediaDescription{ - MediaName: psdp.MediaName{ - Media: "video", - Protos: []string{"RTP", "AVP"}, - Formats: []string{typ}, - }, - Attributes: []psdp.Attribute{ - { - Key: "rtpmap", - Value: typ + " H265/90000", - }, - { - Key: "fmtp", - Value: fmtp, - }, - { - Key: "control", - Value: t.control, - }, - }, - } -} diff --git a/track_jpeg.go b/track_jpeg.go index 079a5036..f5907bec 100644 --- a/track_jpeg.go +++ b/track_jpeg.go @@ -24,12 +24,6 @@ func (t *TrackJPEG) ClockRate() int { return 90000 } -func (t *TrackJPEG) clone() Track { - return &TrackJPEG{ - trackBase: t.trackBase, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackJPEG) MediaDescription() *psdp.MediaDescription { return &psdp.MediaDescription{ @@ -50,3 +44,9 @@ func (t *TrackJPEG) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackJPEG) clone() Track { + return &TrackJPEG{ + trackBase: t.trackBase, + } +} diff --git a/track_mpeg2audio.go b/track_mpeg2audio.go index 770dd3f5..41a9d3ae 100644 --- a/track_mpeg2audio.go +++ b/track_mpeg2audio.go @@ -24,12 +24,6 @@ func (t *TrackMPEG2Audio) ClockRate() int { return 90000 } -func (t *TrackMPEG2Audio) clone() Track { - return &TrackMPEG2Audio{ - trackBase: t.trackBase, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackMPEG2Audio) MediaDescription() *psdp.MediaDescription { return &psdp.MediaDescription{ @@ -46,3 +40,9 @@ func (t *TrackMPEG2Audio) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackMPEG2Audio) clone() Track { + return &TrackMPEG2Audio{ + trackBase: t.trackBase, + } +} diff --git a/track_mpeg2video.go b/track_mpeg2video.go index 4b6097de..d71e48fa 100644 --- a/track_mpeg2video.go +++ b/track_mpeg2video.go @@ -24,12 +24,6 @@ func (t *TrackMPEG2Video) ClockRate() int { return 90000 } -func (t *TrackMPEG2Video) clone() Track { - return &TrackMPEG2Video{ - trackBase: t.trackBase, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackMPEG2Video) MediaDescription() *psdp.MediaDescription { return &psdp.MediaDescription{ @@ -46,3 +40,9 @@ func (t *TrackMPEG2Video) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackMPEG2Video) clone() Track { + return &TrackMPEG2Video{ + trackBase: t.trackBase, + } +} diff --git a/track_mpeg4audio.go b/track_mpeg4audio.go index f016c00d..326e153e 100644 --- a/track_mpeg4audio.go +++ b/track_mpeg4audio.go @@ -9,6 +9,7 @@ import ( psdp "github.com/pion/sdp/v3" "github.com/aler9/gortsplib/pkg/mpeg4audio" + "github.com/aler9/gortsplib/pkg/rtpmpeg4audio" ) // TrackMPEG4Audio is a MPEG-4 audio track. @@ -108,17 +109,6 @@ func (t *TrackMPEG4Audio) ClockRate() int { return t.Config.SampleRate } -func (t *TrackMPEG4Audio) clone() Track { - return &TrackMPEG4Audio{ - PayloadType: t.PayloadType, - Config: t.Config, - SizeLength: t.SizeLength, - IndexLength: t.IndexLength, - IndexDeltaLength: t.IndexDeltaLength, - trackBase: t.trackBase, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackMPEG4Audio) MediaDescription() *psdp.MediaDescription { enc, err := t.Config.Marshal() @@ -176,3 +166,26 @@ func (t *TrackMPEG4Audio) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackMPEG4Audio) clone() Track { + return &TrackMPEG4Audio{ + PayloadType: t.PayloadType, + Config: t.Config, + SizeLength: t.SizeLength, + IndexLength: t.IndexLength, + IndexDeltaLength: t.IndexDeltaLength, + trackBase: t.trackBase, + } +} + +// CreateDecoder creates a decoder able to decode the content of the track. +func (t *TrackMPEG4Audio) CreateDecoder() *rtpmpeg4audio.Decoder { + d := &rtpmpeg4audio.Decoder{ + SampleRate: t.Config.SampleRate, + SizeLength: t.SizeLength, + IndexLength: t.IndexLength, + IndexDeltaLength: t.IndexDeltaLength, + } + d.Init() + return d +} diff --git a/track_opus.go b/track_opus.go index 481f27ed..285cf06e 100644 --- a/track_opus.go +++ b/track_opus.go @@ -6,6 +6,8 @@ import ( "strings" psdp "github.com/pion/sdp/v3" + + "github.com/aler9/gortsplib/pkg/rtpopus" ) // TrackOpus is a Opus track. @@ -53,15 +55,6 @@ func (t *TrackOpus) ClockRate() int { return t.SampleRate } -func (t *TrackOpus) clone() Track { - return &TrackOpus{ - PayloadType: t.PayloadType, - SampleRate: t.SampleRate, - ChannelCount: t.ChannelCount, - trackBase: t.trackBase, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackOpus) MediaDescription() *psdp.MediaDescription { typ := strconv.FormatInt(int64(t.PayloadType), 10) @@ -94,3 +87,21 @@ func (t *TrackOpus) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackOpus) clone() Track { + return &TrackOpus{ + PayloadType: t.PayloadType, + SampleRate: t.SampleRate, + ChannelCount: t.ChannelCount, + trackBase: t.trackBase, + } +} + +// CreateDecoder creates a decoder able to decode the content of the track. +func (t *TrackOpus) CreateDecoder() *rtpopus.Decoder { + d := &rtpopus.Decoder{ + SampleRate: t.SampleRate, + } + d.Init() + return d +} diff --git a/track_pcma.go b/track_pcma.go index 2051e6ed..901dc60e 100644 --- a/track_pcma.go +++ b/track_pcma.go @@ -33,12 +33,6 @@ func (t *TrackPCMA) ClockRate() int { return 8000 } -func (t *TrackPCMA) clone() Track { - return &TrackPCMA{ - trackBase: t.trackBase, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackPCMA) MediaDescription() *psdp.MediaDescription { return &psdp.MediaDescription{ @@ -59,3 +53,9 @@ func (t *TrackPCMA) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackPCMA) clone() Track { + return &TrackPCMA{ + trackBase: t.trackBase, + } +} diff --git a/track_pcmu.go b/track_pcmu.go index d5b5852f..1ceaf965 100644 --- a/track_pcmu.go +++ b/track_pcmu.go @@ -33,12 +33,6 @@ func (t *TrackPCMU) ClockRate() int { return 8000 } -func (t *TrackPCMU) clone() Track { - return &TrackPCMU{ - trackBase: t.trackBase, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackPCMU) MediaDescription() *psdp.MediaDescription { return &psdp.MediaDescription{ @@ -59,3 +53,9 @@ func (t *TrackPCMU) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackPCMU) clone() Track { + return &TrackPCMU{ + trackBase: t.trackBase, + } +} diff --git a/track_vp8.go b/track_vp8.go index 5bc7f77d..0ad0abaa 100644 --- a/track_vp8.go +++ b/track_vp8.go @@ -6,6 +6,8 @@ import ( "strings" psdp "github.com/pion/sdp/v3" + + "github.com/aler9/gortsplib/pkg/rtpvp8" ) // TrackVP8 is a VP8 track. @@ -83,15 +85,6 @@ func (t *TrackVP8) ClockRate() int { return 90000 } -func (t *TrackVP8) clone() Track { - return &TrackVP8{ - trackBase: t.trackBase, - PayloadType: t.PayloadType, - MaxFR: t.MaxFR, - MaxFS: t.MaxFS, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackVP8) MediaDescription() *psdp.MediaDescription { typ := strconv.FormatInt(int64(t.PayloadType), 10) @@ -131,3 +124,19 @@ func (t *TrackVP8) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackVP8) clone() Track { + return &TrackVP8{ + trackBase: t.trackBase, + PayloadType: t.PayloadType, + MaxFR: t.MaxFR, + MaxFS: t.MaxFS, + } +} + +// CreateDecoder creates a decoder able to decode the content of the track. +func (t *TrackVP8) CreateDecoder() *rtpvp8.Decoder { + d := &rtpvp8.Decoder{} + d.Init() + return d +} diff --git a/track_vp9.go b/track_vp9.go index 0857a797..69a89d69 100644 --- a/track_vp9.go +++ b/track_vp9.go @@ -6,6 +6,8 @@ import ( "strings" psdp "github.com/pion/sdp/v3" + + "github.com/aler9/gortsplib/pkg/rtpvp9" ) // TrackVP9 is a VP9 track. @@ -92,16 +94,6 @@ func (t *TrackVP9) ClockRate() int { return 90000 } -func (t *TrackVP9) clone() Track { - return &TrackVP9{ - trackBase: t.trackBase, - PayloadType: t.PayloadType, - MaxFR: t.MaxFR, - MaxFS: t.MaxFS, - ProfileID: t.ProfileID, - } -} - // MediaDescription returns the track media description in SDP format. func (t *TrackVP9) MediaDescription() *psdp.MediaDescription { typ := strconv.FormatInt(int64(t.PayloadType), 10) @@ -144,3 +136,20 @@ func (t *TrackVP9) MediaDescription() *psdp.MediaDescription { }, } } + +func (t *TrackVP9) clone() Track { + return &TrackVP9{ + trackBase: t.trackBase, + PayloadType: t.PayloadType, + MaxFR: t.MaxFR, + MaxFS: t.MaxFS, + ProfileID: t.ProfileID, + } +} + +// CreateDecoder creates a decoder able to decode the content of the track. +func (t *TrackVP9) CreateDecoder() *rtpvp9.Decoder { + d := &rtpvp9.Decoder{} + d.Init() + return d +}