# Technical Documentation: bluenviron/mediamtx

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/bluenviron/mediamtx)

### Overview (`README.md`)

<h1 align="center">
  <a href="https://mediamtx.org">
    <img src="logo.png" alt="MediaMTX">
  </a>

  <br>
  <br>

[](https://mediamtx.org)
[](https://github.com/bluenviron/mediamtx/actions/workflows/test.yml?query=branch%3Amain)
[](https://github.com/bluenviron/mediamtx/actions/workflows/lint.yml?query=branch%3Amain)
[](https://app.codecov.io/gh/bluenviron/mediamtx/tree/main)
[](https://github.com/bluenviron/mediamtx/releases)
[](https://hub.docker.com/r/bluenviron/mediamtx)

</h1>

<br>

_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.

<div align="center">

| [Install](https://mediamtx.org/docs/kickoff/install) | [Documentation](https://mediamtx.org/docs/kickoff/introduction) |
| ---------------------------------------------------- | --------------------------------------------------------------- |

</div>

<h3>Features</h3>

- [Publish streams](https://mediamtx.org/docs/features/publish) 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](https://mediamtx.org/docs/features/read) 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](https://mediamtx.org/docs/features/always-available) even when the publisher is offline
- [Record streams](https://mediamtx.org/docs/features/record) to disk in fMP4 or MPEG-TS format
- [Playback recorded streams](https://mediamtx.org/docs/features/playback) from disk
- [Authenticate](https://mediamtx.org/docs/features/authentication) users with internal, HTTP or JWT authentication
- [Forward streams](https://mediamtx.org/docs/features/forward) to other servers
- [Proxy requests](https://mediamtx.org/docs/features/proxy) to other servers
- [Control](https://mediamtx.org/docs/features/control-api) the server through the Control API
- [Extract metrics](https://mediamtx.org/docs/features/metrics) from the server in a Prometheus-compatible format
- [Monitor performance](https://mediamtx.org/docs/features/performance) to investigate CPU and RAM consumption
- [Run hooks](https://mediamtx.org/docs/features/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](https://mediamtx.org/docs/kickoff/introduction).

---

### 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](../2-features/03-publish.md) 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](../2-features/04-read.md) 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](../2-features/08-always-available.md) even when the publisher is offline
- [Record streams](../2-features/09-record.md) to disk in fMP4 or MPEG-TS format
- [Playback recorded streams](../2-features/10-playback.md) from disk
- [Authenticate](../2-features/06-authentication.md) users with internal, HTTP or JWT authentication
- [Forward streams](../2-features/11-forward.md) to other servers
- [Proxy requests](../2-features/12-proxy.md) to other servers
- [Control](../2-features/21-control-api.md) the server through the Control API
- [Extract metrics](../2-features/22-metrics.md) from the server in a Prometheus-compatible format
- [Monitor performance](../2-features/23-performance.md) to investigate CPU and RAM consumption
- [Run hooks](../2-features/20-hooks.md) (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](#standalone-binary): use this if you are running Windows, macOS or you just want to try out _MediaMTX_.
- [Docker container](#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](#arch-linux-package): use this if you are running Arch Linux.
- [FreeBSD package](#freebsd-package): use this if you are running FreeBSD.
- [OpenWrt binary](#openwrt-binary): use this if you are running OpenWrt.

## Standalone binary

1. Visit the [Releases page](https://github.com/bluenviron/mediamtx/releases) 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](#standalone-binary) and download a Linux binary that corresponds to your architecture.

Otherwise, [compile the server from source](../6-misc/1-compile.md).

---

### 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](2-install.md#docker-container).

## 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](../2-features/03-publish.md) 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](../2-features/04-read.md) 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:

- [Media-over-QUIC clients](../3-publish/01-moq-clients.md)
- [Media-over-QUIC servers](../3-publish/02-moq-servers.md)
- [SRT clients](../3-publish/03-srt-clients.md)
- [SRT cameras and servers](../3-publish/04-srt-cameras-and-servers.md)
- [WebRTC clients](../3-publish/05-webrtc-clients.md)
- [WebRTC servers](../3-publish/06-webrtc-servers.md)
- [RTSP clients](../3-publish/07-rtsp-clients.md)
- [RTSP cameras and servers](../3-publish/08-rtsp-cameras-and-servers.md)
- [RTMP clients](../3-publish/09-rtmp-clients.md)
- [RTMP cameras and servers](../3-publish/10-rtmp-cameras-and-servers.md)
- [HLS cameras and servers](../3-publish/11-hls-cameras-and-servers.md)
- [MPEG-TS](../3-publish/12-mpeg-ts.md)
- [RTP](../3-publish/13-rtp.md)

We provide instructions for publishing with the following devices:

- [Raspberry Pi Cameras](../3-publish/14-raspberry-pi-cameras.md)
- [Generic webcams](../3-publish/15-generic-webcams.md)

We provide instructions for publishing with the following software:

- [Web browsers](../3-publish/16-web-browsers.md)
- [FFmpeg](../3-publish/17-ffmpeg.md)
- [GStreamer](../3-publish/18-gstreamer.md)
- [OBS Studio](../3-publish/19-obs-studio.md)
- [Python and OpenCV](../3-publish/20-python-opencv.md)
- [Golang](../3-publish/21-golang.md)
- [Unity](../3-publish/22-unity.md)

---

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

# Read streams

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

- [Media-over-QUIC clients](../4-read/01-moq.md)
- [SRT clients](../4-read/02-srt.md)
- [WebRTC clients](../4-read/03-webrtc.md)
- [RTSP clients](../4-read/04-rtsp.md)
- [RTMP clients](../4-read/05-rtmp.md)
- [HLS](../4-read/06-hls.md)

We provide instructions for reading with the following software:

- [Web browsers](../4-read/07-web-browsers.md)
- [FFmpeg](../4-read/08-ffmpeg.md)
- [GStreamer](../4-read/09-gstreamer.md)
- [VLC](../4-read/10-vlc.md)
- [OBS Studio](../4-read/11-obs-studio.md)
- [Python and OpenCV](../4-read/12-python-opencv.md)
- [Golang](../4-read/13-golang.md)
- [Unity](../4-read/14-unity.md)

---

### 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](../5-references/1-configuration-file.md) (`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](../1-kickoff/2-install.md#standalone-binary), the configuration file is included into the release bundle.

   When installing the server as a [Docker container](../1-kickoff/2-install.md#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](21-control-api.md).

## 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](https://play.golang.org/p/rX29jwObNe4).

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:

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

```
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](https://www.keycloak.org/) 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:

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

    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
```

### RTMP

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

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

### SRT

Append username and password to `streamid`:

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

### HLS and WebRTC

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

```
Authorization: Basic base64(myuser:mypass)
```

When using a web browser, a dialog is first shown to users, asking for credentials, and then the header is automatically inserted into every request. If you need to automatically fill credentials from a parent web page, read [Embed in a website](../4-read/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
```

## Provide tokens / JWTs

### RTSP

Pass the token as a query parameter:

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

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
```

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
```

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
```

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-JPEG<br/>**Audio**: 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 Video<br/>**Audio**: 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](../5-references/1-configuration-file.md).

## Remote upload

To upload recordings to a remote location, you can use _MediaMTX_ together with [rclone](https://github.com/rclone/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](https://github.com/rclone/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:

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

Where:

- [mypath] is the name of a path
- [start] (optional) is the start date in [RFC3339 format](https://www.utctime.net/)
- [end] (optional) is the end date in [RFC3339 format](https://www.utctime.net/)

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:

```
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](https://www.utctime.net/)
- [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](https://www.urlencoder.org/). For instance:

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

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

- [Media-over-QUIC](#media-over-quic)
- [SRT](#srt)
- [WebRTC](#webrtc)
- [RTSP](#rtsp)
- [RTMP](#rtmp)

It is also possible to use [FFmpeg](#ffmpeg) to perform the forwarding.

We provide instructions to forward streams to the following services:

- [YouTube](#youtube)
- [Twitch](#twitch)

## 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](../3-publish/05-webrtc-clients.md).

## 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](https://help.twitch.tv/s/twitch-ingest-recommendation?language=en_US). 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:

```
#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](https://github.com/bluenviron/gohlslib).

## Absolute timestamp in RTSP and WebRTC

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

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

```
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](https://github.com/bluenviron/gortsplib).

A browser can read absolute timestamps with WebRTC if it exposes the [estimatedPlayoutTimestamp](https://www.w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats-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:

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

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

```
: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](https://github.com/winsw/winsw/releases) 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:

```
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](17-start-on-boot.md), 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:

```
{"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:

```
/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:

```
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](12-proxy.md).
- If the protocol used by readers is WebRTC, disable `webrtcLocalUDPAddress` and `webrtcLocalTCPAddress` and enable a STUN server, as described in [Solving WebRTC connectivity issues](25-webrtc-specific-features.md#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](https://traefik.io/) 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`):

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

   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:

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

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

The control API is documented in the [Control API Reference page](../5-references/2-control-api.md) and in the [OpenAPI / Swagger file](https://github.com/bluenviron/mediamtx/blob/{version_tag}/api/openapi.yaml).

Be aware that by default the Control API is accessible by localhost only; to increase visibility or enforce authentication, check [Authentication](06-authentication.md).

---

### 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](https://prometheus.io/).

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

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

```
curl http://localhost:9998/metrics
```

Obtaining:

```
/* 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](https://github.com/google/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:

```
/* 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:

```
/* 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:

```
/* 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](../3-publish/03-srt-clients.md) and [Read with SRT clients](../4-read/02-srt.md). 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](https://github.com/Haivision/srt/blob/master/docs/features/access-control.md) proposed by the authors of the protocol and enforced by some hardware. The standard syntax can be used in this way:

```
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](../3-publish/05-webrtc-clients.md) and [Read with WebRTC clients](../4-read/03-webrtc.md). 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](https://jsfiddle.net/v24s8q1f/).

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](https://github.com/coturn/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](../3-publish/07-rtsp-clients.md) and [Read with RTSP clients](../4-read/04-rtsp.md). 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:

```
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](../3-publish/07-rtsp-clients.md#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](../3-publish/09-rtmp-clients.md) and [Read with RTMP clients](../4-read/05-rtmp.md). 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:

```
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](https://www.stunnel.org) or [nginx](https://nginx.org/). 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](https://datatracker.ietf.org/doc/html/draft-ietf-moq-transport-19), 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](https://datatracker.ietf.org/doc/html/draft-ietf-moq-msf-00).
- We use the Low Overhead Media Container (LOC) to ship frames, described in [this specification](https://datatracker.ietf.org/doc/draft-ietf-moq-loc/).
- 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:

- If the server certificate is self-signed, browser must support the [serverCertificatesHashes option](https://caniuse.com/mdn-api_webtransport_webtransport_options_servercertificatehashes_parameter) (all except iOS Safari do).
- Browser must support [WebTransport](https://caniuse.com/webtransport) and [WebCodecs](https://caniuse.com/webcodecs) (all modern browsers do)
- When publishing tracks, browser must support [MediaStreamTrackProcessor](https://caniuse.com/mdn-api_mediastreamtrackprocessor) (only Chrome does).

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

```
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](https://www.urlencoder.org/).

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:

```
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](../2-features/24-srt-specific-features.md#standard-stream-id-syntax).

If you want to publish a stream by using a client in listening mode (i.e. with `mode=listener` appended to the URL), read the next section.

Some clients that can publish with SRT are [FFmpeg](17-ffmpeg.md), [GStreamer](18-gstreamer.md), [OBS Studio](19-obs-studio.md).

---

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

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

```
http://localhost:8889/mystream/whip
```

Be aware that not all browsers can publish tracks with any codec, check [Codec support in browsers](../2-features/25-webrtc-specific-features.md#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](../2-features/25-webrtc-specific-features.md#solving-webrtc-connectivity-issues).

Some clients that can publish with WebRTC and WHIP are [FFmpeg](17-ffmpeg.md), [GStreamer](18-gstreamer.md), [OBS Studio](19-obs-studio.md), [Unity](22-unity.md) and [Web browsers](16-web-browsers.md).

---

### 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](../4-read/03-webrtc.md):

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

```
rtsp://localhost:8554/mystream
```

The resulting stream will be available on path `/mystream`.

Some clients that can publish with RTSP are [FFmpeg](17-ffmpeg.md), [GStreamer](18-gstreamer.md), [OBS Studio](19-obs-studio.md), [Python and OpenCV](20-python-opencv.md).

Advanced RTSP features and settings are described in [RTSP-specific features](../2-features/26-rtsp-specific-features.md).

## MPEG-TS inside RTSP

Some RTSP clients encode tracks with MPEG-TS before sending them to the server, causing the server to see a single "MPEG-TS" track, and preventing track conversion from a protocol to another.

It 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](https://www.urlencoder.org/).

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](../5-references/1-configuration-file.md).

Advanced RTSP features and settings are described in [RTSP-specific features](../2-features/26-rtsp-specific-features.md).

## 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](../2-features/27-rtmp-specific-features.md). Streams can be published to the server by using the URL:

```
rtmp://localhost/mystream
```

The resulting stream will be available on path `/mystream`.

Some clients that can publish with RTMP are [FFmpeg](17-ffmpeg.md), [GStreamer](18-gstreamer.md) and [OBS Studio](19-obs-studio.md).

---

### 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](https://www.urlencoder.org/).

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](https://www.urlencoder.org/).

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](17-ffmpeg.md) and [GStreamer](18-gstreamer.md).

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](17-ffmpeg.md) and [GStreamer](18-gstreamer.md).

---

### 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](../5-references/1-configuration-file.md).

## 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](../6-misc/1-compile.md#custom-libcamera).

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

```
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](01-moq-clients.md) or a [WebRTC client](05-webrtc-clients.md).

## Media-over-QUIC

Start the server and open the web page:

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

```
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](../2-features/25-webrtc-specific-features.md#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](https://github.com/bluenviron/mediamtx/blob/{version_tag}/internal/servers/webrtc/publish_index.html). In particular, there's a ready-to-use, standalone JavaScript class for publishing streams with WebRTC, available in [publisher.js](https://github.com/bluenviron/mediamtx/blob/{version_tag}/internal/servers/webrtc/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](07-rtsp-clients.md), [RTMP client](09-rtmp-clients.md), [SRT client](03-srt-clients.md), [WebRTC client](05-webrtc-clients.md) or by sending [MPEG-TS packets](12-mpeg-ts.md) or [RTP packets](13-rtp.md). 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](13-rtp.md)). 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](07-rtsp-clients.md), [RTMP client](09-rtmp-clients.md), [SRT client](03-srt-clients.md), [WebRTC client](05-webrtc-clients.md) or by sending [MPEG-TS packets](12-mpeg-ts.md) or [RTP packets](13-rtp.md). 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](13-rtp.md)). 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](09-rtmp-clients.md) or a [WebRTC client](05-webrtc-clients.md) 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 &ge; 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:

```
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](05-webrtc-clients.md) 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 &ge; 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](https://obsproject.com/kb/whip-streaming-guide).

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:

```
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)](#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](07-rtsp-clients.md). 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:

- [gortsplib](https://github.com/bluenviron/gortsplib) to publish with RTSP.
- [gortmplib](https://github.com/bluenviron/gortmplib) to publish with RTMP.

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](05-webrtc-clients.md).

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:

```
/* 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](../3-publish/01-moq-clients.md).

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

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

```
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](../2-features/24-srt-specific-features.md#standard-stream-id-syntax).

Some clients that can read with SRT are [FFmpeg](08-ffmpeg.md), [GStreamer](09-gstreamer.md) and [VLC](10-vlc.md).

---

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

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

```
http://localhost:8889/mystream/whep
```

Be aware that not all browsers can read tracks with any codec, check [Codec support in browsers](../2-features/25-webrtc-specific-features.md#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](../2-features/25-webrtc-specific-features.md#solving-webrtc-connectivity-issues).

Some clients that can read with WebRTC and WHEP are [web browsers](07-web-browsers.md), [GStreamer](09-gstreamer.md) and [Unity](14-unity.md).

---

### 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](../2-features/26-rtsp-specific-features.md)). In order to read a stream with the RTSP protocol, use this URL:

```
rtsp://localhost:8554/mystream
```

Some clients that can read with RTSP are [FFmpeg](08-ffmpeg.md), [GStreamer](09-gstreamer.md) and [VLC](10-vlc.md).

---

### 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](../2-features/27-rtmp-specific-features.md). Streams can be read from the server by using the URL:

```
rtmp://localhost/mystream
```

Some clients that can read with RTMP are [FFmpeg](08-ffmpeg.md), [GStreamer](09-gstreamer.md) and [VLC](10-vlc.md).

---

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

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

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

Some clients that can read with HLS are [web browsers](07-web-browsers.md), [FFmpeg](08-ffmpeg.md), [GStreamer](09-gstreamer.md) and [VLC](10-vlc.md).

_MediaMTX_ supports generating HLS in several variants (including Low-Latency mode), and provides various parameters to tune HLS generation. These are listed in the [configuration file](../5-references/1-configuration-file.md).

HLS can also be used to [scale the server](../2-features/19-scalability.md) 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](01-moq.md), [WebRTC](03-webrtc.md) and [HLS](06-hls.md) 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:

```
https://localhost:8892/mystream
```

Replace `mystream` with the path name.

### WebRTC

Visit the web page:

```
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](../2-features/25-webrtc-specific-features.md#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:

```
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 `<iframe>` 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 `<iframe>` 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](https://github.com/bluenviron/mediamtx/blob/{version_tag}/internal/servers/webrtc/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 `<iframe>` 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](https://caniuse.com/mediasource), 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](https://www.npmjs.com/package/hls.js) 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](04-rtsp.md), [RTMP](05-rtmp.md), [HLS](06-hls.md) and [SRT](02-srt.md) 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](04-rtsp.md), [RTMP](05-rtmp.md), [HLS](06-hls.md), [SRT](02-srt.md) and [WebRTC](03-webrtc.md) 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](04-rtsp.md), [RTMP](05-rtmp.md), [HLS](06-hls.md) and [SRT](02-srt.md) protocols. The recommended one is RTSP.

In order to minimize latency, it is also suggested to change the `Network caching` parameter of VLC:

1. Open VLC, _Tools_, _Preferences_, _Show Settings_, _All_, page _Input / Codecs_.
2. Find the _Network caching (ms)_ parameter, set it to `50`. Save

## VLC and RTSP

Open the following URL:

```
rtsp://localhost:8554/mystream
```

### RTSP and Ubuntu

The VLC shipped with Ubuntu 21.10 doesn't support playing RTSP due to a license issue (read [here](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=982299) and [here](https://stackoverflow.com/questions/69766748/cvlc-cannot-play-rtsp-omxplayer-instead-can)). To fix the issue, remove the default VLC instance and install the snap version:

```sh
sudo apt purge -y vlc
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](https://www.stunnel.org) or [nginx](https://nginx.org/) or a local _MediaMTX_ instance to decrypt streams before reading them.

## VLC and RTMP

Open the following URL:

```
rtmp://localhost/mystream
```

## VLC and SRT

Open the following URL:

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

---

### 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](04-rtsp.md).

Open OBS, click on _Add Source_, _Media source_, _OK_, uncheck _Local file_, insert in _Input_:

```
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](04-rtsp.md).

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

- [gortsplib](https://github.com/bluenviron/gortsplib) to read with RTSP.
- [gortmplib](https://github.com/bluenviron/gortmplib) to read with RTMP.
- [gohlslib](https://github.com/bluenviron/gohlslib) to read with HLS.

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](03-webrtc.md).

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:

```
/* 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](../2-features/05-configuration.md) 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](https://github.com/bluenviron/mediamtx/blob/{version_tag}/api/openapi.yaml) available in the repository. Check the [Control API usage page](../2-features/21-control-api.md) 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 &ge; 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](https://github.com/bluenviron/mediamtx-rpicamera) and compile it against the external libcamera. Instructions are in the repository.

2. Install git and Go &ge; 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 &ge; 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:

   ```
   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](https://github.com/bluenviron/mediamtx/blob/{version_tag}/LICENSE). Compiled binaries include some third-party dependencies:

- all the Golang dependencies listed into the [go.mod file](https://github.com/bluenviron/mediamtx/blob/{version_tag}/go.mod), 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](https://github.com/video-dev/hls.js/blob/master/LICENSE).
- mediamtx-rpicamera, which is released under the same license of _MediaMTX_ but includes some [third-party dependencies](https://github.com/bluenviron/mediamtx-rpicamera?tab=readme-ov-file#license).

---

### 6 Misc 3 Security (`docs/6-misc/3-security.md`)

# Security

## Security of released binaries

Binaries published in the [Releases](https://github.com/bluenviron/mediamtx/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](https://github.com/bluenviron/mediamtx/actions/workflows/release.yml) 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](https://docs.github.com/en/actions/concepts/security/artifact-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](https://github.com/bluenviron/mediamtx/security/advisories/new) feature of GitHub.

---

### 6 Misc 4 Specifications (`docs/6-misc/4-specifications.md`)

# Specifications

| name                                                                                                          | area            |
| ------------------------------------------------------------------------------------------------------------- | --------------- |
| [RTSP / RTP / RTCP specifications](https://github.com/bluenviron/gortsplib#specifications)                    | RTSP            |
| [HLS specifications](https://github.com/bluenviron/gohlslib#specifications)                                   | HLS             |
| [RTMP specifications](https://github.com/bluenviron/gortmplib#specifications)                                 | RTMP            |
| [WebRTC: Real-Time Communication in Browsers](https://www.w3.org/TR/webrtc/)                                  | WebRTC          |
| [RFC8835, Transports for WebRTC](https://datatracker.ietf.org/doc/html/rfc8835)                               | WebRTC          |
| [RFC7742, WebRTC Video Processing and Codec Requirements](https://datatracker.ietf.org/doc/html/rfc7742)      | WebRTC          |
| [RFC7874, WebRTC Audio Codec and Processing Requirements](https://datatracker.ietf.org/doc/html/rfc7874)      | WebRTC          |
| [RFC7875, Additional WebRTC Audio Codecs for Interoperability](https://datatracker.ietf.org/doc/html/rfc7875) | WebRTC          |
| [H.265 Profile for WebRTC](https://datatracker.ietf.org/doc/html/draft-ietf-avtcore-hevc-webrtc-08)           | WebRTC          |
| [RFC9725, WebRTC-HTTP Ingestion Protocol (WHIP)](https://datatracker.ietf.org/doc/html/rfc9725)               | WebRTC          |
| [WebRTC-HTTP Egress Protocol (WHEP)](https://datatracker.ietf.org/doc/html/draft-ietf-wish-whep)              | WebRTC          |
| [RFC9000, QUIC: A UDP-Based Multiplexed and Secure Transport](https://datatracker.ietf.org/doc/html/rfc9000)  | Media-over-QUIC |
| [RFC9114, HTTP/3](https://datatracker.ietf.org/doc/html/rfc9114)                                              | Media-over-QUIC |
| [Media over QUIC Transport](https://datatracker.ietf.org/doc/html/draft-ietf-moq-transport)                   | Media-over-QUIC |
| [MOQT Streaming Format (MSF)](https://datatracker.ietf.org/doc/html/draft-ietf-moq-msf-00)                    | Media-over-QUIC |
| [Low Overhead Media Container (LOC)](https://datatracker.ietf.org/doc/draft-ietf-moq-loc/)                    | Media-over-QUIC |
| [The SRT Protocol](https://haivision.github.io/srt-rfc/draft-sharabayko-srt.html)                             | SRT             |
| [Codec specifications](https://github.com/bluenviron/mediacommon#specifications)                              | codecs          |
| [Golang project layout](https://github.com/golang-standards/project-layout)                                   | project layout  |

---

### 6 Misc 5 Related Projects (`docs/6-misc/5-related-projects.md`)

# Related projects

- [gortsplib (RTSP library used internally)](https://github.com/bluenviron/gortsplib)
- [gohlslib (HLS library used internally)](https://github.com/bluenviron/gohlslib)
- [gortmplib (RTMP library used internally)](https://github.com/bluenviron/gortmplib)
- [mediacommon (codecs and formats library used internally)](https://github.com/bluenviron/mediacommon)
- [mediamtx-rpicamera (Raspberry Pi Camera component)](https://github.com/bluenviron/mediamtx-rpicamera)
- [datarhei/gosrt (SRT library used internally)](https://github.com/datarhei/gosrt)
- [pion/webrtc (WebRTC library used internally)](https://github.com/pion/webrtc)
- [pion/sdp (SDP library used internally)](https://github.com/pion/sdp)
- [pion/rtp (RTP library used internally)](https://github.com/pion/rtp)
- [pion/rtcp (RTCP library used internally)](https://github.com/pion/rtcp)
- [quic-go/quic-go (QUIC library used internally)](https://github.com/quic-go/quic-go)
- [quic-go/webtransport-go (WebTransport library used internally)](https://github.com/quic-go/webtransport-go)
- [go-astits (MPEG-TS library used internally)](https://github.com/asticode/go-astits)
- [go-mp4 (MP4 library used internally)](https://github.com/abema/go-mp4)
- [hls.js (browser-side HLS library used internally)](https://github.com/video-dev/hls.js)

---

--- METRICS ---
- Files Extracted: 76
- Estimated Token Budget: ~44649 tokens
- Canonical Reference: https://codewiki.google/github.com/bluenviron/mediamtx
