update gortsplib

This commit is contained in:
aler9
2022-01-30 17:36:42 +01:00
parent 9bc364fa21
commit 2bfdcc7d89
23 changed files with 235 additions and 280 deletions

4
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/aler9/rtsp-simple-server
go 1.17 go 1.17
require ( require (
github.com/aler9/gortsplib v0.0.0-20220130132715-cd0db96a5d41 github.com/aler9/gortsplib v0.0.0-20220130155047-8c02b12955f8
github.com/asticode/go-astits v1.10.0 github.com/asticode/go-astits v1.10.0
github.com/fsnotify/fsnotify v1.4.9 github.com/fsnotify/fsnotify v1.4.9
github.com/gin-gonic/gin v1.7.2 github.com/gin-gonic/gin v1.7.2
@@ -12,7 +12,6 @@ require (
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/notedit/rtmp v0.0.2 github.com/notedit/rtmp v0.0.2
github.com/pion/rtp v1.6.2 github.com/pion/rtp v1.6.2
github.com/pion/sdp/v3 v3.0.2
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.6.1
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/alecthomas/kingpin.v2 v2.2.6
@@ -37,6 +36,7 @@ require (
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/pion/randutil v0.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.4 // indirect github.com/pion/rtcp v1.2.4 // indirect
github.com/pion/sdp/v3 v3.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect github.com/ugorji/go/codec v1.1.7 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect

4
go.sum
View File

@@ -2,8 +2,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/aler9/gortsplib v0.0.0-20220130132715-cd0db96a5d41 h1:Ib0hUXSsNYBWeSYAFz4n76qJesJ/i3IpEThnmH6uY38= github.com/aler9/gortsplib v0.0.0-20220130155047-8c02b12955f8 h1:kGq65HZMjRo2ay0eJO/MxkEhD2DcDTkcX4qCgsjUkSs=
github.com/aler9/gortsplib v0.0.0-20220130132715-cd0db96a5d41/go.mod h1:fyQrQyHo8QvdR/h357tkv1g36VesZlzEPsdAu2VrHHc= github.com/aler9/gortsplib v0.0.0-20220130155047-8c02b12955f8/go.mod h1:fyQrQyHo8QvdR/h357tkv1g36VesZlzEPsdAu2VrHHc=
github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927 h1:95mXJ5fUCYpBRdSOnLAQAdJHHKxxxJrVCiaqDi965YQ= github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927 h1:95mXJ5fUCYpBRdSOnLAQAdJHHKxxxJrVCiaqDi965YQ=
github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927/go.mod h1:vzuE21rowz+lT1NGsWbreIvYulgBpCGnQyeTyFblUHc= github.com/aler9/rtmp v0.0.0-20210403095203-3be4a5535927/go.mod h1:vzuE21rowz+lT1NGsWbreIvYulgBpCGnQyeTyFblUHc=
github.com/asticode/go-astikit v0.20.0 h1:+7N+J4E4lWx2QOkRdOf6DafWJMv6O4RRfgClwQokrH8= github.com/asticode/go-astikit v0.20.0 h1:+7N+J4E4lWx2QOkRdOf6DafWJMv6O4RRfgClwQokrH8=

View File

@@ -186,7 +186,7 @@ func TestAPIPathsList(t *testing.T) {
require.Equal(t, true, ok) require.Equal(t, true, ok)
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
func() { func() {
@@ -251,7 +251,7 @@ func TestAPIList(t *testing.T) {
defer p.close() defer p.close()
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
switch ca { switch ca {
@@ -382,7 +382,7 @@ func TestAPIKick(t *testing.T) {
defer p.close() defer p.close()
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
switch ca { switch ca {

View File

@@ -1,8 +1,11 @@
package core package core
import ( import (
"bufio"
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@@ -12,7 +15,7 @@ import (
"github.com/aler9/gortsplib" "github.com/aler9/gortsplib"
"github.com/aler9/gortsplib/pkg/base" "github.com/aler9/gortsplib/pkg/base"
psdp "github.com/pion/sdp/v3" "github.com/aler9/gortsplib/pkg/headers"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -160,33 +163,61 @@ func TestCorePathAutoDeletion(t *testing.T) {
defer p.close() defer p.close()
func() { func() {
c := gortsplib.Client{} conn, err := net.Dial("tcp", "localhost:8554")
err := c.Start("rtsp", "localhost:8554")
require.NoError(t, err) require.NoError(t, err)
defer c.Close() defer conn.Close()
br := bufio.NewReader(conn)
if ca == "describe" { if ca == "describe" {
ur, err := base.ParseURL("rtsp://localhost:8554/mypath") u, err := base.ParseURL("rtsp://localhost:8554/mypath")
require.NoError(t, err) require.NoError(t, err)
_, _, _, err = c.Describe(ur) var bb bytes.Buffer
require.EqualError(t, err, "bad status code: 404 (Not Found)") base.Request{
Method: base.Describe,
URL: u,
Header: base.Header{
"CSeq": base.HeaderValue{"1"},
},
}.Write(&bb)
_, err = conn.Write(bb.Bytes())
require.NoError(t, err)
var res base.Response
err = res.Read(br)
require.NoError(t, err)
require.Equal(t, base.StatusNotFound, res.StatusCode)
} else { } else {
baseURL, err := base.ParseURL("rtsp://localhost:8554/mypath/") u, err := base.ParseURL("rtsp://localhost:8554/mypath/trackID=0")
require.NoError(t, err) require.NoError(t, err)
track, err := gortsplib.NewTrackH264(96, var bb bytes.Buffer
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) base.Request{
Method: base.Setup,
URL: u,
Header: base.Header{
"CSeq": base.HeaderValue{"1"},
"Transport": headers.Transport{
Mode: func() *headers.TransportMode {
v := headers.TransportModePlay
return &v
}(),
Delivery: func() *headers.TransportDelivery {
v := headers.TransportDeliveryUnicast
return &v
}(),
Protocol: headers.TransportProtocolUDP,
ClientPorts: &[2]int{35466, 35467},
}.Write(),
},
}.Write(&bb)
_, err = conn.Write(bb.Bytes())
require.NoError(t, err) require.NoError(t, err)
track.Media.Attributes = append(track.Media.Attributes, psdp.Attribute{ var res base.Response
Key: "control", err = res.Read(br)
Value: "trackID=0", require.NoError(t, err)
}) require.Equal(t, base.StatusNotFound, res.StatusCode)
_, err = c.Setup(true, track, baseURL, 0, 0)
require.EqualError(t, err, "bad status code: 404 (Not Found)")
} }
}() }()
@@ -219,7 +250,7 @@ func main() {
} }
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -270,35 +301,59 @@ func main() {
defer p1.close() defer p1.close()
func() { func() {
c := gortsplib.Client{} conn, err := net.Dial("tcp", "localhost:8554")
err := c.Start("rtsp", "localhost:8554")
require.NoError(t, err) require.NoError(t, err)
defer c.Close() defer conn.Close()
br := bufio.NewReader(conn)
if ca == "describe" || ca == "describe and setup" { if ca == "describe" || ca == "describe and setup" {
ur, err := base.ParseURL("rtsp://localhost:8554/ondemand") u, err := base.ParseURL("rtsp://localhost:8554/ondemand")
require.NoError(t, err) require.NoError(t, err)
_, _, _, err = c.Describe(ur) var bb bytes.Buffer
base.Request{
Method: base.Describe,
URL: u,
Header: base.Header{
"CSeq": base.HeaderValue{"1"},
},
}.Write(&bb)
_, err = conn.Write(bb.Bytes())
require.NoError(t, err) require.NoError(t, err)
var res base.Response
err = res.Read(br)
require.NoError(t, err)
require.Equal(t, base.StatusOK, res.StatusCode)
} }
if ca == "setup" || ca == "describe and setup" { if ca == "setup" || ca == "describe and setup" {
baseURL, err := base.ParseURL("rtsp://localhost:8554/ondemand/") u, err := base.ParseURL("rtsp://localhost:8554/ondemand/trackID=0")
require.NoError(t, err) require.NoError(t, err)
track, err := gortsplib.NewTrackH264(96, var bb bytes.Buffer
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) base.Request{
Method: base.Setup,
URL: u,
Header: base.Header{
"CSeq": base.HeaderValue{"2"},
"Transport": headers.Transport{
Mode: func() *headers.TransportMode {
v := headers.TransportModePlay
return &v
}(),
Protocol: headers.TransportProtocolTCP,
InterleavedIDs: &[2]int{0, 1},
}.Write(),
},
}.Write(&bb)
_, err = conn.Write(bb.Bytes())
require.NoError(t, err) require.NoError(t, err)
track.Media.Attributes = append(track.Media.Attributes, psdp.Attribute{ var res base.Response
Key: "control", err = res.Read(br)
Value: "trackID=0",
})
_, err = c.Setup(true, track, baseURL, 0, 0)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, base.StatusOK, res.StatusCode)
} }
}() }()
@@ -326,7 +381,7 @@ func TestCorePathRunOnReady(t *testing.T) {
require.Equal(t, true, ok) require.Equal(t, true, ok)
defer p.close() defer p.close()
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
c := gortsplib.Client{} c := gortsplib.Client{}
@@ -360,7 +415,7 @@ func TestCoreHotReloading(t *testing.T) {
func() { func() {
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
c := gortsplib.Client{} c := gortsplib.Client{}
@@ -380,7 +435,7 @@ func TestCoreHotReloading(t *testing.T) {
func() { func() {
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
conn := gortsplib.Client{} conn := gortsplib.Client{}

View File

@@ -276,37 +276,32 @@ func (m *hlsMuxer) runInner(innerCtx context.Context, innerReady chan struct{})
m.path.onReaderRemove(pathReaderRemoveReq{author: m}) m.path.onReaderRemove(pathReaderRemoveReq{author: m})
}() }()
var videoTrack *gortsplib.Track var videoTrack *gortsplib.TrackH264
videoTrackID := -1 videoTrackID := -1
var h264Decoder *rtph264.Decoder var h264Decoder *rtph264.Decoder
var audioTrack *gortsplib.Track var audioTrack *gortsplib.TrackAAC
audioTrackID := -1 audioTrackID := -1
var aacDecoder *rtpaac.Decoder var aacDecoder *rtpaac.Decoder
for i, t := range res.stream.tracks() { for i, track := range res.stream.tracks() {
if t.IsH264() { switch tt := track.(type) {
case *gortsplib.TrackH264:
if videoTrack != nil { if videoTrack != nil {
return fmt.Errorf("can't read track %d with HLS: too many tracks", i+1) return fmt.Errorf("can't encode track %d with HLS: too many tracks", i+1)
} }
videoTrack = t videoTrack = tt
videoTrackID = i videoTrackID = i
h264Decoder = rtph264.NewDecoder() h264Decoder = rtph264.NewDecoder()
} else if t.IsAAC() {
case *gortsplib.TrackAAC:
if audioTrack != nil { if audioTrack != nil {
return fmt.Errorf("can't read track %d with HLS: too many tracks", i+1) return fmt.Errorf("can't encode track %d with HLS: too many tracks", i+1)
} }
audioTrack = t audioTrack = tt
audioTrackID = i audioTrackID = i
aacDecoder = rtpaac.NewDecoder(track.ClockRate())
conf, err := t.ExtractConfigAAC()
if err != nil {
return err
}
aacDecoder = rtpaac.NewDecoder(conf.SampleRate)
} }
} }

View File

@@ -99,7 +99,7 @@ func (s *hlsSource) runInner() bool {
} }
}() }()
onTracks := func(videoTrack *gortsplib.Track, audioTrack *gortsplib.Track) error { onTracks := func(videoTrack gortsplib.Track, audioTrack gortsplib.Track) error {
var tracks gortsplib.Tracks var tracks gortsplib.Tracks
if videoTrack != nil { if videoTrack != nil {

View File

@@ -30,7 +30,7 @@ func TestMetrics(t *testing.T) {
defer p.close() defer p.close()
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
source := gortsplib.Client{} source := gortsplib.Client{}

View File

@@ -249,32 +249,33 @@ func (c *rtmpConn) runRead(ctx context.Context) error {
c.state = gortsplib.ServerSessionStateRead c.state = gortsplib.ServerSessionStateRead
c.stateMutex.Unlock() c.stateMutex.Unlock()
var videoTrack *gortsplib.Track var videoTrack *gortsplib.TrackH264
videoTrackID := -1 videoTrackID := -1
var h264Decoder *rtph264.Decoder var h264Decoder *rtph264.Decoder
var audioTrack *gortsplib.Track var audioTrack *gortsplib.TrackAAC
audioTrackID := -1 audioTrackID := -1
var audioClockRate int var audioClockRate int
var aacDecoder *rtpaac.Decoder var aacDecoder *rtpaac.Decoder
for i, t := range res.stream.tracks() { for i, track := range res.stream.tracks() {
if t.IsH264() { switch tt := track.(type) {
case *gortsplib.TrackH264:
if videoTrack != nil { if videoTrack != nil {
return fmt.Errorf("can't read track %d with RTMP: too many tracks", i+1) return fmt.Errorf("can't read track %d with RTMP: too many tracks", i+1)
} }
videoTrack = t videoTrack = tt
videoTrackID = i videoTrackID = i
h264Decoder = rtph264.NewDecoder() h264Decoder = rtph264.NewDecoder()
} else if t.IsAAC() {
case *gortsplib.TrackAAC:
if audioTrack != nil { if audioTrack != nil {
return fmt.Errorf("can't read track %d with RTMP: too many tracks", i+1) return fmt.Errorf("can't read track %d with RTMP: too many tracks", i+1)
} }
audioTrack = t audioTrack = tt
audioTrackID = i audioTrackID = i
audioClockRate, _ = audioTrack.ClockRate() aacDecoder = rtpaac.NewDecoder(track.ClockRate())
aacDecoder = rtpaac.NewDecoder(audioClockRate)
} }
} }
@@ -283,7 +284,10 @@ func (c *rtmpConn) runRead(ctx context.Context) error {
} }
c.conn.SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout))) c.conn.SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout)))
c.conn.WriteMetadata(videoTrack, audioTrack) err := c.conn.WriteMetadata(videoTrack, audioTrack)
if err != nil {
return err
}
c.ringBuffer = ringbuffer.New(uint64(c.readBufferCount)) c.ringBuffer = ringbuffer.New(uint64(c.readBufferCount))
@@ -456,8 +460,7 @@ func (c *rtmpConn) runPublish(ctx context.Context) error {
var aacEncoder *rtpaac.Encoder var aacEncoder *rtpaac.Encoder
if audioTrack != nil { if audioTrack != nil {
clockRate, _ := audioTrack.ClockRate() aacEncoder = rtpaac.NewEncoder(96, audioTrack.ClockRate(), nil, nil, nil)
aacEncoder = rtpaac.NewEncoder(96, clockRate, nil, nil, nil)
audioTrackID = len(tracks) audioTrackID = len(tracks)
tracks = append(tracks, audioTrack) tracks = append(tracks, audioTrack)
} }

View File

@@ -142,8 +142,7 @@ func (s *rtmpSource) runInner() bool {
var aacEncoder *rtpaac.Encoder var aacEncoder *rtpaac.Encoder
if audioTrack != nil { if audioTrack != nil {
clockRate, _ := audioTrack.ClockRate() aacEncoder = rtpaac.NewEncoder(96, audioTrack.ClockRate(), nil, nil, nil)
aacEncoder = rtpaac.NewEncoder(96, clockRate, nil, nil, nil)
audioTrackID = len(tracks) audioTrackID = len(tracks)
tracks = append(tracks, audioTrack) tracks = append(tracks, audioTrack)
} }

View File

@@ -230,7 +230,7 @@ func TestRTSPServerAuth(t *testing.T) {
} }
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
source := gortsplib.Client{} source := gortsplib.Client{}
@@ -268,7 +268,7 @@ func TestRTSPServerAuth(t *testing.T) {
defer p.close() defer p.close()
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
source := gortsplib.Client{} source := gortsplib.Client{}
@@ -314,7 +314,7 @@ func TestRTSPServerAuthFail(t *testing.T) {
defer p.close() defer p.close()
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
c := gortsplib.Client{} c := gortsplib.Client{}
@@ -377,7 +377,7 @@ func TestRTSPServerAuthFail(t *testing.T) {
defer p.close() defer p.close()
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
c := gortsplib.Client{} c := gortsplib.Client{}
@@ -401,7 +401,7 @@ func TestRTSPServerAuthFail(t *testing.T) {
defer a.close() defer a.close()
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
c := gortsplib.Client{} c := gortsplib.Client{}
@@ -434,7 +434,7 @@ func TestRTSPServerPublisherOverride(t *testing.T) {
defer p.close() defer p.close()
track, err := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96,
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x01, 0x02, 0x03, 0x04}}) []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
require.NoError(t, err) require.NoError(t, err)
s1 := gortsplib.Client{} s1 := gortsplib.Client{}

View File

@@ -41,10 +41,10 @@ type rtspSession struct {
path *path path *path
state gortsplib.ServerSessionState state gortsplib.ServerSessionState
stateMutex sync.Mutex stateMutex sync.Mutex
setuppedTracks map[int]*gortsplib.Track // read setuppedTracks map[int]gortsplib.Track // read
onReadCmd *externalcmd.Cmd // read onReadCmd *externalcmd.Cmd // read
announcedTracks gortsplib.Tracks // publish announcedTracks gortsplib.Tracks // publish
stream *stream // publish stream *stream // publish
} }
func newRTSPSession( func newRTSPSession(
@@ -126,30 +126,11 @@ func (s *rtspSession) onClose(err error) {
// onAnnounce is called by rtspServer. // onAnnounce is called by rtspServer.
func (s *rtspSession) onAnnounce(c *rtspConn, ctx *gortsplib.ServerHandlerOnAnnounceCtx) (*base.Response, error) { func (s *rtspSession) onAnnounce(c *rtspConn, ctx *gortsplib.ServerHandlerOnAnnounceCtx) (*base.Response, error) {
for i, track := range ctx.Tracks { for i, track := range ctx.Tracks {
if track.IsH264() { if th264, ok := track.(*gortsplib.TrackH264); ok {
_, err := track.ExtractConfigH264() if th264.SPS() == nil || th264.PPS() == nil {
if err != nil {
return &base.Response{ return &base.Response{
StatusCode: base.StatusBadRequest, StatusCode: base.StatusBadRequest,
}, fmt.Errorf("H264 track %d is not valid: %v", i+1, err) }, fmt.Errorf("track %d can't be used: H264 SPS or PPS not provided into the SDP", i)
}
}
if track.IsAAC() {
_, err := track.ExtractConfigAAC()
if err != nil {
return &base.Response{
StatusCode: base.StatusBadRequest,
}, fmt.Errorf("AAC track %d is not valid: %v", i+1, err)
}
}
if track.IsOpus() {
_, err := track.ExtractConfigOpus()
if err != nil {
return &base.Response{
StatusCode: base.StatusBadRequest,
}, fmt.Errorf("Opus track %d is not valid: %v", i+1, err)
} }
} }
} }
@@ -257,7 +238,7 @@ func (s *rtspSession) onSetup(c *rtspConn, ctx *gortsplib.ServerHandlerOnSetupCt
} }
if s.setuppedTracks == nil { if s.setuppedTracks == nil {
s.setuppedTracks = make(map[int]*gortsplib.Track) s.setuppedTracks = make(map[int]gortsplib.Track)
} }
s.setuppedTracks[ctx.TrackID] = res.stream.tracks()[ctx.TrackID] s.setuppedTracks[ctx.TrackID] = res.stream.tracks()[ctx.TrackID]

View File

@@ -239,20 +239,21 @@ func (s *rtspSource) runInner() bool {
} }
func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortsplib.Tracks) error { func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortsplib.Tracks) error {
h264TrackID := func() int { h264Track, h264TrackID := func() (*gortsplib.TrackH264, int) {
for i, t := range tracks { for i, t := range tracks {
if t.IsH264() { if th264, ok := t.(*gortsplib.TrackH264); ok {
return i if th264.SPS() == nil {
return th264, i
}
} }
} }
return -1 return nil, -1
}() }()
if h264TrackID < 0 { if h264TrackID < 0 {
return nil return nil
} }
_, err := tracks[h264TrackID].ExtractConfigH264() if h264Track.SPS() != nil && h264Track.PPS() != nil {
if err == nil {
return nil return nil
} }
@@ -261,7 +262,6 @@ func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortspl
var streamMutex sync.RWMutex var streamMutex sync.RWMutex
var stream *stream var stream *stream
var payloadType uint8
decoder := rtph264.NewDecoder() decoder := rtph264.NewDecoder()
var sps []byte var sps []byte
var pps []byte var pps []byte
@@ -293,8 +293,6 @@ func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortspl
return return
} }
payloadType = pkt.Header.PayloadType
for _, nalu := range nalus { for _, nalu := range nalus {
typ := h264.NALUType(nalu[0] & 0x1F) typ := h264.NALUType(nalu[0] & 0x1F)
switch typ { switch typ {
@@ -325,7 +323,7 @@ func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortspl
} }
} }
_, err = c.Play(nil) _, err := c.Play(nil)
if err != nil { if err != nil {
return err return err
} }
@@ -348,15 +346,8 @@ func (s *rtspSource) handleMissingH264Params(c *gortsplib.Client, tracks gortspl
case <-paramsReceived: case <-paramsReceived:
s.log(logger.Info, "H264 parameters extracted") s.log(logger.Info, "H264 parameters extracted")
track, err := gortsplib.NewTrackH264(payloadType, &gortsplib.TrackConfigH264{ h264Track.SetSPS(sps)
SPS: sps, h264Track.SetPPS(pps)
PPS: pps,
})
if err != nil {
return err
}
tracks[h264TrackID] = track
res := s.parent.onSourceStaticSetReady(pathSourceStaticSetReadyReq{ res := s.parent.onSourceStaticSetReady(pathSourceStaticSetReadyReq{
source: s, source: s,

View File

@@ -11,7 +11,6 @@ import (
"github.com/aler9/gortsplib/pkg/base" "github.com/aler9/gortsplib/pkg/base"
"github.com/aler9/gortsplib/pkg/rtph264" "github.com/aler9/gortsplib/pkg/rtph264"
"github.com/pion/rtp" "github.com/pion/rtp"
psdp "github.com/pion/sdp/v3"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -41,8 +40,7 @@ func TestRTSPSource(t *testing.T) {
"tls", "tls",
} { } {
t.Run(source, func(t *testing.T) { t.Run(source, func(t *testing.T) {
track, _ := gortsplib.NewTrackH264(96, track, _ := gortsplib.NewTrackH264(96, []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x05, 0x06}, nil)
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x05, 0x06}})
stream := gortsplib.NewServerStream(gortsplib.Tracks{track}) stream := gortsplib.NewServerStream(gortsplib.Tracks{track})
var authValidator *auth.Validator var authValidator *auth.Validator
@@ -151,8 +149,7 @@ func TestRTSPSource(t *testing.T) {
} }
func TestRTSPSourceNoPassword(t *testing.T) { func TestRTSPSourceNoPassword(t *testing.T) {
track, _ := gortsplib.NewTrackH264(96, track, _ := gortsplib.NewTrackH264(96, []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x05, 0x06}, nil)
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x05, 0x06}})
stream := gortsplib.NewServerStream(gortsplib.Tracks{track}) stream := gortsplib.NewServerStream(gortsplib.Tracks{track})
var authValidator *auth.Validator var authValidator *auth.Validator
done := make(chan struct{}) done := make(chan struct{})
@@ -210,15 +207,8 @@ func TestRTSPSourceNoPassword(t *testing.T) {
} }
func TestRTSPSourceMissingH264Params(t *testing.T) { func TestRTSPSourceMissingH264Params(t *testing.T) {
track, _ := gortsplib.NewTrackH264(96, track, err := gortsplib.NewTrackH264(96, nil, nil, nil)
&gortsplib.TrackConfigH264{SPS: []byte{0x01, 0x02, 0x03, 0x04}, PPS: []byte{0x05, 0x06}}) require.NoError(t, err)
var newattrs []psdp.Attribute
for _, attr := range track.Media.Attributes {
if attr.Key != "fmtp" {
newattrs = append(newattrs, attr)
}
}
track.Media.Attributes = newattrs
stream := gortsplib.NewServerStream(gortsplib.Tracks{track}) stream := gortsplib.NewServerStream(gortsplib.Tracks{track})
@@ -275,7 +265,7 @@ func TestRTSPSourceMissingH264Params(t *testing.T) {
}, },
RTSPAddress: "127.0.0.1:8555", RTSPAddress: "127.0.0.1:8555",
} }
err := s.Start() err = s.Start()
require.NoError(t, err) require.NoError(t, err)
defer s.Wait() defer s.Wait()
defer s.Close() defer s.Close()
@@ -314,10 +304,10 @@ func TestRTSPSourceMissingH264Params(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer c.Close() defer c.Close()
conf, err := c.Tracks()[0].ExtractConfigH264() h264Track, ok := c.Tracks()[0].(*gortsplib.TrackH264)
require.NoError(t, err) require.Equal(t, true, ok)
require.Equal(t, []byte{7, 1, 2, 3}, conf.SPS) require.Equal(t, []byte{7, 1, 2, 3}, h264Track.SPS())
require.Equal(t, []byte{8}, conf.PPS) require.Equal(t, []byte{8}, h264Track.PPS())
<-received <-received
} }

View File

@@ -134,7 +134,7 @@ type clientVideoProcessorData struct {
type clientVideoProcessor struct { type clientVideoProcessor struct {
ctx context.Context ctx context.Context
onTrack func(*gortsplib.Track) error onTrack func(gortsplib.Track) error
onPacket func([]byte) onPacket func([]byte)
queue chan clientVideoProcessorData queue chan clientVideoProcessorData
@@ -146,7 +146,7 @@ type clientVideoProcessor struct {
func newClientVideoProcessor( func newClientVideoProcessor(
ctx context.Context, ctx context.Context,
onTrack func(*gortsplib.Track) error, onTrack func(gortsplib.Track) error,
onPacket func([]byte), onPacket func([]byte),
) *clientVideoProcessor { ) *clientVideoProcessor {
p := &clientVideoProcessor{ p := &clientVideoProcessor{
@@ -203,7 +203,7 @@ func (p *clientVideoProcessor) doProcess(
p.sps = append([]byte(nil), nalu...) p.sps = append([]byte(nil), nalu...)
if p.encoder == nil && p.pps != nil { if p.encoder == nil && p.pps != nil {
err := p.initializeTrack() err := p.initializeEncoder()
if err != nil { if err != nil {
return err return err
} }
@@ -218,7 +218,7 @@ func (p *clientVideoProcessor) doProcess(
p.pps = append([]byte(nil), nalu...) p.pps = append([]byte(nil), nalu...)
if p.encoder == nil && p.sps != nil { if p.encoder == nil && p.sps != nil {
err := p.initializeTrack() err := p.initializeEncoder()
if err != nil { if err != nil {
return err return err
} }
@@ -272,8 +272,8 @@ func (p *clientVideoProcessor) process(
p.queue <- clientVideoProcessorData{data, pts, dts} p.queue <- clientVideoProcessorData{data, pts, dts}
} }
func (p *clientVideoProcessor) initializeTrack() error { func (p *clientVideoProcessor) initializeEncoder() error {
track, err := gortsplib.NewTrackH264(96, &gortsplib.TrackConfigH264{SPS: p.sps, PPS: p.pps}) track, err := gortsplib.NewTrackH264(96, p.sps, p.pps, nil)
if err != nil { if err != nil {
return err return err
} }
@@ -290,18 +290,17 @@ type clientAudioProcessorData struct {
type clientAudioProcessor struct { type clientAudioProcessor struct {
ctx context.Context ctx context.Context
onTrack func(*gortsplib.Track) error onTrack func(gortsplib.Track) error
onPacket func([]byte) onPacket func([]byte)
queue chan clientAudioProcessorData queue chan clientAudioProcessorData
conf *gortsplib.TrackConfigAAC
encoder *rtpaac.Encoder encoder *rtpaac.Encoder
clockStartRTC time.Time clockStartRTC time.Time
} }
func newClientAudioProcessor( func newClientAudioProcessor(
ctx context.Context, ctx context.Context,
onTrack func(*gortsplib.Track) error, onTrack func(gortsplib.Track) error,
onPacket func([]byte), onPacket func([]byte),
) *clientAudioProcessor { ) *clientAudioProcessor {
p := &clientAudioProcessor{ p := &clientAudioProcessor{
@@ -354,18 +353,17 @@ func (p *clientAudioProcessor) doProcess(
} }
} }
if p.conf == nil { if p.encoder == nil {
p.conf = &gortsplib.TrackConfigAAC{ track, err := gortsplib.NewTrackAAC(97, pkt.Type, pkt.SampleRate, pkt.ChannelCount, nil)
Type: pkt.Type, if err != nil {
SampleRate: pkt.SampleRate, return err
ChannelCount: pkt.ChannelCount,
} }
if p.encoder == nil { p.encoder = rtpaac.NewEncoder(97, track.ClockRate(), nil, nil, nil)
err := p.initializeTrack()
if err != nil { err = p.onTrack(track)
return err if err != nil {
} return err
} }
} }
@@ -373,10 +371,6 @@ func (p *clientAudioProcessor) doProcess(
pktPts += 1000 * time.Second / time.Duration(pkt.SampleRate) pktPts += 1000 * time.Second / time.Duration(pkt.SampleRate)
} }
if p.encoder == nil {
return nil
}
pkts, err := p.encoder.Encode(aus, pts) pkts, err := p.encoder.Encode(aus, pts)
if err != nil { if err != nil {
return fmt.Errorf("error while encoding AAC: %v", err) return fmt.Errorf("error while encoding AAC: %v", err)
@@ -407,17 +401,6 @@ func (p *clientAudioProcessor) process(
} }
} }
func (p *clientAudioProcessor) initializeTrack() error {
track, err := gortsplib.NewTrackAAC(97, p.conf)
if err != nil {
return err
}
p.encoder = rtpaac.NewEncoder(97, p.conf.SampleRate, nil, nil, nil)
return p.onTrack(track)
}
// ClientParent is the parent of a Client. // ClientParent is the parent of a Client.
type ClientParent interface { type ClientParent interface {
Log(level logger.Level, format string, args ...interface{}) Log(level logger.Level, format string, args ...interface{})
@@ -425,7 +408,7 @@ type ClientParent interface {
// Client is a HLS client. // Client is a HLS client.
type Client struct { type Client struct {
onTracks func(*gortsplib.Track, *gortsplib.Track) error onTracks func(gortsplib.Track, gortsplib.Track) error
onPacket func(bool, []byte) onPacket func(bool, []byte)
parent ClientParent parent ClientParent
@@ -447,8 +430,8 @@ type Client struct {
audioProc *clientAudioProcessor audioProc *clientAudioProcessor
tracksMutex sync.RWMutex tracksMutex sync.RWMutex
videoTrack *gortsplib.Track videoTrack gortsplib.Track
audioTrack *gortsplib.Track audioTrack gortsplib.Track
// in // in
allocateProcs chan clientAllocateProcsReq allocateProcs chan clientAllocateProcsReq
@@ -461,7 +444,7 @@ type Client struct {
func NewClient( func NewClient(
primaryPlaylistURLStr string, primaryPlaylistURLStr string,
fingerprint string, fingerprint string,
onTracks func(*gortsplib.Track, *gortsplib.Track) error, onTracks func(gortsplib.Track, gortsplib.Track) error,
onPacket func(bool, []byte), onPacket func(bool, []byte),
parent ClientParent, parent ClientParent,
) (*Client, error) { ) (*Client, error) {
@@ -896,33 +879,33 @@ func (c *Client) processSegment(innerCtx context.Context, byts []byte) error {
} }
} }
func (c *Client) onVideoTrack(track *gortsplib.Track) error { func (c *Client) onVideoTrack(track gortsplib.Track) error {
c.tracksMutex.Lock() c.tracksMutex.Lock()
defer c.tracksMutex.Unlock() defer c.tracksMutex.Unlock()
c.videoTrack = track c.videoTrack = track
if c.audioPID == nil || c.audioTrack != nil { if c.audioPID == nil || c.audioTrack != nil {
return c.initializeTracks() return c.initializeEncoders()
} }
return nil return nil
} }
func (c *Client) onAudioTrack(track *gortsplib.Track) error { func (c *Client) onAudioTrack(track gortsplib.Track) error {
c.tracksMutex.Lock() c.tracksMutex.Lock()
defer c.tracksMutex.Unlock() defer c.tracksMutex.Unlock()
c.audioTrack = track c.audioTrack = track
if c.videoPID == nil || c.videoTrack != nil { if c.videoPID == nil || c.videoTrack != nil {
return c.initializeTracks() return c.initializeEncoders()
} }
return nil return nil
} }
func (c *Client) initializeTracks() error { func (c *Client) initializeEncoders() error {
return c.onTracks(c.videoTrack, c.audioTrack) return c.onTracks(c.videoTrack, c.audioTrack)
} }

View File

@@ -200,7 +200,7 @@ func TestClient(t *testing.T) {
c, err := NewClient( c, err := NewClient(
prefix+"://localhost:5780/stream.m3u8", prefix+"://localhost:5780/stream.m3u8",
"33949E05FFFB5FF3E8AA16F8213A6251B4D9363804BA53233C4DA9A46D6F2739", "33949E05FFFB5FF3E8AA16F8213A6251B4D9363804BA53233C4DA9A46D6F2739",
func(*gortsplib.Track, *gortsplib.Track) error { func(gortsplib.Track, gortsplib.Track) error {
return nil return nil
}, },
func(isVideo bool, byts []byte) { func(isVideo bool, byts []byte) {

View File

@@ -1,6 +1,7 @@
package hls package hls
import ( import (
"fmt"
"io" "io"
"time" "time"
@@ -18,27 +19,15 @@ type Muxer struct {
func NewMuxer( func NewMuxer(
hlsSegmentCount int, hlsSegmentCount int,
hlsSegmentDuration time.Duration, hlsSegmentDuration time.Duration,
videoTrack *gortsplib.Track, videoTrack *gortsplib.TrackH264,
audioTrack *gortsplib.Track) (*Muxer, error) { audioTrack *gortsplib.TrackAAC) (*Muxer, error) {
var h264Conf *gortsplib.TrackConfigH264
if videoTrack != nil { if videoTrack != nil {
var err error if videoTrack.SPS() == nil || videoTrack.PPS() == nil {
h264Conf, err = videoTrack.ExtractConfigH264() return nil, fmt.Errorf("invalid H264 track: SPS or PPS not provided into the SDP")
if err != nil {
return nil, err
} }
} }
var aacConf *gortsplib.TrackConfigAAC primaryPlaylist := newMuxerPrimaryPlaylist(videoTrack, audioTrack)
if audioTrack != nil {
var err error
aacConf, err = audioTrack.ExtractConfigAAC()
if err != nil {
return nil, err
}
}
primaryPlaylist := newMuxerPrimaryPlaylist(videoTrack, audioTrack, h264Conf, aacConf)
streamPlaylist := newMuxerStreamPlaylist(hlsSegmentCount) streamPlaylist := newMuxerStreamPlaylist(hlsSegmentCount)
@@ -47,8 +36,6 @@ func NewMuxer(
hlsSegmentDuration, hlsSegmentDuration,
videoTrack, videoTrack,
audioTrack, audioTrack,
h264Conf,
aacConf,
streamPlaylist) streamPlaylist)
m := &Muxer{ m := &Muxer{

View File

@@ -11,34 +11,30 @@ import (
) )
type muxerPrimaryPlaylist struct { type muxerPrimaryPlaylist struct {
videoTrack *gortsplib.Track videoTrack *gortsplib.TrackH264
audioTrack *gortsplib.Track audioTrack *gortsplib.TrackAAC
h264Conf *gortsplib.TrackConfigH264
cnt []byte cnt []byte
} }
func newMuxerPrimaryPlaylist( func newMuxerPrimaryPlaylist(
videoTrack *gortsplib.Track, videoTrack *gortsplib.TrackH264,
audioTrack *gortsplib.Track, audioTrack *gortsplib.TrackAAC,
h264Conf *gortsplib.TrackConfigH264,
aacConf *gortsplib.TrackConfigAAC,
) *muxerPrimaryPlaylist { ) *muxerPrimaryPlaylist {
p := &muxerPrimaryPlaylist{ p := &muxerPrimaryPlaylist{
videoTrack: videoTrack, videoTrack: videoTrack,
audioTrack: audioTrack, audioTrack: audioTrack,
h264Conf: h264Conf,
} }
var codecs []string var codecs []string
if p.videoTrack != nil { if p.videoTrack != nil {
codecs = append(codecs, "avc1."+hex.EncodeToString(p.h264Conf.SPS[1:4])) codecs = append(codecs, "avc1."+hex.EncodeToString(p.videoTrack.SPS()[1:4]))
} }
// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter // https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter
if p.audioTrack != nil { if p.audioTrack != nil {
codecs = append(codecs, "mp4a.40."+strconv.FormatInt(int64(aacConf.Type), 10)) codecs = append(codecs, "mp4a.40."+strconv.FormatInt(int64(p.audioTrack.Type()), 10))
} }
p.cnt = []byte("#EXTM3U\n" + p.cnt = []byte("#EXTM3U\n" +

View File

@@ -18,12 +18,10 @@ func checkTSPacket(t *testing.T, byts []byte, pid int, afc int) {
} }
func TestMuxerVideoAudio(t *testing.T) { func TestMuxerVideoAudio(t *testing.T) {
videoTrack, err := gortsplib.NewTrackH264(96, videoTrack, err := gortsplib.NewTrackH264(96, []byte{0x07, 0x01, 0x02, 0x03}, []byte{0x08}, nil)
&gortsplib.TrackConfigH264{SPS: []byte{0x07, 0x01, 0x02, 0x03}, PPS: []byte{0x08}})
require.NoError(t, err) require.NoError(t, err)
audioTrack, err := gortsplib.NewTrackAAC(97, audioTrack, err := gortsplib.NewTrackAAC(97, 2, 44100, 2, nil)
&gortsplib.TrackConfigAAC{Type: 2, SampleRate: 44100, ChannelCount: 2})
require.NoError(t, err) require.NoError(t, err)
m, err := NewMuxer(3, 1*time.Second, videoTrack, audioTrack) m, err := NewMuxer(3, 1*time.Second, videoTrack, audioTrack)
@@ -129,8 +127,7 @@ func TestMuxerVideoAudio(t *testing.T) {
} }
func TestMuxerAudio(t *testing.T) { func TestMuxerAudio(t *testing.T) {
audioTrack, err := gortsplib.NewTrackAAC(97, audioTrack, err := gortsplib.NewTrackAAC(97, 2, 44100, 2, nil)
&gortsplib.TrackConfigAAC{Type: 2, SampleRate: 44100, ChannelCount: 2})
require.NoError(t, err) require.NoError(t, err)
m, err := NewMuxer(3, 1*time.Second, nil, audioTrack) m, err := NewMuxer(3, 1*time.Second, nil, audioTrack)
@@ -178,15 +175,10 @@ func TestMuxerAudio(t *testing.T) {
} }
func TestMuxerCloseBeforeFirstSegment(t *testing.T) { func TestMuxerCloseBeforeFirstSegment(t *testing.T) {
videoTrack, err := gortsplib.NewTrackH264(96, videoTrack, err := gortsplib.NewTrackH264(96, []byte{0x07, 0x01, 0x02, 0x03}, []byte{0x08}, nil)
&gortsplib.TrackConfigH264{SPS: []byte{0x07, 0x01, 0x02, 0x03}, PPS: []byte{0x08}})
require.NoError(t, err) require.NoError(t, err)
audioTrack, err := gortsplib.NewTrackAAC(97, m, err := NewMuxer(3, 1*time.Second, videoTrack, nil)
&gortsplib.TrackConfigAAC{Type: 2, SampleRate: 44100, ChannelCount: 2})
require.NoError(t, err)
m, err := NewMuxer(3, 1*time.Second, videoTrack, audioTrack)
require.NoError(t, err) require.NoError(t, err)
// group with IDR // group with IDR

View File

@@ -28,10 +28,8 @@ func idrPresent(nalus [][]byte) bool {
type muxerTSGenerator struct { type muxerTSGenerator struct {
hlsSegmentCount int hlsSegmentCount int
hlsSegmentDuration time.Duration hlsSegmentDuration time.Duration
videoTrack *gortsplib.Track videoTrack *gortsplib.TrackH264
audioTrack *gortsplib.Track audioTrack *gortsplib.TrackAAC
h264Conf *gortsplib.TrackConfigH264
aacConf *gortsplib.TrackConfigAAC
streamPlaylist *muxerStreamPlaylist streamPlaylist *muxerStreamPlaylist
writer *muxerTSWriter writer *muxerTSWriter
@@ -45,10 +43,8 @@ type muxerTSGenerator struct {
func newMuxerTSGenerator( func newMuxerTSGenerator(
hlsSegmentCount int, hlsSegmentCount int,
hlsSegmentDuration time.Duration, hlsSegmentDuration time.Duration,
videoTrack *gortsplib.Track, videoTrack *gortsplib.TrackH264,
audioTrack *gortsplib.Track, audioTrack *gortsplib.TrackAAC,
h264Conf *gortsplib.TrackConfigH264,
aacConf *gortsplib.TrackConfigAAC,
streamPlaylist *muxerStreamPlaylist, streamPlaylist *muxerStreamPlaylist,
) *muxerTSGenerator { ) *muxerTSGenerator {
m := &muxerTSGenerator{ m := &muxerTSGenerator{
@@ -56,8 +52,6 @@ func newMuxerTSGenerator(
hlsSegmentDuration: hlsSegmentDuration, hlsSegmentDuration: hlsSegmentDuration,
videoTrack: videoTrack, videoTrack: videoTrack,
audioTrack: audioTrack, audioTrack: audioTrack,
h264Conf: h264Conf,
aacConf: aacConf,
streamPlaylist: streamPlaylist, streamPlaylist: streamPlaylist,
writer: newMuxerTSWriter(videoTrack, audioTrack), writer: newMuxerTSWriter(videoTrack, audioTrack),
} }
@@ -109,7 +103,7 @@ func (m *muxerTSGenerator) writeH264(pts time.Duration, nalus [][]byte) error {
case h264.NALUTypeIDR: case h264.NALUTypeIDR:
// add SPS and PPS before every IDR // add SPS and PPS before every IDR
filteredNALUs = append(filteredNALUs, m.h264Conf.SPS, m.h264Conf.PPS) filteredNALUs = append(filteredNALUs, m.videoTrack.SPS(), m.videoTrack.PPS())
} }
filteredNALUs = append(filteredNALUs, nalu) filteredNALUs = append(filteredNALUs, nalu)
@@ -157,9 +151,9 @@ func (m *muxerTSGenerator) writeAAC(pts time.Duration, aus [][]byte) error {
for i, au := range aus { for i, au := range aus {
pkts[i] = &aac.ADTSPacket{ pkts[i] = &aac.ADTSPacket{
Type: m.aacConf.Type, Type: m.audioTrack.Type(),
SampleRate: m.aacConf.SampleRate, SampleRate: m.audioTrack.ClockRate(),
ChannelCount: m.aacConf.ChannelCount, ChannelCount: m.audioTrack.ChannelCount(),
AU: au, AU: au,
} }
} }

View File

@@ -11,7 +11,7 @@ import (
) )
type muxerTSSegment struct { type muxerTSSegment struct {
videoTrack *gortsplib.Track videoTrack gortsplib.Track
writer *muxerTSWriter writer *muxerTSWriter
name string name string
@@ -22,7 +22,7 @@ type muxerTSSegment struct {
} }
func newMuxerTSSegment( func newMuxerTSSegment(
videoTrack *gortsplib.Track, videoTrack gortsplib.Track,
writer *muxerTSWriter, writer *muxerTSWriter,
) *muxerTSSegment { ) *muxerTSSegment {
t := &muxerTSSegment{ t := &muxerTSSegment{

View File

@@ -13,8 +13,8 @@ type muxerTSWriter struct {
} }
func newMuxerTSWriter( func newMuxerTSWriter(
videoTrack *gortsplib.Track, videoTrack gortsplib.Track,
audioTrack *gortsplib.Track) *muxerTSWriter { audioTrack gortsplib.Track) *muxerTSWriter {
w := &muxerTSWriter{} w := &muxerTSWriter{}
w.innerMuxer = astits.NewMuxer(context.Background(), w) w.innerMuxer = astits.NewMuxer(context.Background(), w)

View File

@@ -31,9 +31,8 @@ func New(
} }
s.senders = make([]*rtcpsender.RTCPSender, len(tracks)) s.senders = make([]*rtcpsender.RTCPSender, len(tracks))
for i, t := range tracks { for i, track := range tracks {
clockRate, _ := t.ClockRate() s.senders[i] = rtcpsender.New(track.ClockRate())
s.senders[i] = rtcpsender.New(clockRate)
} }
go s.run() go s.run()

View File

@@ -82,9 +82,9 @@ func (c *Conn) WritePacket(pkt av.Packet) error {
} }
// ReadMetadata reads track informations. // ReadMetadata reads track informations.
func (c *Conn) ReadMetadata() (*gortsplib.Track, *gortsplib.Track, error) { func (c *Conn) ReadMetadata() (*gortsplib.TrackH264, *gortsplib.TrackAAC, error) {
var videoTrack *gortsplib.Track var videoTrack *gortsplib.TrackH264
var audioTrack *gortsplib.Track var audioTrack *gortsplib.TrackAAC
md, err := func() (flvio.AMFMap, error) { md, err := func() (flvio.AMFMap, error) {
pkt, err := c.ReadPacket() pkt, err := c.ReadPacket()
@@ -198,7 +198,7 @@ func (c *Conn) ReadMetadata() (*gortsplib.Track, *gortsplib.Track, error) {
return nil, nil, err return nil, nil, err
} }
videoTrack, err = gortsplib.NewTrackH264(96, &gortsplib.TrackConfigH264{SPS: codec.SPS[0], PPS: codec.PPS[0]}) videoTrack, err = gortsplib.NewTrackH264(96, codec.SPS[0], codec.PPS[0], nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -218,12 +218,8 @@ func (c *Conn) ReadMetadata() (*gortsplib.Track, *gortsplib.Track, error) {
return nil, nil, err return nil, nil, err
} }
audioTrack, err = gortsplib.NewTrackAAC(96, &gortsplib.TrackConfigAAC{ audioTrack, err = gortsplib.NewTrackAAC(96, int(mpegConf.Type), mpegConf.SampleRate,
Type: int(mpegConf.Type), mpegConf.ChannelCount, mpegConf.AOTSpecificConfig)
SampleRate: mpegConf.SampleRate,
ChannelCount: mpegConf.ChannelCount,
AOTSpecificConfig: mpegConf.AOTSpecificConfig,
})
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -237,7 +233,7 @@ func (c *Conn) ReadMetadata() (*gortsplib.Track, *gortsplib.Track, error) {
} }
// WriteMetadata writes track informations. // WriteMetadata writes track informations.
func (c *Conn) WriteMetadata(videoTrack *gortsplib.Track, audioTrack *gortsplib.Track) error { func (c *Conn) WriteMetadata(videoTrack *gortsplib.TrackH264, audioTrack *gortsplib.TrackAAC) error {
err := c.WritePacket(av.Packet{ err := c.WritePacket(av.Packet{
Type: av.Metadata, Type: av.Metadata,
Data: flvio.FillAMF0ValMalloc(flvio.AMFMap{ Data: flvio.FillAMF0ValMalloc(flvio.AMFMap{
@@ -274,17 +270,16 @@ func (c *Conn) WriteMetadata(videoTrack *gortsplib.Track, audioTrack *gortsplib.
} }
if videoTrack != nil { if videoTrack != nil {
conf, err := videoTrack.ExtractConfigH264() if videoTrack.SPS() == nil || videoTrack.PPS() == nil {
if err != nil { return fmt.Errorf("invalid H264 track: SPS or PPS not provided into the SDP")
return err
} }
codec := nh264.Codec{ codec := nh264.Codec{
SPS: map[int][]byte{ SPS: map[int][]byte{
0: conf.SPS, 0: videoTrack.SPS(),
}, },
PPS: map[int][]byte{ PPS: map[int][]byte{
0: conf.PPS, 0: videoTrack.PPS(),
}, },
} }
b := make([]byte, 128) b := make([]byte, 128)
@@ -302,16 +297,11 @@ func (c *Conn) WriteMetadata(videoTrack *gortsplib.Track, audioTrack *gortsplib.
} }
if audioTrack != nil { if audioTrack != nil {
conf, err := audioTrack.ExtractConfigAAC()
if err != nil {
return err
}
enc, err := aac.MPEG4AudioConfig{ enc, err := aac.MPEG4AudioConfig{
Type: aac.MPEG4AudioType(conf.Type), Type: aac.MPEG4AudioType(audioTrack.Type()),
SampleRate: conf.SampleRate, SampleRate: audioTrack.ClockRate(),
ChannelCount: conf.ChannelCount, ChannelCount: audioTrack.ChannelCount(),
AOTSpecificConfig: conf.AOTSpecificConfig, AOTSpecificConfig: audioTrack.AOTSpecificConfig(),
}.Encode() }.Encode()
if err != nil { if err != nil {
return err return err