mirror of
https://github.com/bluenviron/mediamtx
synced 2024-12-13 02:04:58 +00:00
support proxying rtsps streams
This commit is contained in:
parent
ccb8b92bfb
commit
5e32a526e5
@ -157,13 +157,13 @@ serverCert: server.crt
|
||||
Streams can then be published and read with the `rtsps` scheme and the 8555 port:
|
||||
|
||||
```
|
||||
ffmpeg -i rtsps://...
|
||||
ffmpeg -i rtsps://ip:8555/...
|
||||
```
|
||||
|
||||
If the client is _GStreamer_ and the server certificate is self signed, remember to disable the certificate validation:
|
||||
|
||||
```
|
||||
gst-launch-1.0 rtspsrc location=rtsps://... tls-validation-flags=0
|
||||
gst-launch-1.0 rtspsrc location=rtsps://ip:8555/... tls-validation-flags=0
|
||||
```
|
||||
|
||||
If the client is _VLC_, encryption can't be deployed, since _VLC_ doesn't support it.
|
||||
@ -256,7 +256,7 @@ After starting the server, the webcam is available on `rtsp://localhost:8554/cam
|
||||
|
||||
### Convert streams to HLS
|
||||
|
||||
HLS is a media format that allows live streams be embedded in web pages, inside standard `<video>` HTML tags. To generate HLS whenever someone publishes a stream, edit `rtsp-simple-server.yml` and replace everything inside section `paths` with the following content:
|
||||
HLS is a media format that allows to embed live streams into web pages, inside standard `<video>` HTML tags. To generate HLS whenever someone publishes a stream, edit `rtsp-simple-server.yml` and replace everything inside section `paths` with the following content:
|
||||
|
||||
```yml
|
||||
paths:
|
||||
|
2
go.mod
2
go.mod
@ -5,7 +5,7 @@ go 1.15
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
||||
github.com/aler9/gortsplib v0.0.0-20201213221155-9cd36cdd6860
|
||||
github.com/aler9/gortsplib v0.0.0-20201214220650-27636bc8102d
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
|
4
go.sum
4
go.sum
@ -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/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/aler9/gortsplib v0.0.0-20201213221155-9cd36cdd6860 h1:fL41RJvlXWaIk/SS/rNDf9F/26Aq6y2F7quilWolMfg=
|
||||
github.com/aler9/gortsplib v0.0.0-20201213221155-9cd36cdd6860/go.mod h1:8P09VjpiPJFyfkVosyF5/TY82jNwkMN165NS/7sc32I=
|
||||
github.com/aler9/gortsplib v0.0.0-20201214220650-27636bc8102d h1:2ZoBLngSzfy/n4FawfA//Gbwu7xkIswOo7trGKtSZyU=
|
||||
github.com/aler9/gortsplib v0.0.0-20201214220650-27636bc8102d/go.mod h1:8P09VjpiPJFyfkVosyF5/TY82jNwkMN165NS/7sc32I=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
@ -74,14 +74,15 @@ func (pconf *PathConf) fillAndCheck(name string) error {
|
||||
|
||||
if pconf.Source == "record" {
|
||||
|
||||
} else if strings.HasPrefix(pconf.Source, "rtsp://") {
|
||||
} else if strings.HasPrefix(pconf.Source, "rtsp://") ||
|
||||
strings.HasPrefix(pconf.Source, "rtsps://") {
|
||||
if pconf.Regexp != nil {
|
||||
return fmt.Errorf("a path with a regular expression (or path 'all') cannot have a RTSP source; use another path")
|
||||
}
|
||||
|
||||
u, err := base.ParseURL(pconf.Source)
|
||||
if err != nil {
|
||||
return fmt.Errorf("'%s' is not a valid rtsp url", pconf.Source)
|
||||
return fmt.Errorf("'%s' is not a valid RTSP url", pconf.Source)
|
||||
}
|
||||
|
||||
if u.User != nil {
|
||||
@ -119,10 +120,10 @@ func (pconf *PathConf) fillAndCheck(name string) error {
|
||||
|
||||
u, err := url.Parse(pconf.Source)
|
||||
if err != nil {
|
||||
return fmt.Errorf("'%s' is not a valid rtmp url", pconf.Source)
|
||||
return fmt.Errorf("'%s' is not a valid RTMP url", pconf.Source)
|
||||
}
|
||||
if u.Scheme != "rtmp" {
|
||||
return fmt.Errorf("'%s' is not a valid rtmp url", pconf.Source)
|
||||
return fmt.Errorf("'%s' is not a valid RTMP url", pconf.Source)
|
||||
}
|
||||
|
||||
if u.User != nil {
|
||||
@ -141,7 +142,7 @@ func (pconf *PathConf) fillAndCheck(name string) error {
|
||||
|
||||
_, err := base.ParseURL(pconf.SourceRedirect)
|
||||
if err != nil {
|
||||
return fmt.Errorf("'%s' is not a valid rtsp url", pconf.SourceRedirect)
|
||||
return fmt.Errorf("'%s' is not a valid RTSP url", pconf.SourceRedirect)
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -159,7 +160,7 @@ func (pconf *PathConf) fillAndCheck(name string) error {
|
||||
if pconf.Fallback != "" {
|
||||
_, err := base.ParseURL(pconf.Fallback)
|
||||
if err != nil {
|
||||
return fmt.Errorf("'%s' is not a valid rtsp url", pconf.Fallback)
|
||||
return fmt.Errorf("'%s' is not a valid RTSP url", pconf.Fallback)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -475,11 +475,13 @@ func (pa *Path) exhaustChannels() {
|
||||
|
||||
func (pa *Path) hasExternalSource() bool {
|
||||
return strings.HasPrefix(pa.conf.Source, "rtsp://") ||
|
||||
strings.HasPrefix(pa.conf.Source, "rtsps://") ||
|
||||
strings.HasPrefix(pa.conf.Source, "rtmp://")
|
||||
}
|
||||
|
||||
func (pa *Path) startExternalSource() {
|
||||
if strings.HasPrefix(pa.conf.Source, "rtsp://") {
|
||||
if strings.HasPrefix(pa.conf.Source, "rtsp://") ||
|
||||
strings.HasPrefix(pa.conf.Source, "rtsps://") {
|
||||
pa.source = sourcertsp.New(pa.conf.Source, pa.conf.SourceProtocolParsed,
|
||||
pa.readTimeout, pa.writeTimeout, &pa.sourceWg, pa.stats, pa)
|
||||
|
||||
|
62
main_test.go
62
main_test.go
@ -699,6 +699,68 @@ func TestSourceRtsp(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSourceRtsps(t *testing.T) {
|
||||
serverCertFpath, err := writeTempFile(serverCert)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverCertFpath)
|
||||
|
||||
serverKeyFpath, err := writeTempFile(serverKey)
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(serverKeyFpath)
|
||||
|
||||
p, ok := testProgram("readTimeout: 20s\n" +
|
||||
"protocols: [tcp]\n" +
|
||||
"encryption: yes\n" +
|
||||
"serverCert: " + serverCertFpath + "\n" +
|
||||
"serverKey: " + serverKeyFpath + "\n" +
|
||||
"paths:\n" +
|
||||
" all:\n" +
|
||||
" readUser: testuser\n" +
|
||||
" readPass: testpass\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p.close()
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
cnt1, err := newContainer("ffmpeg", "source", []string{
|
||||
"-re",
|
||||
"-stream_loop", "-1",
|
||||
"-i", "emptyvideo.ts",
|
||||
"-c", "copy",
|
||||
"-f", "rtsp",
|
||||
"rtsps://" + ownDockerIP + ":8555/teststream",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer cnt1.close()
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
p2, ok := testProgram("rtspPort: 8556\n" +
|
||||
"rtpPort: 8100\n" +
|
||||
"rtcpPort: 8101\n" +
|
||||
"\n" +
|
||||
"paths:\n" +
|
||||
" proxied:\n" +
|
||||
" source: rtsps://testuser:testpass@localhost:8555/teststream\n" +
|
||||
" sourceOnDemand: yes\n")
|
||||
require.Equal(t, true, ok)
|
||||
defer p2.close()
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
cnt2, err := newContainer("ffmpeg", "dest", []string{
|
||||
"-rtsp_transport", "udp",
|
||||
"-i", "rtsp://" + ownDockerIP + ":8556/proxied",
|
||||
"-vframes", "1",
|
||||
"-f", "image2",
|
||||
"-y", "/dev/null",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer cnt2.close()
|
||||
|
||||
require.Equal(t, 0, cnt2.wait())
|
||||
}
|
||||
|
||||
func TestSourceRtmp(t *testing.T) {
|
||||
cnt1, err := newContainer("nginx-rtmp", "rtmpserver", []string{})
|
||||
require.NoError(t, err)
|
||||
|
@ -57,6 +57,7 @@ paths:
|
||||
# source of the stream - this can be:
|
||||
# * record -> the stream is provided by a RTSP client
|
||||
# * rtsp://existing-url -> the stream is pulled from another RTSP server
|
||||
# * rtsps://existing-url -> the stream is pulled from another RTSP server
|
||||
# * rtmp://existing-url -> the stream is pulled from a RTMP server
|
||||
# * redirect -> the stream is provided by another path or server
|
||||
source: record
|
||||
|
Loading…
Reference in New Issue
Block a user