Update RTSP Server response with all tracks by default
This commit is contained in:
@@ -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
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -9,9 +9,28 @@ 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 {
|
||||||
for _, track := range c.tracks {
|
for _, track := range c.tracks {
|
||||||
if track.Codec == codec {
|
if track.Codec == codec {
|
||||||
@@ -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
@@ -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":
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user