> 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

Stream an uploaded video file as a looping RTSP source for testing inference pipelines without a camera.

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, or upload one from Deployment Manager. The service transcodes it to an RTSP-compatible format and 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

The web UI, CLI, and API accept only `.mp4` files. 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 a Roboflow Video

Set the video from Deployment Manager when you cannot reach the device on its local network. The device downloads the video and streams it.

{% stepper %}
{% step %}

## Open the Settings

On the device's Configuration tab, select "Configure" (the gear icon) on the RTSP Simulator card.
{% endstep %}

{% step %}

## Upload

Under "Video source", select "Roboflow video", then select "Upload Video" and pick an `.mp4` or `.mov` file. The video is saved to your Workspace's Asset Library.
{% endstep %}

{% step %}

## Save

Optionally change the conversion and streaming settings. If the site reaches Roboflow through a Secure Gateway, enter its address in "Secure Gateway (optional)". Select "Save Configuration" in the window, then "Save Configuration" on the Configuration tab. When the device applies the new configuration, it restarts the RTSP Simulator service, downloads the video, and starts streaming.
{% endstep %}
{% endstepper %}

To set the video and point a Stream at the simulator in one step, pick "RTSP Simulator" as the stream type when you [add a Stream](/deployment/self-hosted/enterprise/deployment-manager/setting-up/add-a-stream.md). This also adds the simulator if the device has none.

The card shows the video name, the RTSP URL, and the download and stream status. While a Roboflow video is set, the local web UI shows "Managed from Roboflow", the local web UI and CLI controls are locked, and `/upload`, `/play`, `/stop`, `/delete`, and `POST /stream-settings` return `409`. To go back to local uploads, select "Local upload" and save.

## 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 delete the uploaded video.
{% 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

Upload a video with `/upload`, start the stream with `/play`, check it with `/status`, and stop it with `/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.

{% 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>
