diff --git a/go.mod b/go.mod index 39f089a5..da39edb5 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/alecthomas/kong v1.13.0 github.com/asticode/go-astits v1.14.0 github.com/bluenviron/gohlslib/v2 v2.2.4 - github.com/bluenviron/gortmplib v0.1.2 + github.com/bluenviron/gortmplib v0.2.0 github.com/bluenviron/gortsplib/v5 v5.2.2 github.com/bluenviron/mediacommon/v2 v2.6.0 github.com/datarhei/gosrt v0.9.0 diff --git a/go.sum b/go.sum index 62a3768e..50121fea 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,8 @@ github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYh github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c/go.mod h1:x1vxHcL/9AVzuk5HOloOEPrtJY0MaalYr78afXZ+pWI= github.com/bluenviron/gohlslib/v2 v2.2.4 h1:5F/Ud2VuJrrLYCDV0Ham947UIIrd801/GyoCsPYMqiw= github.com/bluenviron/gohlslib/v2 v2.2.4/go.mod h1:5J8Ry4xraLs6W0B2gVS0IqhCzcq+CDDJIisfkpoHyxM= -github.com/bluenviron/gortmplib v0.1.2 h1:bJ+5pUxKnHjEoKPbNs7lDLyYy5R9Z1lISJ1n54DsjWE= -github.com/bluenviron/gortmplib v0.1.2/go.mod h1:oVOWgfs7wsZNoKYLttyqLar7a71ZTohO1JOVXkNxtHg= +github.com/bluenviron/gortmplib v0.2.0 h1:j15eeHrgVh6Avg9oAx+r4w0HugTqrIqLBsYnhs3D1dE= +github.com/bluenviron/gortmplib v0.2.0/go.mod h1:yzobxBF8zusF2nKbEOF69zIIL429j0kaCWc/euNdvO4= github.com/bluenviron/gortsplib/v5 v5.2.2 h1:5q2viB8PGxWOSXNhVvj8buyr1wighLbHqRZ0U7MLM3o= github.com/bluenviron/gortsplib/v5 v5.2.2/go.mod h1:xkVBOAnR4fzaerPN650CBb7N+zUUsj7PI2HiY1TP7Co= github.com/bluenviron/mediacommon/v2 v2.6.0 h1:wZAPXwv7V78Cx2x7cToYIHOLToHl6APcvHbdQT+gOkg= diff --git a/internal/core/api_test.go b/internal/core/api_test.go index b3d6b4ea..27b65dc9 100644 --- a/internal/core/api_test.go +++ b/internal/core/api_test.go @@ -15,9 +15,9 @@ import ( "time" "github.com/bluenviron/gortmplib" + rtmpcodecs "github.com/bluenviron/gortmplib/pkg/codecs" "github.com/bluenviron/gortsplib/v5" "github.com/bluenviron/gortsplib/v5/pkg/description" - "github.com/bluenviron/gortsplib/v5/pkg/format" "github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts" tscodecs "github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts/codecs" srt "github.com/datarhei/gosrt" @@ -441,14 +441,21 @@ func TestAPIProtocolListGet(t *testing.T) { require.NoError(t, err) defer conn.Close() + track := &gortmplib.Track{ + Codec: &rtmpcodecs.H264{ + SPS: test.FormatH264.SPS, + PPS: test.FormatH264.PPS, + }, + } + w := &gortmplib.Writer{ Conn: conn, - Tracks: []format.Format{test.FormatH264}, + Tracks: []*gortmplib.Track{track}, } err = w.Initialize() require.NoError(t, err) - err = w.WriteH264(test.FormatH264, 2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}}) + err = w.WriteH264(track, 2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}}) require.NoError(t, err) time.Sleep(500 * time.Millisecond) @@ -1038,14 +1045,21 @@ func TestAPIProtocolKick(t *testing.T) { require.NoError(t, err) defer conn.Close() + track := &gortmplib.Track{ + Codec: &rtmpcodecs.H264{ + SPS: test.FormatH264.SPS, + PPS: test.FormatH264.PPS, + }, + } + w := &gortmplib.Writer{ Conn: conn, - Tracks: []format.Format{test.FormatH264}, + Tracks: []*gortmplib.Track{track}, } err = w.Initialize() require.NoError(t, err) - err = w.WriteH264(test.FormatH264, 2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}}) + err = w.WriteH264(track, 2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}}) require.NoError(t, err) case "webrtc": diff --git a/internal/core/metrics_test.go b/internal/core/metrics_test.go index 35754603..1391dfea 100644 --- a/internal/core/metrics_test.go +++ b/internal/core/metrics_test.go @@ -13,9 +13,9 @@ import ( "time" "github.com/bluenviron/gortmplib" + rtmpcodecs "github.com/bluenviron/gortmplib/pkg/codecs" "github.com/bluenviron/gortsplib/v5" "github.com/bluenviron/gortsplib/v5/pkg/description" - "github.com/bluenviron/gortsplib/v5/pkg/format" "github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts" tscodecs "github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts/codecs" srt "github.com/datarhei/gosrt" @@ -218,14 +218,21 @@ webrtc_sessions_rtcp_packets_sent 0 require.NoError(t, err2) defer conn.Close() + track := &gortmplib.Track{ + Codec: &rtmpcodecs.H264{ + SPS: test.FormatH264.SPS, + PPS: test.FormatH264.PPS, + }, + } + w := &gortmplib.Writer{ Conn: conn, - Tracks: []format.Format{test.FormatH264}, + Tracks: []*gortmplib.Track{track}, } err2 = w.Initialize() require.NoError(t, err2) - err2 = w.WriteH264(test.FormatH264, 2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}}) + err2 = w.WriteH264(track, 2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}}) require.NoError(t, err2) <-terminate @@ -246,14 +253,21 @@ webrtc_sessions_rtcp_packets_sent 0 require.NoError(t, err2) defer conn.Close() + track := &gortmplib.Track{ + Codec: &rtmpcodecs.H264{ + SPS: test.FormatH264.SPS, + PPS: test.FormatH264.PPS, + }, + } + w := &gortmplib.Writer{ Conn: conn, - Tracks: []format.Format{test.FormatH264}, + Tracks: []*gortmplib.Track{track}, } err2 = w.Initialize() require.NoError(t, err2) - err2 = w.WriteH264(test.FormatH264, 2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}}) + err2 = w.WriteH264(track, 2*time.Second, 2*time.Second, [][]byte{{5, 2, 3, 4}}) require.NoError(t, err2) <-terminate diff --git a/internal/protocols/rtmp/from_stream.go b/internal/protocols/rtmp/from_stream.go index 4abeee7a..dd8f75f5 100644 --- a/internal/protocols/rtmp/from_stream.go +++ b/internal/protocols/rtmp/from_stream.go @@ -8,6 +8,7 @@ import ( "time" "github.com/bluenviron/gortmplib" + "github.com/bluenviron/gortmplib/pkg/codecs" "github.com/bluenviron/gortmplib/pkg/message" "github.com/bluenviron/gortsplib/v5/pkg/description" "github.com/bluenviron/gortsplib/v5/pkg/format" @@ -44,7 +45,7 @@ func FromStream( nconn net.Conn, writeTimeout time.Duration, ) error { - var tracks []format.Format + var tracks []*gortmplib.Track var w *gortmplib.Writer for _, media := range desc.Medias { @@ -52,6 +53,11 @@ func FromStream( switch forma := forma.(type) { case *format.AV1: if slices.Contains(conn.FourCcList, any(fourCCToString(message.FourCCAV1))) { + track := &gortmplib.Track{ + Codec: &codecs.AV1{}, + } + tracks = append(tracks, track) + r.OnData( media, forma, @@ -62,16 +68,19 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteAV1( - forma, + track, timestampToDuration(u.PTS, forma.ClockRate()), u.Payload.(unit.PayloadAV1)) }) - - tracks = append(tracks, forma) } case *format.VP9: if slices.Contains(conn.FourCcList, any(fourCCToString(message.FourCCVP9))) { + track := &gortmplib.Track{ + Codec: &codecs.VP9{}, + } + tracks = append(tracks, track) + r.OnData( media, forma, @@ -82,16 +91,24 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteVP9( - forma, + track, timestampToDuration(u.PTS, forma.ClockRate()), u.Payload.(unit.PayloadVP9)) }) - - tracks = append(tracks, forma) } case *format.H265: if slices.Contains(conn.FourCcList, any(fourCCToString(message.FourCCHEVC))) { + vps, sps, pps := forma.SafeParams() + track := &gortmplib.Track{ + Codec: &codecs.H265{ + VPS: vps, + SPS: sps, + PPS: pps, + }, + } + tracks = append(tracks, track) + var videoDTSExtractor *h265.DTSExtractor r.OnData( @@ -117,16 +134,23 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteH265( - forma, + track, timestampToDuration(u.PTS, forma.ClockRate()), timestampToDuration(dts, forma.ClockRate()), u.Payload.(unit.PayloadH265)) }) - - tracks = append(tracks, forma) } case *format.H264: + sps, pps := forma.SafeParams() + track := &gortmplib.Track{ + Codec: &codecs.H264{ + SPS: sps, + PPS: pps, + }, + } + tracks = append(tracks, track) + var videoDTSExtractor *h264.DTSExtractor r.OnData( @@ -170,16 +194,21 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteH264( - forma, + track, timestampToDuration(u.PTS, forma.ClockRate()), timestampToDuration(dts, forma.ClockRate()), u.Payload.(unit.PayloadH264)) }) - tracks = append(tracks, forma) - case *format.Opus: if slices.Contains(conn.FourCcList, any(fourCCToString(message.FourCCOpus))) { + track := &gortmplib.Track{ + Codec: &codecs.Opus{ + ChannelCount: forma.ChannelCount, + }, + } + tracks = append(tracks, track) + r.OnData( media, forma, @@ -193,7 +222,7 @@ func FromStream( for _, pkt := range u.Payload.(unit.PayloadOpus) { nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteOpus( - forma, + track, timestampToDuration(pts, forma.ClockRate()), pkt, ) @@ -206,11 +235,16 @@ func FromStream( return nil }) - - tracks = append(tracks, forma) } case *format.MPEG4Audio: + track := &gortmplib.Track{ + Codec: &codecs.MPEG4Audio{ + Config: forma.Config, + }, + } + tracks = append(tracks, track) + r.OnData( media, forma, @@ -224,7 +258,7 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteMPEG4Audio( - forma, + track, timestampToDuration(pts, forma.ClockRate()), au, ) @@ -236,10 +270,15 @@ func FromStream( return nil }) - tracks = append(tracks, forma) - case *format.MPEG4AudioLATM: if !forma.CPresent { + track := &gortmplib.Track{ + Codec: &codecs.MPEG4Audio{ + Config: forma.StreamMuxConfig.Programs[0].Layers[0].AudioSpecificConfig, + }, + } + tracks = append(tracks, track) + r.OnData( media, forma, @@ -257,16 +296,19 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteMPEG4Audio( - forma, + track, timestampToDuration(u.PTS, forma.ClockRate()), ame.Payloads[0][0][0], ) }) - - tracks = append(tracks, forma) } case *format.MPEG1Audio: + track := &gortmplib.Track{ + Codec: &codecs.MPEG1Audio{}, + } + tracks = append(tracks, track) + r.OnData( media, forma, @@ -286,7 +328,7 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err = (*w).WriteMPEG1Audio( - forma, + track, timestampToDuration(pts, forma.ClockRate()), frame) if err != nil { @@ -300,10 +342,16 @@ func FromStream( return nil }) - tracks = append(tracks, forma) - case *format.AC3: if slices.Contains(conn.FourCcList, any(fourCCToString(message.FourCCAC3))) { + track := &gortmplib.Track{ + Codec: &codecs.AC3{ + SampleRate: forma.SampleRate, + ChannelCount: forma.ChannelCount, + }, + } + tracks = append(tracks, track) + r.OnData( media, forma, @@ -317,7 +365,7 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteAC3( - forma, + track, timestampToDuration(pts, forma.ClockRate()), frame) if err != nil { @@ -327,12 +375,19 @@ func FromStream( return nil }) - - tracks = append(tracks, forma) } case *format.G711: if forma.SampleRate == 8000 { + track := &gortmplib.Track{ + Codec: &codecs.G711{ + MULaw: forma.MULaw, + SampleRate: forma.SampleRate, + ChannelCount: forma.ChannelCount, + }, + } + tracks = append(tracks, track) + r.OnData( media, forma, @@ -343,13 +398,11 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteG711( - forma, + track, timestampToDuration(u.PTS, forma.ClockRate()), u.Payload.(unit.PayloadG711), ) }) - - tracks = append(tracks, forma) } case *format.LPCM: @@ -358,6 +411,15 @@ func FromStream( forma.SampleRate == 11025 || forma.SampleRate == 22050 || forma.SampleRate == 44100) { + track := &gortmplib.Track{ + Codec: &codecs.LPCM{ + BitDepth: forma.BitDepth, + SampleRate: forma.SampleRate, + ChannelCount: forma.ChannelCount, + }, + } + tracks = append(tracks, track) + r.OnData( media, forma, @@ -368,13 +430,11 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteLPCM( - forma, + track, timestampToDuration(u.PTS, forma.ClockRate()), u.Payload.(unit.PayloadLPCM), ) }) - - tracks = append(tracks, forma) } } } @@ -393,10 +453,12 @@ func FromStream( return err } + setuppedFormats := r.Formats() + n := 1 for _, media := range desc.Medias { for _, forma := range media.Formats { - if !slices.Contains(tracks, forma) { + if !slices.Contains(setuppedFormats, forma) { r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, forma.Codec()) } n++ diff --git a/internal/protocols/rtmp/from_stream_test.go b/internal/protocols/rtmp/from_stream_test.go index e315b632..ac15dd64 100644 --- a/internal/protocols/rtmp/from_stream_test.go +++ b/internal/protocols/rtmp/from_stream_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/bluenviron/gortmplib" + "github.com/bluenviron/gortmplib/pkg/codecs" "github.com/bluenviron/gortsplib/v5/pkg/description" "github.com/bluenviron/gortsplib/v5/pkg/format" "github.com/bluenviron/mediamtx/internal/codecprocessor" @@ -20,405 +21,49 @@ import ( ) func TestFromStream(t *testing.T) { - for _, ca := range []string{ - "h264 + aac", - "av1", - "vp9", - "h265", - "h264", - "opus", - "aac", - "mp3", - "ac-3", - "pcma", - "pcmu", - "lpcm", - "h265 + h264 + vp9 + av1 + opus + aac", - } { - t.Run(ca, func(t *testing.T) { - var medias []*description.Media + h265VPS := []byte{ + 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, + 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x03, 0x00, 0x78, 0xba, 0x02, 0x40, + } + h265SPS := []byte{ + 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, + 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, + 0x00, 0x78, 0xa0, 0x03, 0xc0, 0x80, 0x11, 0x07, + 0xcb, 0x96, 0xe9, 0x29, 0x30, 0xbc, 0x05, 0xa0, + 0x20, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, + 0x03, 0x03, 0xc1, + } + h265PPS := []byte{ + 0x44, 0x01, 0xc0, 0x73, 0xc1, 0x89, + } - switch ca { - case "h264 + aac": - medias = []*description.Media{ - { - Formats: []format.Format{test.FormatH264}, - }, - { - Formats: []format.Format{test.FormatMPEG4Audio}, - }, - } - - case "av1": - medias = []*description.Media{ - { - Formats: []format.Format{&format.AV1{ - PayloadTyp: 96, - }}, - }, - } - - case "vp9": - medias = []*description.Media{ - { - Formats: []format.Format{&format.VP9{ - PayloadTyp: 96, - }}, - }, - } - - case "h265": - medias = []*description.Media{ - { - Formats: []format.Format{ - &format.H265{ - PayloadTyp: 96, - VPS: []byte{ - 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, - 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x03, 0x00, 0x78, 0xba, 0x02, 0x40, - }, - SPS: []byte{ - 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, - 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, - 0x00, 0x78, 0xa0, 0x03, 0xc0, 0x80, 0x11, 0x07, - 0xcb, 0x96, 0xe9, 0x29, 0x30, 0xbc, 0x05, 0xa0, - 0x20, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, - 0x03, 0x03, 0xc1, - }, - PPS: []byte{ - 0x44, 0x01, 0xc0, 0x73, 0xc1, 0x89, - }, - }, - }, - }, - } - - case "h264": - medias = []*description.Media{ - { - Formats: []format.Format{test.FormatH264}, - }, - } - - case "opus": - medias = []*description.Media{ - { - Formats: []format.Format{&format.Opus{ - PayloadTyp: 96, - ChannelCount: 2, - }}, - }, - } - - case "aac": - medias = []*description.Media{ - { - Formats: []format.Format{test.FormatMPEG4Audio}, - }, - } - - case "mp3": - medias = []*description.Media{ - { - Formats: []format.Format{&format.MPEG1Audio{}}, - }, - } - - case "ac-3": - medias = []*description.Media{ - { - Formats: []format.Format{&format.AC3{ - SampleRate: 44100, - ChannelCount: 2, - }}, - }, - } - - case "pcma": - medias = []*description.Media{ - { - Formats: []format.Format{&format.G711{ - MULaw: false, - SampleRate: 8000, - ChannelCount: 1, - }}, - }, - } - - case "pcmu": - medias = []*description.Media{ - { - Formats: []format.Format{&format.G711{ - MULaw: true, - SampleRate: 8000, - ChannelCount: 1, - }}, - }, - } - - case "lpcm": - medias = []*description.Media{ - { - Formats: []format.Format{&format.LPCM{ - BitDepth: 16, - SampleRate: 44100, - ChannelCount: 2, - }}, - }, - } - - case "h265 + h264 + vp9 + av1 + opus + aac": - medias = []*description.Media{ - { - Formats: []format.Format{&format.H265{}}, - }, - { - Formats: []format.Format{&format.H264{}}, - }, - { - Formats: []format.Format{&format.VP9{}}, - }, - { - Formats: []format.Format{&format.AV1{}}, - }, - { - Formats: []format.Format{&format.Opus{ - PayloadTyp: 96, - ChannelCount: 2, - }}, - }, - { - Formats: []format.Format{&format.MPEG4Audio{ - PayloadTyp: 96, - Config: test.FormatMPEG4Audio.Config, - SizeLength: 13, - IndexLength: 3, - IndexDeltaLength: 3, - }}, - }, - } - } - - strm := &stream.Stream{ - WriteQueueSize: 512, - RTPMaxPayloadSize: 1450, - Desc: &description.Session{Medias: medias}, - GenerateRTPPackets: true, - Parent: test.NilLogger, - } - err := strm.Initialize() - require.NoError(t, err) - - ln, err := net.Listen("tcp", "127.0.0.1:9121") - require.NoError(t, err) - defer ln.Close() - - done := make(chan struct{}) - - go func() { - u, err2 := url.Parse("rtmp://127.0.0.1:9121/stream") - require.NoError(t, err2) - - c := &gortmplib.Client{ - URL: u, - } - err2 = c.Initialize(context.Background()) - require.NoError(t, err2) - - r := &gortmplib.Reader{ - Conn: c, - } - err2 = r.Initialize() - require.NoError(t, err2) - - switch ca { - case "h264 + aac": - require.Equal(t, []format.Format{ - &format.H264{ - SPS: test.FormatH264.SPS, - PPS: test.FormatH264.PPS, - PacketizationMode: 1, - PayloadTyp: 96, - }, - &format.MPEG4Audio{ - PayloadTyp: 96, - Config: test.FormatMPEG4Audio.Config, - SizeLength: 13, - IndexLength: 3, - IndexDeltaLength: 3, - }, - }, r.Tracks()) - - case "av1": - require.Equal(t, []format.Format{ - &format.AV1{ - PayloadTyp: 96, - }, - }, r.Tracks()) - - case "vp9": - require.Equal(t, []format.Format{ - &format.VP9{ - PayloadTyp: 96, - }, - }, r.Tracks()) - - case "h265": - require.Equal(t, []format.Format{ - &format.H265{ - VPS: []byte{ - 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, - 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x03, 0x00, 0x78, 0xba, 0x02, 0x40, - }, - SPS: []byte{ - 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, - 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, - 0x00, 0x78, 0xa0, 0x03, 0xc0, 0x80, 0x11, 0x07, - 0xcb, 0x96, 0xe9, 0x29, 0x30, 0xbc, 0x05, 0xa0, - 0x20, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, - 0x03, 0x03, 0xc1, - }, - PPS: []byte{ - 0x44, 0x01, 0xc0, 0x73, 0xc1, 0x89, - }, - PayloadTyp: 96, - }, - }, r.Tracks()) - - case "h264": - require.Equal(t, []format.Format{ - &format.H264{ - SPS: test.FormatH264.SPS, - PPS: test.FormatH264.PPS, - PacketizationMode: 1, - PayloadTyp: 96, - }, - }, r.Tracks()) - - case "opus": - require.Equal(t, []format.Format{ - &format.Opus{ - PayloadTyp: 96, - ChannelCount: 2, - }, - }, r.Tracks()) - - case "aac": - require.Equal(t, []format.Format{ - &format.MPEG4Audio{ - PayloadTyp: 96, - Config: test.FormatMPEG4Audio.Config, - SizeLength: 13, - IndexLength: 3, - IndexDeltaLength: 3, - }, - }, r.Tracks()) - - case "mp3": - require.Equal(t, []format.Format{ - &format.MPEG1Audio{}, - }, r.Tracks()) - - case "ac-3": - require.Equal(t, []format.Format{ - &format.AC3{ - PayloadTyp: 96, - SampleRate: 48000, - ChannelCount: 1, - }, - }, r.Tracks()) - - case "pcma": - require.Equal(t, []format.Format{ - &format.G711{ - PayloadTyp: 8, - MULaw: false, - ChannelCount: 1, - SampleRate: 8000, - }, - }, r.Tracks()) - - case "pcmu": - require.Equal(t, []format.Format{ - &format.G711{ - MULaw: true, - ChannelCount: 1, - SampleRate: 8000, - }, - }, r.Tracks()) - - case "lpcm": - require.Equal(t, []format.Format{ - &format.LPCM{ - PayloadTyp: 96, - BitDepth: 16, - SampleRate: 44100, - ChannelCount: 2, - }, - }, r.Tracks()) - - case "h265 + h264 + vp9 + av1 + opus + aac": - require.Equal(t, []format.Format{ - &format.H265{ - PayloadTyp: 96, - VPS: codecprocessor.H265DefaultVPS, - SPS: codecprocessor.H265DefaultSPS, - PPS: codecprocessor.H265DefaultPPS, - }, - &format.H264{ - PayloadTyp: 96, - PacketizationMode: 1, - SPS: codecprocessor.H264DefaultSPS, - PPS: codecprocessor.H264DefaultPPS, - }, - &format.VP9{ - PayloadTyp: 96, - }, - &format.AV1{ - PayloadTyp: 96, - }, - &format.Opus{ - PayloadTyp: 96, - ChannelCount: 2, - }, - &format.MPEG4Audio{ - PayloadTyp: 96, - Config: test.FormatMPEG4Audio.Config, - SizeLength: 13, - IndexLength: 3, - IndexDeltaLength: 3, - }, - }, r.Tracks()) - } - - close(done) - }() - - nconn, err := ln.Accept() - require.NoError(t, err) - defer nconn.Close() - - conn := &gortmplib.ServerConn{ - RW: nconn, - } - err = conn.Initialize() - require.NoError(t, err) - - err = conn.Accept() - require.NoError(t, err) - - r := &stream.Reader{Parent: test.NilLogger} - - err = FromStream(strm.Desc, r, conn, nconn, 10*time.Second) - require.NoError(t, err) - - strm.AddReader(r) - defer strm.RemoveReader(r) - - switch ca { - case "h264 + aac": + cases := []struct { + name string + medias []*description.Media + expectedTracks []*gortmplib.Track + writeUnits func([]*description.Media, *stream.Stream) + }{ + { + name: "h264 + aac", + medias: []*description.Media{ + { + Formats: []format.Format{test.FormatH264}, + }, + { + Formats: []format.Format{test.FormatMPEG4Audio}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.H264{ + SPS: test.FormatH264.SPS, + PPS: test.FormatH264.PPS, + }}, + {Codec: &codecs.MPEG4Audio{ + Config: test.FormatMPEG4Audio.Config, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 0, Payload: unit.PayloadH264{ @@ -432,8 +77,21 @@ func TestFromStream(t *testing.T) { {3, 4}, }, }) - - case "av1": + }, + }, + { + name: "av1", + medias: []*description.Media{ + { + Formats: []format.Format{&format.AV1{ + PayloadTyp: 96, + }}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.AV1{}}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 2 * int64(i), @@ -443,16 +101,51 @@ func TestFromStream(t *testing.T) { }}, }) } - - case "vp9": + }, + }, + { + name: "vp9", + medias: []*description.Media{ + { + Formats: []format.Format{&format.VP9{ + PayloadTyp: 96, + }}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.VP9{}}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 2 * int64(i), Payload: unit.PayloadVP9{1, 2}, }) } - - case "h265": + }, + }, + { + name: "h265", + medias: []*description.Media{ + { + Formats: []format.Format{ + &format.H265{ + PayloadTyp: 96, + VPS: h265VPS, + SPS: h265SPS, + PPS: h265PPS, + }, + }, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.H265{ + VPS: h265VPS, + SPS: h265SPS, + PPS: h265PPS, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 2 * int64(i), @@ -462,8 +155,22 @@ func TestFromStream(t *testing.T) { }}, }) } - - case "h264": + }, + }, + { + name: "h264", + medias: []*description.Media{ + { + Formats: []format.Format{test.FormatH264}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.H264{ + SPS: test.FormatH264.SPS, + PPS: test.FormatH264.PPS, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 2 * int64(i), @@ -472,8 +179,24 @@ func TestFromStream(t *testing.T) { }, }) } - - case "opus": + }, + }, + { + name: "opus", + medias: []*description.Media{ + { + Formats: []format.Format{&format.Opus{ + PayloadTyp: 96, + ChannelCount: 2, + }}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.Opus{ + ChannelCount: 2, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 5 * int64(i), @@ -482,8 +205,21 @@ func TestFromStream(t *testing.T) { }, }) } - - case "aac": + }, + }, + { + name: "aac", + medias: []*description.Media{ + { + Formats: []format.Format{test.FormatMPEG4Audio}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.MPEG4Audio{ + Config: test.FormatMPEG4Audio.Config, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 5 * int64(i), @@ -492,8 +228,19 @@ func TestFromStream(t *testing.T) { }, }) } - - case "mp3": + }, + }, + { + name: "mp3", + medias: []*description.Media{ + { + Formats: []format.Format{&format.MPEG1Audio{}}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.MPEG1Audio{}}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 5 * int64(i), @@ -504,8 +251,25 @@ func TestFromStream(t *testing.T) { }, }) } - - case "ac-3": + }, + }, + { + name: "ac-3", + medias: []*description.Media{ + { + Formats: []format.Format{&format.AC3{ + SampleRate: 44100, + ChannelCount: 2, + }}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.AC3{ + SampleRate: 48000, + ChannelCount: 1, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 5 * int64(i), @@ -563,8 +327,27 @@ func TestFromStream(t *testing.T) { }, }) } - - case "pcma", "pcmu": + }, + }, + { + name: "pcma", + medias: []*description.Media{ + { + Formats: []format.Format{&format.G711{ + MULaw: false, + SampleRate: 8000, + ChannelCount: 1, + }}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.G711{ + MULaw: false, + ChannelCount: 1, + SampleRate: 8000, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 5 * int64(i), @@ -573,8 +356,56 @@ func TestFromStream(t *testing.T) { }, }) } - - case "lpcm": + }, + }, + { + name: "pcmu", + medias: []*description.Media{ + { + Formats: []format.Format{&format.G711{ + MULaw: true, + SampleRate: 8000, + ChannelCount: 1, + }}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.G711{ + MULaw: true, + ChannelCount: 1, + SampleRate: 8000, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { + for i := range 2 { + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 5 * int64(i), + Payload: unit.PayloadG711{ + 3, 4, + }, + }) + } + }, + }, + { + name: "lpcm", + medias: []*description.Media{ + { + Formats: []format.Format{&format.LPCM{ + BitDepth: 16, + SampleRate: 44100, + ChannelCount: 2, + }}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.LPCM{ + BitDepth: 16, + SampleRate: 44100, + ChannelCount: 2, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { for i := range 2 { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ PTS: 90000 * 5 * int64(i), @@ -583,8 +414,59 @@ func TestFromStream(t *testing.T) { }, }) } - - case "h265 + h264 + vp9 + av1 + opus + aac": + }, + }, + { + name: "h265 + h264 + vp9 + av1 + opus + aac", + medias: []*description.Media{ + { + Formats: []format.Format{&format.H265{}}, + }, + { + Formats: []format.Format{&format.H264{}}, + }, + { + Formats: []format.Format{&format.VP9{}}, + }, + { + Formats: []format.Format{&format.AV1{}}, + }, + { + Formats: []format.Format{&format.Opus{ + PayloadTyp: 96, + ChannelCount: 2, + }}, + }, + { + Formats: []format.Format{&format.MPEG4Audio{ + PayloadTyp: 96, + Config: test.FormatMPEG4Audio.Config, + SizeLength: 13, + IndexLength: 3, + IndexDeltaLength: 3, + }}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.H265{ + VPS: codecprocessor.H265DefaultVPS, + SPS: codecprocessor.H265DefaultSPS, + PPS: codecprocessor.H265DefaultPPS, + }}, + {Codec: &codecs.H264{ + SPS: codecprocessor.H264DefaultSPS, + PPS: codecprocessor.H264DefaultPPS, + }}, + {Codec: &codecs.VP9{}}, + {Codec: &codecs.AV1{}}, + {Codec: &codecs.Opus{ + ChannelCount: 2, + }}, + {Codec: &codecs.MPEG4Audio{ + Config: test.FormatMPEG4Audio.Config, + }}, + }, + writeUnits: func(medias []*description.Media, strm *stream.Stream) { strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ Payload: unit.PayloadH265{ { @@ -641,7 +523,73 @@ func TestFromStream(t *testing.T) { {3, 4}, }, }) + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + medias := tc.medias + + strm := &stream.Stream{ + WriteQueueSize: 512, + RTPMaxPayloadSize: 1450, + Desc: &description.Session{Medias: medias}, + GenerateRTPPackets: true, + Parent: test.NilLogger, } + err := strm.Initialize() + require.NoError(t, err) + + ln, err := net.Listen("tcp", "127.0.0.1:9121") + require.NoError(t, err) + defer ln.Close() + + done := make(chan struct{}) + + go func() { + u, err2 := url.Parse("rtmp://127.0.0.1:9121/stream") + require.NoError(t, err2) + + c := &gortmplib.Client{ + URL: u, + } + err2 = c.Initialize(context.Background()) + require.NoError(t, err2) + + r := &gortmplib.Reader{ + Conn: c, + } + err2 = r.Initialize() + require.NoError(t, err2) + + require.Equal(t, tc.expectedTracks, r.Tracks()) + + close(done) + }() + + nconn, err := ln.Accept() + require.NoError(t, err) + defer nconn.Close() + + conn := &gortmplib.ServerConn{ + RW: nconn, + } + err = conn.Initialize() + require.NoError(t, err) + + err = conn.Accept() + require.NoError(t, err) + + r := &stream.Reader{Parent: test.NilLogger} + + err = FromStream(strm.Desc, r, conn, nconn, 10*time.Second) + require.NoError(t, err) + + strm.AddReader(r) + defer strm.RemoveReader(r) + + tc.writeUnits(medias, strm) <-done }) diff --git a/internal/protocols/rtmp/to_stream.go b/internal/protocols/rtmp/to_stream.go index c98c9c53..53a36017 100644 --- a/internal/protocols/rtmp/to_stream.go +++ b/internal/protocols/rtmp/to_stream.go @@ -5,6 +5,7 @@ import ( "time" "github.com/bluenviron/gortmplib" + "github.com/bluenviron/gortmplib/pkg/codecs" "github.com/bluenviron/gortmplib/pkg/message" "github.com/bluenviron/gortsplib/v5/pkg/description" "github.com/bluenviron/gortsplib/v5/pkg/format" @@ -38,145 +39,199 @@ func ToStream( var medias []*description.Media for _, track := range r.Tracks() { - ctrack := track - - switch ttrack := track.(type) { - case *format.AV1: + switch codec := track.Codec.(type) { + case *codecs.AV1: + forma := &format.AV1{ + PayloadTyp: 96, + } medi := &description.Media{ Type: description.MediaTypeVideo, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataAV1(ttrack, func(pts time.Duration, tu [][]byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataAV1(track, func(pts time.Duration, tu [][]byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadAV1(tu), }) }) - case *format.VP9: + case *codecs.VP9: + forma := &format.VP9{ + PayloadTyp: 96, + } medi := &description.Media{ Type: description.MediaTypeVideo, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataVP9(ttrack, func(pts time.Duration, frame []byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataVP9(track, func(pts time.Duration, frame []byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadVP9(frame), }) }) - case *format.H265: + case *codecs.H265: + forma := &format.H265{ + PayloadTyp: 96, + VPS: codec.VPS, + SPS: codec.SPS, + PPS: codec.PPS, + } medi := &description.Media{ Type: description.MediaTypeVideo, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataH265(ttrack, func(pts time.Duration, _ time.Duration, au [][]byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataH265(track, func(pts time.Duration, _ time.Duration, au [][]byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadH265(au), }) }) - case *format.H264: + case *codecs.H264: + forma := &format.H264{ + PayloadTyp: 96, + SPS: codec.SPS, + PPS: codec.PPS, + PacketizationMode: 1, + } medi := &description.Media{ Type: description.MediaTypeVideo, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataH264(ttrack, func(pts time.Duration, _ time.Duration, au [][]byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataH264(track, func(pts time.Duration, _ time.Duration, au [][]byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadH264(au), }) }) - case *format.Opus: + case *codecs.Opus: + forma := &format.Opus{ + PayloadTyp: 96, + ChannelCount: codec.ChannelCount, + } medi := &description.Media{ Type: description.MediaTypeAudio, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataOpus(ttrack, func(pts time.Duration, packet []byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataOpus(track, func(pts time.Duration, packet []byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadOpus{packet}, }) }) - case *format.MPEG4Audio: + case *codecs.MPEG4Audio: + forma := &format.MPEG4Audio{ + PayloadTyp: 96, + Config: codec.Config, + SizeLength: 13, + IndexLength: 3, + IndexDeltaLength: 3, + } medi := &description.Media{ Type: description.MediaTypeAudio, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataMPEG4Audio(ttrack, func(pts time.Duration, au []byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataMPEG4Audio(track, func(pts time.Duration, au []byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadMPEG4Audio{au}, }) }) - case *format.MPEG1Audio: + case *codecs.MPEG1Audio: + forma := &format.MPEG1Audio{} medi := &description.Media{ Type: description.MediaTypeAudio, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataMPEG1Audio(ttrack, func(pts time.Duration, frame []byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataMPEG1Audio(track, func(pts time.Duration, frame []byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadMPEG1Audio{frame}, }) }) - case *format.AC3: + case *codecs.AC3: + forma := &format.AC3{ + PayloadTyp: 96, + SampleRate: codec.SampleRate, + ChannelCount: codec.ChannelCount, + } medi := &description.Media{ Type: description.MediaTypeAudio, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataAC3(ttrack, func(pts time.Duration, frame []byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataAC3(track, func(pts time.Duration, frame []byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadAC3{frame}, }) }) - case *format.G711: + case *codecs.G711: + forma := &format.G711{ + PayloadTyp: func() uint8 { + switch { + case codec.ChannelCount == 1 && codec.MULaw: + return 0 + case codec.ChannelCount == 1 && !codec.MULaw: + return 8 + default: + return 96 + } + }(), + MULaw: codec.MULaw, + SampleRate: codec.SampleRate, + ChannelCount: codec.ChannelCount, + } medi := &description.Media{ Type: description.MediaTypeAudio, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataG711(ttrack, func(pts time.Duration, samples []byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataG711(track, func(pts time.Duration, samples []byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadG711(samples), }) }) - case *format.LPCM: + case *codecs.LPCM: + forma := &format.LPCM{ + PayloadTyp: 96, + BitDepth: codec.BitDepth, + SampleRate: codec.SampleRate, + ChannelCount: codec.ChannelCount, + } medi := &description.Media{ Type: description.MediaTypeAudio, - Formats: []format.Format{ctrack}, + Formats: []format.Format{forma}, } medias = append(medias, medi) - r.OnDataLPCM(ttrack, func(pts time.Duration, samples []byte) { - (*strm).WriteUnit(medi, ctrack, &unit.Unit{ - PTS: durationToTimestamp(pts, ctrack.ClockRate()), + r.OnDataLPCM(track, func(pts time.Duration, samples []byte) { + (*strm).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), Payload: unit.PayloadLPCM(samples), }) }) diff --git a/internal/protocols/webrtc/from_stream.go b/internal/protocols/webrtc/from_stream.go index 33113bc4..518fb5e1 100644 --- a/internal/protocols/webrtc/from_stream.go +++ b/internal/protocols/webrtc/from_stream.go @@ -4,6 +4,7 @@ import ( "crypto/rand" "errors" "fmt" + "slices" "time" "github.com/bluenviron/gortsplib/v5/pkg/description" @@ -666,10 +667,12 @@ func FromStream( return errNoSupportedCodecsFrom } + setuppedFormats := r.Formats() + n := 1 for _, media := range desc.Medias { for _, forma := range media.Formats { - if forma != videoFormat && forma != audioFormat { + if !slices.Contains(setuppedFormats, forma) { r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, forma.Codec()) } n++ diff --git a/internal/servers/rtmp/server_test.go b/internal/servers/rtmp/server_test.go index 2ae60f5a..d6abebbd 100644 --- a/internal/servers/rtmp/server_test.go +++ b/internal/servers/rtmp/server_test.go @@ -9,8 +9,8 @@ import ( "time" "github.com/bluenviron/gortmplib" + "github.com/bluenviron/gortmplib/pkg/codecs" "github.com/bluenviron/gortsplib/v5/pkg/description" - "github.com/bluenviron/gortsplib/v5/pkg/format" "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/defs" "github.com/bluenviron/mediamtx/internal/externalcmd" @@ -158,14 +158,22 @@ func TestServerPublish(t *testing.T) { defer conn.Close() w := &gortmplib.Writer{ - Conn: conn, - Tracks: []format.Format{test.FormatH264, test.FormatMPEG4Audio}, + Conn: conn, + Tracks: []*gortmplib.Track{ + {Codec: &codecs.H264{ + SPS: test.FormatH264.SPS, + PPS: test.FormatH264.PPS, + }}, + {Codec: &codecs.MPEG4Audio{ + Config: test.FormatMPEG4Audio.Config, + }}, + }, } err = w.Initialize() require.NoError(t, err) err = w.WriteH264( - test.FormatH264, + w.Tracks[0], 2*time.Second, 2*time.Second, [][]byte{ {5, 2, 3, 4}, }) @@ -292,9 +300,11 @@ func TestServerRead(t *testing.T) { require.NoError(t, err) tracks := r.Tracks() - require.Equal(t, []format.Format{test.FormatH264}, tracks) + require.Len(t, tracks, 1) + _, ok := tracks[0].Codec.(*codecs.H264) + require.True(t, ok) - r.OnDataH264(tracks[0].(*format.H264), func(_ time.Duration, _ time.Duration, au [][]byte) { + r.OnDataH264(tracks[0], func(_ time.Duration, _ time.Duration, au [][]byte) { require.Equal(t, [][]byte{ test.FormatH264.SPS, test.FormatH264.PPS, diff --git a/internal/staticsources/rtmp/source_test.go b/internal/staticsources/rtmp/source_test.go index ca3ef33c..633275f4 100644 --- a/internal/staticsources/rtmp/source_test.go +++ b/internal/staticsources/rtmp/source_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/bluenviron/gortmplib" - "github.com/bluenviron/gortsplib/v5/pkg/format" + "github.com/bluenviron/gortmplib/pkg/codecs" "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/defs" "github.com/bluenviron/mediamtx/internal/test" @@ -118,13 +118,21 @@ func TestSource(t *testing.T) { require.NoError(t, err) w := &gortmplib.Writer{ - Conn: conn, - Tracks: []format.Format{test.FormatH264, test.FormatMPEG4Audio}, + Conn: conn, + Tracks: []*gortmplib.Track{ + {Codec: &codecs.H264{ + SPS: test.FormatH264.SPS, + PPS: test.FormatH264.PPS, + }}, + {Codec: &codecs.MPEG4Audio{ + Config: test.FormatMPEG4Audio.Config, + }}, + }, } err = w.Initialize() require.NoError(t, err) - err = w.WriteMPEG4Audio(test.FormatMPEG4Audio, 2*time.Second, []byte{5, 2, 3, 4}) + err = w.WriteMPEG4Audio(w.Tracks[1], 2*time.Second, []byte{5, 2, 3, 4}) require.NoError(t, err) break