rtsp: support unwrapping MPEG-TS tracks (#5476)

this allows to use MPEG-TS tracks with other protocols and with the recording system.

---------

Co-authored-by: aler9 <46489434+aler9@users.noreply.github.com>
This commit is contained in:
eh
2026-03-17 19:14:04 +01:00
committed by GitHub
co-authored by aler9
parent c8e07b55d5
commit f98c9c59ca
22 changed files with 380 additions and 18 deletions
+2
View File
@@ -717,6 +717,8 @@ components:
deprecated: true
srtPublishPassphrase:
type: string
rtspDemuxMpegts:
type: boolean
# RTSP source
rtspTransport:
+1 -1
View File
@@ -8,7 +8,7 @@ srt://localhost:8890?streamid=publish:mystream&pkt_size=1316
Replace `mystream` with any name you want. The resulting stream will be available on path `/mystream`.
If you need to use the standard stream ID syntax instead of the custom one in use by this server, see [Standard stream ID syntax](../4-other/21-srt-specific-features.md#standard-stream-id-syntax).
If you need to use the standard stream ID syntax instead of the custom one in use by this server, read [Standard stream ID syntax](../4-other/21-srt-specific-features.md#standard-stream-id-syntax).
If you want to publish a stream by using a client in listening mode (i.e. with `mode=listener` appended to the URL), read the next section.
+18 -1
View File
@@ -1,6 +1,6 @@
# RTSP clients
RTSP is a protocol that allows to publish and read streams. It supports several underlying transport protocols and encryption (see [RTSP-specific features](../4-other/23-rtsp-specific-features.md)). In order to publish a stream to the server with the RTSP protocol, use this URL:
RTSP is a protocol that allows to publish and read streams. It supports several underlying transport protocols and encryption. In order to publish a stream to the server with the RTSP protocol, use this URL:
```
rtsp://localhost:8554/mystream
@@ -9,3 +9,20 @@ rtsp://localhost:8554/mystream
The resulting stream will be available on path `/mystream`.
Some clients that can publish with RTSP are [FFmpeg](15-ffmpeg.md), [GStreamer](16-gstreamer.md), [OBS Studio](17-obs-studio.md), [Python and OpenCV](18-python-opencv.md).
Advanced RTSP features and settings are described in [RTSP-specific features](../4-other/23-rtsp-specific-features.md).
## MPEG-TS inside RTSP
Some RTSP clients encode tracks with MPEG-TS before sending them to the server, causing the server to see a single "MPEG-TS" track, and preventing track conversion from a protocol to another.
It's possible to automatically demux these MPEG-TS-encoded streams, by toggling `rtspDemuxMpegts`:
```yml
pathDefaults:
# Demux MPEG-TS over RTSP into elementary streams.
# When enabled, RTSP publishers sending MP2T/90000 will be demultiplexed
# and their elementary streams (H.264, H.265, AAC, etc.) exposed as native tracks.
# This allows HLS, WebRTC, and other outputs to work transparently with MPEG-TS sources.
rtspDemuxMpegts: true
```
@@ -44,4 +44,4 @@ paths:
All available parameters are listed in the [configuration file](../5-references/1-configuration-file.md).
Advanced RTSP features are described in [RTSP-specific features](../4-other/23-rtsp-specific-features.md).
Advanced RTSP features and settings are described in [RTSP-specific features](../4-other/23-rtsp-specific-features.md).
+1 -1
View File
@@ -1,6 +1,6 @@
# RTMP clients
RTMP is a protocol that allows to read and publish streams. It supports encryption, see [RTMP-specific features](../4-other/24-rtmp-specific-features.md). Streams can be published to the server by using the URL:
RTMP is a protocol that allows to read and publish streams. It supports encryption, read [RTMP-specific features](../4-other/24-rtmp-specific-features.md). Streams can be published to the server by using the URL:
```
rtmp://localhost/mystream
+1 -1
View File
@@ -36,7 +36,7 @@ ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
## FFmpeg and RTP over UDP
In _MediaMTX_ configuration, add a path with `source: udp+rtp://238.0.0.1:1234` and a valid `rtpSDP` (see [RTP](12-rtp.md)). Then:
In _MediaMTX_ configuration, add a path with `source: udp+rtp://238.0.0.1:1234` and a valid `rtpSDP` (read [RTP](12-rtp.md)). Then:
```sh
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
+2 -2
View File
@@ -20,7 +20,7 @@ d.video_0 ! rtspclientsink location=rtsp://localhost:8554/mystream
The resulting stream will be available on path `/mystream`.
For advanced options, see [RTSP-specific features](../4-other/23-rtsp-specific-features.md).
For advanced options, read [RTSP-specific features](../4-other/23-rtsp-specific-features.md).
## GStreamer and RTMP
@@ -38,7 +38,7 @@ videotestsrc ! video/x-raw,width=1280,height=720,format=I420 ! x264enc speed-pre
audiotestsrc ! audioconvert ! avenc_aac ! mux.
```
For advanced options, see [RTSP-specific features](../4-other/23-rtsp-specific-features.md).
For advanced options, read [RTSP-specific features](../4-other/23-rtsp-specific-features.md).
## GStreamer and WebRTC
+1 -1
View File
@@ -8,6 +8,6 @@ srt://localhost:8890?streamid=read:mystream
Replace `mystream` with the path name.
If you need to use the standard stream ID syntax instead of the custom one in use by this server, see [Standard stream ID syntax](../4-other/21-srt-specific-features.md#standard-stream-id-syntax).
If you need to use the standard stream ID syntax instead of the custom one in use by this server, read [Standard stream ID syntax](../4-other/21-srt-specific-features.md#standard-stream-id-syntax).
Some clients that can read with SRT are [FFmpeg](07-ffmpeg.md), [GStreamer](08-gstreamer.md) and [VLC](09-vlc.md).
+1 -1
View File
@@ -1,6 +1,6 @@
# RTSP clients
RTSP is a protocol that allows to publish and read streams. It supports several underlying transport protocols and encryption (see [RTSP-specific features](../4-other/23-rtsp-specific-features.md)). In order to read a stream with the RTSP protocol, use this URL:
RTSP is a protocol that allows to publish and read streams. It supports several underlying transport protocols and encryption (read [RTSP-specific features](../4-other/23-rtsp-specific-features.md)). In order to read a stream with the RTSP protocol, use this URL:
```
rtsp://localhost:8554/mystream
+1 -1
View File
@@ -1,6 +1,6 @@
# RTMP clients
RTMP is a protocol that allows to read and publish streams. It supports encryption, see [RTMP-specific features](../4-other/24-rtmp-specific-features.md). Streams can be read from the server by using the URL:
RTMP is a protocol that allows to read and publish streams. It supports encryption, read [RTMP-specific features](../4-other/24-rtmp-specific-features.md). Streams can be read from the server by using the URL:
```
rtmp://localhost/mystream
+1 -1
View File
@@ -8,7 +8,7 @@ GStreamer can read a stream from the server in several ways. The recommended one
gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/mystream latency=0 ! decodebin ! autovideosink
```
For advanced options, see [RTSP-specific features](../4-other/23-rtsp-specific-features.md).
For advanced options, read [RTSP-specific features](../4-other/23-rtsp-specific-features.md).
## GStreamer and WebRTC
+1 -1
View File
@@ -8,7 +8,7 @@ vlc --network-caching=50 rtsp://localhost:8554/mystream
## RTSP and Ubuntu compatibility
The VLC shipped with Ubuntu 21.10 doesn't support playing RTSP due to a license issue (see [here](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=982299) and [here](https://stackoverflow.com/questions/69766748/cvlc-cannot-play-rtsp-omxplayer-instead-can)). To fix the issue, remove the default VLC instance and install the snap version:
The VLC shipped with Ubuntu 21.10 doesn't support playing RTSP due to a license issue (read [here](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=982299) and [here](https://stackoverflow.com/questions/69766748/cvlc-cannot-play-rtsp-omxplayer-instead-can)). To fix the issue, remove the default VLC instance and install the snap version:
```sh
sudo apt purge -y vlc
+1 -1
View File
@@ -297,7 +297,7 @@ Username and password can be passed through the `Authorization: Basic` HTTP head
Authorization: Basic base64(user:pass)
```
When using a web browser, a dialog is first shown to users, asking for credentials, and then the header is automatically inserted into every request. If you need to automatically fill credentials from a parent web page, see [Embed streams in a website](14-embed-streams-in-a-website.md).
When using a web browser, a dialog is first shown to users, asking for credentials, and then the header is automatically inserted into every request. If you need to automatically fill credentials from a parent web page, read [Embed streams in a website](14-embed-streams-in-a-website.md).
If the `Authorization: Basic` header cannot be used (for instance, in software like OBS Studio, which only allows to provide a "Bearer Token"), credentials can be passed through the `Authorization: Bearer` header (i.e. the "Bearer Token" in OBS), where the value is the concatenation of username and password, separated by a colon:
+1 -1
View File
@@ -1,6 +1,6 @@
# SRT-specific features
SRT is a protocol that can be used for publishing and reading streams. Regarding specific tasks, see [Publish](../2-publish/02-srt-clients.md) and [Read](../3-read/02-srt.md). Features in this page are shared among both tasks.
SRT is a protocol that can be used for publishing and reading streams. Regarding specific tasks, read [Publish](../2-publish/02-srt-clients.md) and [Read](../3-read/02-srt.md). Features in this page are shared among both tasks.
## Standard stream ID syntax
+1 -1
View File
@@ -1,6 +1,6 @@
# WebRTC-specific features
WebRTC is a protocol that can be used for publishing and reading streams. Regarding specific tasks, see [Publish](../2-publish/04-webrtc-clients.md) and [Read](../3-read/03-webrtc.md). Features in this page are shared among both tasks.
WebRTC is a protocol that can be used for publishing and reading streams. Regarding specific tasks, read [Publish](../2-publish/04-webrtc-clients.md) and [Read](../3-read/03-webrtc.md). Features in this page are shared among both tasks.
## Codec support in browsers
+5 -1
View File
@@ -1,6 +1,6 @@
# RTSP-specific features
RTSP is a protocol that can be used for publishing and reading streams. Regarding specific tasks, see [Publish](../2-publish/06-rtsp-clients.md) and [Read](../3-read/04-rtsp.md). Features in this page are shared among both tasks.
RTSP is a protocol that can be used for publishing and reading streams. Regarding specific tasks, read [Publish](../2-publish/06-rtsp-clients.md) and [Read](../3-read/04-rtsp.md). Features in this page are shared among both tasks.
## Transport protocols
@@ -104,3 +104,7 @@ paths:
```
There are also the `rtsp+https`, `rtsp+ws`, `rtsp+wss` schemes to handle any combination.
## MPEG-TS inside RTSP
read [MPEG-TS inside RTSP](../2-publish/06-rtsp-clients.md#mpeg-ts-inside-rtsp) in the "Publish with RTSP clients" page.
+1 -1
View File
@@ -1,6 +1,6 @@
# RTMP-specific features
RTMP is a protocol that can be used for publishing and reading streams. Regarding specific tasks, see [Publish](../2-publish/08-rtmp-clients.md) and [Read](../3-read/05-rtmp.md). Features in this page are shared among both tasks.
RTMP is a protocol that can be used for publishing and reading streams. Regarding specific tasks, read [Publish](../2-publish/08-rtmp-clients.md) and [Read](../3-read/05-rtmp.md). Features in this page are shared among both tasks.
## Encryption
+1
View File
@@ -210,6 +210,7 @@ type Path struct {
OverridePublisher bool `json:"overridePublisher"`
DisablePublisherOverride *bool `json:"disablePublisherOverride,omitempty" deprecated:"true"`
SRTPublishPassphrase string `json:"srtPublishPassphrase"`
RTSPDemuxMpegts bool `json:"rtspDemuxMpegts"`
// RTSP source
RTSPTransport RTSPTransport `json:"rtspTransport"`
+124
View File
@@ -0,0 +1,124 @@
package rtsp
import (
"errors"
"fmt"
"io"
"github.com/bluenviron/gortsplib/v5/pkg/description"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/defs"
"github.com/bluenviron/mediamtx/internal/errordumper"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/mpegts"
"github.com/bluenviron/mediamtx/internal/stream"
)
// mpegtsDemuxer demuxes an MPEG-TS stream received via RTP into component streams.
type mpegtsDemuxer struct {
session *session
pathManager serverPathManager
pathConf *conf.Path
mpegtsMedia *description.Media
mpegtsFormat *format.MPEGTS
decodeErrors *errordumper.Dumper
pathName string
query string
pipeWriter *io.PipeWriter
}
func (d *mpegtsDemuxer) initialize() error {
decoder, err := d.mpegtsFormat.CreateDecoder()
if err != nil {
return fmt.Errorf("failed to create MPEG-TS decoder: %w", err)
}
pr, pw := io.Pipe()
d.pipeWriter = pw
d.session.rsession.OnPacketRTP(d.mpegtsMedia, d.mpegtsFormat, func(pkt *rtp.Packet) {
tsData, decErr := decoder.Decode(pkt)
if decErr != nil {
d.decodeErrors.Add(decErr)
return
}
for _, data := range tsData {
_, err = pw.Write(data)
if err != nil {
d.session.Log(logger.Warn, "demuxer pipe write error: %v", err)
return
}
}
})
go d.run(pr)
return nil
}
func (d *mpegtsDemuxer) close() {
d.pipeWriter.CloseWithError(io.EOF)
}
func (d *mpegtsDemuxer) run(pr *io.PipeReader) {
err := d.doRun(pr)
if err != nil {
d.session.Log(logger.Error, "MPEG-TS demuxer error: %v", err)
d.session.Close()
}
}
func (d *mpegtsDemuxer) doRun(pr *io.PipeReader) error {
r := &mpegts.EnhancedReader{R: pr}
err := r.Initialize()
if err != nil {
return fmt.Errorf("failed to initialize MPEG-TS reader: %w", err)
}
r.OnDecodeError(func(err error) {
d.decodeErrors.Add(err)
})
var subStream *stream.SubStream
medias, err := mpegts.ToStream(r, &subStream, d.session)
if err != nil {
return fmt.Errorf("failed to map MPEG-TS to stream: %w", err)
}
res, err := d.pathManager.AddPublisher(defs.PathAddPublisherReq{
Author: d.session,
Desc: &description.Session{Medias: medias},
UseRTPPackets: false,
ReplaceNTP: true,
ConfToCompare: d.pathConf,
AccessRequest: defs.PathAccessRequest{
Name: d.pathName,
Query: d.query,
Publish: true,
SkipAuth: true,
},
})
if err != nil {
return fmt.Errorf("failed to add publisher: %w", err)
}
defer res.Path.RemovePublisher(defs.PathRemovePublisherReq{Author: d.session})
subStream = res.SubStream
for {
err = r.Read()
if err != nil {
if !errors.Is(err, io.EOF) {
return err
}
return nil
}
}
}
+151
View File
@@ -1,6 +1,8 @@
package rtsp
import (
"bufio"
"bytes"
"fmt"
"sync/atomic"
"testing"
@@ -11,6 +13,8 @@ import (
"github.com/bluenviron/gortsplib/v5/pkg/base"
"github.com/bluenviron/gortsplib/v5/pkg/description"
"github.com/bluenviron/gortsplib/v5/pkg/format"
mpegts "github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts"
tscodecs "github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts/codecs"
"github.com/bluenviron/mediamtx/internal/auth"
"github.com/bluenviron/mediamtx/internal/conf"
"github.com/bluenviron/mediamtx/internal/defs"
@@ -206,6 +210,153 @@ func TestServerPublish(t *testing.T) {
}
}
func TestServerPublishMPEGTS(t *testing.T) {
var strm *stream.Stream
var reader *stream.Reader
defer func() {
if strm != nil && reader != nil {
strm.RemoveReader(reader)
}
}()
dataReceived := make(chan struct{})
pathConf := &conf.Path{RTSPDemuxMpegts: true}
pathManager := &test.PathManager{
FindPathConfImpl: func(req defs.PathFindPathConfReq) (*defs.PathFindPathConfRes, error) {
require.Equal(t, "teststream", req.AccessRequest.Name)
require.Equal(t, "param=value", req.AccessRequest.Query)
return &defs.PathFindPathConfRes{Conf: pathConf}, nil
},
AddPublisherImpl: func(req defs.PathAddPublisherReq) (*defs.PathAddPublisherRes, error) {
require.Equal(t, "teststream", req.AccessRequest.Name)
require.Equal(t, "param=value", req.AccessRequest.Query)
require.True(t, req.AccessRequest.SkipAuth)
require.False(t, req.UseRTPPackets)
require.True(t, req.ReplaceNTP)
require.Same(t, pathConf, req.ConfToCompare)
require.Equal(t, &description.Session{Medias: []*description.Media{{
Type: description.MediaTypeVideo,
Formats: []format.Format{&format.H264{
PayloadTyp: 96,
PacketizationMode: 1,
}},
}}}, req.Desc)
strm = &stream.Stream{
Desc: req.Desc,
WriteQueueSize: 512,
RTPMaxPayloadSize: 1450,
Parent: test.NilLogger,
}
err := strm.Initialize()
require.NoError(t, err)
subStream := &stream.SubStream{
Stream: strm,
UseRTPPackets: false,
}
err = subStream.Initialize()
require.NoError(t, err)
reader = &stream.Reader{Parent: test.NilLogger}
n := 0
reader.OnData(
strm.Desc.Medias[0],
strm.Desc.Medias[0].Formats[0],
func(u *unit.Unit) error {
if n == 0 {
require.Equal(t, unit.PayloadH264{
test.FormatH264.SPS,
test.FormatH264.PPS,
{5, 1},
}, u.Payload)
close(dataReceived)
}
n++
return nil
})
strm.AddReader(reader)
return &defs.PathAddPublisherRes{Path: &dummyPath{}, SubStream: subStream}, nil
},
}
s := &Server{
Address: "127.0.0.1:8557",
ReadTimeout: conf.Duration(10 * time.Second),
WriteTimeout: conf.Duration(10 * time.Second),
WriteQueueSize: 512,
Transports: conf.RTSPTransports{gortsplib.ProtocolTCP: {}},
PathManager: pathManager,
Parent: test.NilLogger,
}
err := s.Initialize()
require.NoError(t, err)
defer s.Close()
source := gortsplib.Client{}
media0 := &description.Media{
Type: description.MediaTypeApplication,
Formats: []format.Format{&format.MPEGTS{}},
}
err = source.StartRecording(
"rtsp://127.0.0.1:8557/teststream?param=value",
&description.Session{Medias: []*description.Media{media0}})
require.NoError(t, err)
defer source.Close()
track := &mpegts.Track{Codec: &tscodecs.H264{}}
var buf bytes.Buffer
bw := bufio.NewWriter(&buf)
w := &mpegts.Writer{W: bw, Tracks: []*mpegts.Track{track}}
err = w.Initialize()
require.NoError(t, err)
// the MPEG-TS muxer needs two PES packets in order to write the first one
err = w.WriteH264(track, 0, 0, [][]byte{
test.FormatH264.SPS,
test.FormatH264.PPS,
{5, 1},
})
require.NoError(t, err)
err = w.WriteH264(track, 0, 0, [][]byte{{5, 2}})
require.NoError(t, err)
err = bw.Flush()
require.NoError(t, err)
raw := buf.Bytes()
require.NotEmpty(t, raw)
require.Zero(t, len(raw)%188)
tsPackets := make([][]byte, 0, len(raw)/188)
for len(raw) > 0 {
tsPackets = append(tsPackets, raw[:188:188])
raw = raw[188:]
}
encoder, err := media0.Formats[0].(*format.MPEGTS).CreateEncoder()
require.NoError(t, err)
rtpPackets, err := encoder.Encode(tsPackets)
require.NoError(t, err)
for _, pkt := range rtpPackets {
err = source.WritePacketRTP(media0, pkt)
require.NoError(t, err)
}
<-dataReceived
}
func TestServerRead(t *testing.T) {
for _, ca := range []string{"basic", "digest", "basic+digest"} {
t.Run(ca, func(t *testing.T) {
+59 -1
View File
@@ -12,6 +12,8 @@ import (
"github.com/bluenviron/gortsplib/v5"
rtspauth "github.com/bluenviron/gortsplib/v5/pkg/auth"
"github.com/bluenviron/gortsplib/v5/pkg/base"
"github.com/bluenviron/gortsplib/v5/pkg/description"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/headers"
"github.com/google/uuid"
@@ -37,6 +39,19 @@ func profileLabel(p headers.TransportProfile) string {
return "unknown"
}
func findSingleMPEGTSFormat(desc *description.Session) (*description.Media, *format.MPEGTS) {
if len(desc.Medias) != 1 || len(desc.Medias[0].Formats) != 1 {
return nil, nil
}
forma := desc.Medias[0].Formats[0]
if forma, ok := forma.(*format.MPEGTS); ok {
return desc.Medias[0], forma
}
return nil, nil
}
type sessionParent interface {
logger.Writer
getConnByRConnUnsafe(rconn *gortsplib.ServerConn) *conn
@@ -64,6 +79,7 @@ type session struct {
outboundRTPPacketsDiscarded *counterdumper.Dumper
mutex sync.RWMutex
user string
mpegtsDemuxer *mpegtsDemuxer
}
func (s *session) initialize() {
@@ -135,12 +151,18 @@ func (s *session) onClose(err error) {
s.onUnreadHook()
}
if s.mpegtsDemuxer != nil {
s.mpegtsDemuxer.close()
}
switch s.rsession.State() {
case gortsplib.ServerSessionStatePrePlay, gortsplib.ServerSessionStatePlay:
s.path.RemoveReader(defs.PathRemoveReaderReq{Author: s})
case gortsplib.ServerSessionStateRecord:
s.path.RemovePublisher(defs.PathRemovePublisherReq{Author: s})
if s.path != nil {
s.path.RemovePublisher(defs.PathRemovePublisherReq{Author: s})
}
}
s.path = nil
@@ -328,6 +350,34 @@ func (s *session) onPlay(_ *gortsplib.ServerHandlerOnPlayCtx) (*base.Response, e
// onRecord is called by rtspServer.
func (s *session) onRecord(_ *gortsplib.ServerHandlerOnRecordCtx) (*base.Response, error) {
if s.pathConf.RTSPDemuxMpegts {
mpegtsMedia, mpegtsFormat := findSingleMPEGTSFormat(s.rsession.AnnouncedDescription())
if mpegtsFormat != nil {
s.Log(logger.Info, "MPEG-TS demux mode enabled, starting demuxer...")
s.mpegtsDemuxer = &mpegtsDemuxer{
session: s,
pathManager: s.pathManager,
pathConf: s.pathConf,
mpegtsMedia: mpegtsMedia,
mpegtsFormat: mpegtsFormat,
decodeErrors: s.inboundRTPPacketsInError,
pathName: s.rsession.Path()[1:],
query: s.rsession.Query(),
}
err := s.mpegtsDemuxer.initialize()
if err != nil {
return &base.Response{
StatusCode: base.StatusInternalServerError,
}, err
}
return &base.Response{
StatusCode: base.StatusOK,
}, nil
}
}
res, err := s.pathManager.AddPublisher(defs.PathAddPublisherReq{
Author: s,
Desc: s.rsession.AnnouncedDescription(),
@@ -364,6 +414,14 @@ func (s *session) onRecord(_ *gortsplib.ServerHandlerOnRecordCtx) (*base.Respons
// onPause is called by rtspServer.
func (s *session) onPause(_ *gortsplib.ServerHandlerOnPauseCtx) (*base.Response, error) {
// we can't close mpegtsDemuxer during pause because OnPacketRTP() is paused after onPause(),
// therefore a call to pipeWriter.CloseWithError() would cause a race condition.
if s.mpegtsDemuxer != nil {
return &base.Response{
StatusCode: base.StatusBadRequest,
}, fmt.Errorf("cannot pause in MPEG-TS demux mode")
}
switch s.rsession.State() {
case gortsplib.ServerSessionStatePlay:
s.onUnreadHook()
+5
View File
@@ -548,6 +548,11 @@ pathDefaults:
overridePublisher: true
# SRT encryption passphrase required to publish to this path.
srtPublishPassphrase:
# Demux MPEG-TS over RTSP into elementary streams.
# When enabled, RTSP publishers sending MP2T/90000 will be demultiplexed
# and their elementary streams (H.264, H.265, AAC, etc.) exposed as native tracks.
# This allows HLS, WebRTC, and other outputs to work transparently with MPEG-TS sources.
rtspDemuxMpegts: false
###############################################
# Default path settings -> RTSP source (when source is a RTSP or a RTSPS URL)