> For the complete documentation index, see [llms.txt](https://docs.roboflow.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.roboflow.com/deployment/self-hosted/enterprise/deployment-manager/services/rtsp-simulator.md).

# RTSP Simulator

RTSP Simulator is an edge container service that turns an uploaded video file into a live RTSP stream. Use it to build and test inference pipelines on a device before a physical camera is installed, or to replay a known clip against a Workflow.

You upload an `.mp4` file through the web interface or the REST API, the service transcodes it to an RTSP-compatible format, and it publishes the result on a continuous loop until you stop it.

{% hint style="info" %}
RTSP Simulator is available exclusively for Enterprise customers. [Contact the Roboflow sales team](https://roboflow.com/sales) to learn more.
{% endhint %}

## Connection Details

Replace `<device-ip>` with the IP address shown on the device page in Deployment Manager.

<table data-search="false"><thead><tr><th>Purpose</th><th>Address</th></tr></thead><tbody><tr><td>RTSP stream</td><td><code>rtsp://&#x3C;device-ip>:8554/stream</code></td></tr><tr><td>Web UI, REST API, and Swagger docs</td><td><code>http://&#x3C;device-ip>:8080</code></td></tr></tbody></table>

<table data-search="false"><thead><tr><th>Port</th><th>Protocol</th><th>Purpose</th></tr></thead><tbody><tr><td>8080</td><td>HTTP</td><td>Web UI, REST API, Swagger docs at <code>/docs</code></td></tr><tr><td>8554</td><td>RTSP (TCP)</td><td>Video stream output. UDP transport is disabled; clients that prefer UDP negotiate down to TCP-interleaved.</td></tr></tbody></table>

Multiple clients can read the stream at the same time.

## Video Format

Only `.mp4` files are accepted. Uploads are transcoded automatically so the stream works with any RTSP client:

* Codec: H.264, Baseline profile
* Pixel format: yuv420p
* Audio: stripped, video only
* Maximum file size: 5 GB by default

## Using the Web Interface

Open `http://<device-ip>:8080` in a browser.

{% stepper %}
{% step %}

## Upload

Drag an `.mp4` file onto the page. The file uploads and is converted to the streaming format.
{% endstep %}

{% step %}

## Play

Select "Play" to start streaming. The video loops indefinitely and is published to the RTSP server.
{% endstep %}

{% step %}

## Connect

Point your inference pipeline, a Deployment Manager stream, or any RTSP client at `rtsp://<device-ip>:8554/stream`.
{% endstep %}

{% step %}

## Stop

Select "Stop" to end the stream and remove the converted files.
{% endstep %}
{% endstepper %}

To use the simulated stream in a deployment, add it as a stream source on the device the same way you would a camera. See [Add a Stream](/deployment/self-hosted/enterprise/deployment-manager/setting-up/add-a-stream.md).

## Using the CLI

For headless or SSH-only access, the `rtsp-cli` tool provides an interactive terminal interface on the device.

```bash
docker exec -it rtsp-simulator rtsp-cli
```

To import a video without the web UI, copy it into the input directory first, then launch the CLI and press `I`.

```bash
scp video.mp4 user@<device-ip>:/var/lib/rfdm/rtsp-simulator/data/input/
```

<table data-search="false"><thead><tr><th>Key</th><th>Command</th><th>Description</th></tr></thead><tbody><tr><td><code>I</code></td><td>Import</td><td>Select and convert a video from <code>/data/input/</code></td></tr><tr><td><code>P</code></td><td>Play</td><td>Start RTSP streaming</td></tr><tr><td><code>S</code></td><td>Stop</td><td>Stop streaming and delete converted files</td></tr><tr><td><code>D</code></td><td>Delete</td><td>Delete video files</td></tr><tr><td><code>C</code></td><td>Config</td><td>Adjust stream settings (bitrate, buffer, delay)</td></tr><tr><td><code>R</code></td><td>Refresh</td><td>Refresh the status display</td></tr><tr><td><code>Q</code></td><td>Quit</td><td>Exit the CLI</td></tr></tbody></table>

## Testing the Stream

Connect with any RTSP player to confirm the stream is live.

{% tabs %}
{% tab title="VLC" %}

```bash
vlc rtsp://<device-ip>:8554/stream
```

{% endtab %}

{% tab title="ffplay" %}
The stream is served over TCP only, so force TCP transport rather than letting ffplay try UDP first.

```bash
ffplay -rtsp_transport tcp rtsp://<device-ip>:8554/stream
```

{% endtab %}
{% endtabs %}

## HTTP API

All endpoints return JSON. Interactive Swagger documentation is served at `http://<device-ip>:8080/docs`. See [Services](/deployment/self-hosted/enterprise/deployment-manager/services.md#using-the-apis) for the rules shared by all on-device service APIs.

{% hint style="warning" %}
The API is unauthenticated, and it can stop a running stream and delete uploaded video. Anything that can reach port 8080 can do both.
{% endhint %}

### Typical Flow

```bash
curl -X POST http://<device-ip>:8080/upload -F "file=@video.mp4"
curl -X POST http://<device-ip>:8080/play
curl http://<device-ip>:8080/status
curl -X POST http://<device-ip>:8080/stop
```

{% hint style="warning" %}
The `rtsp_url` returned by `/play` and `/status` always names `localhost`, because the service reports the URL from its own point of view. Only a consumer running on the device can use it verbatim. Anywhere else, substitute the device address: `rtsp://<device-ip>:8554/stream`.

The port is `RTSP_PORT`, which defaults to `8554` but is configurable per device. Read `rtsp_port` from `/info` rather than assuming the default.
{% endhint %}

`/stop` also deletes both the original and converted files to free disk space, so a new upload is required before the next `/play`.

### Upload

Only `.mp4` is accepted, and an active stream is stopped before the upload begins. The optional `settings` part is a JSON string of conversion settings applied during transcoding. Because they are baked into the converted file, changing them later requires re-uploading.

```bash
curl -X POST http://<device-ip>:8080/upload \
  -F "file=@video.mp4" \
  -F 'settings={"target_fps": 30, "crf_quality": 23, "max_width": 1920}'
```

{% openapi src="/files/0dYPQzNQOOMLAnf6feuC" path="/upload" method="post" %}
[edge-rtsp-simulator.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-1608d6873191fab7e4d614a21aa77a56bab11279%2Fedge-rtsp-simulator.yaml?alt=media)
{% endopenapi %}

### Streaming

{% openapi src="/files/0dYPQzNQOOMLAnf6feuC" path="/play" method="post" %}
[edge-rtsp-simulator.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-1608d6873191fab7e4d614a21aa77a56bab11279%2Fedge-rtsp-simulator.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/0dYPQzNQOOMLAnf6feuC" path="/stop" method="post" %}
[edge-rtsp-simulator.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-1608d6873191fab7e4d614a21aa77a56bab11279%2Fedge-rtsp-simulator.yaml?alt=media)
{% endopenapi %}

`/delete` removes the video files without requiring a stream to be running, stopping one first if it is.

{% openapi src="/files/0dYPQzNQOOMLAnf6feuC" path="/delete" method="post" %}
[edge-rtsp-simulator.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-1608d6873191fab7e4d614a21aa77a56bab11279%2Fedge-rtsp-simulator.yaml?alt=media)
{% endopenapi %}

### Status

`streaming` is true when `components.mediamtx.healthy` (the streaming server) and `components.ffmpeg_process.running` (the transcode and publish process) are both true. The `components.stream` entry does not gate it: `components.stream.source_ready` can be false briefly during startup while `streaming` already reads true, which is normal. The breakdown is the fastest way to localize a failed stream: check `components` to see which part is unhealthy before restarting anything.

{% openapi src="/files/0dYPQzNQOOMLAnf6feuC" path="/status" method="get" %}
[edge-rtsp-simulator.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-1608d6873191fab7e4d614a21aa77a56bab11279%2Fedge-rtsp-simulator.yaml?alt=media)
{% endopenapi %}

`/info` reports the limits the service is running with, including free disk space and the maximum upload size, which is worth checking before pushing a large file.

{% openapi src="/files/0dYPQzNQOOMLAnf6feuC" path="/info" method="get" %}
[edge-rtsp-simulator.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-1608d6873191fab7e4d614a21aa77a56bab11279%2Fedge-rtsp-simulator.yaml?alt=media)
{% endopenapi %}

### Stream Settings Endpoints

Playback settings differ from upload settings: they apply at streaming time and can be changed between sessions without re-uploading. An update takes effect on the next `/play`, not the stream currently running.

{% openapi src="/files/0dYPQzNQOOMLAnf6feuC" path="/stream-settings" method="get" %}
[edge-rtsp-simulator.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-1608d6873191fab7e4d614a21aa77a56bab11279%2Fedge-rtsp-simulator.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/0dYPQzNQOOMLAnf6feuC" path="/stream-settings" method="post" %}
[edge-rtsp-simulator.yaml](https://1583372177-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoksNmwps1HmYr8TqHDnX%2Fuploads%2Fgit-blob-1608d6873191fab7e4d614a21aa77a56bab11279%2Fedge-rtsp-simulator.yaml?alt=media)
{% endopenapi %}

## Configuration

### Environment Variables

Set these on the service in the device's Configuration tab. See [Update Device Configuration](/deployment/self-hosted/enterprise/deployment-manager/making-changes/update-device-configuration.md).

<table data-search="false"><thead><tr><th>Variable</th><th>Default</th><th>Description</th></tr></thead><tbody><tr><td><code>MAX_FILE_SIZE</code></td><td><code>5368709120</code></td><td>Maximum upload size in bytes (5 GB)</td></tr><tr><td><code>RTSP_PORT</code></td><td><code>8554</code></td><td>RTSP server port</td></tr><tr><td><code>WEB_PORT</code></td><td><code>8080</code></td><td>Web UI and API port</td></tr><tr><td><code>LOG_LEVEL</code></td><td><code>INFO</code></td><td>Logging verbosity: <code>DEBUG</code>, <code>INFO</code>, <code>WARNING</code>, or <code>ERROR</code></td></tr></tbody></table>

### Upload Settings

These are applied during conversion, so changing them requires re-uploading the video.

<table data-search="false"><thead><tr><th>Setting</th><th>Default</th><th>Description</th></tr></thead><tbody><tr><td><code>target_fps</code></td><td>original</td><td>Target frame rate, 1 to 120. Omit to keep the original</td></tr><tr><td><code>crf_quality</code></td><td><code>23</code></td><td>Quality level, 0 to 51 (18 is high, 23 is medium, 28 is low)</td></tr><tr><td><code>max_width</code></td><td>original</td><td>Maximum width for downscaling, 320 to 7680. Omit to keep the original</td></tr></tbody></table>

### Stream Settings

These are applied at playback and can be changed between streaming sessions from the CLI config menu or the `/stream-settings` endpoint.

<table data-search="false"><thead><tr><th>Setting</th><th>Default</th><th>Description</th></tr></thead><tbody><tr><td><code>max_bitrate_kbps</code></td><td><code>5000</code></td><td>Maximum bitrate in kbps, 100 to 100,000</td></tr><tr><td><code>buffer_size_kb</code></td><td><code>3000</code></td><td>Buffer size in KB, 100 to 50,000</td></tr><tr><td><code>max_delay_ms</code></td><td><code>500</code></td><td>Maximum delay in milliseconds, 50 to 5,000</td></tr></tbody></table>
