MediaMTX
lastmod 2025-12-05created 2023-04-1222 edits
A ready-to-use SRT / RTSP / RTMP / LL-HLS / WebRTC media server and media proxy that can read, publish, and proxy video and audio streams.
Its old name is rtsp-simple-server.
Categories
- MediaMTX:Configuration (how to configure the mediamtx.yml file)
Features
- Publish live streams to the server
- Read live streams from the server
- Proxy streams from other servers or cameras, always or on-demand
- Streams are automatically converted from one protocol to another. For example, you can publish a stream with RTSP and read it with HLS.
- Serve multiple streams at once in separate paths
- Authenticate users; use internal or external authentication
- Redirect readers to other RTSP servers (load balancing)
- Query and control the server through the API
- Reload the configuration without disconnecting existing clients (hot reloading)
- Read Prometheus-compatible metrics
- Run external commands when clients connect, disconnect, read or publish streams
- Compatible with Linux, Windows and macOS, does not require any dependency or interpreter, it's a single executable
Docker Image
FFmpeg-compatible package name: bluenviron/mediamtx:latest-ffmpeg
The --network=host flag is mandatory because Docker can change the source port of UDP packets for routing reasons, and this prevents the RTSP server from identifying the senders of the packets. This issue can be avoided by disabling the UDP transport protocol.
# 8554 - rtsp
# 1935 - rtmp
docker run --rm -it \
-e MTX_PROTOCOLS=tcp \
-p 8554:8554 \
-p 1935:1935 \
-p 8888:8888 \
-p 8889:8889 \
bluenviron/mediamtx
The mediamtx.yml file can be shared with the host at the following path:
How to set environment variables for the mystream path:
docker run --rm -it -e MTX_PATHS_MYSTREAM_SOURCE=rtsp://admin:[email protected]/stream1 -e MTX_PROTOCOLS=tcp -p 8554:8554 -p 1935:1935 -p 8888:8888 -p 8889:8889 bluenviron/mediamtx
To connect to the API as an Anonymouse user:
docker run --rm -it \
-e MTX_API=yes \
-e MTX_RTSPTRANSPORTS=tcp \
-e MTX_AUTHINTERNALUSERS_0_USER=any \
-e MTX_AUTHINTERNALUSERS_0_PASS= \
-e MTX_AUTHINTERNALUSERS_0_PERMISSIONS_0_ACTION=publish \
-e MTX_AUTHINTERNALUSERS_0_PERMISSIONS_1_ACTION=read \
-e MTX_AUTHINTERNALUSERS_0_PERMISSIONS_2_ACTION=playback \
-e MTX_AUTHINTERNALUSERS_0_PERMISSIONS_3_ACTION=api \
-e MTX_AUTHINTERNALUSERS_0_PERMISSIONS_4_ACTION=metrics \
-e MTX_AUTHINTERNALUSERS_0_PERMISSIONS_5_ACTION=pprof \
-p 8554:8554 \
-p 9997:9997 \
bluenviron/mediamtx:latest-ffmpeg
Publishing streams: by program
Assuming Docker is running and the address for publishing is rtsp://localhost:8554/mystream
FFmpeg
You can publish a video/audio file.
To send over TCP, add -rtsp_transport tcp:
ffmpeg -re -stream_loop -1 -i file.ts -c copy -f rtsp -rtsp_transport tcp rtsp://localhost:8554/mystream
For RTMP, use the flv format:
To make a demo video:
ffmpeg -f lavfi -i testsrc=size=1280x720:rate=30 -c:v libx264 -preset fast -tune zerolatency -f rtsp rtsp://localhost:8554/demo
GStreamer
gst-launch-1.0 rtspclientsink name=s location=rtsp://localhost:8554/mystream filesrc location=file.mp4 ! qtdemux name=d d.video_0 ! queue ! s.sink_0 d.audio_0 ! queue ! s.sink_1
If the stream is video only
gst-launch-1.0 filesrc location=file.mp4 ! qtdemux name=d d.video_0 ! rtspclientsink name=s location=rtsp://localhost:8554/mystream
The transport protocol can be set with the protocols flag
gst-launch-1.0 filesrc location=file.mp4 ! qtdemux name=d d.video_0 ! rtspclientsink protocols=tcp name=s location=rtsp://localhost:8554/mystream
OBS Studio
You can stream with RTMP, or, with recent versions of OBS Studio, publish to the server using the WebRTC/WHIP protocol:
- Service: WHIP
- Server:
http://localhost:8889/mystream/whip
OpenCV
GStreamer support is required.
Check that python3 -c 'import cv2; print(cv2.getBuildInformation())' prints GStreamer: YES.
out = cv2.VideoWriter('appsrc ! videoconvert' + \
' ! x264enc speed-preset=ultrafast bitrate=600 key-int-max=' + str(fps * 2) + \
' ! video/x-h264,profile=baseline' + \
' ! rtspclientsink location=rtsp://localhost:8554/mystream',
cv2.CAP_GSTREAMER, 0, fps, (width, height), True)
if not out.isOpened():
raise Exception("can't open video writer")
Browser
Open http://localhost:8889/mystream/publish to publish with WebRTC.
If needed, embed the page as an iframe.
Publishing streams: by protocol
WebRTC
http://localhost:8889/mystream/publish
WebRTC WHIP
http://localhost:8889/mystream/whip
RTSP
rtsp://localhost:8554/mystream, the resulting stream is /mystream.
For cameras and servers:
The resulting streams are available at /proxied1 and /proxied2.
RTMP
rtmp://localhost/mystream, the resulting stream is /mystream.
For cameras and servers:
paths:
proxied:
# url of the source stream, in the format rtmp://user:pass@host:port/path
source: rtmp://original-url
HLS cameras and servers
paths:
proxied:
# url of the playlist of the stream, in the format http://user:pass@host:port/path
source: http://original-url/stream/index.m3u8
UDP/MPEG-TS
The server supports ingesting UDP/MPEG-TS packets (i.e. MPEG-TS packets sent with UDP). Packets can be unicast, broadcast or multicast. For instance, you can generate a multicast UDP/MPEG-TS stream with GStreamer:
gst-launch-1.0 -v mpegtsmux name=mux alignment=1 ! udpsink host=238.0.0.1 port=1234 \
videotestsrc ! video/x-raw,width=1280,height=720 ! x264enc speed-preset=ultrafast bitrate=3000 key-int-max=60 ! video/x-h264,profile=high ! mux. \
audiotestsrc ! audioconvert ! avenc_aac ! mux.
mediamtx.yml:
Playing streams
For example, you can open the stream with VLC.
| Ubuntu 21.10 bug |
| On Ubuntu 21.10, the bundled VLC does not support RTSP playback due to licensing issues. To fix this, remove the default VLC instance and install the snap version. |
Or GStreamer:
Or FFmpeg:
Unlimited connection for unstable connections
Connect via RTMP with VLC, then turn on "infinite loop" (important).
Authentication
Only clients that provide username and passwords will be able to perform a certain action:
If storing plain credentials in the configuration file is a security problem, username and passwords can be stored as hashed strings. The Argon2 and SHA256 hashing algorithms are supported. To use Argon2, the string must be hashed using Argon2id (recommended) or Argon2i:
Then stored with the argon2: prefix:
authInternalUsers:
- user: argon2:$argon2id$v=19$m=4096,t=3,p=1$MTIzNDU2Nzg$OGGO0eCMN0ievb4YGSzvS/H+Vajx1pcbUmtLp2tRqRU
pass: argon2:$argon2i$v=19$m=4096,t=3,p=1$MTIzNDU2Nzg$oct3kOiFywTdDdt19kT07hdvmsPTvt9zxAUho2DLqZw
permissions:
- action: publish
To use SHA256, the string must be hashed with SHA256 and encoded with base64:
Then stored with the sha256: prefix:
authInternalUsers:
- user: sha256:j1tsRqDEw9xvq/D7/9tMx6Jh/jMhk3UfjwIB2f1zgMo=
pass: sha256:BdSWkrdV+ZxFBLUQQY7+7uv9RmiSVA8nrPmjGjJtZQQ=
permissions:
- action: publish
Remuxing, re-encoding, compression (Save streams to disk)
To save available streams to disk, use FFmpeg inside the runOnReady parameter:
paths:
all:
runOnReady: >
ffmpeg -i rtsp://localhost:$RTSP_PORT/$MTX_PATH
-c copy
-f segment -strftime 1 -segment_time 60 -segment_format mpegts saved_%Y-%m-%d_%H-%M-%S.ts
runOnReadyRestart: yes
Record streams to disk
To save available streams to disk, set the record and the recordPath parameter in the configuration file:
pathDefaults:
# Record streams to disk.
record: yes
# Path of recording segments.
# Extension is added automatically.
# Available variables are %path (path name), %Y %m %d %H %M %S %f %s (time in strftime format)
recordPath: ./recordings/%path/%Y-%m-%d_%H-%M-%S-%f
To sync (upload) to a remote storage, install rclone:
pathDefaults:
# this is needed to sync segments after a crash.
# replace myconfig with the name of the rclone config.
runOnInit: rclone sync -v ./recordings myconfig:/my-path/recordings
# this is called when a segment has been finalized.
# replace myconfig with the name of the rclone config.
runOnRecordSegmentComplete: rclone sync -v --min-age=1ms ./recordings myconfig:/my-path/recordings
Setting the auto-delete period or Disable
By default, recordings are kept for only 1 day. To turn off auto-save:
Note that in older versions, setting auto-delete to 1 day (==1d) does not work. Use seconds instead. (==86400s)
List of Record options
pathDefaults:
###############################################
# Default path settings -> Record
# Record streams to disk.
record: no
# Path of recording segments.
# Extension is added automatically.
# Available variables are %path (path name), %Y %m %d %H %M %S %f %s (time in strftime format)
recordPath: ./recordings/%path/%Y-%m-%d_%H-%M-%S-%f
# Format of recorded segments.
# Available formats are "fmp4" (fragmented MP4) and "mpegts" (MPEG-TS).
recordFormat: fmp4
# fMP4 segments are concatenation of small MP4 files (parts), each with this duration.
# MPEG-TS segments are concatenation of 188-bytes packets, flushed to disk with this period.
# When a system failure occurs, the last part gets lost.
# Therefore, the part duration is equal to the RPO (recovery point objective).
recordPartDuration: 1s
# Minimum duration of each segment.
recordSegmentDuration: 1h
# Delete segments after this timespan.
# Set to 0s to disable automatic deletion.
recordDeleteAfter: 1d
See also
-
rtsp-simple-server- old name. - Simple Realtime Server (srs; SRS)