From 0edc3dbe8600f6e6fba1e528080dfd754c422557 Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Thu, 21 May 2026 14:50:06 +0200 Subject: [PATCH] rtmp: support reading and writing FLAC (#5778) (#5789) --- docs/2-features/03-publish.md | 14 +++--- docs/2-features/04-read.md | 16 +++--- docs/2-features/06-authentication.md | 4 +- docs/3-publish/01-srt-clients.md | 2 +- docs/3-publish/03-webrtc-clients.md | 2 +- docs/3-publish/05-rtsp-clients.md | 2 +- docs/3-publish/07-rtmp-clients.md | 10 ++-- docs/3-publish/08-rtmp-cameras-and-servers.md | 8 +-- docs/3-publish/10-mpeg-ts.md | 2 +- docs/3-publish/11-rtp.md | 2 +- ...{20-web-browsers.md => 14-web-browsers.md} | 0 docs/3-publish/{14-ffmpeg.md => 15-ffmpeg.md} | 2 +- .../{15-gstreamer.md => 16-gstreamer.md} | 2 +- .../{16-obs-studio.md => 17-obs-studio.md} | 2 +- ...7-python-opencv.md => 18-python-opencv.md} | 0 docs/3-publish/{18-golang.md => 19-golang.md} | 0 docs/3-publish/{19-unity.md => 20-unity.md} | 0 docs/4-read/01-srt.md | 2 +- docs/4-read/02-webrtc.md | 2 +- docs/4-read/03-rtsp.md | 2 +- docs/4-read/04-rtmp.md | 10 ++-- docs/4-read/05-hls.md | 2 +- ...{13-web-browsers.md => 06-web-browsers.md} | 6 +-- docs/4-read/{06-ffmpeg.md => 07-ffmpeg.md} | 4 +- .../{07-gstreamer.md => 08-gstreamer.md} | 2 +- docs/4-read/08-vlc.md | 20 -------- docs/4-read/09-vlc.md | 45 +++++++++++++++++ .../{09-obs-studio.md => 10-obs-studio.md} | 0 ...0-python-opencv.md => 11-python-opencv.md} | 0 docs/4-read/{11-golang.md => 12-golang.md} | 0 docs/4-read/{12-unity.md => 13-unity.md} | 0 go.mod | 4 +- go.sum | 8 +-- internal/formatlabel/label.go | 11 +++- internal/formatlabel/label_test.go | 2 + internal/protocols/rtmp/from_stream.go | 46 ++++++++++++++++- internal/protocols/rtmp/from_stream_test.go | 50 ++++++++++++++++++- internal/protocols/rtmp/to_stream.go | 44 ++++++++++++++-- internal/stream/rtp_decoder.go | 5 +- internal/stream/rtp_encoder.go | 24 ++++++++- internal/unit/payload_flac.go | 6 +++ 41 files changed, 272 insertions(+), 91 deletions(-) rename docs/3-publish/{20-web-browsers.md => 14-web-browsers.md} (100%) rename docs/3-publish/{14-ffmpeg.md => 15-ffmpeg.md} (86%) rename docs/3-publish/{15-gstreamer.md => 16-gstreamer.md} (89%) rename docs/3-publish/{16-obs-studio.md => 17-obs-studio.md} (97%) rename docs/3-publish/{17-python-opencv.md => 18-python-opencv.md} (100%) rename docs/3-publish/{18-golang.md => 19-golang.md} (100%) rename docs/3-publish/{19-unity.md => 20-unity.md} (100%) rename docs/4-read/{13-web-browsers.md => 06-web-browsers.md} (92%) rename docs/4-read/{06-ffmpeg.md => 07-ffmpeg.md} (52%) rename docs/4-read/{07-gstreamer.md => 08-gstreamer.md} (91%) delete mode 100644 docs/4-read/08-vlc.md create mode 100644 docs/4-read/09-vlc.md rename docs/4-read/{09-obs-studio.md => 10-obs-studio.md} (100%) rename docs/4-read/{10-python-opencv.md => 11-python-opencv.md} (100%) rename docs/4-read/{11-golang.md => 12-golang.md} (100%) rename docs/4-read/{12-unity.md => 13-unity.md} (100%) create mode 100644 internal/unit/payload_flac.go diff --git a/docs/2-features/03-publish.md b/docs/2-features/03-publish.md index 7c93a0e4..deedac41 100644 --- a/docs/2-features/03-publish.md +++ b/docs/2-features/03-publish.md @@ -21,10 +21,10 @@ We provide instructions for publishing with the following devices: We provide instructions for publishing with the following software: -- [FFmpeg](../3-publish/14-ffmpeg.md) -- [GStreamer](../3-publish/15-gstreamer.md) -- [OBS Studio](../3-publish/16-obs-studio.md) -- [Python and OpenCV](../3-publish/17-python-opencv.md) -- [Golang](../3-publish/18-golang.md) -- [Unity](../3-publish/19-unity.md) -- [Web browsers](../3-publish/20-web-browsers.md) +- [Web browsers](../3-publish/14-web-browsers.md) +- [FFmpeg](../3-publish/15-ffmpeg.md) +- [GStreamer](../3-publish/16-gstreamer.md) +- [OBS Studio](../3-publish/17-obs-studio.md) +- [Python and OpenCV](../3-publish/18-python-opencv.md) +- [Golang](../3-publish/19-golang.md) +- [Unity](../3-publish/20-unity.md) diff --git a/docs/2-features/04-read.md b/docs/2-features/04-read.md index d79d6d17..2d799bf2 100644 --- a/docs/2-features/04-read.md +++ b/docs/2-features/04-read.md @@ -10,11 +10,11 @@ Live streams can be read from the server with the following protocols: We provide instructions for reading with the following software: -- [FFmpeg](../4-read/06-ffmpeg.md) -- [GStreamer](../4-read/07-gstreamer.md) -- [VLC](../4-read/08-vlc.md) -- [OBS Studio](../4-read/09-obs-studio.md) -- [Python and OpenCV](../4-read/10-python-opencv.md) -- [Golang](../4-read/11-golang.md) -- [Unity](../4-read/12-unity.md) -- [Web browsers](../4-read/13-web-browsers.md) +- [Web browsers](../4-read/06-web-browsers.md) +- [FFmpeg](../4-read/07-ffmpeg.md) +- [GStreamer](../4-read/08-gstreamer.md) +- [VLC](../4-read/09-vlc.md) +- [OBS Studio](../4-read/10-obs-studio.md) +- [Python and OpenCV](../4-read/11-python-opencv.md) +- [Golang](../4-read/12-golang.md) +- [Unity](../4-read/13-unity.md) diff --git a/docs/2-features/06-authentication.md b/docs/2-features/06-authentication.md index d125be4f..85bd1a70 100644 --- a/docs/2-features/06-authentication.md +++ b/docs/2-features/06-authentication.md @@ -298,7 +298,7 @@ Username and password can be passed through the `Authorization: Basic` HTTP head Authorization: Basic base64(myuser:mypass) ``` -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 in a website](../4-read/13-web-browsers.md#embed-in-a-website). +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 in a website](../4-read/06-web-browsers.md#embed-in-a-website). 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: @@ -350,4 +350,4 @@ In OBS Studio, this is the "Bearer Token" field. If the `Authorization: Bearer` token cannot be directly provided (for instance, with web browsers that directly access _MediaMTX_ and show a credential dialog), you can pass the token as password, using an arbitrary user. -In web browsers, if you need to automatically fill credentials from a parent web page, read [Embed in a website](../4-read/13-web-browsers.md#embed-in-a-website). +In web browsers, if you need to automatically fill credentials from a parent web page, read [Embed in a website](../4-read/06-web-browsers.md#embed-in-a-website). diff --git a/docs/3-publish/01-srt-clients.md b/docs/3-publish/01-srt-clients.md index cd23a98c..c06ce85f 100644 --- a/docs/3-publish/01-srt-clients.md +++ b/docs/3-publish/01-srt-clients.md @@ -18,4 +18,4 @@ If you need to use the standard stream ID syntax instead of the custom one in us 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. -Some clients that can publish with SRT are [FFmpeg](14-ffmpeg.md), [GStreamer](15-gstreamer.md), [OBS Studio](16-obs-studio.md). +Some clients that can publish with SRT are [FFmpeg](15-ffmpeg.md), [GStreamer](16-gstreamer.md), [OBS Studio](17-obs-studio.md). diff --git a/docs/3-publish/03-webrtc-clients.md b/docs/3-publish/03-webrtc-clients.md index 03edc354..335bec1b 100644 --- a/docs/3-publish/03-webrtc-clients.md +++ b/docs/3-publish/03-webrtc-clients.md @@ -23,4 +23,4 @@ Be aware that not all browsers can read any codec, check [Codec support in brows Depending on the network it might be difficult to establish a connection between server and clients, read [Solving WebRTC connectivity issues](../2-features/26-webrtc-specific-features.md#solving-webrtc-connectivity-issues). -Some clients that can publish with WebRTC and WHIP are [FFmpeg](14-ffmpeg.md), [GStreamer](15-gstreamer.md), [OBS Studio](16-obs-studio.md), [Unity](19-unity.md) and [Web browsers](20-web-browsers.md). +Some clients that can publish with WebRTC and WHIP are [FFmpeg](15-ffmpeg.md), [GStreamer](16-gstreamer.md), [OBS Studio](17-obs-studio.md), [Unity](20-unity.md) and [Web browsers](14-web-browsers.md). diff --git a/docs/3-publish/05-rtsp-clients.md b/docs/3-publish/05-rtsp-clients.md index 43dd20d5..7e6c41bf 100644 --- a/docs/3-publish/05-rtsp-clients.md +++ b/docs/3-publish/05-rtsp-clients.md @@ -14,7 +14,7 @@ rtsp://localhost:8554/mystream The resulting stream will be available on path `/mystream`. -Some clients that can publish with RTSP are [FFmpeg](14-ffmpeg.md), [GStreamer](15-gstreamer.md), [OBS Studio](16-obs-studio.md), [Python and OpenCV](17-python-opencv.md). +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](../2-features/27-rtsp-specific-features.md). diff --git a/docs/3-publish/07-rtmp-clients.md b/docs/3-publish/07-rtmp-clients.md index 734c4758..fd7b7239 100644 --- a/docs/3-publish/07-rtmp-clients.md +++ b/docs/3-publish/07-rtmp-clients.md @@ -1,9 +1,9 @@ # RTMP clients -| | supported codecs | -| --------- | ----------------------------------------------------------------------------- | -| **video** | AV1, VP9, H265, H264 | -| **audio** | Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM | +| | supported codecs | +| --------- | ----------------------------------------------------------------------------------- | +| **video** | AV1, VP9, H265, H264 | +| **audio** | Opus, FLAC, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM | RTMP is a protocol that allows to read and publish streams. It has been expanded to support modern codecs (Enhanced RTMP) and it supports encryption, read [RTMP-specific features](../2-features/28-rtmp-specific-features.md). Streams can be published to the server by using the URL: @@ -13,4 +13,4 @@ rtmp://localhost/mystream The resulting stream will be available on path `/mystream`. -Some clients that can publish with RTMP are [FFmpeg](14-ffmpeg.md), [GStreamer](15-gstreamer.md), [OBS Studio](16-obs-studio.md). +Some clients that can publish with RTMP are [FFmpeg](15-ffmpeg.md), [GStreamer](16-gstreamer.md) and [OBS Studio](17-obs-studio.md). diff --git a/docs/3-publish/08-rtmp-cameras-and-servers.md b/docs/3-publish/08-rtmp-cameras-and-servers.md index a3a7838b..4caaf6ef 100644 --- a/docs/3-publish/08-rtmp-cameras-and-servers.md +++ b/docs/3-publish/08-rtmp-cameras-and-servers.md @@ -1,9 +1,9 @@ # RTMP cameras and servers -| | supported codecs | -| --------- | ----------------------------------------------------------------------------- | -| **video** | AV1, VP9, H265, H264 | -| **audio** | Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM | +| | supported codecs | +| --------- | ----------------------------------------------------------------------------------- | +| **video** | AV1, VP9, H265, H264 | +| **audio** | Opus, FLAC, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM | You can use _MediaMTX_ to connect to one or several existing RTMP servers and read their media streams: diff --git a/docs/3-publish/10-mpeg-ts.md b/docs/3-publish/10-mpeg-ts.md index 5fe06e1f..ba9c5018 100644 --- a/docs/3-publish/10-mpeg-ts.md +++ b/docs/3-publish/10-mpeg-ts.md @@ -34,7 +34,7 @@ paths: source: udp+mpegts://0.0.0.0:1234?source=192.168.3.5 ``` -Some clients that can publish with UDP and MPEG-TS are [FFmpeg](14-ffmpeg.md) and [GStreamer](15-gstreamer.md). +Some clients that can publish with UDP and MPEG-TS are [FFmpeg](15-ffmpeg.md) and [GStreamer](16-gstreamer.md). Unix sockets are more efficient than UDP packets and can be used as transport by specifying the `unix+mpegts` scheme: diff --git a/docs/3-publish/11-rtp.md b/docs/3-publish/11-rtp.md index 1b378a44..e92086f9 100644 --- a/docs/3-publish/11-rtp.md +++ b/docs/3-publish/11-rtp.md @@ -27,4 +27,4 @@ paths: `rtpSDP` must contain a valid SDP, that is a description of the RTP session. -Some clients that can publish with UDP and MPEG-TS are [FFmpeg](14-ffmpeg.md) and [GStreamer](15-gstreamer.md). +Some clients that can publish with UDP and MPEG-TS are [FFmpeg](15-ffmpeg.md) and [GStreamer](16-gstreamer.md). diff --git a/docs/3-publish/20-web-browsers.md b/docs/3-publish/14-web-browsers.md similarity index 100% rename from docs/3-publish/20-web-browsers.md rename to docs/3-publish/14-web-browsers.md diff --git a/docs/3-publish/14-ffmpeg.md b/docs/3-publish/15-ffmpeg.md similarity index 86% rename from docs/3-publish/14-ffmpeg.md rename to docs/3-publish/15-ffmpeg.md index ba712311..633150cd 100644 --- a/docs/3-publish/14-ffmpeg.md +++ b/docs/3-publish/15-ffmpeg.md @@ -1,6 +1,6 @@ # FFmpeg -FFmpeg can publish a stream to the server in several ways. The recommended one consists in publishing with RTSP. +FFmpeg can publish a stream to the server by using the [RTSP](05-rtsp-clients.md), [RTMP](07-rtmp-clients.md), [MPEG-TS](10-mpeg-ts.md), [RTP](11-rtp.md), [SRT](01-srt-clients.md) and [WebRTC](03-webrtc-clients.md) protocols. The recommended one is RTSP. ## FFmpeg and RTSP diff --git a/docs/3-publish/15-gstreamer.md b/docs/3-publish/16-gstreamer.md similarity index 89% rename from docs/3-publish/15-gstreamer.md rename to docs/3-publish/16-gstreamer.md index 4a9a0a99..51e0421d 100644 --- a/docs/3-publish/15-gstreamer.md +++ b/docs/3-publish/16-gstreamer.md @@ -1,6 +1,6 @@ # GStreamer -GStreamer can publish a stream to the server in several ways. The recommended one consists in publishing with RTSP. +GStreamer can publish a stream to the server by using the [RTSP](05-rtsp-clients.md), [RTMP](07-rtmp-clients.md), [SRT](01-srt-clients.md), [MPEG-TS](10-mpeg-ts.md) and [WebRTC](03-webrtc-clients.md) protocols. The recommended one is RTSP. ## GStreamer and RTSP diff --git a/docs/3-publish/16-obs-studio.md b/docs/3-publish/17-obs-studio.md similarity index 97% rename from docs/3-publish/16-obs-studio.md rename to docs/3-publish/17-obs-studio.md index 5d76f955..ab3a1183 100644 --- a/docs/3-publish/16-obs-studio.md +++ b/docs/3-publish/17-obs-studio.md @@ -1,6 +1,6 @@ # OBS Studio -OBS Studio can publish streams to the server in several ways. The recommended one consists in publishing with RTMP. +OBS Studio can publish streams to the server by using the [RTMP](07-rtmp-clients.md) and [WebRTC](03-webrtc-clients.md) protocols. The recommended one is RTMP. ## OBS Studio and RTMP diff --git a/docs/3-publish/17-python-opencv.md b/docs/3-publish/18-python-opencv.md similarity index 100% rename from docs/3-publish/17-python-opencv.md rename to docs/3-publish/18-python-opencv.md diff --git a/docs/3-publish/18-golang.md b/docs/3-publish/19-golang.md similarity index 100% rename from docs/3-publish/18-golang.md rename to docs/3-publish/19-golang.md diff --git a/docs/3-publish/19-unity.md b/docs/3-publish/20-unity.md similarity index 100% rename from docs/3-publish/19-unity.md rename to docs/3-publish/20-unity.md diff --git a/docs/4-read/01-srt.md b/docs/4-read/01-srt.md index 8da288d2..a40f419a 100644 --- a/docs/4-read/01-srt.md +++ b/docs/4-read/01-srt.md @@ -16,4 +16,4 @@ 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, read [Standard stream ID syntax](../2-features/25-srt-specific-features.md#standard-stream-id-syntax). -Some clients that can read with SRT are [FFmpeg](06-ffmpeg.md), [GStreamer](07-gstreamer.md) and [VLC](08-vlc.md). +Some clients that can read with SRT are [FFmpeg](07-ffmpeg.md), [GStreamer](08-gstreamer.md) and [VLC](09-vlc.md). diff --git a/docs/4-read/02-webrtc.md b/docs/4-read/02-webrtc.md index 71da9701..a7a18081 100644 --- a/docs/4-read/02-webrtc.md +++ b/docs/4-read/02-webrtc.md @@ -22,4 +22,4 @@ Be aware that not all browsers can read any codec, check [Codec support in brows Depending on the network it may be difficult to establish a connection between server and clients, read [Solving WebRTC connectivity issues](../2-features/26-webrtc-specific-features.md#solving-webrtc-connectivity-issues). -Some clients that can read with WebRTC and WHEP are [GStreamer](07-gstreamer.md), [Unity](12-unity.md) and [web browsers](13-web-browsers.md). +Some clients that can read with WebRTC and WHEP are [GStreamer](08-gstreamer.md), [Unity](13-unity.md) and [web browsers](06-web-browsers.md). diff --git a/docs/4-read/03-rtsp.md b/docs/4-read/03-rtsp.md index 90bb6d59..c1c51270 100644 --- a/docs/4-read/03-rtsp.md +++ b/docs/4-read/03-rtsp.md @@ -12,4 +12,4 @@ RTSP is a protocol that allows to publish and read streams. It supports several rtsp://localhost:8554/mystream ``` -Some clients that can read with RTSP are [FFmpeg](06-ffmpeg.md), [GStreamer](07-gstreamer.md) and [VLC](08-vlc.md). +Some clients that can read with RTSP are [FFmpeg](07-ffmpeg.md), [GStreamer](08-gstreamer.md) and [VLC](09-vlc.md). diff --git a/docs/4-read/04-rtmp.md b/docs/4-read/04-rtmp.md index c932f7d5..108b10b0 100644 --- a/docs/4-read/04-rtmp.md +++ b/docs/4-read/04-rtmp.md @@ -1,9 +1,9 @@ # RTMP clients -| | supported codecs | -| --------- | ----------------------------------------------------------------------------- | -| **video** | AV1, VP9, H265, H264 | -| **audio** | Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM | +| | supported codecs | +| --------- | ----------------------------------------------------------------------------------- | +| **video** | AV1, VP9, H265, H264 | +| **audio** | Opus, FLAC, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM | RTMP is a protocol that allows to read and publish streams. It has been expanded to support modern codecs (Enhanced RTMP) and it supports encryption, read [RTMP-specific features](../2-features/28-rtmp-specific-features.md). Streams can be read from the server by using the URL: @@ -11,4 +11,4 @@ RTMP is a protocol that allows to read and publish streams. It has been expanded rtmp://localhost/mystream ``` -Some clients that can read with RTMP are [FFmpeg](06-ffmpeg.md), [GStreamer](07-gstreamer.md) and [VLC](08-vlc.md). +Some clients that can read with RTMP are [FFmpeg](07-ffmpeg.md), [GStreamer](08-gstreamer.md) and [VLC](09-vlc.md). diff --git a/docs/4-read/05-hls.md b/docs/4-read/05-hls.md index 3a753096..add640da 100644 --- a/docs/4-read/05-hls.md +++ b/docs/4-read/05-hls.md @@ -18,7 +18,7 @@ and can also be accessed without using the browsers, by software that supports t http://localhost:8888/mystream/index.m3u8 ``` -Some clients that can read with HLS are [FFmpeg](06-ffmpeg.md), [GStreamer](07-gstreamer.md), [VLC](08-vlc.md) and [web browsers](13-web-browsers.md). +Some clients that can read with HLS are [FFmpeg](07-ffmpeg.md), [GStreamer](08-gstreamer.md), [VLC](09-vlc.md) and [web browsers](06-web-browsers.md). _MediaMTX_ supports generating HLS in several variants (including Low-Latency mode), and provides various parameters to tune HLS generation. These are listed in the [configuration file](../5-references/1-configuration-file.md): diff --git a/docs/4-read/13-web-browsers.md b/docs/4-read/06-web-browsers.md similarity index 92% rename from docs/4-read/13-web-browsers.md rename to docs/4-read/06-web-browsers.md index c0feff45..fbf5e39e 100644 --- a/docs/4-read/13-web-browsers.md +++ b/docs/4-read/06-web-browsers.md @@ -1,12 +1,12 @@ # Web browsers -Web browsers can read a stream from the server with the WebRTC or the HLS protocol, by directly accessing web pages provided by the server. It is also possible to embed streams into an external website. +Web browsers can read a stream from the server with the [WebRTC](02-webrtc.md) and [HLS](05-hls.md) protocols, by accessing web pages hosted by the server. It is also possible to embed streams into an external website. ## Direct read ### WebRTC -Web browsers can read a stream with the [WebRTC protocol](02-webrtc.md) by visiting the web page: +Visit the web page: ``` http://localhost:8889/mystream @@ -16,7 +16,7 @@ Replace `mystream` with the path name. ### HLS -Web browsers can also read a stream with the [HLS protocol](05-hls.md). Latency is higher but there are fewer problems related to connectivity between server and clients. Visit the web page: +The HLS protocol has a higher latency with respect to WebRTC, but there are fewer problems related to connectivity between server and clients. Visit the web page: ``` http://localhost:8888/mystream diff --git a/docs/4-read/06-ffmpeg.md b/docs/4-read/07-ffmpeg.md similarity index 52% rename from docs/4-read/06-ffmpeg.md rename to docs/4-read/07-ffmpeg.md index 71265939..e4218f2c 100644 --- a/docs/4-read/06-ffmpeg.md +++ b/docs/4-read/07-ffmpeg.md @@ -1,6 +1,6 @@ # FFmpeg -FFmpeg can read a stream from the server in several ways. The recommended one consists in reading with RTSP. +FFmpeg can read a stream from the server the [RTSP](03-rtsp.md), [RTMP](04-rtmp.md), [HLS](05-hls.md) and [SRT](01-srt.md) protocols. The recommended one is RTSP. ## FFmpeg and RTSP @@ -14,7 +14,7 @@ ffmpeg -i rtsp://localhost:8554/mystream -c copy output.mp4 ffmpeg -i rtmp://localhost/mystream -c copy output.mp4 ``` -In order to read AV1, VP9, H265, Opus, AC3 tracks and in order to read multiple video or audio tracks, the `-rtmp_enhanced_codecs` flag must be present: +In order to read tracks that make use of modern codecs (AV1, VP9, H265, Opus, FLAC, AC-3) and in order to read multiple video or audio tracks, the `-rtmp_enhanced_codecs` flag must be present and filled with the following values: ```sh ffmpeg -rtmp_enhanced_codecs ac-3,av01,avc1,ec-3,fLaC,hvc1,.mp3,mp4a,Opus,vp09 \ diff --git a/docs/4-read/07-gstreamer.md b/docs/4-read/08-gstreamer.md similarity index 91% rename from docs/4-read/07-gstreamer.md rename to docs/4-read/08-gstreamer.md index 9018eefc..43b10a21 100644 --- a/docs/4-read/07-gstreamer.md +++ b/docs/4-read/08-gstreamer.md @@ -1,6 +1,6 @@ # GStreamer -GStreamer can read a stream from the server in several ways. The recommended one consists in reading with RTSP. +GStreamer can read a stream from the server by using the [RTSP](03-rtsp.md), [RTMP](04-rtmp.md), [HLS](05-hls.md), [SRT](01-srt.md) and [WebRTC](02-webrtc.md) protocols. The recommended one is RTSP. ## GStreamer and RTSP diff --git a/docs/4-read/08-vlc.md b/docs/4-read/08-vlc.md deleted file mode 100644 index 9eac9add..00000000 --- a/docs/4-read/08-vlc.md +++ /dev/null @@ -1,20 +0,0 @@ -# VLC - -VLC can read a stream from the server in several ways. The recommended one consists in reading with RTSP: - -```sh -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 (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 -snap install vlc -``` - -## Encrypted RTSP compatibility - -At the moment VLC doesn't support reading encrypted RTSP streams. However, you can use a proxy like [stunnel](https://www.stunnel.org) or [nginx](https://nginx.org/) or a local _MediaMTX_ instance to decrypt streams before reading them. diff --git a/docs/4-read/09-vlc.md b/docs/4-read/09-vlc.md new file mode 100644 index 00000000..cc623fb6 --- /dev/null +++ b/docs/4-read/09-vlc.md @@ -0,0 +1,45 @@ +# VLC + +VLC can read a stream from the server by using the [RTSP](03-rtsp.md), [RTMP](04-rtmp.md), [HLS](05-hls.md) and [SRT](01-srt.md) protocols. The recommended one is RTSP. + +In order to minimize latency, it is also suggested to change the `Network caching` parameter of VLC: + +1. Open VLC, _Tools_, _Preferences_, _Show Settings_, _All_, page _Input / Codecs_. +2. Find the _Network caching (ms)_ parameter, set it to `50`. Save + +## VLC and RTSP + +Open the following URL: + +``` +rtsp://localhost:8554/mystream +``` + +### RTSP and Ubuntu + +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 +snap install vlc +``` + +### Encrypted RTSP + +At the moment VLC doesn't support reading encrypted RTSP streams (RTSPS). However, you can use a proxy like [stunnel](https://www.stunnel.org) or [nginx](https://nginx.org/) or a local _MediaMTX_ instance to decrypt streams before reading them. + +## VLC and RTMP + +Open the following URL: + +``` +rtmp://localhost/mystream +``` + +## VLC and SRT + +Open the following URL: + +``` +srt://localhost:8890?streamid=read:mystream +``` diff --git a/docs/4-read/09-obs-studio.md b/docs/4-read/10-obs-studio.md similarity index 100% rename from docs/4-read/09-obs-studio.md rename to docs/4-read/10-obs-studio.md diff --git a/docs/4-read/10-python-opencv.md b/docs/4-read/11-python-opencv.md similarity index 100% rename from docs/4-read/10-python-opencv.md rename to docs/4-read/11-python-opencv.md diff --git a/docs/4-read/11-golang.md b/docs/4-read/12-golang.md similarity index 100% rename from docs/4-read/11-golang.md rename to docs/4-read/12-golang.md diff --git a/docs/4-read/12-unity.md b/docs/4-read/13-unity.md similarity index 100% rename from docs/4-read/12-unity.md rename to docs/4-read/13-unity.md diff --git a/go.mod b/go.mod index 4a763ab8..049e7fa2 100644 --- a/go.mod +++ b/go.mod @@ -11,9 +11,9 @@ require ( github.com/alecthomas/kong v1.15.0 github.com/asticode/go-astits v1.15.0 github.com/bluenviron/gohlslib/v2 v2.3.2 - github.com/bluenviron/gortmplib v0.3.2 + github.com/bluenviron/gortmplib v0.3.3-0.20260520213319-89bf8b0c2c7f github.com/bluenviron/gortsplib/v5 v5.5.3 - github.com/bluenviron/mediacommon/v2 v2.8.3 + github.com/bluenviron/mediacommon/v2 v2.8.4-0.20260520210731-a2f6c851f7b5 github.com/datarhei/gosrt v0.11.0 github.com/fsnotify/fsnotify v1.10.1 github.com/gin-contrib/pprof v1.5.4 diff --git a/go.sum b/go.sum index f6843138..f18a9b76 100644 --- a/go.sum +++ b/go.sum @@ -35,12 +35,12 @@ github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYh github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c/go.mod h1:x1vxHcL/9AVzuk5HOloOEPrtJY0MaalYr78afXZ+pWI= github.com/bluenviron/gohlslib/v2 v2.3.2 h1:Q6ZAYRFZ++rSfK0sm8vOEYhtH7KKBpfzQdenWJOgNMY= github.com/bluenviron/gohlslib/v2 v2.3.2/go.mod h1:kA0hTg96hmTZjeZ/Vxwpu/Njy0emAoidEoDGQ/KlMH0= -github.com/bluenviron/gortmplib v0.3.2 h1:jtIWdN3FrnVh7Av8aWBIp2l6t1DeEUI80qPpRmONUCU= -github.com/bluenviron/gortmplib v0.3.2/go.mod h1:15031Vx53/kjKdbhmLdfggv3thOv6fyRVZafAZfZh6c= +github.com/bluenviron/gortmplib v0.3.3-0.20260520213319-89bf8b0c2c7f h1:glyddGmkLFBtsGgNqP8ypnHp9Hpra0Q0EpmMlYbuarA= +github.com/bluenviron/gortmplib v0.3.3-0.20260520213319-89bf8b0c2c7f/go.mod h1:6jOS24kmD3TVhmlfy1vpbFTO7L8NJBJYVGt0D2CGSZ8= github.com/bluenviron/gortsplib/v5 v5.5.3 h1:aKdP14cRP8CorUCw2K4Qn/Zrs4AXTbAKUENVqh3B3vM= github.com/bluenviron/gortsplib/v5 v5.5.3/go.mod h1:e4abL49yJF5TR+1m9+0K+UuCSkyJn345Dt2XIJfu4Nc= -github.com/bluenviron/mediacommon/v2 v2.8.3 h1:T6xb7ZK3eBixi/HynzhtGRCEIrazwcmGIeu0WDTVISY= -github.com/bluenviron/mediacommon/v2 v2.8.3/go.mod h1:CsYjGgzIz8RbloQf4BHR4uReogZsB4PEKWfePVIzJv8= +github.com/bluenviron/mediacommon/v2 v2.8.4-0.20260520210731-a2f6c851f7b5 h1:eJynVwJEHnGuQxXvyuf/KU6B6ya4X7/03tcJKBmy7Pg= +github.com/bluenviron/mediacommon/v2 v2.8.4-0.20260520210731-a2f6c851f7b5/go.mod h1:syqw4j2RmBCKZgUtGFtB/7gcnh1aaX8I3vd24+bgXWc= github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE= diff --git a/internal/formatlabel/label.go b/internal/formatlabel/label.go index b7c48c2c..24efe7fe 100644 --- a/internal/formatlabel/label.go +++ b/internal/formatlabel/label.go @@ -2,6 +2,8 @@ package formatlabel import ( + "strings" + "github.com/bluenviron/gortsplib/v5/pkg/description" "github.com/bluenviron/gortsplib/v5/pkg/format" ) @@ -22,6 +24,7 @@ const ( MJPEG Label = "M-JPEG" // audio Opus Label = "Opus" + FLAC Label = "FLAC" Vorbis Label = "Vorbis" MPEG4Audio Label = "MPEG-4 Audio" MPEG4AudioLATM Label = "MPEG-4 Audio LATM" @@ -86,9 +89,13 @@ func FormatToLabel(forma format.Format) Label { return MPEGTS case *format.KLV: return KLV - default: - return Generic + case *format.Generic: + if strings.HasPrefix(strings.ToLower(forma.RTPMap()), "flac/") { + return FLAC + } } + + return Generic } func gatherFormats(medias []*description.Media) []format.Format { diff --git a/internal/formatlabel/label_test.go b/internal/formatlabel/label_test.go index b627f9d3..8feeee19 100644 --- a/internal/formatlabel/label_test.go +++ b/internal/formatlabel/label_test.go @@ -19,6 +19,7 @@ func TestFormatToLabel(t *testing.T) { FormatToLabel(&format.MPEG1Video{}), FormatToLabel(&format.MJPEG{}), FormatToLabel(&format.Opus{}), + FormatToLabel(&format.Generic{RTPMa: "FLAC/44100/2"}), FormatToLabel(&format.Vorbis{}), FormatToLabel(&format.MPEG4Audio{}), FormatToLabel(&format.MPEG4AudioLATM{}), @@ -44,6 +45,7 @@ func TestFormatToLabel(t *testing.T) { MPEG1Video, MJPEG, Opus, + FLAC, Vorbis, MPEG4Audio, MPEG4AudioLATM, diff --git a/internal/protocols/rtmp/from_stream.go b/internal/protocols/rtmp/from_stream.go index eee7d577..3cf486b4 100644 --- a/internal/protocols/rtmp/from_stream.go +++ b/internal/protocols/rtmp/from_stream.go @@ -5,6 +5,8 @@ import ( "errors" "net" "slices" + "strconv" + "strings" "time" "github.com/bluenviron/gortmplib" @@ -13,6 +15,7 @@ import ( "github.com/bluenviron/gortsplib/v5/pkg/description" "github.com/bluenviron/gortsplib/v5/pkg/format" "github.com/bluenviron/mediacommon/v2/pkg/codecs/ac3" + "github.com/bluenviron/mediacommon/v2/pkg/codecs/flac" "github.com/bluenviron/mediacommon/v2/pkg/codecs/h264" "github.com/bluenviron/mediacommon/v2/pkg/codecs/h265" "github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg1audio" @@ -26,7 +29,7 @@ import ( var errNoSupportedCodecsFrom = errors.New( "the stream doesn't contain any supported codec, which are currently " + - "AV1, VP9, H265, H264, Opus, MPEG-4 Audio, MPEG-1/2 Audio, AC-3, G711, LPCM") + "AV1, VP9, H265, H264, Opus, FLAC, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711, LPCM") func multiplyAndDivide2(v, m, d time.Duration) time.Duration { secs := v / d @@ -212,7 +215,11 @@ func FromStream( if slices.Contains(conn.FourCcList, any(fourCCToString(message.FourCCOpus))) { track := &gortmplib.Track{ Codec: &codecs.Opus{ - ChannelCount: forma.ChannelCount, + IDHeader: &opus.IDHeader{ + Version: 0x1, + ChannelCount: uint8(forma.ChannelCount), + PreSkip: 3840, + }, }, } tracks = append(tracks, track) @@ -453,6 +460,41 @@ func FromStream( ) }) } + + case *format.Generic: + if strings.HasPrefix(strings.ToLower(forma.RTPMap()), "flac/") && + slices.Contains(conn.FourCcList, any(fourCCToString(message.FourCCFLAC))) { + sampleRate, _ := strconv.Atoi(forma.FMTP()["samplerate"]) + channelCount, _ := strconv.Atoi(forma.FMTP()["channels"]) + bitDepth, _ := strconv.Atoi(forma.FMTP()["bitdepth"]) + + track := &gortmplib.Track{ + Codec: &codecs.FLAC{ + StreamInfo: &flac.StreamInfo{ + SampleRate: uint32(sampleRate), + ChannelCount: uint8(channelCount), + BitDepth: uint8(bitDepth), + }, + }, + } + tracks = append(tracks, track) + + r.OnData( + media, + forma, + func(u *unit.Unit) error { + if u.NilPayload() { + return nil + } + + nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) + return (*w).WriteFLAC( + track, + timestampToDuration(u.PTS, forma.ClockRate()), + u.Payload.(unit.PayloadFLAC), + ) + }) + } } } } diff --git a/internal/protocols/rtmp/from_stream_test.go b/internal/protocols/rtmp/from_stream_test.go index cfaf0d23..e133d88f 100644 --- a/internal/protocols/rtmp/from_stream_test.go +++ b/internal/protocols/rtmp/from_stream_test.go @@ -12,7 +12,9 @@ import ( "github.com/bluenviron/gortmplib/pkg/codecs" "github.com/bluenviron/gortsplib/v5/pkg/description" "github.com/bluenviron/gortsplib/v5/pkg/format" + "github.com/bluenviron/mediacommon/v2/pkg/codecs/flac" "github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg4audio" + "github.com/bluenviron/mediacommon/v2/pkg/codecs/opus" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/test" @@ -224,7 +226,12 @@ func TestFromStream(t *testing.T) { }, expectedTracks: []*gortmplib.Track{ {Codec: &codecs.Opus{ - ChannelCount: 2, + IDHeader: &opus.IDHeader{ + Version: 0x1, + ChannelCount: 2, + PreSkip: 3840, + ChannelMappingTable: []uint8{}, + }, }}, }, writeUnits: func(medias []*description.Media, subStream *stream.SubStream) { @@ -445,6 +452,40 @@ func TestFromStream(t *testing.T) { } }, }, + { + name: "flac", + medias: []*description.Media{ + { + Formats: []format.Format{&format.Generic{ + PayloadTyp: 96, + RTPMa: "FLAC/90000", + ClockRat: 90000, + FMT: map[string]string{ + "samplerate": "44100", + "channels": "2", + "bitdepth": "16", + }, + }}, + }, + }, + expectedTracks: []*gortmplib.Track{ + {Codec: &codecs.FLAC{ + StreamInfo: &flac.StreamInfo{ + SampleRate: 44100, + ChannelCount: 2, + BitDepth: 16, + }, + }}, + }, + writeUnits: func(medias []*description.Media, subStream *stream.SubStream) { + for i := range 2 { + subStream.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 5 * int64(i), + Payload: unit.PayloadFLAC{3, 4}, + }) + } + }, + }, { name: "h265 + h264 + vp9 + av1 + opus + aac", medias: []*description.Media{ @@ -489,7 +530,12 @@ func TestFromStream(t *testing.T) { {Codec: &codecs.VP9{}}, {Codec: &codecs.AV1{}}, {Codec: &codecs.Opus{ - ChannelCount: 2, + IDHeader: &opus.IDHeader{ + Version: 0x1, + ChannelCount: 2, + PreSkip: 3840, + ChannelMappingTable: []uint8{}, + }, }}, {Codec: &codecs.MPEG4Audio{ Config: test.FormatMPEG4Audio.Config, diff --git a/internal/protocols/rtmp/to_stream.go b/internal/protocols/rtmp/to_stream.go index 4b195064..e98898e2 100644 --- a/internal/protocols/rtmp/to_stream.go +++ b/internal/protocols/rtmp/to_stream.go @@ -2,6 +2,7 @@ package rtmp import ( "errors" + "strconv" "time" "github.com/bluenviron/gortmplib" @@ -15,7 +16,7 @@ import ( var errNoSupportedCodecsTo = errors.New( "the stream doesn't contain any supported codec, which are currently " + - "AV1, VP9, H265, H264, MPEG-4 Audio, MPEG-1/2 Audio, G711, LPCM") + "AV1, VP9, H265, H264, Opus, FLAC, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711, LPCM") func multiplyAndDivide(v, m, d int64) int64 { secs := v / d @@ -115,9 +116,13 @@ func ToStream( }) case *codecs.Opus: + channelCount := 2 + if codec.IDHeader != nil { + channelCount = int(codec.IDHeader.ChannelCount) + } forma := &format.Opus{ PayloadTyp: 96, - ChannelCount: codec.ChannelCount, + ChannelCount: channelCount, } medi := &description.Media{ Type: description.MediaTypeAudio, @@ -132,6 +137,38 @@ func ToStream( }) }) + case *codecs.FLAC: + sampleRate := 0 + channelCount := 0 + bitDepth := 0 + if codec.StreamInfo != nil { + sampleRate = int(codec.StreamInfo.SampleRate) + channelCount = int(codec.StreamInfo.ChannelCount) + bitDepth = int(codec.StreamInfo.BitDepth) + } + forma := &format.Generic{ + PayloadTyp: 96, + RTPMa: "flac/90000", + ClockRat: 90000, + FMT: map[string]string{ + "samplerate": strconv.Itoa(sampleRate), + "channels": strconv.Itoa(channelCount), + "bitdepth": strconv.Itoa(bitDepth), + }, + } + medi := &description.Media{ + Type: description.MediaTypeApplication, + Formats: []format.Format{forma}, + } + medias = append(medias, medi) + + r.OnDataFLAC(track, func(pts time.Duration, frame []byte) { + (*subStream).WriteUnit(medi, forma, &unit.Unit{ + PTS: durationToTimestamp(pts, forma.ClockRate()), + Payload: unit.PayloadFLAC(frame), + }) + }) + case *codecs.MPEG4Audio: forma := &format.MPEG4Audio{ PayloadTyp: 96, @@ -235,9 +272,6 @@ func ToStream( Payload: unit.PayloadLPCM(samples), }) }) - - default: - panic("should not happen") } } diff --git a/internal/stream/rtp_decoder.go b/internal/stream/rtp_decoder.go index 432a11c4..edca4e78 100644 --- a/internal/stream/rtp_decoder.go +++ b/internal/stream/rtp_decoder.go @@ -359,8 +359,7 @@ func newRTPDecoder(forma format.Format) (rtpDecoder, error) { return nil, err } return (*rtpDecoderKLV)(wrapped), nil - - default: - return nil, nil } + + return nil, nil } diff --git a/internal/stream/rtp_encoder.go b/internal/stream/rtp_encoder.go index ee7428cb..15a6de82 100644 --- a/internal/stream/rtp_encoder.go +++ b/internal/stream/rtp_encoder.go @@ -2,6 +2,7 @@ package stream import ( "fmt" + "strings" "github.com/bluenviron/gortsplib/v5/pkg/format" "github.com/bluenviron/gortsplib/v5/pkg/format/rtpac3" @@ -151,6 +152,16 @@ func (e *rtpEncoderKLV) encode(payload unit.Payload) ([]*rtp.Packet, error) { return (*rtpklv.Encoder)(e).Encode(payload.(unit.PayloadKLV)) } +type rtpEncoderEmpty struct{} + +func (e *rtpEncoderEmpty) init() error { + return nil +} + +func (e *rtpEncoderEmpty) encode(_ unit.Payload) ([]*rtp.Packet, error) { + return nil, nil +} + func newRTPEncoder( forma format.Format, rtpMaxPayloadSize int, @@ -388,7 +399,16 @@ func newRTPEncoder( return (*rtpEncoderKLV)(wrapped), nil - default: - return nil, rtpEncoderNotAvailableError{forma} + case *format.Generic: + if strings.HasPrefix(strings.ToLower(forma.RTPMap()), "flac/") { + enc := &rtpEncoderEmpty{} + err := enc.init() + if err != nil { + return nil, err + } + return enc, nil + } } + + return nil, rtpEncoderNotAvailableError{forma} } diff --git a/internal/unit/payload_flac.go b/internal/unit/payload_flac.go new file mode 100644 index 00000000..2da2c6cf --- /dev/null +++ b/internal/unit/payload_flac.go @@ -0,0 +1,6 @@ +package unit + +// PayloadFLAC is the payload of a FLAC track. +type PayloadFLAC []byte + +func (PayloadFLAC) isPayload() {}