Skip to content

Commit f81c50e

Browse files
authored
rtsp: support reading streams tunneled with HTTP or WebSocket (#4986)
1 parent 558d1c3 commit f81c50e

File tree

6 files changed

+50
-17
lines changed

6 files changed

+50
-17
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/asticode/go-astits v1.13.0
1212
github.com/bluenviron/gohlslib/v2 v2.2.3
1313
github.com/bluenviron/gortmplib v0.0.0-20250916095243-72b6eaffb6a4
14-
github.com/bluenviron/gortsplib/v5 v5.0.0-20250917174653-288b637b2301
14+
github.com/bluenviron/gortsplib/v5 v5.0.0-20250917193011-6107dea9a082
1515
github.com/bluenviron/mediacommon/v2 v2.4.2
1616
github.com/datarhei/gosrt v0.9.0
1717
github.com/fsnotify/fsnotify v1.9.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ github.com/bluenviron/gohlslib/v2 v2.2.3 h1:1R/Jnh1kNR9UB09KAX6xjS2GcdKFRLuPd9wM
3535
github.com/bluenviron/gohlslib/v2 v2.2.3/go.mod h1:z4Viks+Mdgcl7OcOVJ1fgSmuUwCCJBxYJPLN49n7Vnw=
3636
github.com/bluenviron/gortmplib v0.0.0-20250916095243-72b6eaffb6a4 h1:ZDsCiFpmOoEy2eWcJBEhV8jb0sA9MxO/BzYmyrmm4hE=
3737
github.com/bluenviron/gortmplib v0.0.0-20250916095243-72b6eaffb6a4/go.mod h1:73VbUEJLkaixSRPRI/imEkVRkBccvR1GKrd6SUOdkrQ=
38-
github.com/bluenviron/gortsplib/v5 v5.0.0-20250917174653-288b637b2301 h1:dLEqNi4/uTN6lUM3djwWXhO0uqs9/TbRSg4AfDOJjH8=
39-
github.com/bluenviron/gortsplib/v5 v5.0.0-20250917174653-288b637b2301/go.mod h1:zp5tDI2tkjVMgyWiy+B2tRQowqYq/GwHjdAdYFQAxrU=
38+
github.com/bluenviron/gortsplib/v5 v5.0.0-20250917193011-6107dea9a082 h1:x/YfIKksGOKaY/PmKg7USS81gyw2tzF7HLXk5ftWlKY=
39+
github.com/bluenviron/gortsplib/v5 v5.0.0-20250917193011-6107dea9a082/go.mod h1:zp5tDI2tkjVMgyWiy+B2tRQowqYq/GwHjdAdYFQAxrU=
4040
github.com/bluenviron/mediacommon/v2 v2.4.2 h1:rggs61nTaqPcR1+RhlIE8/nDqfF5PO57QxpxBzSFfrw=
4141
github.com/bluenviron/mediacommon/v2 v2.4.2/go.mod h1:zy1fODPuS/kBd93ftgJS1Jhvjq7LFWfAo32KP7By9AE=
4242
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=

internal/conf/path.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66
"net"
7-
gourl "net/url"
7+
"net/url"
88
"reflect"
99
"regexp"
1010
"sort"
@@ -372,8 +372,12 @@ func (pconf *Path) validate(
372372
}
373373

374374
case strings.HasPrefix(pconf.Source, "rtsp://") ||
375-
strings.HasPrefix(pconf.Source, "rtsps://"):
376-
_, err := base.ParseURL(pconf.Source)
375+
strings.HasPrefix(pconf.Source, "rtsps://") ||
376+
strings.HasPrefix(pconf.Source, "rtsp+http://") ||
377+
strings.HasPrefix(pconf.Source, "rtsps+http://") ||
378+
strings.HasPrefix(pconf.Source, "rtsp+ws://") ||
379+
strings.HasPrefix(pconf.Source, "rtsps+ws://"):
380+
_, err := url.Parse(pconf.Source)
377381
if err != nil {
378382
return fmt.Errorf("'%s' is not a valid URL", pconf.Source)
379383
}
@@ -390,7 +394,7 @@ func (pconf *Path) validate(
390394

391395
case strings.HasPrefix(pconf.Source, "rtmp://") ||
392396
strings.HasPrefix(pconf.Source, "rtmps://"):
393-
u, err := gourl.Parse(pconf.Source)
397+
u, err := url.Parse(pconf.Source)
394398
if err != nil {
395399
return fmt.Errorf("'%s' is not a valid URL", pconf.Source)
396400
}
@@ -406,15 +410,11 @@ func (pconf *Path) validate(
406410

407411
case strings.HasPrefix(pconf.Source, "http://") ||
408412
strings.HasPrefix(pconf.Source, "https://"):
409-
u, err := gourl.Parse(pconf.Source)
413+
u, err := url.Parse(pconf.Source)
410414
if err != nil {
411415
return fmt.Errorf("'%s' is not a valid URL", pconf.Source)
412416
}
413417

414-
if u.Scheme != "http" && u.Scheme != "https" {
415-
return fmt.Errorf("'%s' is not a valid URL", pconf.Source)
416-
}
417-
418418
if u.User != nil {
419419
pass, _ := u.User.Password()
420420
user := u.User.Username()
@@ -454,14 +454,14 @@ func (pconf *Path) validate(
454454
}
455455

456456
case strings.HasPrefix(pconf.Source, "srt://"):
457-
_, err := gourl.Parse(pconf.Source)
457+
_, err := url.Parse(pconf.Source)
458458
if err != nil {
459459
return fmt.Errorf("'%s' is not a valid URL", pconf.Source)
460460
}
461461

462462
case strings.HasPrefix(pconf.Source, "whep://") ||
463463
strings.HasPrefix(pconf.Source, "wheps://"):
464-
_, err := gourl.Parse(pconf.Source)
464+
_, err := url.Parse(pconf.Source)
465465
if err != nil {
466466
return fmt.Errorf("'%s' is not a valid URL", pconf.Source)
467467
}

internal/staticsources/handler.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ func (s *Handler) Initialize() {
9595

9696
switch {
9797
case strings.HasPrefix(s.Conf.Source, "rtsp://") ||
98-
strings.HasPrefix(s.Conf.Source, "rtsps://"):
98+
strings.HasPrefix(s.Conf.Source, "rtsps://") ||
99+
strings.HasPrefix(s.Conf.Source, "rtsp+http://") ||
100+
strings.HasPrefix(s.Conf.Source, "rtsps+http://") ||
101+
strings.HasPrefix(s.Conf.Source, "rtsp+ws://") ||
102+
strings.HasPrefix(s.Conf.Source, "rtsps+ws://"):
99103
s.instance = &ssrtsp.Source{
100104
ReadTimeout: s.ReadTimeout,
101105
WriteTimeout: s.WriteTimeout,

internal/staticsources/rtsp/source.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
package rtsp
33

44
import (
5+
"net/url"
6+
"regexp"
57
"time"
68

79
"github.com/bluenviron/gortsplib/v5"
@@ -116,14 +118,37 @@ func (s *Source) Run(params defs.StaticSourceRunParams) error {
116118
decodeErrors.Start()
117119
defer decodeErrors.Stop()
118120

119-
u, err := base.ParseURL(params.ResolvedSource)
121+
u0, err := url.Parse(params.ResolvedSource)
122+
if err != nil {
123+
return err
124+
}
125+
126+
var scheme string
127+
if u0.Scheme == "rtsp" || u0.Scheme == "rtsp+http" || u0.Scheme == "rtsp+ws" {
128+
scheme = "rtsp"
129+
} else {
130+
scheme = "rtsps"
131+
}
132+
133+
var tunnel gortsplib.Tunnel
134+
switch u0.Scheme {
135+
case "rtsp+http", "rtsps+http":
136+
tunnel = gortsplib.TunnelHTTP
137+
case "rtsp+ws", "rtsps+ws":
138+
tunnel = gortsplib.TunnelWebSocket
139+
default:
140+
tunnel = gortsplib.TunnelNone
141+
}
142+
143+
u, err := base.ParseURL(regexp.MustCompile("^.*?://").ReplaceAllString(params.ResolvedSource, "rtsp://"))
120144
if err != nil {
121145
return err
122146
}
123147

124148
c := &gortsplib.Client{
125-
Scheme: u.Scheme,
149+
Scheme: scheme,
126150
Host: u.Host,
151+
Tunnel: tunnel,
127152
Protocol: params.Conf.RTSPTransport.Protocol,
128153
TLSConfig: tls.MakeConfig(u.Hostname(), params.Conf.SourceFingerprint),
129154
ReadTimeout: time.Duration(s.ReadTimeout),

mediamtx.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,10 @@ pathDefaults:
438438
# * publisher -> the stream is provided by a RTSP, RTMP, WebRTC or SRT client
439439
# * rtsp://existing-url -> the stream is pulled from another RTSP server / camera
440440
# * rtsps://existing-url -> the stream is pulled from another RTSP server / camera with RTSPS
441+
# * rtsp+http://existing-url -> the stream is pulled from another RTSP server / camera, with HTTP tunneling
442+
# * rtsps+http://existing-url -> the stream is pulled from another RTSP server / camera, with HTTPS tunneling
443+
# * rtsp+ws://existing-url -> the stream is pulled from another RTSP server / camera, with WebSocket tunneling
444+
# * rtsps+ws://existing-url -> the stream is pulled from another RTSP server / camera, with secure WebSocket tunneling
441445
# * rtmp://existing-url -> the stream is pulled from another RTMP server / camera
442446
# * rtmps://existing-url -> the stream is pulled from another RTMP server / camera with RTMPS
443447
# * http://existing-url/stream.m3u8 -> the stream is pulled from another HLS server / camera

0 commit comments

Comments
 (0)