Update RTSP Server response with all tracks by default

This commit is contained in:
Alexey Khit
2023-01-27 20:43:56 +03:00
parent 5243aca8e9
commit bef8e6454d
6 changed files with 80 additions and 55 deletions
+2
View File
@@ -142,6 +142,8 @@ func parseArgs(s string) *Args {
s += "?video" s += "?video"
case args.audio > 0 && args.video == 0: case args.audio > 0 && args.video == 0:
s += "?audio" s += "?audio"
default:
s += "?video&audio"
} }
args.input = strings.Replace(defaults["rtsp"], "{input}", s, 1) args.input = strings.Replace(defaults["rtsp"], "{input}", s, 1)
} else if strings.HasPrefix(s, "device?") { } else if strings.HasPrefix(s, "device?") {
+7 -37
View File
@@ -3,6 +3,7 @@ package rtsp
import ( import (
"github.com/AlexxIT/go2rtc/cmd/app" "github.com/AlexxIT/go2rtc/cmd/app"
"github.com/AlexxIT/go2rtc/cmd/streams" "github.com/AlexxIT/go2rtc/cmd/streams"
"github.com/AlexxIT/go2rtc/pkg/mp4"
"github.com/AlexxIT/go2rtc/pkg/rtsp" "github.com/AlexxIT/go2rtc/pkg/rtsp"
"github.com/AlexxIT/go2rtc/pkg/streamer" "github.com/AlexxIT/go2rtc/pkg/streamer"
"github.com/AlexxIT/go2rtc/pkg/tcp" "github.com/AlexxIT/go2rtc/pkg/tcp"
@@ -164,13 +165,7 @@ func tcpHandler(conn *rtsp.Conn) {
conn.SessionName = app.UserAgent conn.SessionName = app.UserAgent
conn.Medias = streamer.ParseQuery(conn.URL.Query()) conn.Medias = ParseQuery(conn.URL.Query())
if conn.Medias == nil {
conn.Medias = []*streamer.Media{
{Kind: streamer.KindVideo, Direction: streamer.DirectionRecvonly},
{Kind: streamer.KindAudio, Direction: streamer.DirectionRecvonly},
}
}
if err := stream.AddConsumer(conn); err != nil { if err := stream.AddConsumer(conn); err != nil {
log.Warn().Err(err).Str("stream", name).Msg("[rtsp]") log.Warn().Err(err).Str("stream", name).Msg("[rtsp]")
@@ -235,36 +230,11 @@ func tcpHandler(conn *rtsp.Conn) {
_ = conn.Close() _ = conn.Close()
} }
func initMedias(conn *rtsp.Conn) { func ParseQuery(query map[string][]string) []*streamer.Media {
// set media candidates from query list if query["mp4"] != nil {
for key, value := range conn.URL.Query() { cons := mp4.Consumer{}
switch key { return cons.GetMedias()
case streamer.KindVideo, streamer.KindAudio:
for _, name := range value {
name = strings.ToUpper(name)
// check aliases
switch name {
case "COPY":
name = "" // pass empty codecs list
case "MJPEG":
name = streamer.CodecJPEG
case "AAC":
name = streamer.CodecAAC
} }
media := &streamer.Media{ return streamer.ParseQuery(query)
Kind: key, Direction: streamer.DirectionRecvonly,
}
// empty codecs match all codecs
if name != "" {
// empty clock rate and channels match any values
media.Codecs = []*streamer.Codec{{Name: name}}
}
conn.Medias = append(conn.Medias, media)
}
}
}
} }
+2
View File
@@ -91,11 +91,13 @@ func (s *Stream) AddConsumer(cons streamer.Consumer) (err error) {
consumer.tracks = append(consumer.tracks, consTrack) consumer.tracks = append(consumer.tracks, consTrack)
producers = append(producers, prod) producers = append(producers, prod)
if !consMedia.MatchAll() {
break producers break producers
} }
} }
} }
} }
}
if atomic.AddInt32(&s.requests, -1) == 0 { if atomic.AddInt32(&s.requests, -1) == 0 {
s.stopProducers() s.stopProducers()
+28
View File
@@ -9,7 +9,26 @@ import (
// Element Producer // Element Producer
func (c *Conn) GetMedias() []*streamer.Media { func (c *Conn) GetMedias() []*streamer.Media {
if c.Medias != nil {
return c.Medias return c.Medias
}
return []*streamer.Media{
{
Kind: streamer.KindVideo,
Direction: streamer.DirectionRecvonly,
Codecs: []*streamer.Codec{
{Name: streamer.CodecAll},
},
},
{
Kind: streamer.KindAudio,
Direction: streamer.DirectionRecvonly,
Codecs: []*streamer.Codec{
{Name: streamer.CodecAll},
},
},
}
} }
func (c *Conn) GetTrack(media *streamer.Media, codec *streamer.Codec) *streamer.Track { func (c *Conn) GetTrack(media *streamer.Media, codec *streamer.Codec) *streamer.Track {
@@ -63,6 +82,14 @@ func (c *Conn) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.
codec := track.Codec.Clone() codec := track.Codec.Clone()
codec.PayloadType = uint8(96 + i) codec.PayloadType = uint8(96 + i)
if media.MatchAll() {
// fill consumer medias list
c.Medias = append(c.Medias, &streamer.Media{
Kind: media.Kind, Direction: media.Direction,
Codecs: []*streamer.Codec{codec},
})
} else {
// find consumer media and replace codec with right one
for i, m := range c.Medias { for i, m := range c.Medias {
if m == media { if m == media {
media.Codecs = []*streamer.Codec{codec} media.Codecs = []*streamer.Codec{codec}
@@ -70,6 +97,7 @@ func (c *Conn) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.
break break
} }
} }
}
track = c.bindTrack(track, channelID, codec.PayloadType) track = c.bindTrack(track, channelID, codec.PayloadType)
track.Codec = codec track.Codec = codec
+14 -10
View File
@@ -36,6 +36,9 @@ const (
CodecMP3 = "MPA" // payload: 14, aka MPEG-1 Layer III CodecMP3 = "MPA" // payload: 14, aka MPEG-1 Layer III
CodecELD = "ELD" // AAC-ELD CodecELD = "ELD" // AAC-ELD
CodecAll = "ALL"
CodecAny = "ANY"
) )
const PayloadTypeRAW byte = 255 const PayloadTypeRAW byte = 255
@@ -111,10 +114,6 @@ func (m *Media) MatchMedia(media *Media) *Codec {
} }
for _, localCodec := range m.Codecs { for _, localCodec := range m.Codecs {
if media.Codecs == nil {
return localCodec
}
for _, remoteCodec := range media.Codecs { for _, remoteCodec := range media.Codecs {
if localCodec.Match(remoteCodec) { if localCodec.Match(remoteCodec) {
return localCodec return localCodec
@@ -124,6 +123,10 @@ func (m *Media) MatchMedia(media *Media) *Codec {
return nil return nil
} }
func (m *Media) MatchAll() bool {
return len(m.Codecs) > 0 && m.Codecs[0].Name == CodecAll
}
// Codec take best from: // Codec take best from:
// - deepch/vdk/av.CodecData // - deepch/vdk/av.CodecData
// - pion/webrtc.RTPCodecCapability // - pion/webrtc.RTPCodecCapability
@@ -153,6 +156,11 @@ func (c *Codec) Clone() *Codec {
} }
func (c *Codec) Match(codec *Codec) bool { func (c *Codec) Match(codec *Codec) bool {
switch codec.Name {
case CodecAll, CodecAny:
return true
}
return c.Name == codec.Name && return c.Name == codec.Name &&
(c.ClockRate == codec.ClockRate || codec.ClockRate == 0) && (c.ClockRate == codec.ClockRate || codec.ClockRate == 0) &&
(c.Channels == codec.Channels || codec.Channels == 0) (c.Channels == codec.Channels || codec.Channels == 0)
@@ -307,16 +315,12 @@ func ParseQuery(query map[string][]string) (medias []*Media) {
media := &Media{Kind: key, Direction: DirectionRecvonly} media := &Media{Kind: key, Direction: DirectionRecvonly}
for _, name := range strings.Split(value, ",") { for _, name := range strings.Split(value, ",") {
if name == "" {
continue
}
name = strings.ToUpper(name) name = strings.ToUpper(name)
// check aliases // check aliases
switch name { switch name {
case "COPY": case "", "COPY":
name = "" // pass empty codecs list name = CodecAny
case "MJPEG": case "MJPEG":
name = CodecJPEG name = CodecJPEG
case "AAC": case "AAC":
+19
View File
@@ -3,6 +3,7 @@ package streamer
import ( import (
"github.com/pion/sdp/v3" "github.com/pion/sdp/v3"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"net/url"
"testing" "testing"
) )
@@ -21,3 +22,21 @@ func TestSDP(t *testing.T) {
err = sd.Unmarshal(data) err = sd.Unmarshal(data)
assert.Empty(t, err) assert.Empty(t, err)
} }
func TestParseQuery(t *testing.T) {
u, _ := url.Parse("rtsp://localhost:8554/camera1")
medias := ParseQuery(u.Query())
assert.Nil(t, medias)
for _, rawULR := range []string{
"rtsp://localhost:8554/camera1?video",
"rtsp://localhost:8554/camera1?video=copy",
"rtsp://localhost:8554/camera1?video=any",
} {
u, _ = url.Parse(rawULR)
medias = ParseQuery(u.Query())
assert.Equal(t, []*Media{
{Kind: KindVideo, Direction: DirectionRecvonly, Codecs: []*Codec{{Name: CodecAny}}},
}, medias)
}
}