mediamtx Documentation

Ready-to-use Media-over-QUIC / SRT / WebRTC / RTSP / RTMP / LL-HLS / MPEG-TS / RTP live media server and media proxy that allows to read, publish, proxy,...

20,413 stars Go Go 76 files · ~44,731 tokens #go#golang#hls#media-over-quic#media-server#moq#obs-studio#rtcp
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy mediamtx on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name mediamtx --restart always bluenviron/mediamtx:latest

Technical Documentation: bluenviron/mediamtx

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)






MediaMTX is a ready-to-use and zero-dependency live media server and media proxy that allows to publish, read, proxy, record and playback real-time video and audio streams. It has been conceived as a "media router" that routes media streams from one end to the other, with a focus on efficiency and portability.

Features

  • Publish streams to the server with Media-over-QUIC, SRT, WebRTC, RTSP, RTMP, HLS, MPEG-TS, RTP, using FFmpeg, GStreamer, OBS Studio, Python , Golang, Unity, Web browsers, Raspberry Pi Cameras and more.
  • Read streams from the server with Media-over-QUIC, SRT, WebRTC, RTSP, RTMP, HLS, using FFmpeg, GStreamer, VLC, OBS Studio, Python , Golang, Unity, Web browsers and more.
  • Streams are automatically converted from a protocol to another
  • Serve several streams at once in separate paths
  • Reload the configuration without disconnecting existing clients (hot reloading)
  • Serve always-available streams even when the publisher is offline
  • Record streams to disk in fMP4 or MPEG-TS format
  • Playback recorded streams from disk
  • Authenticate users with internal, HTTP or JWT authentication
  • Forward streams to other servers
  • Proxy requests to other servers
  • Control the server through the Control API
  • Extract metrics from the server in a Prometheus-compatible format
  • Monitor performance to investigate CPU and RAM consumption
  • Run hooks (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
  • ...and many others.

Redirects.Yaml (`docs/redirects.yaml`)

kickoff/installation: kickoff/install
kickoff/basic-usage: features/basic-usage
kickoff/architecture: features/architecture

usage/publish: publish/overview
usage/read: read/overview
usage/log-management: other/logging
usage/basic-usage: other/basic-usage
usage/configuration: other/configuration
usage/authentication: other/authentication
usage/remuxing-reencoding-compression: other/remuxing-reencoding-compression
usage/always-available: other/always-available
usage/record: other/record
usage/playback: other/playback
usage/forward: other/forward
usage/proxy: other/proxy
usage/extract-snapshots: other/extract-snapshots
usage/on-demand-publishing: other/on-demand-publishing
usage/route-absolute-timestamps: other/route-absolute-timestamps
usage/expose-the-server-in-a-subfolder: other/expose-the-server-in-a-subfolder
usage/embed-streams-in-a-website: other/embed-streams-in-a-website
usage/start-on-boot: other/start-on-boot
usage/logging: other/logging
usage/hooks: other/hooks
usage/control-api: other/control-api
usage/metrics: other/metrics
usage/performance: other/performance
usage/srt-specific-features: other/srt-specific-features
usage/webrtc-specific-features: other/webrtc-specific-features
usage/rtsp-specific-features: other/rtsp-specific-features
usage/rtmp-specific-features: other/rtmp-specific-features
usage/decrease-packet-loss: other/decrease-packet-loss

other/configuration: features/configuration
other/authentication: features/authentication
other/remuxing-reencoding-compression: features/remuxing-reencoding-compression
other/always-available: features/always-available
other/record: features/record
other/playback: features/playback
other/forward: features/forward
other/proxy: features/proxy
other/extract-snapshots: features/extract-snapshots
other/on-demand-publishing: features/on-demand-publishing
other/absolute-timestamps: features/absolute-timestamps
other/expose-the-server-in-a-subfolder: features/expose-the-server-in-a-subfolder
other/embed-streams-in-a-website: features/embed-streams-in-a-website
other/start-on-boot: features/start-on-boot
other/logging: features/logging
other/hooks: features/hooks
other/control-api: features/control-api
other/metrics: features/metrics
other/performance: features/performance
other/srt-specific-features: features/srt-specific-features
other/webrtc-specific-features: features/webrtc-specific-features
other/rtsp-specific-features: features/rtsp-specific-features
other/rtmp-specific-features: features/rtmp-specific-features
other/decrease-packet-loss: features/decrease-packet-loss
other/index: features/index
other/compile: misc/compile
other/license: misc/license
other/security: misc/security
other/specifications: misc/specifications
other/related-projects: misc/related-projects
other/route-absolute-timestamps: other/absolute-timestamps

publish/overview: features/publish

read/overview: features/read

features/embed-streams-in-a-website: read/web-browsers
features/scaling: features/scalability


1 Kickoff 1 Introduction (`docs/1-kickoff/1-introduction.md`)

Introduction

Welcome to the MediaMTX documentation!

MediaMTX is a ready-to-use and zero-dependency live media server and media proxy that allows to publish, read, proxy, record and playback real-time video and audio streams. It has been conceived as a "media router" that routes media streams from one end to the other, with a focus on efficiency and portability.

Main features:

  • Publish streams to the server with Media-over-QUIC, SRT, WebRTC, RTSP, RTMP, HLS, MPEG-TS, RTP, using FFmpeg, GStreamer, OBS Studio, Python , Golang, Unity, Web browsers, Raspberry Pi Cameras and more.
  • Read streams from the server with Media-over-QUIC, SRT, WebRTC, RTSP, RTMP, HLS, using FFmpeg, GStreamer, VLC, OBS Studio, Python , Golang, Unity, Web browsers and more.
  • Streams are automatically converted from a protocol to another
  • Serve several streams at once in separate paths
  • Reload the configuration without disconnecting existing clients (hot reloading)
  • Serve always-available streams even when the publisher is offline
  • Record streams to disk in fMP4 or MPEG-TS format
  • Playback recorded streams from disk
  • Authenticate users with internal, HTTP or JWT authentication
  • Forward streams to other servers
  • Proxy requests to other servers
  • Control the server through the Control API
  • Extract metrics from the server in a Prometheus-compatible format
  • Monitor performance to investigate CPU and RAM consumption
  • Run hooks (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

Use the menu to navigate through the documentation.


1 Kickoff 2 Install (`docs/1-kickoff/2-install.md`)

Install

There are several installation methods available:

  • Standalone binary: use this if you are running Windows, macOS or you just want to try out MediaMTX.
  • Docker container: use this if you want to run MediaMTX in an isolated and deterministic way. This is recommended for production environments.
  • Arch Linux package: use this if you are running Arch Linux.
  • FreeBSD package: use this if you are running FreeBSD.
  • OpenWrt binary: use this if you are running OpenWrt.

Standalone binary

  1. Visit the Releases page on GitHub, download and extract a standalone binary that corresponds to your operating system and architecture (example: mediamtx_{version_tag}_linux_amd64.tar.gz).

  2. Start the server by double clicking on mediamtx (mediamtx.exe on Windows) or writing in the terminal:

    sh
    ./mediamtx

Docker container

Download and launch the bluenviron/mediamtx:1 image with the following environment variables and ports:

sh
docker run --rm -it \
-e MTX_RTSPTRANSPORTS=tcp \
-e MTX_WEBRTCADDITIONALHOSTS=192.168.x.x \
-p 8554:8554 \
-p 1935:1935 \
-p 8888:8888 \
-p 8889:8889 \
-p 8892:8892 \
-p 8890:8890/udp \
-p 8189:8189/udp \
-p 8892:8892/udp \
-p 8893:8893/udp \
bluenviron/mediamtx:1

Fill the MTX_WEBRTCADDITIONALHOSTS environment variable with the IP that will be used to connect to the server.

The MTX_RTSPTRANSPORTS=tcp environment variable is meant to disable the UDP transport protocol of the RTSP server (which requires the real IP address and port of incoming UDP packets, that are sometimes replaced by the Docker network stack). If you want to use it, you need to bypass the Docker network stack through the --network=host flag (which is not compatible with Windows, macOS and Kubernetes):

sh
docker run --rm -it --network=host bluenviron/mediamtx:1

There are four image variants:

name FFmpeg included RPI Camera support
bluenviron/mediamtx:1 :x: :x:
bluenviron/mediamtx:1-ffmpeg :heavy_check_mark: :x:
bluenviron/mediamtx:1-rpi :x: :heavy_check_mark:
bluenviron/mediamtx:1-ffmpeg-rpi :heavy_check_mark: :heavy_check_mark:

The 1 tag corresponds to the latest 1.x.x release, that should guarantee backward compatibility when upgrading. It is also possible to bind the image to a specific release, by using the release name as tag (bluenviron/mediamtx:{docker_version_tag}).

The base image does not contain any utility, in order to minimize size and frequency of updates. If you need additional software (like curl, wget, GStreamer), you can build a custom image by creating a file named Dockerfile with this content:

dockerfile
FROM bluenviron/mediamtx:1 AS mediamtx

# pick any Linux-based operating system you want.
FROM ubuntu:24.04

COPY --from=mediamtx /mediamtx /
COPY --from=mediamtx /mediamtx.yml /

# add anything you need.
RUN apt update && apt install -y \
   gstreamer1.0-tools

ENTRYPOINT [ "/mediamtx" ]

And then build it:

sh
docker build . -t my-mediamtx

Arch Linux package

If you are running the Arch Linux distribution, launch:

sh
git clone https://aur.archlinux.org/mediamtx.git
cd mediamtx
makepkg -si

FreeBSD package

Available via ports tree or using packages (2025Q2 and later) as listed below:

sh
cd /usr/ports/multimedia/mediamtx && make install clean
pkg install mediamtx

OpenWrt binary

If the architecture of the OpenWrt device is amd64, armv6, armv7 or arm64, use the standalone binary method and download a Linux binary that corresponds to your architecture.

Otherwise, compile the server from source.


1 Kickoff 3 Upgrade (`docs/1-kickoff/3-upgrade.md`)

Upgrade

If you have an existing MediaMTX installation, you can upgrade it to the latest version. The procedure depends on how MediaMTX was installed.

Standalone binary

The standalone binary comes with an upgrade utility that can be launched with:

sh
./mediamtx --upgrade

This will replace the MediaMTX executable with its latest version. Privileges to write to the executable location are required.

Docker container

Stop and remove the container:

sh
docker stop id-of-mediamtx-container
docker rm id-of-mediamtx-container

Remove the MediaMTX image from cache:

sh
docker rm bluenviron/mediamtx:1

Then recreate the container as described in Install.

Arch Linux package

Repeat the installation procedure.

FreeBSD package

Repeat the installation procedure.

OpenWrt binary

If the architecture of the OpenWrt device is amd64, armv6, armv7 or arm64, you can use the standalone binary method.

Otherwise, recompile the server from source.


2 Features 01 Basic Usage (`docs/2-features/01-basic-usage.md`)

Basic usage

  1. Publish a stream. For instance, you can publish a stream from a MP4 file with FFmpeg and the RTSP protocol:

    sh
    ffmpeg -re -stream_loop -1 -i file.mp4 -c copy \
    -f rtsp rtsp://localhost:8554/mystream

    or GStreamer:

    sh
    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
  2. Read the stream. For instance, you can read the stream with VLC and the RTSP protocol:

    sh
    vlc --network-caching=50 rtsp://localhost:8554/mystream

    or GStreamer:

    sh
    gst-play-1.0 rtsp://localhost:8554/mystream

    or FFmpeg:

    sh
    ffmpeg -i rtsp://localhost:8554/mystream -c copy output.mp4

2 Features 02 Architecture (`docs/2-features/02-architecture.md`)

Architecture

In order to provide its features, MediaMTX performs the following network interactions:

  • It interacts with any external source defined in the configuration, as a client, pulling streams.
  • It exposes a series of servers that allow clients to publish and read streams with several protocols (RTSP, RTMP, WebRTC, SRT, HLS).
  • It exposes a playback server that allows to read streams stored on disk.
  • It exposes a series of administrative services (metrics, pprof, Control API).

Internally, the service revolves around these components:

  • A path manager, that is in charge of managing paths, performing authentication and linking clients to paths.
  • Paths. Each path contains a stream, which is provided by a single publisher or by a single external source, and is then broadcasted to any reader.
  • A recorder, in charge of storing streams to disks.

Everything is controlled through configuration parameters, defined in the configuration file or in environment variables.

Furthermore, the server can be configured to interact with an identity server in order to perform authentication.


2 Features 03 Publish (`docs/2-features/03-publish.md`)

Publish streams

Live streams can be published to the server with the following protocols:

We provide instructions for publishing with the following devices:

We provide instructions for publishing with the following software:


2 Features 04 Read (`docs/2-features/04-read.md`)

Read streams

Live streams can be read from the server with the following protocols:

We provide instructions for reading with the following software:


2 Features 05 Configuration (`docs/2-features/05-configuration.md`)

Configuration

MediaMTX can be configured through parameters that are listed and commented in the configuration file (mediamtx.yml).

Change the configuration

There are several ways to change configuration parameters:

  1. Edit the configuration file.

    When installing the server as a standalone binary, the configuration file is included into the release bundle.

    When installing the server as a Docker container, you need to download the configuration file in a local folder, mount the folder and point MediaMTX to the file in the folder:

    sh
    mkdir config
    wget https://raw.githubusercontent.com/bluenviron/mediamtx/{version_tag}/mediamtx.yml -O config/mediamtx.yml
    docker run --rm -it \
    -p 8554:8554 \
    -p 1935:1935 \
    -p 8888:8888 \
    -p 8889:8889 \
    -p 8892:8892 \
    -p 8890:8890/udp \
    -p 8189:8189/udp \
    -p 8892:8892/udp \
    -p 8893:8893/udp \
    -v "$PWD/config:/config" \
    -w /config \
    bluenviron/mediamtx:1 ./mediamtx.yml

    You can edit the configuration file when the server is running (hot reloading). Changes are detected and applied without disconnecting existing clients, whenever it's possible.

  2. Use environment variables, in the format MTX_PARAMNAME, where PARAMNAME is the uppercase name of a parameter. For instance, the rtspAddress parameter can be overridden in the following way:

    sh
    MTX_RTSPADDRESS="127.0.0.1:8554" ./mediamtx

    Parameters that have array as value can be overridden by setting a comma-separated list. For example:

    sh
    MTX_RTSPTRANSPORTS="tcp,udp"

    Parameters in maps can be overridden by using underscores, in the following way:

    sh
    MTX_PATHS_TEST_SOURCE=rtsp://myurl ./mediamtx

    Parameters in lists can be overridden in the same way as parameters in maps, using their position like an additional key. This is particularly useful if you want to use internal users but define credentials through environment variables:

    sh
    MTX_AUTHINTERNALUSERS_0_USER=username
    MTX_AUTHINTERNALUSERS_0_PASS=password

    This method is particularly useful when using Docker; any configuration parameter can be changed by passing environment variables with the -e flag:

    sh
    docker run --rm -it \
    --network=host \
    -e MTX_PATHS_TEST_SOURCE=rtsp://myurl \
    bluenviron/mediamtx:1
  3. Use the Control API.

Validate the configuration

You can validate a configuration file without starting the server:

sh
./mediamtx --validate-conf=/path/to/mediamtx.yml

Encrypt the configuration

The configuration file can be entirely encrypted for security purposes by using the crypto_secretbox function of the NaCL library. An online tool for performing this operation is available here.

After performing the encryption, put the base64-encoded result into the configuration file, and launch the server with the MTX_CONFKEY variable:

sh
MTX_CONFKEY=mykey ./mediamtx

2 Features 06 Authentication (`docs/2-features/06-authentication.md`)

Authentication

MediaMTX can be configured to ask clients for credentials, either in the form of username/password or a string-based token. These credentials are then validated through a chosen method.

Validate credentials

Credentials can be validated through one of these methods:

  • Internal database: credentials are stored in the configuration file
  • External HTTP server: an external HTTP URL is contacted for each authentication request
  • External JWT provider: credentials are signed tokens released by an external identity server

Internal database

The internal authentication method is the default one. Users are stored inside the configuration file, in this format:

yml
authInternalUsers:
  # Username. 'any' means any user, including anonymous ones.
  - user: any
    # Password. Not used in case of 'any' user.
    pass:
    # IPs or networks allowed to use this user. An empty list means any IP.
    ips: []
    # Permissions.
    permissions:
      # Available actions are: publish, read, playback, api, metrics, pprof.
      - action: publish
        # Paths can be set to further restrict access to a specific path.
        # An empty path means any path.
        # Regular expressions can be used by using a tilde as prefix.
        path:
      - action: read
        path:
      - action: playback
        path:

Only clients that provide a valid username and password 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:

text
echo -n "mypass" | argon2 saltItWithSalt -id -l 32 -e

Then stored with the argon2: prefix:

yml
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:

text
echo -n "mypass" | openssl dgst -binary -sha256 | openssl base64

Then stored with the sha256: prefix:

yml
authInternalUsers:
  - user: sha256:j1tsRqDEw9xvq/D7/9tMx6Jh/jMhk3UfjwIB2f1zgMo=
    pass: sha256:BdSWkrdV+ZxFBLUQQY7+7uv9RmiSVA8nrPmjGjJtZQQ=
    permissions:
      - action: publish

WARNING: enable encryption or use a VPN to ensure that no one is intercepting the credentials in transit.

External HTTP server

Authentication can be delegated to an external HTTP server:

yml
authMethod: http
authHTTPAddress: http://myauthserver/auth

Each time a user needs to be authenticated, the specified URL will be requested with the POST method and this payload:

json
{
  "user": "user",
  "password": "password",
  "token": "token",
  "ip": "ip",
  "action": "publish|read|playback|api|metrics|pprof",
  "path": "path",
  "protocol": "rtsp|rtmp|hls|webrtc|srt",
  "id": "id",
  "query": "query",
  "userAgent": "userAgent"
}

If the URL returns a status code that begins with 20 (i.e. 200), authentication is successful, otherwise it fails. Be aware that it's perfectly normal for the authentication server to receive requests with empty users and passwords, i.e.:

json
{
  "user": "",
  "password": ""
}

This happens because RTSP clients don't provide credentials until they are asked to. In order to receive the credentials, the authentication server must reply with status code 401, then the client will send credentials.

Some actions can be excluded from the validation process:

yml
# Actions to exclude from HTTP-based authentication.
# Format is the same as the one of user permissions.
authHTTPExclude:
  - action: api
  - action: metrics
  - action: pprof

If the authentication server uses HTTPS and has a self-signed or invalid TLS certificate, you can provide the fingerprint of the certificate to validate it anyway:

yml
authMethod: http
authHTTPAddress: https://myauthserver/auth
authHTTPFingerprint: 33949e05fffb5ff3e8aa16f8213a6251b4d9363804ba53233c4da9a46d6f2739

The fingerprint can be obtained with:

sh
openssl s_client -connect myauthserver:443 </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'

External JWT provider

Authentication can be delegated to an external identity server, that is capable of generating JWTs and provides a JWKS endpoint. With respect to the HTTP-based method, this has the advantage that the external identity server is contacted once, not for each authentication request, greatly improving performance. In order to use the JWT-based authentication method, set authMethod and authJWTJWKS:

yml
authMethod: jwt
authJWTJWKS: http://my_identity_server/jwks_endpoint

Users are expected to pass the encoded JWT as token.

The JWT is expected to contain a mediamtx_permissions claim, with a list of permissions in the same format as the one of user permissions:

json
{
  "mediamtx_permissions": [
    {
      "action": "publish",
      "path": ""
    }
  ]
}

If the JWKS server uses TLS and has a self-signed or invalid TLS certificate, you can provide the fingerprint of the certificate to validate it anyway:

yml
authMethod: jwt
authJWTJWKS: https://my_identity_server/jwks_endpoint
authJWTJWKSFingerprint: 33949e05fffb5ff3e8aa16f8213a6251b4d9363804ba53233c4da9a46d6f2739

The fingerprint can be obtained with:

sh
openssl s_client -connect my_identity_server:443 </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'

Optionally, the JWT iss (issuer) and aud (audience) claims can be validated by setting authJWTIssuer and authJWTAudience. When set, tokens that don't contain the expected values will be rejected:

yml
authMethod: jwt
authJWTJWKS: http://my_identity_server/jwks_endpoint
authJWTIssuer: http://my_identity_server
authJWTAudience: mediamtx

Leave these fields empty to skip validation of the respective claims.

Keycloak setup

Here's a tutorial on how to setup the Keycloak identity server in order to provide JWTs.

  1. Start Keycloak:

    sh
    docker run --name=keycloak -p 8080:8080 \
    -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \
    quay.io/keycloak/keycloak:23.0.7 start-dev
  2. Open the Keycloak web UI on http://localhost:8080, click on Administration Console and log in.

  3. Click on master in the top left corner, Create realm, set realm name to mediamtx, Create.

  4. Open page Client scopes, Create client scope, set name to mediamtx, Save.

  5. Open tab Mappers, Configure a new Mapper, User Attribute:

    • Name: mediamtx_permissions
    • User Attribute: mediamtx_permissions
    • Token Claim Name: mediamtx_permissions
    • Claim JSON Type: JSON
    • Multivalued: On

    Save.

  6. Open page Clients, Create client, set Client ID to mediamtx, Next, Client authentication On, Next, Save.

  7. Open tab Credentials, copy client secret somewhere.

  8. Open tab Client scopes, set Assigned type of all existing client scopes to Optional. This decreases the length of the JWT, since many clients have limits on it.

  9. In the same tab, click on Add client scope, Select mediamtx, Add, Default.

  10. Open tab Advanced, set Access token signature algorithm to ES256. Save. This further decreases the JWT length.

  11. Open page Users, Add user, pick a username, Create, Tab Credentials, Set password, pick a password, Save.

  12. Open tab Attributes, Add an attribute:

    • Key: mediamtx_permissions
    • Value: {"action":"publish", "path": ""}

    You can add as many attributes with key mediamtx_permissions as you want, each with a single permission in it.

  13. In MediaMTX, use the following JWKS URL:

    yml
    authJWTJWKS: http://localhost:8080/realms/mediamtx/protocol/openid-connect/certs
  14. Perform authentication on Keycloak:

    sh
    curl \
    -d "client_id=mediamtx" \
    -d "client_secret=my-client-secret" \
    -d "username=my-user" \
    -d "password=my-pass" \
    -d "grant_type=password" \
    http://localhost:8080/realms/mediamtx/protocol/openid-connect/token

    This results in:

    text

/* Detailed source-code truncated for AI context efficiency. */

text
The JWT is inside the `access_token` key.

## Provide username and password

### RTSP

Prepend username and password and a `@` to the host:

rtsp rtsp://myuser:mypass@localhost:8554/mystream

text
### RTMP

Use the `user` and `pass` query parameters:

rtmp://localhost/mystream?user=myuser&pass=mypass

text
### SRT

Append username and password to `streamid`:

srt://localhost:8890?streamid=publish:mystream:myuser:mypass&pkt_size=1316

text
### HLS and WebRTC

Username and password can be passed through the `Authorization: Basic` HTTP header:

Authorization: Basic base64(myuser:mypass)

text
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/07-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:

Authorization: Bearer myuser:mypass

text
## Provide tokens / JWTs

### RTSP

Pass the token as a query parameter:

rtsp://localhost:8554/mystream?token=mytoken

text
WARNING: FFmpeg implementation of RTSP does not support URLs that are longer than 4096 characters (this is the [MAX_URL_SIZE constant](https://github.com/FFmpeg/FFmpeg/blob/f951aa9ef382d6bb517e05d04d52710f751de427/libavformat/internal.h#L30)), therefore you have to configure your identity server in order to produce JWTs that are shorter than this threshold.

### RTMP

Pass the token as a query parameter:

rtmp://localhost/mystream?token=mytoken

text
WARNING: FFmpeg implementation of RTMP does not support URLs that are longer than 1024 characters (this is the [TCURL_MAX_LENGTH constant](https://github.com/FFmpeg/FFmpeg/blob/f951aa9ef382d6bb517e05d04d52710f751de427/libavformat/rtmpproto.c#L55)), therefore you have to configure your identity server in order to produce JWTs that are shorter than this threshold.

### SRT

Pass the token as password, with an arbitrary user:

srt://localhost:8890?streamid=publish:mystream:user:mytoken&pkt_size=1316

text
WARNING: SRT does not support Stream IDs that are longer than 512 characters, therefore you have to configure your identity server in order to produce JWTs that are shorter than this threshold.

### HLS and WebRTC

The token can be passed through the `Authorization: Bearer` header:

Authorization: Bearer mytoken

text
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/07-web-browsers.md#embed-in-a-website).

## Ban after failed attempts

It is possible to prevent certain IPs from connecting to the server after some failed attempts by using `fail2ban` together with _MediaMTX_.

First configure _MediaMTX_ to store logs in a file:

```yml
logDestinations: [stdout, file]
logFile: /var/log/mediamtx.log

Install fail2ban:

sh
sudo apt install -y fail2ban

Create the /etc/fail2ban/filter.d/mediamtx.conf file with this content:

ini
[Definition]

failregex = ^\s*WAR \[[^\]]+\] \[conn <ADDR>:\d+\] failed to authenticate: authentication failed$
            ^\s*INF \[(?P<proto>[^\]]+)\] \[session (?P<sess>[0-9A-Fa-f]+)\] created by <ADDR>:\d+\n\s*WAR \[(?P=proto)\] \[session (?P=sess)\] failed to authenticate: authentication failed\n$

maxlines = 20
datepattern = ^%%Y/%%m/%%d %%H:%%M:%%S

Create the /etc/fail2ban/jail.d/mediamtx.conf file with this content:

ini
[mediamtx]
enabled  = true
filter   = mediamtx
logpath  = /var/log/mediamtx.log
backend  = auto
maxretry = 5
findtime = 600
bantime  = 3600

Restart fail2ban:

sh
sudo systemctl restart fail2ban

2 Features 07 Remuxing Reencoding Compression (`docs/2-features/07-remuxing-reencoding-compression.md`)

Re-encoding

To change the format, codec or compression of a stream, use FFmpeg or GStreamer together with MediaMTX. For instance, to re-encode an existing stream, that is available in the /original path, and publish the resulting stream in the /compressed path, edit mediamtx.yml and replace everything inside section paths with the following content:

yml
paths:
  compressed:
  original:
    runOnAvailable: >
      ffmpeg -i rtsp://localhost:$RTSP_PORT/$MTX_PATH
        -c:v libx264 -pix_fmt yuv420p -preset ultrafast -b:v 600k
        -max_muxing_queue_size 1024 -f rtsp rtsp://localhost:$RTSP_PORT/compressed
    runOnAvailableRestart: yes

2 Features 08 Always Available (`docs/2-features/08-always-available.md`)

Always-available

When the publisher or source of a stream is offline, the server can be configured to fill gaps in the stream with an offline segment that is played on repeat until a publisher comes back online. This allows readers to stay connected regardless of the state of the stream. The offline segment and online stream are concatenated without re-encoding any frame, using the original codec.

This feature can be enabled by toggling the alwaysAvailable flag and filling alwaysAvailableTracks:

yml
paths:
  mypath:
    alwaysAvailable: true
    alwaysAvailableTracks:
      # Available values are: AV1, VP9, H265, H264, Opus, MPEG4Audio, G711, LPCM
      - codec: H264
        # in case of MPEG4Audio, G711, LPCM, sampleRate and ChannelCount must be provided too.
        #  sampleRate: 48000
        #  channelCount: 2
        #  in case of G711, muLaw must be provided too.
        #  muLaw: false

By default, the server uses a default offline segment with the text "STREAM IS OFFLINE". The segment can be replaced with an external MP4 file:

yml
paths:
  mypath:
    alwaysAvailable: true
    alwaysAvailableFile: "./h264.mp4"

By default, the stream is recorded even when no source is connected and the offline segment is playing. To record only when a source is connected, set alwaysAvailableRecorded to false:

yml
paths:
  mypath:
    alwaysAvailable: true
    alwaysAvailableRecorded: false
    record: true
    alwaysAvailableTracks:
      - codec: H264

2 Features 09 Record (`docs/2-features/09-record.md`)

Record streams

Live streams be recorded to disk and played back with the following file containers and codecs:

container codecs
fMP4 Video: AV1, VP9, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEGAudio: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G711 (PCMA, PCMU), LPCM
MPEG-TS Video: H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 VideoAudio: Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3

Usage

To record available streams to disk, set the record parameter in the configuration file:

yml
pathDefaults:
  # Record streams to disk.
  record: yes

It's also possible to specify additional parameters:

yml
pathDefaults:
  # Record streams to disk.
  record: yes
  # Path of recording segments.
  # Extension is added automatically.
  # Available variables are %path (path name), %Y %m %d (year, month, day),
  # %H %M %S (hours, minutes, seconds), %f (microseconds), %z (time zone), %s (unix epoch).
  recordPath: ./recordings/%path/%Y-%m-%d_%H-%M-%S-%f_%z
  # 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
  # This prevents RAM exhaustion.
  recordMaxPartSize: 50M
  # Minimum duration of each segment.
  recordSegmentDuration: 1h
  # Delete segments after this timespan.
  # Set to 0s to disable automatic deletion.
  recordDeleteAfter: 1d

All available recording parameters are listed in the configuration file.

Remote upload

To upload recordings to a remote location, you can use MediaMTX together with rclone, a command line tool that provides file synchronization capabilities with a huge variety of services (including S3, FTP, SMB, Google Drive):

  1. Download and install rclone.

  2. Configure rclone:

    sh
    rclone config
  3. Place rclone into the runOnInit and runOnRecordSegmentComplete hooks:

    yml
    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

    If you want to delete local segments after they are uploaded, replace rclone sync with rclone move.


2 Features 10 Playback (`docs/2-features/10-playback.md`)

Playback recorded streams

Existing recordings can be played back to users through a dedicated HTTP server, that can be enabled inside the configuration:

yml
playback: yes
playbackAddress: :9996

The server provides an endpoint to list recorded timespans:

text
http://localhost:9996/list?path=[mypath]&start=[start]&end=[end]

Where:

The server will return a list of timespans in JSON format:

json
[
  {
    "start": "2006-01-02T15:04:05Z07:00",
    "duration": 60.0,
    "url": "http://localhost:9996/get?path=[mypath]&start=2006-01-02T15%3A04%3A05Z07%3A00&duration=60.0"
  },
  {
    "start": "2006-01-02T15:07:05Z07:00",
    "duration": 32.33,
    "url": "http://localhost:9996/get?path=[mypath]&start=2006-01-02T15%3A07%3A05Z07%3A00&duration=32.33"
  }
]

The server provides an endpoint to download recordings:

text
http://localhost:9996/get?path=[mypath]&start=[start]&duration=[duration]&format=[format]

Where:

  • [mypath] is the path name
  • [start] is the start date in RFC3339 format
  • [duration] is the maximum duration of the recording in seconds
  • [format] (optional) is the output format of the stream. Available values are "fmp4" (default) and "mp4"

All parameters must be url-encoded. For instance:

text
http://localhost:9996/get?path=mypath&start=2024-01-14T16%3A33%3A17%2B00%3A00&duration=200.5

The resulting stream uses the fMP4 format, that is natively compatible with any browser, therefore its URL can be directly inserted into a <video> tag:

html
<video controls>
  <source
    src="http://localhost:9996/get?path=[mypath]&start=[start_date]&duration=[duration]"
    type="video/mp4"
  />
</video>

The fMP4 format may offer limited compatibility with some players. To fix the issue, it's possible to use the standard MP4 format, by adding format=mp4 to a /get request:

text
http://localhost:9996/get?path=[mypath]&start=[start_date]&duration=[duration]&format=mp4

2 Features 11 Forward (`docs/2-features/11-forward.md`)

Forward streams

Incoming streams can be natively forwarded to other servers with the following protocols:

It is also possible to use FFmpeg to perform the forwarding.

We provide instructions to forward streams to the following services:

Media-over-QUIC

Add the target URL inside dest of a forward entry:

yml
paths:
  mypath:
    forward:
      - dest: moqt://user:pass@host:port/path
        # Transport protocol used to forward the stream. available values are "quic", "webtransport".
        moqTransport: quic
        # If the destination TLS certificate is self-signed or invalid, you can provide the
        # fingerprint of the certificate in order to validate it anyway. It can be obtained by running:
        # openssl s_client -connect dest_ip:dest_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
        # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
        destFingerprint:

SRT

Add the target URL inside dest of a forward entry:

yml
paths:
  mypath:
    forward:
      - dest: srt://host:port?streamid=streamid

WebRTC

We support forwarding streams by using the WebRTC protocol and the WHIP extension. Add the target URL inside dest of a forward entry. Use whip:// for HTTP and whips:// for HTTPS:

yml
paths:
  mypath:
    forward:
      # use whip:// for HTTP and whips:// for HTTPS.
      - dest: whip://host:port/mystream/whip
        # Token to insert in the Authorization: Bearer header.
        whipBearerToken: ""
        # If the destination is HTTPS and the destination TLS certificate is self-signed
        # or invalid, you can provide the fingerprint of the certificate in order to
        # validate it anyway. It can be obtained by running:
        # openssl s_client -connect dest_ip:dest_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
        # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
        destFingerprint:

If the remote server is a MediaMTX instance, remember to add a /whip suffix after the stream name, since in MediaMTX it's part of the WHIP URL.

RTSP

Add the target URL inside dest of a forward entry:

yml
paths:
  mypath:
    forward:
      # Use rtsp:// for plain RTSP and rtsps:// for encrypted RTSP.
      - dest: rtsp://user:pass@host:port/path
        # If the destination is RTSPS and the destination TLS certificate is self-signed
        # or invalid, you can provide the fingerprint of the certificate in order to
        # validate it anyway. It can be obtained by running:
        # openssl s_client -connect dest_ip:dest_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
        # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
        destFingerprint:

RTMP

Add the target URL inside dest of a forward entry:

yml
paths:
  mypath:
    forward:
      # Use rtmp:// for plain RTMP and rtmps:// for encrypted RTMP.
      - dest: rtmp://user:pass@host:port/path#streamKey
        # If the destination is RTMPS and the destination TLS certificate is self-signed
        # or invalid, you can provide the fingerprint of the certificate in order to
        # validate it anyway. It can be obtained by running:
        # openssl s_client -connect dest_ip:dest_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
        # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
        destFingerprint:

FFmpeg

When the destination requires transcoding, filtering or a protocol that is not supported by forward, use FFmpeg inside the runOnAvailable parameter instead:

yml
pathDefaults:
  runOnAvailable: >
    ffmpeg -i rtsp://localhost:$RTSP_PORT/$MTX_PATH
    -c copy
    -f rtsp rtsp://other-server:8554/another-path
  runOnAvailableRestart: yes

YouTube

Open YouTube, sign in with a valid account, search for the Create, Go Live button, click it. In the next page, search for Default stream key, copy the key somewhere, then search for the Stream URL section and copy the URL. Insert the stream URL and the stream key in MediaMTX in this way:

yml
paths:
  mypath:
    forward:
      # Use an hashtag to separate the URL from the stream key.
      # "a.rtmp.youtube.com/live2" was the URL YouTube was reporting last time this documentation was updated. Check that it is still correct.
      # Also replace rtmp:// with rtmps:// and rtmp with rtmps in the URI in order to enable encryption in-transit.
      - dest: rtmps://a.rtmps.youtube.com/live2#streamKey

Warning: YouTube requires streams to have both a video and an audio track. Video-only streams are silently rejected.

Twitch

Open Twitch, sign in with a valid account, go to Settings, Stream. Search for the Primary Stream Key, copy it somewhere. Then search for Recommended Ingest Endpoints, that should be in this page. Copy one of the URLs. Insert the URL and the stream key in MediaMTX in this way:

yml
paths:
  mypath:
    forward:
      # Use an hashtag to separate the URL from the stream key.
      # "rtmp://ingest.global-contribute.live-video.net/app" was the URL Twitch was reporting last time this documentation was updated. Check that it is still correct.
      # Also replace rtmp:// with rtmps:// in order to enable encryption in-transit.
      - dest: rtmps://ingest.global-contribute.live-video.net/app#streamKey

2 Features 12 Proxy (`docs/2-features/12-proxy.md`)

Proxy requests

The server allows to proxy incoming requests to other servers or cameras. This is useful to expose servers or cameras behind a NAT. Edit mediamtx.yml and replace everything inside section paths with the following content:

yml
paths:
  "~^(.+)$":
    # If path name is a regular expression, $G1, $G2, etc will be replaced
    # with regular expression groups.
    source: rtsp://other-server:8554/$G1
    sourceOnDemand: yes

All requests addressed to rtsp://mediamtx:8554/a will be forwarded to rtsp://other-server:8554/a and so on.


2 Features 13 Extract Snapshots (`docs/2-features/13-extract-snapshots.md`)

Extract snapshots

You can periodically extract snapshots from available streams by using FFmpeg inside the runOnAvailable hook:

yml
pathDefaults:
  runOnAvailable: |
    bash -c "
    while true; do
      mkdir -p $(dirname snapshots/$MTX_PATH)
      ffmpeg -i rtsp://localhost:8554/$MTX_PATH -frames:v 1 -update true -y snapshots/$MTX_PATH.jpg
      sleep 10
    done"

Where 10 is the interval between snapshots.


2 Features 14 On Demand Publishing (`docs/2-features/14-on-demand-publishing.md`)

On-demand publishing

Edit mediamtx.yml and replace everything inside section paths with the following content:

yml
paths:
  ondemand:
    runOnDemand: ffmpeg -re -stream_loop -1 -i file.mp4 -c copy -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH
    runOnDemandRestart: yes

The command inserted into runOnDemand will start only when a client requests the path ondemand, therefore the file will start streaming only when requested.


2 Features 15 Absolute Timestamps (`docs/2-features/15-absolute-timestamps.md`)

Route absolute timestamps

Some streaming protocols allow to route absolute timestamps, associated with each frame, that are useful for synchronizing several video or data streams together. In particular, MediaMTX supports receiving absolute timestamps with the following protocols and devices:

  • HLS
  • RTSP
  • WebRTC
  • Raspberry Pi Camera

and supports sending absolute timestamps with the following protocols:

  • HLS
  • RTSP
  • WebRTC

By default, absolute timestamps of incoming frames are not used, instead they are replaced with the system timestamp. This prevents users from arbitrarily changing recording dates, and also allows to support sources that do not send absolute timestamps. It is possible to preserve original absolute timestamps by toggling the useAbsoluteTimestamp parameter:

yml
pathDefaults:
  # Use absolute timestamp of frames, instead of replacing them with the current time.
  useAbsoluteTimestamp: false

Absolute timestamp in HLS

In the HLS protocol, absolute timestamps are routed by adding a EXT-X-PROGRAM-DATE-TIME tag before each segment:

text
#EXTM3U
#EXT-X-VERSION:9
#EXT-X-MEDIA-SEQUENCE:20
#EXT-X-TARGETDURATION:2
#EXT-X-PROGRAM-DATE-TIME:2015-02-05T01:02:00Z
#EXTINF:2,
segment1.mp4
#EXT-X-PROGRAM-DATE-TIME:2015-02-05T01:04:00Z
#EXTINF:2,
segment2.mp4

The EXT-X-PROGRAM-DATE-TIME value is the absolute timestamp that corresponds to the first frame of the segment. The absolute timestamp of following frames can be obtained by summing EXT-X-PROGRAM-DATE-TIME with the relative frame timestamp.

A library that can read absolute timestamps with HLS is gohlslib.

Absolute timestamp in RTSP and WebRTC

In RTSP and WebRTC, absolute timestamps are routed through periodic RTCP sender reports:

text
0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P|    RC   |   PT=SR=200   |             length            |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         SSRC of sender                        |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
sender |              NTP timestamp, most significant word             |
info   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |             NTP timestamp, least significant word             |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         RTP timestamp                         |
...

The sender report contains a reference absolute timestamp (NTP timestamp) and a reference relative timestamp (RTP timestamp). The absolute timestamp of each frame can be computed by using these values together with the RTP timestamp of the frame (shipped with each frame), through the formula:

text
frame_abs_timestamp = ref_ntp_timestamp + (frame_rtp_timestamp - ref_rtp_timestamp) / clock_rate

A library that can read absolute timestamps with RTSP is gortsplib.

A browser can read absolute timestamps with WebRTC if it exposes the estimatedPlayoutTimestamp statistic.


2 Features 16 Expose The Server In A Subfolder (`docs/2-features/16-expose-the-server-in-a-subfolder.md`)

Expose the server in a subfolder

HTTP-based services (Media-over-QUIC, WebRTC, HLS, Control API, Playback Server, Metrics, pprof) can be exposed in a subfolder of an external HTTP server or reverse proxy. The reverse proxy must be able to intercept HTTP requests addressed to MediaMTX and corresponding responses, and must perform the following changes:

  • The subfolder path must be stripped from request paths. For instance, if the server is exposed behind /subpath and the reverse proxy receives a request with path /subpath/mystream/index.m3u8, this has to be changed into /mystream/index.m3u8.

  • Any Location header in responses must be prefixed with the subfolder path. For instance, if the server is exposed behind /subpath and the server sends a response with Location: /mystream/index.m3u8, this has to be changed into Location: /subfolder/mystream/index.m3u8.

Nginx

When Nginx is the reverse proxy, rules described above can be implemented with the following configuration:

text
location /subpath/ {
    proxy_pass http://mediamtx-ip:8889/;
    proxy_redirect / /subpath/;
}

Apache HTTP Server

When Apache HTTP Server is the reverse proxy, rules described above can be implemented with the following configuration:

text
<Location /subpath>
    ProxyPass http://mediamtx-ip:8889
    ProxyPassReverse http://mediamtx-ip:8889
    Header edit Location ^(.*)$ "/subpath$1"
</Location>

Caddy

When Caddy is the reverse proxy, rules described above can be implemented with the following configuration:

text
:80 {
    handle_path /subpath/* {
        reverse_proxy {
            to mediamtx-ip:8889
            header_down Location ^/ /subpath/
        }
    }
}

2 Features 17 Start On Boot (`docs/2-features/17-start-on-boot.md`)

Start on boot

Linux

On most Linux distributions (including Ubuntu and Debian, but not OpenWrt), systemd is in charge of managing services and starting them on boot.

Move the server executable and configuration in global folders:

sh
sudo mv mediamtx /usr/local/bin/
sudo mv mediamtx.yml /usr/local/etc/

Create a systemd service:

sh
sudo tee /etc/systemd/system/mediamtx.service >/dev/null << EOF
[Unit]
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/mediamtx /usr/local/etc/mediamtx.yml
[Install]
WantedBy=multi-user.target
EOF

Enable a wait-online service to make sure that MediaMTX is started after network has been properly initialized:

sh
sudo systemctl enable systemd-networkd-wait-online.service

If SELinux is enabled (for instance in case of RedHat, Rocky, CentOS++), add correct security context:

sh
semanage fcontext -a -t bin_t /usr/local/bin/mediamtx
restorecon -Fv /usr/local/bin/mediamtx

Enable and start the service:

sh
sudo systemctl daemon-reload
sudo systemctl enable mediamtx
sudo systemctl start mediamtx

OpenWrt

Move the server executable and configuration in global folders:

sh
mv mediamtx /usr/bin/
mkdir -p /usr/etc && mv mediamtx.yml /usr/etc/

Create a procd service:

sh
tee /etc/init.d/mediamtx >/dev/null << EOF
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=95
STOP=01
start_service() {
    procd_open_instance
    procd_set_param command /usr/bin/mediamtx
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_close_instance
}
EOF

Enable and start the service:

sh
chmod +x /etc/init.d/mediamtx
/etc/init.d/mediamtx enable
/etc/init.d/mediamtx start

Read the server logs:

sh
logread

Windows

Download the WinSW v2 executable and place it into the same folder of mediamtx.exe.

In the same folder, create a file named WinSW-x64.xml with this content:

xml
<service>
  <id>mediamtx</id>
  <name>mediamtx</name>
  <description></description>
  <executable>%BASE%/mediamtx.exe</executable>
</service>

Open a terminal, navigate to the folder and run:

text
WinSW-x64 install

The server is now installed as a system service and will start at boot time.


2 Features 18 Logging (`docs/2-features/18-logging.md`)

Logging

Log verbosity

Log verbosity can be set with the logLevel parameter:

yml
# Verbosity of the program; available values are "error", "warn", "info", "debug".
logLevel: info

Log destinations

Log entries can be sent to multiple destinations. By default, they are printed on the console (stdout).

It is possible to write logs to a file by using these parameters:

yml
# Destinations of log messages; available values are "stdout", "file" and "syslog".
logDestinations: [file]
# If "file" is in logDestinations, this is the file which will receive the logs.
logFile: mediamtx.log

It is possible to write logs to the system logging server (syslog) by using these parameters:

yml
# Destinations of log messages; available values are "stdout", "file" and "syslog".
logDestinations: [syslog]
# If "syslog" is in logDestinations, use prefix for logs.
sysLogPrefix: mediamtx

Log entries can be queried by using:

sh
journalctl SYSLOG_IDENTIFIER=mediamtx

If MediaMTX is also running as a system service, log entries can be queried by using:

sh
journalctl -u mediamtx

Structured logging

Log collectors (like Loki, Logstash, CloudWatch and fluentd) parse logs in a more reliable way if they are fed with entries in structured format (JSONL). This can be enabled with the logStructured parameter:

yml
# When destination is "stdout" or "file", emit logs in structured format (JSONL).
logStructured: true

Obtaining:

text
{"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[RTSP] listener opened on :8554 (TCP/RTSP), :8000 (UDP/RTP), :8001 (UDP/RTCP)"}
{"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[RTMP] listener opened on :1935"}
{"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[HLS] listener opened on :8888"}
{"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[WebRTC] listener opened on :8889 (TCP/HTTP), :8189 (UDP/ICE)"}
{"timestamp":"20XX-YY-ZZT10:45:05.999999999+01:00","level":"INF","message":"[SRT] listener opened on :8890 (UDP)"}

Log file rotation

The log file can be periodically rotated or truncated by using an external utility.

On most Linux distributions, the logrotate utility is in charge of managing log files. It can be configured to handle the MediaMTX log file too by creating a configuration file, placed in /etc/logrotate.d/mediamtx, with this content:

text
/my/mediamtx/path/mediamtx.log {
    daily
    copytruncate
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
}

This file will rotate the log file every day, adding a .NUMBER suffix to older copies:

text
mediamtx.log.1
mediamtx.log.2
mediamtx.log.3
...

2 Features 19 Scalability (`docs/2-features/19-scalability.md`)

Scalability

When handling large amounts of readers or publishers, streaming performance might get degraded due to bottlenecks in the underlying hardware infrastructure. In case of streaming without re-encoding (which is what MediaMTX does), these bottlenecks are almost always related to the limited bandwidth between server and readers. This issue can be strongly mitigated by implementing horizontal scalability, which means deploying multiple coordinated server instances, and evenly distributing load on them.

There are several methods available to implement horizontal scalability, the main ones are described in this page.

Read replicas

The main technique for handling additional readers consists in instantiating additional MediaMTX instances, called read replicas, that are in charge of picking streams from a MediaMTX "origin" instance and serving them to users. User connections and requests are distributed to each replica by a load balancer.

Publishers are meant to publish to the origin instance.

Read replicas must be configured in this way:

  • Add one or more proxy paths, pointing to the MediaMTX origin instance, as described in Proxy.
  • If the protocol used by readers is WebRTC, disable webrtcLocalUDPAddress and webrtcLocalTCPAddress and enable a STUN server, as described in Solving WebRTC connectivity issues.

The load balancer has to behave differently depending on the protocol(s) readers are gonna use to read the stream:

  • When using RTSP, RTMP, SRT, the load balancer must be a Layer 4 LB.
  • When using HLS and WebRTC, the load balancer must be a Layer 7 LB with sticky sessions enabled. Sticky sessions are needed to forward HTTP requests from the same user to the same replica, since a single HLS or WebRTC session is composed of several HTTP requests.

Generic implementation

  1. On the machine meant to host the MediaMTX origin instance, launch the instance:

    sh
    docker run -d \
    --name mediamtx \
    --restart always \
    --network host \
    bluenviron/mediamtx:1
  2. On machines meant to host read replicas, create this MediaMTX configuration (mediamtx.yml):

    yml
    webrtcLocalUDPAddress:
    webrtcICEServers2:
      - url: stun:stun.l.google.com:19302
    
    paths:
      "~^(.+)$":
        source: rtsp://dns-of-origin:8554/$G1
        sourceOnDemand: yes

    Replace dns-of-origin with the DNS or IP of the origin machine.

    Then launch MediaMTX:

    sh
    docker run -d \
    --name mediamtx \
    --restart always \
    --network host \
    -v $PWD/mediamtx.yml:/mediamtx.yml \
    bluenviron/mediamtx:1
  3. On machines meant to host the load balancer, create this Traefik configuration (traefik.yml):

    yml
    entryPoints:
      rtsp:
        address: ":8554"
      rtmp:
        address: ":1935"
      srt:
        address: ":8890/udp" # SRT usually uses UDP
      hls:
        address: ":8888"
      webrtc:
        address: ":8889"
    
    providers:
      file:
        filename: "/etc/traefik/dynamic_conf.yml"
        watch: true

    Create this second, dynamic, configuration (dynamic_conf.yml):

    text

/* Detailed source-code truncated for AI context efficiency. */

text
Then launch Traefik:

   ```sh
   docker run -d \
   --name traefik \
   --restart always \
   --network host \
   -v $PWD/traefik.yml:/etc/traefik/traefik.yml \
   -v $PWD/dynamic_conf.yml:/etc/traefik/dynamic_conf.yml \
   traefik:v3.6.14

You can now use the IP address or DNS of the load balancer machines to read streams with any protocol.

It is also possible to entirely skip the load balancer setup by creating a domain name associated with all read replica IPs, and using that to read streams, although it is up to the DNS provider to randomize the IP order and it is up to clients to pick a random one.

AWS implementation

  1. Create a Security group called mediamtx-load-balancer, that will be used by the load balancers. In Inbound rules, add:

    • a rule with type All TCP, source 0.0.0.0/0 (anywhere).
    • a rule with type All UDP, source 0.0.0.0/0 (anywhere).
  2. Create a Security group called mediamtx-read-replicas, that will be used by the read replicas. In Inbound rules, add:

    • a rule of type SSH. In the source field, insert the IP range of administrators.
    • a rule with type All TCP, source Custom, pick the mediamtx-load-balancer security group.
    • a rule with type All UDP, source Custom, pick the mediamtx-load-balancer security group.
  3. Create a Security group called mediamtx-origin, that will be used by the origin. In Inbound rules, add:

    • a rule of type SSH. In the source field, insert the IP range of administrators.
    • a rule with type Custom TCP, port 8554 (RTSP), source Custom, pick the mediamtx-read-replicas security group.
    • a rule with type All UDP, source Custom, pick the mediamtx-read-replicas security group.
    • a rule of type Custom TCP, port 8554 (RTSP). In the source field, insert the IP range of publishers.
    • a rule of type All UDP. In the Source field, insert the IP range of publishers.
  4. Launch an EC2 instance that is meant to host the MediaMTX origin instance. Pick the Amazon Linux AMI. Assign the mediamtx-origin Security group to the instance. In Advanced Details, in the User data textarea, copy and paste this:

    sh
    #!/bin/bash
    dnf update -y
    dnf install -y docker
    systemctl start docker
    systemctl enable docker
    usermod -aG docker ec2-user
    
    docker run -d \
    --name mediamtx \
    --restart always \
    --network host \
    bluenviron/mediamtx:1
  5. Create a Launch template for the read replicas. Pick the Amazon Linux AMI. Assign the mediamtx-read-replicas Security group to the launch template. In Advanced Details, in the User data textarea, copy and paste this:

    sh
    #!/bin/bash
    dnf update -y
    dnf install -y docker
    systemctl start docker
    systemctl enable docker
    usermod -aG docker ec2-user
    
    mkdir -p /etc/mediamtx/
    tee /etc/mediamtx/mediamtx.yml << EOF
    webrtcLocalUDPAddress:
    webrtcICEServers2:
      - url: stun:stun.l.google.com:19302
    
    paths:
      "~^(.+)$":
        source: rtsp://dns-of-origin:8554/\$G1
        sourceOnDemand: yes
    EOF
    
    docker run -d \
    --name mediamtx \
    --restart always \
    --network host \
    -v /etc/mediamtx/mediamtx.yml:/mediamtx.yml \
    bluenviron/mediamtx:1

    Replace dns-of-origin with the private DNS of the origin EC2 instance.

  6. Create several Target groups, with target type Instances, one for each of the following Protocol / Port combinations:

    • Name mediamtx-read-replicas-8554, Protocol TCP, port 8554 (RTSP), health check protocol TCP.
    • Name mediamtx-read-replicas-1935, Protocol TCP, port 1935 (RTMP), health check protocol TCP.
    • Name mediamtx-read-replicas-8890, Protocol UDP, port 8890 (SRT), health check protocol TCP, Advanced health check settings, Health check port, override, insert 8554.
    • Name mediamtx-read-replicas-8888, Protocol HTTP, port 8888 (HLS), health check protocol HTTP, Advanced health check settings, Health check success codes 404.
    • Name mediamtx-read-replicas-8889, Protocol HTTP, port 8889 (WebRTC), health check protocol HTTP, Advanced health check settings, Health check success codes 404.

    Do not associate these target groups with any instance for now.

  7. Select the mediamtx-read-replicas-8888 target group, tab Attributes, Edit, section Target selection configuration, Turn on stickiness, Save. Do the same for the mediamtx-read-replicas-8889 target group.

  8. Create a Load Balancer, type Network Load Balancer. Assign the mediamtx-load-balancer Security group to the load balancer. In Listeners, define 3 listeners:

    • Protocol TCP, port 8554 (RTSP), forward to target group mediamtx-read-replicas-8554
    • Protocol TCP, port 1935 (RTMP), forward to target group mediamtx-read-replicas-1935
    • Protocol UDP, port 8890 (SRT), forward to target group mediamtx-read-replicas-8890
  9. Create a Load Balancer, type Application Load Balancer. Assign the mediamtx-load-balancer Security group to the load balancer. In Listeners, define 2 listeners:

    • Protocol HTTP, port 8888 (HLS), forward to target group mediamtx-read-replicas-8888
    • Protocol HTTP, port 8889 (WebRTC), forward to target group mediamtx-read-replicas-8889
  10. Create an Auto scaling group for the read replicas. Pick the launch template that was defined before. CPU and Memory parameters are usually not important. In the Load balancing section, pick Attach to an existing load balancer and select all 5 target groups that were created before. In the Group size section, in Desired capacity, set the desired instance count.

You can now use the DNS of the Network Load Balancer to read streams with RTSP, RTMP and SRT, and the DNS of the Application Load Balancer to read streams with HLS and WebRTC.

This process involved all available protocols, but it can be greatly simplified if users are meant to read streams with a single protocol only (for instance, WebRTC), in this case, opening specific ports only (8889) and creating specific load balancers only (Application load balancer) is enough.

CDN

The read replicas technique provides the lowest latency, is compatible with all protocols and can be implemented on any on-premises or cloud environment, but it comes with some limitations regarding performance and cost:

  • Sudden load spikes can be handled by adjusting read replica count, but this adjustement is not immediate and depends on either an autoscaling policy or a manual action, leading to a potential temporary performance degradation.
  • Increasing the read replica count can lead to saturation of the bandwidth between read replicas and the origin, creating a new bottleneck.
  • Each read replica requires a dedicated and potentially expensive machine.

An alternative way to serve streams consists in putting a CDN in front of the MediaMTX HLS server, in charge of storing cacheable files and serving requests, freeing the server from the load of most user requests. This method overcomes scalability and cost limitations, but has some drawbacks:

  • Only the HLS protocol is available.
  • Low-Latency HLS playlists cannot be cached and are always requested from the server, therefore it is often necessary to disable the Low-Latency HLS variant, introducing significant latency.
  • Standard MediaMTX authentication mechanisms are not available. Streams are always accessible by anyone, unless the CDN enforces its own authentication system.

In order to allow MediaMTX to recognize CDN requests and serve cacheable files, the CDN must insert into every request an Authorization: Bearer header with a secret, that must match the one defined in the hlsCDNSecret configuration parameter in MediaMTX.

Generic implementation

  1. On the machine meant to host MediaMTX, create this MediaMTX configuration (mediamtx.yml):

    yml
    hlsCDNSecret: XXXXXXXXXX
    hlsVariant: fmp4
    paths:
      all:

    Replace hlsCDNSecret with some secret key. Using the fmp4 HLS variant is strongly encouraged to prevent playlist requests from always reaching the server.

    Then launch MediaMTX:

    sh
    docker run -d \
    --name mediamtx \
    --restart always \
    --network host \
    bluenviron/mediamtx:1
  2. Configure the CDN to use the MediaMTX machine as origin, and to inject hlsCDNSecret in the Authorization: Bearer header.

AWS implementation

  1. Create a Security group called mediamtx-load-balancer, that will be used by the load balancer in front of the origin. In Inbound rules, add:

    • a rule with type All TCP, source 0.0.0.0/0 (anywhere).
  2. Create a Security group called mediamtx-origin, that will be used by the EC2 instance that will host MediaMTX. In Inbound rules, add:

    • a rule of type SSH. In the source field, insert the IP range of administrators.
    • a rule of type Custom TCP, port 8554 (RTSP). In the source field, insert the IP range of publishers.
    • a rule of type All UDP. In the Source field, insert the IP range of publishers.
    • a rule with type All TCP, source Custom, pick the mediamtx-load-balancer security group.
  3. Create an EC2 instance. Assign the mediamtx-origin Security group to the instance.

  4. Log into the EC2 instance. create this MediaMTX configuration (mediamtx.yml):

    yml
    hlsCDNSecret: XXXXXXXXXX
    hlsVariant: fmp4
    paths:
      all:

    Replace hlsCDNSecret with some secret key. Using the fmp4 HLS variant is strongly encouraged to prevent playlist requests from always reaching the server.

    Then launch MediaMTX:

    sh
    sudo dnf update -y
    sudo dnf install -y docker
    sudo systemctl start docker
    sudo systemctl enable docker
    sudo usermod -aG docker ec2-user
    sudo docker run \
    -d \
    --restart=always \
    --name mediamtx \
    --network host \
    -v $PWD/mediamtx.yml:/mediamtx.yml \
    bluenviron/mediamtx:1
  5. Create a Target group. In Target Type leave Instance, in Protocol leave HTTP, in Port insert 8888 (HLS). Open Advanced health check settings, in Success codes insert 404. Associate the Target group with the EC2 instance.

  6. Create a Load Balancer, type Application Load Balancer. Assign the mediamtx-load-balancer Security group to the load balancer. In Listeners, set the HTTP port to 8888 (HLS) and in Target group select the target group that was created previously.

  7. Create a CloudFront distribution. Point it to the load balancer. In HTTP port, insert 8888 (HLS).

    In the distribution page, edit the origin. Under Add custom header, click on Add header and fill:

    • Header name: Authorization
    • Value: Bearer XXXXX (replace XXXX with the hlsCDNSecret value)

    In the distribution page, edit the default behavior. In Cache policy, pick UseOriginCacheControlHeaders.

You can now use the URL of the CloudFront distribution to read HLS streams, for instance:

text
https://xxxxxx.cloudfront.net/stream/

Replace xxxxxx.cloudfront.net with the distribution domain, and stream with the stream path.


2 Features 20 Hooks (`docs/2-features/20-hooks.md`)

Hooks

The server allows to specify commands that are executed when a certain event happens, allowing the propagation of events to external software.

runOnConnect

runOnConnect allows to run a command when a client connects to the server:

yml
# Command to run when a client connects to the server.
# This is terminated with SIGINT when a client disconnects from the server.
# The following environment variables are available:
# * MTX_CONN_TYPE: connection type
# * MTX_CONN_ID: connection ID
# * RTSP_PORT: RTSP server port
runOnConnect: curl http://my-custom-server/webhook?conn_type=$MTX_CONN_TYPE&conn_id=$MTX_CONN_ID
# Restart the command if it exits.
runOnConnectRestart: no

runOnDisconnect

runOnDisconnect allows to run a command when a client disconnects from the server:

yml
# Command to run when a client disconnects from the server.
# Environment variables are the same as runOnConnect.
runOnDisconnect: curl http://my-custom-server/webhook?conn_type=$MTX_CONN_TYPE&conn_id=$MTX_CONN_ID

runOnInit

runOnInit allows to run a command when a path is initialized. This can be used to publish a stream when the server is launched:

yml
paths:
  mypath:
    # Command to run when this path is initialized.
    # This can be used to publish a stream when the server is launched.
    # This is terminated with SIGINT when the program closes.
    # The following environment variables are available:
    # * MTX_PATH: path name
    # * RTSP_PORT: RTSP server port
    # * G1, G2, ...: regular expression groups, if path name is
    #   a regular expression.
    runOnInit: ffmpeg -i my_file.mp4 -c copy -f rtsp rtsp://localhost:8554/mypath
    # Restart the command if it exits.
    runOnInitRestart: no

runOnDemand

runOnDemand allows to run a command when a path is requested by a reader. This can be used to publish a stream on demand:

yml
pathDefaults:
  # Command to run when this path is requested by a reader
  # and no one is publishing to this path yet.
  # This can be used to publish a stream on demand.
  # This is terminated with SIGINT when there are no readers anymore.
  # The following environment variables are available:
  # * MTX_PATH: path name
  # * MTX_QUERY: query parameters (passed by first reader) (url-encoded)
  # * RTSP_PORT: RTSP server port
  # * G1, G2, ...: regular expression groups, if path name is
  #   a regular expression.
  runOnDemand: ffmpeg -i my_file.mp4 -c copy -f rtsp rtsp://localhost:8554/mypath
  # Restart the command if it exits.
  runOnDemandRestart: no

runOnUnDemand

runOnUnDemand allows to run a command when there are no readers anymore:

yml
pathDefaults:
  # Command to run when there are no readers anymore.
  # Environment variables are the same as runOnDemand.
  runOnUnDemand:

runOnAvailable

runOnAvailable allows to run a command when a stream is available to be read:

yml
pathDefaults:
  # Command to run when the stream is available to be read.
  # This is terminated with SIGINT when the stream is not available anymore.
  # The following environment variables are available:
  # * MTX_PATH: path name
  # * MTX_QUERY: query parameters (passed by publisher) (url-encoded)
  # * MTX_SOURCE_TYPE: source type
  # * MTX_SOURCE_ID: source ID
  # * RTSP_PORT: RTSP server port
  # * G1, G2, ...: regular expression groups, if path name is
  #   a regular expression.
  runOnAvailable: curl http://my-custom-server/webhook?path=$MTX_PATH&source_type=$MTX_SOURCE_TYPE&source_id=$MTX_SOURCE_ID
  # Restart the command if it exits.
  runOnAvailableRestart: no

runOnUnavailable

runOnUnavailable allows to run a command when a stream is not available anymore:

yml
pathDefaults:
  # Command to run when the stream is not available anymore.
  # Environment variables are the same as runOnAvailable.
  runOnUnavailable: curl http://my-custom-server/webhook?path=$MTX_PATH&source_type=$MTX_SOURCE_TYPE&source_id=$MTX_SOURCE_ID

runOnOnline

runOnOnline allows to run a command when a stream is online, which means that the stream is available and provided by a online source (not an offline segment):

yml
pathDefaults:
  # Command to run when the stream is online, which means
  # that the stream is available and provided by a online source (not an offline segment).
  # This is terminated with SIGINT when the stream is not online anymore.
  # The following environment variables are available:
  # * MTX_PATH: path name
  # * MTX_QUERY: query parameters (passed by publisher) (url-encoded)
  # * MTX_SOURCE_TYPE: source type
  # * MTX_SOURCE_ID: source ID
  # * RTSP_PORT: RTSP server port
  # * G1, G2, ...: regular expression groups, if path name is
  #   a regular expression.
  runOnOnline: curl http://my-custom-server/webhook?path=$MTX_PATH&source_type=$MTX_SOURCE_TYPE&source_id=$MTX_SOURCE_ID
  # Restart the command if it exits.
  runOnOnlineRestart: no

runOnOffline

runOnOffline allows to run a command when a stream is not online anymore:

yml
pathDefaults:
  # Command to run when the stream is not online anymore.
  # Environment variables are the same as runOnOnline.
  runOnOffline: curl http://my-custom-server/webhook?path=$MTX_PATH&source_type=$MTX_SOURCE_TYPE&source_id=$MTX_SOURCE_ID

runOnRead

runOnRead allows to run a command when a client starts reading:

yml
pathDefaults:
  # Command to run when a client starts reading.
  # This is terminated with SIGINT when a client stops reading.
  # The following environment variables are available:
  # * MTX_PATH: path name
  # * MTX_QUERY: query parameters (passed by reader) (url-encoded)
  # * MTX_READER_TYPE: reader type
  # * MTX_READER_ID: reader ID
  # * RTSP_PORT: RTSP server port
  # * G1, G2, ...: regular expression groups, if path name is
  #   a regular expression.
  runOnRead: curl http://my-custom-server/webhook?path=$MTX_PATH&reader_type=$MTX_READER_TYPE&reader_id=$MTX_READER_ID
  # Restart the command if it exits.
  runOnReadRestart: no

runOnUnread

runOnUnread allows to run a command when a client stops reading:

yml
pathDefaults:
  # Command to run when a client stops reading.
  # Environment variables are the same as runOnRead.
  runOnUnread: curl http://my-custom-server/webhook?path=$MTX_PATH&reader_type=$MTX_READER_TYPE&reader_id=$MTX_READER_ID

runOnRecordSegmentCreate

runOnRecordSegmentCreate allows to run a command when a recording segment is created:

yml
pathDefaults:
  # Command to run when a recording segment is created.
  # The following environment variables are available:
  # * MTX_PATH: path name
  # * MTX_SEGMENT_PATH: segment file path
  # * RTSP_PORT: RTSP server port
  # * G1, G2, ...: regular expression groups, if path name is
  #   a regular expression.
  runOnRecordSegmentCreate: curl http://my-custom-server/webhook?path=$MTX_PATH&segment_path=$MTX_SEGMENT_PATH

runOnRecordSegmentComplete

runOnRecordSegmentComplete allows to run a command when a recording segment is complete:

yml
pathDefaults:
  # Command to run when a recording segment is complete.
  # The following environment variables are available:
  # * MTX_PATH: path name
  # * MTX_SEGMENT_PATH: segment file path
  # * MTX_SEGMENT_DURATION: segment duration
  # * RTSP_PORT: RTSP server port
  # * G1, G2, ...: regular expression groups, if path name is
  #   a regular expression.
  runOnRecordSegmentComplete: curl http://my-custom-server/webhook?path=$MTX_PATH&segment_path=$MTX_SEGMENT_PATH

2 Features 21 Control Api (`docs/2-features/21-control-api.md`)

Control API

The server can be queried and controlled with an API, that can be enabled by toggling the api parameter in the configuration:

yml
api: yes

To obtain a list of active paths, run:

text
curl http://127.0.0.1:9997/v3/paths/list

The control API is documented in the Control API Reference page and in the OpenAPI / Swagger file.

Be aware that by default the Control API is accessible by localhost only; to increase visibility or enforce authentication, check Authentication.


2 Features 22 Metrics (`docs/2-features/22-metrics.md`)

Extract metrics

MediaMTX provides several metrics through a dedicated HTTP server, in a format compatible with Prometheus.

This server can be enabled by setting metrics: yes in the configuration.

Metrics can be extracted with Prometheus or with a simple HTTP request:

text
curl http://localhost:9998/metrics

Obtaining:

text
/* Detailed source-code truncated for AI context efficiency. */

Bitrates are not provided directly as metrics because they can be computed from received and sent bytes by any metrics analyzer (for instance Grafana).

Metrics can be filtered by using HTTP query parameters:

  • type=[TYPE]: show metrics of a certain type only. TYPE can be paths, forward_dests, hls_sessions, hls_muxers, rtsp_conns, rtsp_sessions, rtsps_conns, rtsps_sessions, rtmp_conns, rtmps_conns, srt_conns, webrtc_sessions, moq_sessions.
  • path=[PATH]: show metrics belonging to a specific path only
  • hls_muxer=[PATH]: show metrics belonging to a specific HLS muxer only
  • hls_session=[ID]: show metrics belonging to a specific HLS session only
  • rtsp_conn=[ID] show metrics belonging to a specific RTSP connection only
  • rtsp_session=[SESSION]: show metrics belonging to a specific RTSP session only
  • rtsps_conn=[ID] show metrics belonging to a specific RTSPS connection only
  • rtsps_session=[SESSION]: show metrics belonging to a specific RTSPS session only
  • rtmp_conn=[ID] show metrics belonging to a specific RTMP connection only
  • rtmps_conn=[ID] show metrics belonging to a specific RTMPS connection only
  • srt_conn=[ID] show metrics belonging to a specific SRT connection only
  • webrtc_session=[ID] show metrics belonging to a specific WebRTC session only
  • forward_dest=[ID] show metrics belonging to a specific forward destination only
  • moq_session=[ID] show metrics belonging to a specific MoQ session only

2 Features 23 Performance (`docs/2-features/23-performance.md`)

Monitor performance

CPU and memory consumption can be monitored over time through an integrated performance monitor, that produces reports in a format compatible with pprof, which is a tool included in any Go installation.

The performance monitor can be enabled by setting pprof: yes in the configuration.

Reports can be extracted and displayed by using the go tool pprof command.

Occupied memory can be analyzed by running:

sh
go tool pprof -text http://localhost:9999/debug/pprof/heap

Obtaining:

text
/* Detailed source-code truncated for AI context efficiency. */

Consumed CPU can be analyzed by running:

sh
go tool pprof -text http://localhost:9999/debug/pprof/profile?seconds=15

Obtaining:

text
/* Detailed source-code truncated for AI context efficiency. */

Active routines can be listed by running:

sh
go tool pprof -text http://localhost:9999/debug/pprof/goroutine

Obtaining:

text
/* Detailed source-code truncated for AI context efficiency. */

2 Features 24 Srt Specific Features (`docs/2-features/24-srt-specific-features.md`)

SRT-specific features

SRT is a protocol that can be used for publishing and reading streams. Regarding specific tasks, check out Publish with SRT clients and Read with SRT clients. Features in this page are shared among both tasks.

Standard stream ID syntax

In SRT, the stream ID is a string that is sent to the remote part in order to advertise what action the caller is going to do (publish or read), the path and the credentials. All this information has to be encoded into a single string. This server supports two stream ID syntaxes, a custom one (that is the one reported in the rest of the README) and also a standard one proposed by the authors of the protocol and enforced by some hardware. The standard syntax can be used in this way:

text
srt://localhost:8890?streamid=#!::m=publish,r=mypath,u=myuser,s=mypass&pkt_size=1316

Where:

  • key m contains the action (publish or request)
  • key r contains the path
  • key u contains the username
  • key s contains the password

2 Features 25 Webrtc Specific Features (`docs/2-features/25-webrtc-specific-features.md`)

WebRTC-specific features

WebRTC is a protocol that can be used for publishing and reading streams. Regarding specific tasks, check out Publish with WebRTC clients and Read with WebRTC clients. Features in this page are shared among both tasks.

Codec support in browsers

WebRTC can be used to publish and read streams encoded with a wide variety of video and audio codecs, but not every browser can publish and read streams with every codec due to internal limitations that cannot be overcome by this or any other server.

You can check what codecs your browser supports by using this tool.

In particular, the following codecs might cause compatibility issues:

  • H265. Lots of browsers do not support reading H265 tracks with WebRTC, others do only if some strict conditions are met. For instance, Chrome supports publishing and reading H265 tracks only on Windows and only when a capable GPU is present.

  • H264, when the stream contains B-frames. These are not part of the WebRTC specification and support for them has been intentionally left out by every browser.

In order to support most browsers, you can re-encode the stream by using the H264 codec with the baseline profile (which does not produce B-frames) and the Opus codec, for instance by using FFmpeg:

sh
ffmpeg -i rtsp://original-source \
-c:v libx264 -pix_fmt yuv420p -preset ultrafast -b:v 600k \
-c:a libopus -b:a 64K -async 50 \
-f rtsp rtsp://localhost:8554/mystream

Solving WebRTC connectivity issues

In WebRTC, the handshake between server and clients happens through standard HTTP requests and responses, while media streaming takes place inside a dedicated communication channel (peer connection) that is set up shortly after the handshake. The server supports establishing peer connections through the following methods (ordered by efficiency and simplicity):

  1. using a static UDP server port (webrtcLocalUDPAddress must be filled, it is by default)
  2. using a static TCP server port (webrtcLocalTCPAddress must be filled, it is not by default)
  3. using a random UDP server port and UDP client port with the hole-punching technique (webrtcICEServers2 must contain a STUN server, not present by default)
  4. using a relay (TURN server) that exposes a TCP port that is accessed by both server and clients (webrtcICEServers2 must contain a TURN server, not present by default)

Establishing the peer connection might get difficult when the server is hosted inside a container or there is a NAT / firewall between server and clients.

The first thing to do is making sure that webrtcAdditionalHosts includes your public IPs, that are IPs that can be used by clients to reach the server. If clients are on the same LAN as the server, add the LAN address of the server. If clients are coming from the internet, add the public IP address of the server, or alternatively a DNS name, if you have one. You can add several values to support all scenarios:

yml
webrtcAdditionalHosts: [192.168.x.x, 1.2.3.4, my-dns.example.org, ...]

If there's a NAT / container between server and clients, it must be configured to route all incoming UDP packets on port 8189 to the server. If you're using Docker, this can be achieved with the flag:

sh
docker run --rm -it \
-p 8189:8189/udp
....
bluenviron/mediamtx:1

If you still have problems, the UDP protocol might be blocked by a firewall. Switch to the TCP protocol by enabling the TCP server port:

yml
webrtcLocalTCPAddress: :8189

If there's a NAT / container between server and clients, it must be configured to route all incoming TCP packets on port 8189 to the server.

If you still have problems, add a STUN server, that is used by both server and clients to find out their public IP. Connections are then established with the "UDP hole punching" technique, that uses a random UDP port that does not need to be explicitly opened. For instance:

yml
webrtcICEServers2:
  - url: stun:stun.l.google.com:19302

If you really still have problems, you can force all WebRTC/ICE connections to pass through a TURN server. The server address and credentials must be set in the configuration file:

yml
webrtcICEServers2:
  - url: turn:host:port
    username: user
    password: password

Where user and pass are the username and password of the server. Note that port is not optional.

If the server uses a secret-based authentication (for instance, Coturn with the use-auth-secret option), it must be configured by using AUTH_SECRET as username, and the secret as password:

yml
webrtcICEServers2:
  - url: turn:host:port
    username: AUTH_SECRET
    password: secret

Where secret is the secret of the TURN server. MediaMTX will generate a set of credentials by using the secret, and credentials will be sent to clients before the WebRTC/ICE connection is established.

In some cases you may want the browser to connect using TURN servers but have MediaMTX not using TURN (for example if the TURN server is on the same network as mediamtx). To allow this you can configure the TURN server to be client only:

yml
webrtcICEServers2:
  - url: turn:host:port
    username: user
    password: password
    clientOnly: true

Coturn setup

Here's how to setup the Coturn TURN server and use it with MediaMTX. This is needed only if all other WebRTC connectivity methods have failed. Start Coturn with Docker:

sh
docker run --rm -it \
--network=host \
coturn/coturn \
--log-file=stdout -v \
--no-udp --no-dtls --no-tls \
--min-port=49152 --max-port=65535 \
--use-auth-secret --static-auth-secret=mysecret -r myrealm

We are suggesting and using the following settings:

  • enable the TCP transport only. We are assuming you are setting up Coturn because other connectivity methods have failed, thus TCP is more reliable.
  • toggle --network=host since Coturn allocates a TCP port for each peer connection.
  • set min-port and max-port to specify the range of TCP ports.
  • enable secret-based authentication, that prevents clients from storing permanently valid credentials.

Configure MediaMTX to use the TURN server:

yml
webrtcICEServers2:
  - url: turn:REPLACE_WITH_COTURN_IP:3478?transport=tcp
    username: AUTH_SECRET
    password: mysecret

The ?transport=tcp suffix is needed to force TCP usage. Use AUTH_SECRET as username and the shared secret as the password.


2 Features 26 Rtsp Specific Features (`docs/2-features/26-rtsp-specific-features.md`)

RTSP-specific features

RTSP is a protocol that can be used for publishing and reading streams. Regarding specific tasks, check out Publish with RTSP clients and Read with RTSP clients. Features in this page are shared among both tasks.

Transport protocols

A RTSP session is split in two parts: the handshake, which is always performed with the TCP protocol, and data streaming, which can be performed with an arbitrary underlying transport protocol, which is chosen by the client during the handshake:

  • UDP: the most performant, but requires clients to access two additional UDP ports on the server, which is often impossible due to blocking or remapping by NATs/firewalls in between.
  • UDP-multicast: allows to save bandwidth when clients are all in the same LAN, by sending packets once to a fixed multicast IP.
  • TCP: the most versatile.

To change the transport protocol, you have to tune the configuration of the client you are using to publish or read streams. In most clients, the default transport protocol is UDP.

FFmpeg allows to change the transport protocol with the -rtsp_transport flag:

sh
ffmpeg -rtsp_transport tcp -i rtsp://localhost:8554/mystream -c copy output.mp4

Available options are:

  • -rtsp_transport tcp to pick the TCP transport protocol
  • -rtsp_transport udp to pick the UDP transport protocol
  • -rtsp_transport udp_multicast to pick the UDP-multicast transport protocol

GStreamer allows to change the transport protocol with the protocols property of rtspsrc and rtspclientsink:

sh
gst-launch-1.0 filesrc location=file.mp4 ! qtdemux name=d \
d.video_0 ! rtspclientsink location=rtsp://localhost:8554/mystream protocols=tcp

Available options are:

  • protocols=tcp to pick the TCP transport protocol
  • protocols=udp to pick the UDP transport protocol
  • protocols=udp-mcast to pick the UDP-multicast transport protocol

VLC allows to use the TCP transport protocol through the --rtsp_tcp flag:

sh
vlc --network-caching=50 --rtsp-tcp rtsp://localhost:8554/mystream

VLC allows to use the UDP-multicast transport protocol by appending ?vlcmulticast to the URL:

sh
vlc --network-caching=50 rtsp://localhost:8554/mystream?vlcmulticast

Encryption

Incoming and outgoing RTSP streams can be encrypted by replacing all the subprotocols that are normally used in RTSP with their secure variants (RTSPS, SRTP, SRTCP). A TLS certificate is needed and can be generated with OpenSSL:

sh
openssl genrsa -out server.key 2048
openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650

Edit mediamtx.yml and set the encryption, serverKey and serverCert parameters:

yml
rtspEncryption: optional
rtspServerKey: server.key
rtspServerCert: server.crt

Streams can be published and read with the rtsps scheme and the 8322 port:

text
rtsps://localhost:8322/mystream

Some clients require additional flags for encryption to work properly.

When reading with GStreamer, set tls-validation-flags to 0:

sh
gst-launch-1.0 rtspsrc tls-validation-flags=0 location=rtsps://ip:8322/...

When publishing with GStreamer, set tls-validation-flags to 0 and profiles to GST_RTSP_PROFILE_SAVP:

sh
gst-launch-1.0 filesrc location=file.mp4 ! qtdemux name=d \
d.video_0 ! rtspclientsink location=rtsp://localhost:8554/mystream tls-validation-flags=0 profiles=GST_RTSP_PROFILE_SAVP

Tunneling

In environments where HTTP is the only protocol available for exposing services (for instance, when there are mandatory API gateways or strict firewalls), the RTSP protocol can be tunneled inside HTTP. There are two standardized HTTP tunneling variants:

  • RTSP over WebSocket: more efficient, requires WebSocket support from the gateway / firewall
  • RTSP over HTTP: older variant, should work even in extreme cases

MediaMTX is automatically able to handle incoming HTTP-tunneled RTSP connections without any configuration required.

In order to read a stream from an external RTSP server using HTTP tunneling, you can use the rtsp+http scheme:

yml
paths:
  source: rtsp+http://standard-rtsp-url

There are also the rtsps+http, rtsp+ws, rtsps+ws schemes to handle any variant.

MPEG-TS inside RTSP

read MPEG-TS inside RTSP in the "Publish with RTSP clients" page.


2 Features 27 Rtmp Specific Features (`docs/2-features/27-rtmp-specific-features.md`)

RTMP-specific features

RTMP is a protocol that can be used for publishing and reading streams. Regarding specific tasks, check out Publish with RTMP clients and Read with RTMP clients. Features in this page are shared among both tasks.

Encryption

RTMP connections can be encrypted by using the secure protocol variant (RTMPS). A TLS certificate is needed and can be generated with OpenSSL:

yml
openssl genrsa -out server.key 2048
openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650

Edit mediamtx.yml and set the rtmpEncryption, rtmpServerKey and rtmpServerCert parameters:

yml
rtmpEncryption: optional
rtmpServerKey: server.key
rtmpServerCert: server.crt

Streams can be published and read with the rtmps scheme and the 1937 port:

text
rtmps://localhost:1937/...

Be aware that RTMPS is currently unsupported by most major players. However, you can use a local MediaMTX instance to decrypt streams before reading them, or alternatively a proxy like stunnel or nginx. For instance, you can launch a local MediaMTX instance with this configuration:

yml
paths:
  decrypted:
    source: rtmps://original-stream

And then read rtmp://localhost/decrypted instead of rtmps://original-stream.


2 Features 28 Decrease Packet Loss (`docs/2-features/28-decrease-packet-loss.md`)

Decrease packet loss

MediaMTX is meant for routing live streams, and makes use of a series of protocols and techniques which try to preserve the real-time aspect of streams and minimize latency at cost of losing packets in transmit, in particular:

  • most protocols are built on UDP, which is an "unreliable transport", specifically picked because it allows dropping late packets in case of network congestion.
  • there's a circular buffer that stores outgoing packets and drops packets if full.

Packet losses are usually detected and printed in MediaMTX logs.

If you need to improve the stream reliability and decrease packet losses, the first thing to do is to check whether the physical network between the MediaMTX instance and the intended publishers and readers has sufficient bandwidth for transmitting the media stream. Most of the time, packet losses are caused by a network which is not fit for this scope. This limitation can be overcome by either recompressing the stream with a lower bitrate, or by upgrading the network infrastructure (routers, cables, Wi-Fi, firewalls, topology, etc).

Nonetheless there are some parameters that can be tuned to improve the situation, at cost of increasing RAM consumption:

  • When publishing a stream with a UDP-based protocol (currently RTSP, MPEG-TS, RTP, SRT, WebRTC), packets might get discarded by the server because the read buffer size of UDP sockets is too small. It can be increased with this parameter:

    yml
    udpReadBufferSize: 1000000

    The udpReadBufferSize parameter requires the net.core.rmem_max system parameter to be equal or greater than it. It can be set with this command:

    sh
    sudo sysctl net.core.rmem_max=100000000
  • When reading a stream, packets might get discarded because the write queue is too small. This can be noticed in logs through the "reader is too slow" message. Try increasing the write queue:

    yml
    writeQueueSize: 1024
  • When publishing or reading a stream with RTSP, it's possible to switch from the UDP transport protocol to the TCP transport protocol, which is less performant but has a packet retransmission mechanism:

    yml
    rtspTransports: [tcp]

    In case the source is a camera:

    yml
    paths:
      test:
        source: rtsp://..
        rtspTransport: tcp

3 Publish 01 Moq Clients (`docs/3-publish/01-moq-clients.md`)

Media-over-QUIC clients

supported codecs
video AV1, VP9, VP8, H265, H264
audio Opus, MPEG-4 Audio (AAC)

Media-over-QUIC is a streaming protocol built upon cutting edge protocols (QUIC, HTTP3) and browser APIs (WebTransport, WebCodecs) that can be used to publish and read live media streams. It's slightly faster than WebRTC, has an advanced data recovery mechanism, supports additional codecs (FLAC and future ones), supports B-frames and is less complicated to route.

Media-over-QUIC has a wide range of features and variants, most of them in active development. We currently support the following:

  • The server supports draft-19, draft-18, draft-17 and draft-16 of the main specification, and prefers draft-19 when multiple versions are offered during negotiation.
  • We support using Media-over-QUIC through browsers with the WebTransport API and through native QUIC clients.
  • We support the PUBLISH and SUBSCRIBE messages only, which are the ones meant to be used with a routing solution like MediaMTX.
  • We use the MOQT Streaming Format (MSF) to advertise tracks, described in this specification.
  • We use the Low Overhead Media Container (LOC) to ship frames, described in this specification.
  • We host web pages through a HTTP/2 listener and host the WebTransport endpoint through a HTTP/3 listener. This hybrid setup allows to use self-signed certificates, that are normally forbidden in pure HTTP/3.

There are some server requirements:

  • HTTPS is mandatory.
  • Clients must be able to access both the HTTP/2 listener (:8892/TCP) and the HTTP/3 listener (:8892/UDP).
  • If the server is behind Docker, NAT or a firewall, expose and forward both 8892/TCP and 8892/UDP to the server.

And there are some client (browser) requirements:

You can publish a stream with Media-over-QUIC and a web browser by visiting:

text
https://localhost:8892/mystream/publish

You can also publish with native QUIC clients by connecting directly to moqQUICAddress (default is :8893).


3 Publish 02 Moq Servers (`docs/3-publish/02-moq-servers.md`)

Media-over-QUIC servers

supported codecs
video AV1, VP9, VP8, H265, H264
audio Opus, MPEG-4 Audio (AAC)

In order to ingest a Media-over-QUIC stream from a remote server, add the corresponding URL into the source parameter of a path:

yml
paths:
  proxied:
    source: moqt://user:pass@host:port/path
    # Transport protocol used to pull the stream. available values are "quic", "webtransport".
    moqTransport: quic

If username or password contain special characters (like ?, :, etc), they need to be url-encoded.

If host is a stateless IPv6 address, wrap the address in square brackets and write the zone separator % as %25, for example moqt://[fe80::1234:5678:9abc:def0%25eth0]:8892/path.


3 Publish 03 Srt Clients (`docs/3-publish/03-srt-clients.md`)

SRT clients

supported codecs
video H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
audio Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
other KLV

SRT is a protocol that allows to publish and read live data stream, providing encryption, integrity and a retransmission mechanism. It is usually used to transfer media streams encoded with MPEG-TS. In order to publish a stream to the server with the SRT protocol, use this URL:

text
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, read 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.

Some clients that can publish with SRT are FFmpeg, GStreamer, OBS Studio.


3 Publish 04 Srt Cameras And Servers (`docs/3-publish/04-srt-cameras-and-servers.md`)

SRT cameras and servers

supported codecs
video H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
audio Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
other KLV

In order to ingest a SRT stream from a remote server, camera or client in listening mode (i.e. with mode=listener appended to the URL), add the corresponding URL into the source parameter of a path:

yml
paths:
  proxied:
    source: srt://host:port?streamid=streamid

3 Publish 05 Webrtc Clients (`docs/3-publish/05-webrtc-clients.md`)

WebRTC clients

supported codecs
video AV1, VP9, VP8, H265, H264
audio Opus, G722, G711 (PCMA, PCMU)

WebRTC is an API that makes use of a set of protocols and methods to connect two clients together and allow them to exchange live media or data streams. You can publish a stream with WebRTC and a web browser by visiting:

text
http://localhost:8889/mystream/publish

The resulting stream will be available on path /mystream.

WHIP is a WebRTC extension that allows to publish streams by using a URL, without passing through a web page. This allows to use WebRTC as a general purpose streaming protocol. If you are using a software that supports WHIP (for instance, latest versions of OBS Studio), you can publish a stream to the server by using this URL:

text
http://localhost:8889/mystream/whip

Be aware that not all browsers can publish tracks with any codec, check Codec support in browsers.

Depending on the network it might be difficult to establish a connection between server and clients, read Solving WebRTC connectivity issues.

Some clients that can publish with WebRTC and WHIP are FFmpeg, GStreamer, OBS Studio, Unity and Web browsers.


3 Publish 06 Webrtc Servers (`docs/3-publish/06-webrtc-servers.md`)

WebRTC servers

supported codecs
video AV1, VP9, VP8, H265, H264
audio Opus, G722, G711 (PCMA, PCMU)

In order to ingest a WebRTC stream from a remote server, add the corresponding WHEP URL into the source parameter of a path:

yml
paths:
  proxied:
    # Use whep:// for HTTP and wheps:// for HTTPS.
    source: whep://host:port/path
    # If the source is HTTPS and the source TLS certificate is self-signed
    # or invalid, you can provide the fingerprint of the certificate in order to
    # validate it anyway. It can be obtained by running:
    # openssl s_client -connect source_ip:source_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
    # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
    sourceFingerprint:
    # Token to insert in the Authorization: Bearer header.
    whepBearerToken: ""

If host is a stateless IPv6 address, wrap the address in square brackets and write the zone separator % as %25, for example whep://[fe80::1234:5678:9abc:def0%25eth0]:8889/path.

If the remote server is a MediaMTX instance, remember to add a /whep suffix after the stream name, since in MediaMTX it's part of the WHEP URL:

yml
paths:
  proxied:
    source: whep://host:port/mystream/whep

3 Publish 07 Rtsp Clients (`docs/3-publish/07-rtsp-clients.md`)

RTSP clients

supported codecs
video AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, MJPEG
audio Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
other KLV, MPEG-TS, any RTP-compatible codec

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:

text
rtsp://localhost:8554/mystream

The resulting stream will be available on path /mystream.

Some clients that can publish with RTSP are FFmpeg, GStreamer, OBS Studio, Python and OpenCV.

Advanced RTSP features and settings are described in RTSP-specific features.

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 is possible to automatically demux these MPEG-TS-encoded streams by toggling rtspDemuxMpegts:

yml
pathDefaults:
  rtspDemuxMpegts: true

3 Publish 08 Rtsp Cameras And Servers (`docs/3-publish/08-rtsp-cameras-and-servers.md`)

RTSP cameras and servers

supported codecs
video AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, MJPEG
audio Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
other KLV, MPEG-TS, any RTP-compatible codec

Most IP cameras expose their video stream by using a RTSP server that is embedded into the camera itself. In particular, cameras that are compliant with ONVIF profile S or T meet this requirement. You can use MediaMTX to connect to one or several existing RTSP servers and read their media streams:

yml
paths:
  proxied:
    # Use rtsp:// for plain RTSP and rtsps:// for encrypted RTSP.
    source: rtsp://user:pass@host:port/path
    # If the source is RTSPS and the source TLS certificate is self-signed
    # or invalid, you can provide the fingerprint of the certificate in order to
    # validate it anyway. It can be obtained by running:
    # openssl s_client -connect source_ip:source_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
    # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
    sourceFingerprint:

If username or password contain special characters (like ?, :, etc), they need to be url-encoded.

If host is a stateless IPv6 address, wrap the address in square brackets and write the zone separator % as %25, for example rtsp://[fe80::1234:5678:9abc:def0%25eth0]:554/path.

Some cameras require a username but an empty password. In this case, keep the colon after the username (rtsp://user:@host:port/path): a username without a colon (rtsp://user@host:port/path) is treated as a missing password and rejected.

The resulting stream will be available on path /proxied.

It is possible to tune the connection by using several additional parameters, that are listed in the configuration file.

Advanced RTSP features and settings are described in RTSP-specific features.

MPEG-TS inside RTSP

Some RTSP servers expose a single MPEG-TS (MP2T) track instead of elementary H.264 / H.265. In that case MediaMTX would keep tracks: ["MPEG-TS"] and HLS / WebRTC would not attach. Enable rtspDemuxMpegts on the path (same flag as RTSP publishers):

yml
paths:
  proxied:
    source: rtsp://user:pass@host:port/path
    rtspTransport: tcp
    rtspDemuxMpegts: true

3 Publish 09 Rtmp Clients (`docs/3-publish/09-rtmp-clients.md`)

RTMP clients

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. Streams can be published to the server by using the URL:

text
rtmp://localhost/mystream

The resulting stream will be available on path /mystream.

Some clients that can publish with RTMP are FFmpeg, GStreamer and OBS Studio.


3 Publish 10 Rtmp Cameras And Servers (`docs/3-publish/10-rtmp-cameras-and-servers.md`)

RTMP cameras and servers

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:

yml
paths:
  proxied:
    # Use rtmp:// for plain RTMP and rtmps:// for encrypted RTMP.
    source: rtmp://user:pass@host:port/path#streamKey
    # If the source is RTMPS and the source TLS certificate is self-signed
    # or invalid, you can provide the fingerprint of the certificate in order to
    # validate it anyway. It can be obtained by running:
    # openssl s_client -connect source_ip:source_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
    # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
    sourceFingerprint:

If username or password contain special characters (like ?, :, etc), they need to be url-encoded.

If host is a stateless IPv6 address, wrap the address in square brackets and write the zone separator % as %25, for example rtmp://[fe80::1234:5678:9abc:def0%25eth0]:1935/path.

The resulting stream will be available on path /proxied.


3 Publish 11 Hls Cameras And Servers (`docs/3-publish/11-hls-cameras-and-servers.md`)

HLS cameras and servers

supported codecs
video AV1, VP9, H265, H264
audio Opus, FLAC, MPEG-4 Audio (AAC)
other KLV (MPEG-TS-based HLS only)

HLS is a streaming protocol that works by splitting streams into segments, and by serving these segments and a playlist with the HTTP protocol. You can use MediaMTX to connect to one or several existing HLS servers and read their media streams:

yml
paths:
  proxied:
    # Use http:// for plain HTTP and https:// for HTTPS.
    source: http://user:pass@host:port/path
    # If the source is HTTPS and the source TLS certificate is self-signed
    # or invalid, you can provide the fingerprint of the certificate in order to
    # validate it anyway. It can be obtained by running:
    # openssl s_client -connect source_ip:source_port </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
    # openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
    sourceFingerprint:

If username or password contain special characters (like ?, :, etc), they need to be url-encoded.

If host is a stateless IPv6 address, wrap the address in square brackets and write the zone separator % as %25, for example http://[fe80::1234:5678:9abc:def0%25eth0]:8080/path.

The resulting stream will be available on path /proxied.


3 Publish 12 Mpeg Ts (`docs/3-publish/12-mpeg-ts.md`)

MPEG-TS

supported codecs
video H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
audio Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
other KLV

The server supports ingesting MPEG-TS streams, shipped in two different ways (UDP packets or Unix sockets).

In order to read a UDP MPEG-TS stream, edit mediamtx.yml and replace everything inside section paths with the following content:

yml
paths:
  mypath:
    source: udp+mpegts://ip:port

The IP is usually a multicast IP, for instance:

yml
paths:
  mypath:
    source: udp+mpegts://238.0.0.1:1234

If the listening IP is a multicast IP, MediaMTX will listen for incoming packets on the default multicast interface, picked by the operating system. It is possible to specify the interface manually by using the interface parameter:

yml
paths:
  mypath:
    source: udp+mpegts://238.0.0.1:1234?interface=eth0

It is possible to restrict who can send packets by using the source parameter:

yml
paths:
  mypath:
    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 and GStreamer.

Unix sockets are more efficient than UDP packets and can be used as transport by specifying the unix+mpegts scheme:

yml
paths:
  mypath:
    source: unix+mpegts:///tmp/socket.sock

3 Publish 13 Rtp (`docs/3-publish/13-rtp.md`)

RTP

supported codecs
video AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG
audio Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
other KLV, MPEG-TS, any RTP-compatible codec

The server supports ingesting RTP streams, transmitted with UDP packets.

In order to read a UDP RTP stream, edit mediamtx.yml and replace everything inside section paths with the following content:

yml
paths:
  mypath:
    source: udp+rtp://238.0.0.1:1234
    rtpSDP: |
      v=0
      o=- 123456789 123456789 IN IP4 192.168.1.100
      s=H264 Video Stream
      c=IN IP4 192.168.1.100
      t=0 0
      m=video 5004 RTP/AVP 96
      a=rtpmap:96 H264/90000

rtpSDP must contain a valid SDP, that is a description of the RTP session.

If the listening IP is a multicast IP, MediaMTX will listen for incoming packets on the default multicast interface, picked by the operating system. It is possible to specify the interface manually by using the interface parameter:

yml
paths:
  mypath:
    source: udp+rtp://238.0.0.1:1234?interface=eth0
    rtpSDP: |
      v=0
      o=- 123456789 123456789 IN IP4 192.168.1.100
      s=H264 Video Stream
      c=IN IP4 192.168.1.100
      t=0 0
      m=video 5004 RTP/AVP 96
      a=rtpmap:96 H264/90000

It is possible to restrict who can send packets by using the source parameter:

yml
paths:
  mypath:
    source: udp+rtp://238.0.0.1:1234?source=192.168.3.5
    rtpSDP: |
      v=0
      o=- 123456789 123456789 IN IP4 192.168.1.100
      s=H264 Video Stream
      c=IN IP4 192.168.1.100
      t=0 0
      m=video 5004 RTP/AVP 96
      a=rtpmap:96 H264/90000

Some clients that can publish with UDP and MPEG-TS are FFmpeg and GStreamer.


3 Publish 14 Raspberry Pi Cameras (`docs/3-publish/14-raspberry-pi-cameras.md`)

Raspberry Pi Cameras

MediaMTX natively supports most Raspberry Pi Camera models, enabling high-quality and low-latency video streaming from the camera to any user, for any purpose.

The server must run on a Raspberry Pi, with one of the following operating systems:

  • Raspberry Pi OS Trixie
  • Raspberry Pi OS Bookworm

Both 32-bit and 64-bit architectures are supported.

The setup procedure depends on whether you want to run the server outside or inside Docker:

  • If you want to run the standard (non-Dockerized) version of the server:

    1. Download the server executable. If you're using 64-bit version of the operative system, make sure to pick the arm64 variant.

    2. Edit mediamtx.yml and replace everything inside section paths with the following content:

    yml
    paths:
      cam:
        source: rpiCamera

    The resulting stream will be available on path /cam.

  • If you want to run the server inside Docker, you need to use the 1-rpi image and launch the container with some additional flags:

    sh
    docker run --rm -it \
    --network=host \
    --privileged \
    --tmpfs /dev/shm:exec \
    -v /run/udev:/run/udev:ro \
    -e MTX_PATHS_CAM_SOURCE=rpiCamera \
    bluenviron/mediamtx:1-rpi

The Raspberry Pi Camera can be controlled through a wide range of parameters, that are listed in the configuration file.

Custom libcamera

Some cameras, in particular ArduCam products, require a custom libcamera. These are not compatible with precompiled MediaMTX binaries and Docker images, since they embed a standard libcamera.

If you want to interact with these cameras, you need to compile MediaMTX from source.

Adding audio

In order to add audio from a USB microphone, install GStreamer and alsa-utils:

sh
sudo apt install -y gstreamer1.0-tools gstreamer1.0-rtsp gstreamer1.0-alsa alsa-utils

list available audio cards with:

sh
arecord -L

Sample output:

text
surround51:CARD=ICH5,DEV=0
    Intel ICH5, Intel ICH5
    5.1 Surround output to Front, Center, Rear and Subwoofer speakers
default:CARD=U0x46d0x809
    USB Device 0x46d:0x809, USB Audio
    Default Audio Device

Find the audio card of the microphone and take note of its name, for instance default:CARD=U0x46d0x809. Then create a new path that takes the video stream from the camera and audio from the microphone:

yml
paths:
  cam:
    source: rpiCamera

  cam_with_audio:
    runOnInit: >
      gst-launch-1.0
      rtspclientsink name=s location=rtsp://localhost:$RTSP_PORT/cam_with_audio
      rtspsrc location=rtsp://127.0.0.1:$RTSP_PORT/cam latency=0 ! rtph264depay ! s.
      alsasrc device=default:CARD=U0x46d0x809 ! opusenc bitrate=16000 ! s.
    runOnInitRestart: yes

The resulting stream will be available on path /cam_with_audio.

Secondary stream

It is possible to enable a secondary stream from the same camera, with a different resolution, FPS and codec. Configuration is the same of a primary stream, with rpiCameraSecondary set to true and parameters adjusted accordingly:

yml
paths:
  # primary stream
  rpi:
    source: rpiCamera
    # Width of frames.
    rpiCameraWidth: 1920
    # Height of frames.
    rpiCameraHeight: 1080
    # FPS.
    rpiCameraFPS: 30

  # secondary stream
  secondary:
    source: rpiCamera
    # This is a secondary stream.
    rpiCameraSecondary: true
    # Width of frames.
    rpiCameraWidth: 640
    # Height of frames.
    rpiCameraHeight: 480
    # FPS.
    rpiCameraFPS: 10
    # Codec. in case of secondary streams, it defaults to M-JPEG.
    rpiCameraCodec: auto
    # JPEG quality.
    rpiCameraMJPEGQuality: 60

The secondary stream will be available on path /secondary.

Multiple cameras

It is possible to stream several cameras at once by using rpiCameraCamID:

yml
paths:
  # first camera
  cam1:
    source: rpiCamera
    rpiCameraCamID: 0

  # second camera
  cam2:
    source: rpiCamera
    rpiCameraCamID: 1

3 Publish 15 Generic Webcams (`docs/3-publish/15-generic-webcams.md`)

Generic webcams

If the operating system is Linux, edit mediamtx.yml and replace everything inside section paths with the following content:

yml
paths:
  cam:
    runOnInit: ffmpeg -f v4l2 -i /dev/video0 -c:v libx264 -pix_fmt yuv420p -preset ultrafast -b:v 600k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH
    runOnInitRestart: yes

If the operating system is Windows:

yml
paths:
  cam:
    runOnInit: ffmpeg -f dshow -i video="USB2.0 HD UVC WebCam" -c:v libx264 -pix_fmt yuv420p -preset ultrafast -b:v 600k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH
    runOnInitRestart: yes

Where USB2.0 HD UVC WebCam is the name of a webcam, that can be obtained with:

sh
ffmpeg -list_devices true -f dshow -i dummy

The resulting stream will be available on path /cam.


3 Publish 16 Web Browsers (`docs/3-publish/16-web-browsers.md`)

Web browsers

Web browsers can publish a stream to the server by acting as a Media-over-QUIC client or a WebRTC client.

Media-over-QUIC

Start the server and open the web page:

text
https://localhost:8892/mystream/publish

The resulting stream will be available on path /mystream.

This web page can be embedded into another web page by using an iframe:

html
<iframe src="https://mediamtx-ip:8892/mystream/publish" scrolling="no"></iframe>

WebRTC

Start the server and open the web page:

text
http://localhost:8889/mystream/publish

The resulting stream will be available on path /mystream.

Be aware that not all browsers can publish tracks with any codec, check Codec support in browsers.

This web page can be embedded into another web page by using an iframe:

html
<iframe src="http://mediamtx-ip:8889/mystream/publish" scrolling="no"></iframe>

For more advanced setups, you can create and serve a custom web page by starting from the source code of the WebRTC publish page. In particular, there's a ready-to-use, standalone JavaScript class for publishing streams with WebRTC, available in publisher.js.


3 Publish 17 Ffmpeg (`docs/3-publish/17-ffmpeg.md`)

FFmpeg

FFmpeg can publish a stream to the server by acting as a RTSP client, RTMP client, SRT client, WebRTC client or by sending MPEG-TS packets or RTP packets. The recommended way is acting as a RTSP client.

FFmpeg as a RTSP client

sh
ffmpeg -re -stream_loop -1 -i file.mp4 -c copy -f rtsp rtsp://localhost:8554/mystream

FFmpeg as a RTMP client

sh
ffmpeg -re -stream_loop -1 -i file.mp4 -c copy -f flv rtmp://localhost:1935/mystream

FFmpeg as a SRT client

sh
ffmpeg -re -stream_loop -1 -i file.mp4 -c copy -f mpegts 'srt://localhost:8890?streamid=publish:stream&pkt_size=1316'

FFmpeg as a WebRTC client

sh
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
-f lavfi -i "sine=frequency=1000:sample_rate=48000" \
-c:v libx264 -pix_fmt yuv420p -preset ultrafast -b:v 600k \
-c:a libopus -ar 48000 -ac 2 -b:a 128k \
-f whip http://localhost:8889/stream/whip

WARNING: in case of FFmpeg 8.0, a video track and an audio track must both be present.

FFmpeg and MPEG-TS over UDP

In MediaMTX configuration, add a path with source: udp+mpegts://238.0.0.1:1234. Then:

sh
ffmpeg -re -stream_loop -1 -i file.mp4 -c copy -f mpegts 'udp://238.0.0.1:1234?pkt_size=1316'

FFmpeg and MPEG-TS over Unix socket

In MediaMTX configuration, add a path with source: unix+mpegts:///tmp/socket.sock. Then:

sh
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
-c:v libx264 -pix_fmt yuv420p -preset ultrafast -b:v 600k \
-f mpegts unix:/tmp/socket.sock

FFmpeg and RTP over UDP

In MediaMTX configuration, add a path with source: udp+rtp://238.0.0.1:1234 and a valid rtpSDP (read RTP). Then:

sh
ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
-c:v libx264 -pix_fmt yuv420p -preset ultrafast -b:v 600k \
-f rtp udp://238.0.0.1:1234?pkt_size=1316

3 Publish 18 Gstreamer (`docs/3-publish/18-gstreamer.md`)

GStreamer

GStreamer can publish a stream to the server by acting as a RTSP client, RTMP client, SRT client, WebRTC client or by sending MPEG-TS packets or RTP packets. The recommended way is acting as a RTSP client.

GStreamer as a RTSP client

sh
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:

sh
gst-launch-1.0 filesrc location=file.mp4 ! qtdemux name=d \
d.video_0 ! rtspclientsink location=rtsp://localhost:8554/mystream

GStreamer as a RTMP client

sh
gst-launch-1.0 -v flvmux name=mux ! rtmpsink location=rtmp://localhost/stream \
videotestsrc ! video/x-raw,width=1280,height=720,format=I420 ! x264enc speed-preset=ultrafast bitrate=3000 key-int-max=60 ! video/x-h264,profile=high ! mux. \
audiotestsrc ! audioconvert ! avenc_aac ! mux.

GStreamer as a SRT client

sh
gst-launch-1.0 -v mpegtsmux name=mux ! srtsink uri="srt://localhost:8890?streamid=publish:mystream&pkt_size=1316" \
videotestsrc ! video/x-raw,width=1280,height=720,format=I420 ! x264enc speed-preset=ultrafast bitrate=3000 key-int-max=60 ! video/x-h264,profile=high ! mux. \
audiotestsrc ! audioconvert ! avenc_aac ! mux.

GStreamer as a WebRTC client

Make sure that GStreamer version is at least 1.22, and that if the codec is H264, the profile is baseline. Use the whipclientsink element:

sh
gst-launch-1.0 videotestsrc \
! video/x-raw,width=1920,height=1080,format=I420 \
! x264enc speed-preset=ultrafast bitrate=2000 \
! video/x-h264,profile=baseline \
! whipclientsink signaller::whip-endpoint=http://localhost:8889/mystream/whip

GStreamer and MPEG-TS over UDP

In MediaMTX configuration, add a path with source: unix+mpegts:///tmp/socket.sock. Then:

sh
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,format=I420 ! x264enc speed-preset=ultrafast bitrate=3000 key-int-max=60 ! video/x-h264,profile=high ! mux. \
audiotestsrc ! audioconvert ! avenc_aac ! mux.

GStreamer and RTP over UDP

In MediaMTX configuration, add a path with source: udp+rtp://238.0.0.1:1234 and a valid rtpSDP (read RTP). Then:

sh
gst-launch-1.0 -v \
videotestsrc ! video/x-raw,width=1280,height=720,format=I420 ! x264enc speed-preset=ultrafast bitrate=3000 key-int-max=60 ! video/x-h264,profile=high ! rtph264pay config-interval=1 ! udpsink host=238.0.0.1 port=1234 \
audiotestsrc ! audioconvert ! avenc_aac ! rtpmp4gpay ! udpsink host=238.0.0.1 port=1236

3 Publish 19 Obs Studio (`docs/3-publish/19-obs-studio.md`)

OBS Studio

OBS Studio can publish streams to the server by acting as a RTMP client or a WebRTC client protocols. The recommended way is acting as a RTMP client.

OBS Studio as a RTMP client

Standard

In Settings -> Stream (or in the Auto-configuration Wizard), use the following parameters:

  • Service: Custom...
  • Server: rtmp://localhost/mystream
  • Stream key: (empty)

Save the configuration and click Start streaming.

The resulting stream will be available on path /mystream.

If you want to generate a stream that can be read with WebRTC, open Settings -> Output -> Recording and use the following parameters:

  • FFmpeg output type: Output to URL
  • File path or URL: rtsp://localhost:8554/mystream
  • Container format: rtsp
  • Check show all codecs (even if potentially incompatible)
  • Video encoder: h264_nvenc (libx264)
  • Video encoder settings (if any): bf=0
  • Audio track: 1
  • Audio encoder: libopus

Then use the button Start Recording (instead of Start Streaming) to start streaming.

Multitrack video

OBS Studio can publish multiple video tracks or renditions at once (simulcast). Make sure that the OBS Studio version is ≥ 31.0.0. Open Settings -> Stream and use the following parameters:

  • Service: Custom...

  • Server: rtmp://localhost/mystream

  • Stream key: (empty)

  • Turn on Enable Multitrack Video

  • Leave Maximum Streaming Bandwidth and Maximum Video Tracks to Auto

  • Turn on Enable Config Override

  • Fill Config Override (JSON) with the following text:

    json
    {
      "encoder_configurations": [
        {
          "type": "obs_x264",
          "width": 1920,
          "height": 1080,
          "framerate": {
            "numerator": 30,
            "denominator": 1
          },
          "settings": {
            "rate_control": "CBR",
            "bitrate": 6000,
            "keyint_sec": 2,
            "preset": "veryfast",
            "profile": "high",
            "tune": "zerolatency"
          },
          "canvas_index": 0
        },
        {
          "type": "obs_x264",
          "width": 640,
          "height": 480,
          "framerate": {
            "numerator": 30,
            "denominator": 1
          },
          "settings": {
            "rate_control": "CBR",
            "bitrate": 3000,
            "keyint_sec": 2,
            "preset": "veryfast",
            "profile": "main",
            "tune": "zerolatency"
          },
          "canvas_index": 0
        }
      ],
      "audio_configurations": {
        "live": [
          {
            "codec": "ffmpeg_aac",
            "track_id": 1,
            "channels": 2,
            "settings": {
              "bitrate": 160
            }
          }
        ]
      }
    }

    This can be adjusted according to specific needs. In particular, the type field is used to set the video encoder, and these are the available parameters:

    • obs_nvenc_av1_tex: NVIDIA NVENC AV1
    • obs_nvenc_hevc_tex: NVIDIA NVENC H265
    • obs_nvenc_h264_tex: NVIDIA NVENC H264
    • av1_texture_amf: AMD AV1
    • h265_texture_amf: AMD H265
    • h264_texture_amf: AMD H264
    • obs_qsv11_av1: QuickSync AV1
    • obs_qsv11_v2: QuickSync H264
    • obs_x264: software H264

Save the configuration and click Start streaming.

The resulting stream will be available on path /mystream.

Encryption (RTMPS)

When publishing streams to MediaMTX with RTMP, you can encrypt streams in transit by using the encrypted variant of RTMP (RTMPS). This can be enabled by using the rtmps scheme and the 1936 port:

text
rtmps://localhost:1936/mystream

Make sure that RTMP encryption is allowed in MediaMTX (rtmpEncryption: "optional").

OBS Studio requires MediaMTX to use a TLS certificate signed by a public certificate authority and silently rejects self-signed certificates. You can either buy a certificate from a public certificate authority or create a local certificate authority and use it to generate the server certificate and validate it on the OBS Studio machine, by following these instructions:

  1. Create the key pair of the local certificate authority:

    sh
    openssl req \
    -x509 \
    -nodes \
    -days 3650 \
    -newkey rsa:4096 \
    -keyout myca.key \
    -out myca.crt \
    -subj "/O=myca/CN=myca"
  2. Use the key pair to create the server certificate. Replace localhost with the domain name OBS Studio will use to connect to the server:

    sh
    openssl req \
    -newkey rsa:4096 \
    -nodes \
    -keyout server.key \
    -CA myca.crt \
    -CAkey myca.key \
    -subj "/CN=localhost" \
    -x509 \
    -days 3650 \
    -out server.crt

    You must use a domain name to connect to the server, not an IP address. If you do not have a domain name, edit the /etc/hosts file of the OBS Studio machine and associate a dummy domain name to the IP address of the server.

  3. Put the newly-generated server.key and server.cert on the MediaMTX machine, in the same folder of the MediaMTX executable, and check that the configuration points to them.

  4. Install the public key (ca.crt) of the local certificate authority on the OBS Studio machine.

    If you are using Linux, this can be accomplished with these commands:

    sh
    sudo mkdir -p /usr/local/share/ca-certificates
    sudo cp myca.crt /usr/local/share/ca-certificates/
    sudo update-ca-certificates

    WARNING: this will still not work when OBS Studio is installed with Flatpak, since Flatpak isolates OBS Studio from the host and prevents it from reading the ca-certificates folder. Install OBS Studio through another mean (snap / ppa / .deb).

    If you are using Windows, this can be accomplished with the command:

    sh
    certutil -addstore "Root" myca.crt

OBS Studio as a WebRTC client

Standard

Recent versions of OBS Studio can also publish streams to the server with the WebRTC / WHIP protocol Use the following parameters:

  • Service: WHIP
  • Server: http://localhost:8889/mystream/whip

Save the configuration and click Start streaming.

The resulting stream will be available on path /mystream.

Multitrack video

OBS Studio can publish multiple video tracks or renditions at once (simulcast) with WebRTC / WHIP too. Make sure that the OBS Studio version is ≥ 32.1.0. Open Settings -> Stream and use the following parameters:

  • Service: WHIP
  • Server: http://localhost:8889/mystream/whip
  • Simulcast, Total Layers: 2 (or greater)

Currently it's not possible to change resolution or bitrate (or canvas) of renditions, since quality of secondary renditions is hardcoded as a percentage of the main one. You can find details on the OBS documentation.

Save the configuration and click Start streaming.

The resulting stream will be available on path /mystream.

Encryption

When publishing streams to MediaMTX with WebRTC, you can encrypt the WebRTC handshake by using the HTTPS-based variant of WHIP. This can be enabled by using the https scheme:

text
https://localhost:8889/mystream

Make sure that WebRTC encryption is enabled in MediaMTX (webrtcEncryption: true).

OBS Studio requires MediaMTX to use a TLS certificate signed by a public certificate authority and silently rejects self-signed certificates. You can either buy a certificate from a public certificate authority or create a local certificate authority and use it to generate the server certificate and validate it on the OBS Studio machine. Instructions are reported in OBS Studio and RTMP, encryption (RTMPS).


3 Publish 20 Python Opencv (`docs/3-publish/20-python-opencv.md`)

Python and OpenCV

Python-based software can publish streams to the server with the OpenCV library and its GStreamer plugin, acting as a RTSP client. OpenCV must be compiled with support for GStreamer, by following this procedure:

sh
sudo apt install -y libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-ugly gstreamer1.0-rtsp python3-dev python3-numpy
git clone --depth=1 -b 4.5.4 https://github.com/opencv/opencv
cd opencv
mkdir build && cd build
cmake -D CMAKE_INSTALL_PREFIX=/usr -D WITH_GSTREAMER=ON ..
make -j$(nproc)
sudo make install

You can check that OpenCV has been installed correctly by running:

sh
python3 -c 'import cv2; print(cv2.getBuildInformation())'

Check that the output contains GStreamer: YES.

Videos can then be published with cv2.VideoWriter:

python
from datetime import datetime
from time import sleep, time

import cv2
import numpy as np

fps = 15
width = 800
height = 600
colors = [
    (0, 0, 255),
    (255, 0, 0),
    (0, 255, 0),
]

out = cv2.VideoWriter('appsrc ! videoconvert' + \
    ' ! video/x-raw,format=I420' + \
    ' ! 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")

curcolor = 0
start = time()

while True:
    frame = np.zeros((height, width, 3), np.uint8)

    # create a rectangle
    color = colors[curcolor]
    curcolor += 1
    curcolor %= len(colors)
    for y in range(0, int(frame.shape[0] / 2)):
        for x in range(0, int(frame.shape[1] / 2)):
            frame[y][x] = color

    out.write(frame)
    print("%s frame written to the server" % datetime.now())

    now = time()
    diff = (1 / fps) - now - start
    if diff > 0:
        sleep(diff)
    start = now

The resulting stream will be available on path /mystream.


3 Publish 21 Golang (`docs/3-publish/21-golang.md`)

Golang

You can publish a stream to the server by using the Go programming language and the following libraries:

Both powers MediaMTX itself. In the repositories of these projects there are several examples on how to connect to a server and push data.


3 Publish 22 Unity (`docs/3-publish/22-unity.md`)

Unity

Software written with the Unity Engine can publish a stream to the server by acting as a WebRTC client.

Create a new Unity project or open an existing one.

Open Window -> Package Manager, click on the plus sign, Add Package by name... and insert com.unity.webrtc. Wait for the package to be installed.

In the Project window, under Assets, create a new C# Script called WebRTCPublisher.cs with this content:

text
/* Detailed source-code truncated for AI context efficiency. */

In the Hierarchy window, find or create a scene and a camera, then add the WebRTCPublisher.cs script as component of the camera, by dragging it inside the Inspector window. then Press the Play button at the top of the page.

The resulting stream will be available on path /unity.


4 Read 01 Moq (`docs/4-read/01-moq.md`)

Media-over-QUIC clients

supported codecs
video AV1, VP9, VP8, H265, H264
audio Opus, FLAC, MPEG-4 Audio (AAC), G711 (PCMA, PCMU), LPCM

Media-over-QUIC is a streaming protocol built upon cutting edge protocols (QUIC, HTTP3) and browser APIs (WebTransport, WebCodecs) that can be used to publish and read live media streams. It's slightly faster than WebRTC, has an advanced data recovery mechanism, supports additional codecs (FLAC and future ones), supports B-frames and is less complicated to route.

There are some limitations and requirements that are listed in Publish with Media-over-QUIC clients.

You can read a stream with Media-over-QUIC and a web browser by visiting:

text
https://localhost:8892/mystream

You can also read with native QUIC clients by connecting directly to moqQUICAddress (default is :8893).


4 Read 02 Srt (`docs/4-read/02-srt.md`)

SRT clients

supported codecs
video H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video
audio Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3
other KLV

SRT is a protocol that allows to publish and read live data stream, providing encryption, integrity and a retransmission mechanism. It is usually used to transfer media streams encoded with MPEG-TS. In order to read a stream from the server with the SRT protocol, use this URL:

text
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, read Standard stream ID syntax.

Some clients that can read with SRT are FFmpeg, GStreamer and VLC.


4 Read 03 Webrtc (`docs/4-read/03-webrtc.md`)

WebRTC clients

supported codecs
video AV1, VP9, VP8, H265, H264
audio Opus, G722, G711 (PCMA, PCMU)
other KLV

WebRTC is an API that makes use of a set of protocols and methods to connect two clients together and allow them to exchange live media or data streams. You can read a stream with WebRTC and a web browser by visiting:

text
http://localhost:8889/mystream

WHEP is a WebRTC extension that allows to read streams by using a URL, without passing through a web page. This allows to use WebRTC as a general purpose streaming protocol. If you are using a software that supports WHEP, you can read a stream from the server by using this URL:

text
http://localhost:8889/mystream/whep

Be aware that not all browsers can read tracks with any codec, check Codec support in browsers.

Depending on the network it may be difficult to establish a connection between server and clients, read Solving WebRTC connectivity issues.

Some clients that can read with WebRTC and WHEP are web browsers, GStreamer and Unity.


4 Read 04 Rtsp (`docs/4-read/04-rtsp.md`)

RTSP clients

supported codecs
video AV1, VP9, VP8, H265, H264, MPEG-4 Video (H263, Xvid), MPEG-1/2 Video, M-JPEG
audio Opus, MPEG-4 Audio (AAC), MPEG-1/2 Audio (MP3), AC-3, G726, G722, G711 (PCMA, PCMU), LPCM
other KLV, MPEG-TS, any RTP-compatible codec

RTSP is a protocol that allows to publish and read streams. It supports several underlying transport protocols and encryption (read RTSP-specific features). In order to read a stream with the RTSP protocol, use this URL:

text
rtsp://localhost:8554/mystream

Some clients that can read with RTSP are FFmpeg, GStreamer and VLC.


4 Read 05 Rtmp (`docs/4-read/05-rtmp.md`)

RTMP clients

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. Streams can be read from the server by using the URL:

text
rtmp://localhost/mystream

Some clients that can read with RTMP are FFmpeg, GStreamer and VLC.


4 Read 06 Hls (`docs/4-read/06-hls.md`)

HLS

supported codecs
video AV1, VP9, H265, H264
audio Opus, FLAC, MPEG-4 Audio (AAC)
other KLV (MPEG-TS-based HLS only)

HLS is a protocol that works by splitting streams into segments, and by serving these segments and a playlist with the HTTP protocol. You can use MediaMTX to generate an HLS stream, that is accessible through a web page:

text
http://localhost:8888/mystream

and can also be accessed without using the browsers, by software that supports the HLS protocol (for instance VLC or MediaMTX itself) by using this URL:

text
http://localhost:8888/mystream/index.m3u8

Some clients that can read with HLS are web browsers, FFmpeg, GStreamer and VLC.

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.

HLS can also be used to scale the server through a CDN.


4 Read 07 Web Browsers (`docs/4-read/07-web-browsers.md`)

Web browsers

Web browsers can read a stream from the server with the Media-over-QUIC, WebRTC and HLS protocols, by accessing web pages hosted by the server. It is also possible to embed streams into an external website.

Direct read

Media-over-QUIC

Visit the web page:

text
https://localhost:8892/mystream

Replace mystream with the path name.

WebRTC

Visit the web page:

text
http://localhost:8889/mystream

Replace mystream with the path name.

Be aware that not all browsers can read tracks with any codec, check Codec support in browsers.

HLS

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:

text
http://localhost:8888/mystream

Replace mystream with the path name.

Embed in a website

Live streams can be embedded into an external website by using the WebRTC or HLS protocol. Before embedding, check that the stream is ready and can be accessed with intended protocol by visiting web pages mentioned in the previous section.

Media-over-QUIC in iframe

The simplest way to embed a live stream in a web page, using the Media-over-QUIC protocol, consists in adding an `` tag to the body section of the HTML:

html
<iframe src="https://mediamtx-ip:8892/mystream" scrolling="no"></iframe>

WebRTC in iframe

The simplest way to embed a live stream in a web page, using the WebRTC protocol, consists in adding an `` tag to the body section of the HTML:

html
<iframe src="http://mediamtx-ip:8889/mystream" scrolling="no"></iframe>

The iframe can be controlled by adding query parameters to the URL (example: http://mediamtx-ip:8889/mystream?muted=false). The following parameters are available:

  • controls (boolean): whether to show controls. Default is true.
  • muted (boolean): whether to start the stream muted. Default is true.
  • autoplay (boolean): whether to autoplay the stream. Default is true.
  • playsInline (boolean): whether to play the stream without using the entire window of mobile devices. Default is true.
  • disablepictureinpicture (boolean): whether to disable the ability to open the stream in a dedicated window. Default is false.

The iframe method is fit for most use cases, but it has some limitations:

  • it doesn't allow to pass credentials (username, password or token) from the website to MediaMTX; credentials are asked directly to users.
  • it doesn't allow to directly access the video tag, to extract data from it, or to perform dynamic actions.

WebRTC with JavaScript

In order to overcome the limitations of the iframe-based method, it is possible to load the stream directly inside a <video> tag in the web page, through a JavaScript library.

Download reader.js from the repository and serve it together with the other assets of the website.

If you are using a JavaScript bundler, you can import it by using:

js
import "./reader.js";

Otherwise, you can add a <script> tag to the <head> section of the page:

html
<script defer src="./reader.js"></script>

Add a <video> tag:

html
<video
  id="myvideo"
  controls
  muted
  autoplay
  playsinline
  width="640"
  height="480"
></video>

After the video tag, add a script that initializes the stream when the page is fully loaded:

html
<script>
  let reader = null;

  window.addEventListener("load", () => {
    reader = new MediaMTXWebRTCReader({
      url: "http://mediamtx-ip:8889/mystream/whep",
      user: "", // fill if needed
      pass: "", // fill if needed
      token: "", // fill if needed
      onError: (err) => {
        console.error(err);
      },
      onTrack: (evt) => {
        document.getElementById("myvideo").srcObject = evt.streams[0];
      },
      onDataChannel: (evt) => {
        evt.channel.binaryType = "arraybuffer";
        evt.channel.onmessage = (evt) => {
          console.log("data channel message", evt.data);
        };
      },
    });
  });

  window.addEventListener("beforeunload", () => {
    if (reader !== null) {
      reader.close();
    }
  });
</script>

HLS in iframe

Reading a stream with the HLS protocol introduces some latency, but is usually easier to setup since it doesn't involve managing additional ports that in WebRTC are used to transmit the stream.

The simplest way to embed a live stream in a web page, using the HLS protocol, consists in adding an `` tag to the body section of the HTML:

html
<iframe src="http://mediamtx-ip:8888/mystream" scrolling="no"></iframe>

The iframe can be controlled by adding query parameters to the URL (example: http://mediamtx-ip:8888/mystream?muted=false). The following parameters are available:

  • controls (boolean): whether to show controls. Default is true.
  • muted (boolean): whether to start the stream muted. Default is true.
  • autoplay (boolean): whether to autoplay the stream. Default is true.
  • playsInline (boolean): whether to play the stream without using the entire window of mobile devices. Default is true.
  • disablepictureinpicture (boolean): whether to disable the ability to open the stream in a dedicated window. Default is false.

The iframe method is fit for most use cases, but it has some limitations:

  • it doesn't allow to pass credentials (username, password or token) from the website to MediaMTX; credentials are asked directly to users.
  • it doesn't allow to directly access the video tag, to extract data from it, or to perform dynamic actions.

HLS with JavaScript

In order to overcome the limitations of the iframe-based method, it is possible to load the stream directly inside a <video> tag in the web page, through the hls.js library.

Be aware that hls.js is not compatible with browsers that do not expose the Media Source Extensions API, in particular old iOS versions (iPad iOS < 13, iPhone iOS < 17).

If you are using a JavaScript bundler, you can import hls.js by adding its npm package as dependency and then importing it:

js
import Hls from "hls.js";

Otherwise, you can use a <script> tag inside the <head> section that points to a CDN:

html
<script defer src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>

Add a <video> tag:

html
<video
  id="myvideo"
  controls
  muted
  autoplay
  playsinline
  width="640"
  height="480"
></video>

After the video tag, add a script that initializes the stream when the page is fully loaded:

html
<script>
  window.addEventListener("load", () => {
    const video = document.getElementById("myvideo");

    const hls = new Hls({
      xhrSetup: function (xhr, url) {
        let user = ""; // fill if needed
        let pass = ""; // fill if needed
        let token = ""; // fill if needed

        if (user !== "") {
          const credentials = btoa(`${user}:${pass}`);
          xhr.setRequestHeader("Authorization", `Basic ${credentials}`);
        } else if (token !== "") {
          xhr.setRequestHeader("Authorization", `Bearer ${token}`);
        }
      },
    });

    hls.on(Hls.Events.MEDIA_ATTACHED, () => {
      hls.loadSource("http://mediamtx-ip:8888/mystream/index.m3u8");
    });

    // when the video is resumed after a manual or forced pause
    // (i.e. when the window is minimized), restore live streaming.
    video.onplay = () => {
      video.currentTime = hls.liveSyncPosition;
    };

    hls.attachMedia(video);
  });
</script>

4 Read 08 Ffmpeg (`docs/4-read/08-ffmpeg.md`)

FFmpeg

FFmpeg can read a stream from the server the RTSP, RTMP, HLS and SRT protocols. The recommended one is RTSP.

FFmpeg and RTSP

sh
ffmpeg -i rtsp://localhost:8554/mystream -c copy output.mp4

FFmpeg and RTMP

sh
ffmpeg -i rtmp://localhost/mystream -c copy output.mp4

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 \
-i rtmp://localhost/mystream -c copy output.mp4

FFmpeg and SRT

sh
ffmpeg -i 'srt://localhost:8890?streamid=read:test' -c copy output.mp4

4 Read 09 Gstreamer (`docs/4-read/09-gstreamer.md`)

GStreamer

GStreamer can read a stream from the server by using the RTSP, RTMP, HLS, SRT and WebRTC protocols. The recommended one is RTSP.

GStreamer and RTSP

sh
gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/mystream latency=0 ! decodebin ! autovideosink

GStreamer and RTMP

GStreamer supports reading streams with the RTMP protocol, but the path must be composed by at least two elements, for instance mypath/mysubpath:

sh
gst-launch-1.0 rtmpsrc location=rtmp://localhost/mypath/mysubpath ! flvdemux name=d \
d.video ! queue ! decodebin ! autovideosink

GStreamer and SRT

sh
gst-launch-1.0 srtsrc uri="srt://localhost:8890?streamid=read:mystream" ! tsdemux ! decodebin ! autovideosink

GStreamer and WebRTC

GStreamer supports reading streams with WebRTC/WHEP, although track codecs must be specified in advance through the video-caps and audio-caps parameters. Furthermore, if audio is not present, audio-caps must be set anyway and must point to a PCMU codec. For instance, the command for reading a video-only H264 stream is:

sh
gst-launch-1.0 whepsrc whep-endpoint=http://127.0.0.1:8889/stream/whep use-link-headers=true \
video-caps="application/x-rtp,media=video,encoding-name=H264,payload=127,clock-rate=90000" \
audio-caps="application/x-rtp,media=audio,encoding-name=PCMU,payload=0,clock-rate=8000" \
! rtph264depay ! decodebin ! autovideosink

While the command for reading an audio-only Opus stream is:

sh
gst-launch-1.0 whepsrc whep-endpoint="http://127.0.0.1:8889/stream/whep" use-link-headers=true \
audio-caps="application/x-rtp,media=audio,encoding-name=OPUS,payload=111,clock-rate=48000,encoding-params=(string)2" \
! rtpopusdepay ! decodebin ! autoaudiosink

While the command for reading a H264 and Opus stream is:

sh
gst-launch-1.0 whepsrc whep-endpoint=http://127.0.0.1:8889/stream/whep use-link-headers=true \
video-caps="application/x-rtp,media=video,encoding-name=H264,payload=127,clock-rate=90000" \
audio-caps="application/x-rtp,media=audio,encoding-name=OPUS,payload=111,clock-rate=48000,encoding-params=(string)2" \
! decodebin ! autovideosink

4 Read 10 Vlc (`docs/4-read/10-vlc.md`)

VLC

VLC can read a stream from the server by using the RTSP, RTMP, HLS and SRT 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:

text
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 and here). To fix the issue, remove the default VLC instance and install the snap version:

sh
sudo apt purge -y vlc
sudo 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 or nginx or a local MediaMTX instance to decrypt streams before reading them.

VLC and RTMP

Open the following URL:

text
rtmp://localhost/mystream

VLC and SRT

Open the following URL:

text
srt://localhost:8890?streamid=read:mystream

4 Read 11 Obs Studio (`docs/4-read/11-obs-studio.md`)

OBS Studio

OBS Studio can read streams from the server by using the RTSP protocol.

Open OBS, click on Add Source, Media source, OK, uncheck Local file, insert in Input:

text
rtsp://localhost:8554/stream

Then Ok.


4 Read 12 Python Opencv (`docs/4-read/12-python-opencv.md`)

Python and OpenCV

Python-based software can read streams from the server with the OpenCV library, acting as a RTSP client.

python
import cv2

cap = cv2.VideoCapture('rtsp://localhost:8554/mystream')
if not cap.isOpened():
    raise Exception("can't open video capture")

while True:
    ret, frame = cap.read()
    if not ret:
        raise Exception("can't receive frame")

    cv2.imshow('frame', frame)

    if cv2.waitKey(1) == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

4 Read 13 Golang (`docs/4-read/13-golang.md`)

Golang

You can read a stream from the server by using the Go programming language and the following libraries:

All these power MediaMTX itself. In the repositories of these projects there are several examples on how to connect to a server and read data.


4 Read 14 Unity (`docs/4-read/14-unity.md`)

Unity

Software written with the Unity Engine can read a stream from the server by using the WebRTC protocol.

Create a new Unity project or open an existing one.

Open Window -> Package Manager, click on the plus sign, Add Package by name... and insert com.unity.webrtc. Wait for the package to be installed.

In the Project window, under Assets, create a new C# Script called WebRTCReader.cs with this content:

text
/* Detailed source-code truncated for AI context efficiency. */

Edit the url variable according to your needs.

In the Hierarchy window, find or create a scene. Inside the scene, add a Canvas. Inside the Canvas, add a Raw Image and an Audio Source. Then add the WebRTCReader.cs script as component of the canvas, by dragging it inside the Inspector window. then Press the Play button at the top of the page.


5 References 1 Configuration File (`docs/5-references/1-configuration-file.md`)

Configuration file reference

This is a copy of the configuration file (mediamtx.yml) of the latest MediaMTX release ({version_tag}), that contains all available parameters. Check the Configuration usage page for instructions on how to change it.


5 References 2 Control Api (`docs/5-references/2-control-api.md`)

Control API reference

This is the reference of the Control API of the latest MediaMTX release ({version_tag}), generated automatically from the OpenAPI / Swagger file available in the repository. Check the Control API usage page for instructions on how to use the API.


6 Misc 1 Compile (`docs/6-misc/1-compile.md`)

Compile from source

Standard procedure

  1. Install git and Go ≥ 1.27.

  2. Clone the repository, enter into the folder and start the building process:

    sh
    git clone https://github.com/bluenviron/mediamtx
    cd mediamtx
    go generate ./...
    CGO_ENABLED=0 go build .

    This will produce the mediamtx binary.

Custom libcamera

If you need to use a custom or external libcamera to interact with some Raspberry Pi Camera models that require it, additional steps are required:

  1. Download mediamtx-rpicamera source code and compile it against the external libcamera. Instructions are in the repository.

  2. Install git and Go ≥ 1.27.

  3. Clone the MediaMTX repository:

    sh
    git clone https://github.com/bluenviron/mediamtx
  4. Inside the MediaMTX folder, run:

    sh
    go generate ./...
  5. Copy build/mtxrpicam_32 and/or build/mtxrpicam_64 (depending on the architecture) from mediamtx-rpicamera to mediamtx, inside folder internal/staticsources/rpicamera/, overriding existing folders.

  6. Compile:

    sh
    go run .

    This will produce the mediamtx binary.

Cross compile

Cross compilation allows to build an executable for a target machine from another machine with a different operating system or architecture. This is useful in case the target machine doesn't have enough resources for compilation or if you don't want to install the compilation dependencies on it.

  1. On the machine you want to use to compile, install git and Go ≥ 1.27.

  2. Clone the repository, enter into the folder and start the building process:

    sh
    git clone https://github.com/bluenviron/mediamtx
    cd mediamtx
    go generate ./...
    CGO_ENABLED=0 GOOS=my_os GOARCH=my_arch go build .

    Replace my_os and my_arch with the operating system and architecture of your target machine. A list of all supported combinations can be obtained with:

    sh
    go tool dist list

    For instance:

    sh
    CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build .

    In case of the arm architecture, there's an additional flag available, GOARM, that allows to set the ARM version:

    sh
    CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GOARM=7 go build .

    In case of the mips architecture, there's an additional flag available, GOMIPS, that allows to set additional parameters:

    sh
    CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build .

    The command will produce the mediamtx binary.

Compile for all supported platforms

Install Docker and launch:

sh
make binaries

The command will produce tarballs in folder binaries/.

Docker image

The official Docker image can be recompiled by following these steps:

  1. Build binaries for all supported platforms:

    sh
    make binaries
  2. Build the image by using one of the Dockerfiles inside the docker/ folder:

    text
    docker build . -f docker/standard.Dockerfile -t my-mediamtx

    This will produce the my-mediamtx image.

    A Dockerfile is available for each image variant (standard.Dockerfile, ffmpeg.Dockerfile, rpi.Dockerfile, ffmpeg-rpi.Dockerfile).


6 Misc 2 License (`docs/6-misc/2-license.md`)

License

All the code in the main MediaMTX repository is released under the MIT License. Compiled binaries include some third-party dependencies:

  • all the Golang dependencies listed into the go.mod file, which are all released under either the MIT license, BSD 3-Clause license or Apache License 2.0.
  • hls.js, released under the Apache License 2.0.
  • mediamtx-rpicamera, which is released under the same license of MediaMTX but includes some third-party dependencies.

6 Misc 3 Security (`docs/6-misc/3-security.md`)

Security

Security of released binaries

Binaries published in the Releases section of GitHub are the output of a building process that is fully visible, prevents hidden changes or external interferences in published artifacts, and allows validation by third parties:

  1. During every release, the Release workflow is triggered on GitHub.

  2. The release workflow pulls the source code and builds binaries.

  3. The release workflow computes SHA256 checksums of binaries and publishes them to a public blockchain (Sigstore Public Good Instance) through GitHub Attestations.

  4. Checksums and binaries are published on the Release page.

  5. Binaries can be downloaded by users.

It is possible to verify that SHA256 checksums of binaries correspond to the one published on Sigstore by running:

sh
ls mediamtx_* | xargs -L1 gh attestation verify --repo bluenviron/mediamtx

It is possible to verify that binaries have not been altered during transfer from GitHub to the final destination by downloading checksums.sha256 and running:

sh
cat checksums.sha256 | grep "$(ls mediamtx_*)" | sha256sum --check

Reporting vulnerabilities

Vulnerabilities can be reported privately by using the Security Advisory feature of GitHub.


6 Misc 4 Specifications (`docs/6-misc/4-specifications.md`)

Specifications

name area
RTSP / RTP / RTCP specifications RTSP
HLS specifications HLS
RTMP specifications RTMP
WebRTC: Real-Time Communication in Browsers WebRTC
RFC8835, Transports for WebRTC WebRTC
RFC7742, WebRTC Video Processing and Codec Requirements WebRTC
RFC7874, WebRTC Audio Codec and Processing Requirements WebRTC
RFC7875, Additional WebRTC Audio Codecs for Interoperability WebRTC
H.265 Profile for WebRTC WebRTC
RFC9725, WebRTC-HTTP Ingestion Protocol (WHIP) WebRTC
WebRTC-HTTP Egress Protocol (WHEP) WebRTC
RFC9000, QUIC: A UDP-Based Multiplexed and Secure Transport Media-over-QUIC
RFC9114, HTTP/3 Media-over-QUIC
Media over QUIC Transport Media-over-QUIC
MOQT Streaming Format (MSF) Media-over-QUIC
Low Overhead Media Container (LOC) Media-over-QUIC
The SRT Protocol SRT
Codec specifications codecs
Golang project layout project layout


--- METRICS ---