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, the service transcodes it to an RTSP-compatible format, and it publishes the result on a continuous loop until you stop it.
Connection Details
Replace <device-ip> with the IP address shown on the device page in Deployment Manager.
RTSP stream
rtsp://<device-ip>:8554/stream
Web UI, REST API, and Swagger docs
http://<device-ip>:8080
8080
HTTP
Web UI, REST API, Swagger docs at /docs
8554
RTSP (TCP)
Video stream output. UDP transport is disabled; clients that prefer UDP negotiate down to TCP-interleaved.
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.
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.
Using the CLI
For headless or SSH-only access, the rtsp-cli tool provides an interactive terminal interface on the device.
To import a video without the web UI, copy it into the input directory first, then launch the CLI and press I.
I
Import
Select and convert a video from /data/input/
P
Play
Start RTSP streaming
S
Stop
Stop streaming and delete converted files
D
Delete
Delete video files
C
Config
Adjust stream settings (bitrate, buffer, delay)
R
Refresh
Refresh the status display
Q
Quit
Exit the CLI
Testing the Stream
Connect with any RTSP player to confirm the stream is live.
The stream is served over TCP only, so force TCP transport rather than letting ffplay try UDP first.
HTTP API
All endpoints return JSON. Interactive Swagger documentation is served at http://<device-ip>:8080/docs. See Services for the rules shared by all on-device service APIs.
The API is unauthenticated, and it can stop a running stream and delete uploaded video. Anything that can reach port 8080 can do both.
Typical Flow
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.
/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.
Uploads a video and converts it to the RTSP streaming format. Only .mp4 is accepted. 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.
Video file to upload. Must be .mp4.
Optional JSON string holding an UploadSettings object. It is a string part rather than a nested object because the service parses it with json.loads before validating, so the UploadSettings schema below documents the shape rather than being referenced here.
{"target_fps": 30, "crf_quality": 23, "max_width": 1920}Upload and conversion succeeded
No file selected, unsupported extension, invalid upload settings, or the file is not a readable video
File exceeds MAX_FILE_SIZE (5 GB by default)
Request failed validation
Conversion failed
Not enough free disk space for the upload
POST /upload HTTP/1.1
Host: device-ip:8080
Content-Type: multipart/form-data
Accept: */*
Content-Length: 93
{
"file": "binary",
"settings": "{\"target_fps\": 30, \"crf_quality\": 23, \"max_width\": 1920}"
}{
"success": true,
"message": "Video uploaded successfully",
"video": {
"filename": "factory_line.mp4",
"size": 125000000,
"size_mb": 119.21,
"extension": ".mp4"
}
}Streaming
Starts publishing the converted video to the RTSP server, looping until stopped. Uses the current stream settings.
Streaming started
RTSP stream URL as the service sees it, always naming localhost, on the port set by RTSP_PORT (8554 by default). Consumers off the device must substitute the device address; read rtsp_port from /info rather than assuming 8554.
Already streaming, or no video has been uploaded
The stream failed to start
POST /play HTTP/1.1
Host: device-ip:8080
Accept: */*
{
"success": true,
"message": "Streaming started",
"rtsp_url": "rtsp://localhost:8554/stream"
}Stops the stream and deletes both the original and converted files to free disk space. Uploading again is required before the next /play.
Streaming stopped and files deleted
Not currently streaming
Stop failed
POST /stop HTTP/1.1
Host: device-ip:8080
Accept: */*
{
"success": true,
"message": "text"
}/delete removes the video files without requiring a stream to be running, stopping one first if it is.
Deletes the original and converted video files, stopping the stream first if it is running. Unlike /stop, this succeeds whether or not a stream is active.
Files deleted
No video files found to delete
Delete failed
POST /delete HTTP/1.1
Host: device-ip:8080
Accept: */*
{
"success": true,
"message": "text"
}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.
Returns whether the stream is live, plus the health of each component, which is the fastest way to localize a failure.
streaming is true when components.mediamtx.healthy and components.ffmpeg_process.running are both true; the components.stream entry does not gate it. components.stream.source_ready can be false briefly during startup, which is normal.
Current status
RTSP stream URL as the service sees it, always naming localhost, on the port set by RTSP_PORT (8554 by default). Null when not streaming. Consumers off the device must substitute the device address; read rtsp_port from /info rather than assuming 8554.
GET /status HTTP/1.1
Host: device-ip:8080
Accept: */*
Current status
{
"streaming": true,
"rtsp_url": "rtsp://localhost:8554/stream",
"video": {
"filename": "sample.mp4",
"size": 1048576,
"size_mb": 1,
"extension": ".mp4"
},
"components": {
"mediamtx": {
"healthy": true,
"error": null
},
"ffmpeg_process": {
"exists": true,
"pid": 1234,
"running": true,
"exit_code": null
},
"stream": {
"api_available": true,
"source_ready": true,
"readers": 1,
"error": null
}
}
}/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.
Returns disk space, the upload size limit, accepted extensions, and the RTSP port.
System information
Maximum upload size in bytes, set by MAX_FILE_SIZE
Accepted file extensions. Only .mp4 today.
Port the RTSP stream is served on, set by RTSP_PORT
GET /info HTTP/1.1
Host: device-ip:8080
Accept: */*
System information
{
"disk_space": {
"total": 1,
"used": 1,
"free": 1,
"free_gb": 1
},
"max_file_size": 1,
"max_file_size_gb": 1,
"allowed_extensions": [
"text"
],
"rtsp_port": 1
}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.
Returns the current playback settings.
Current settings
Playback settings, changeable between streaming sessions without re-uploading.
Maximum bitrate in kbps
5000Buffer size in KB
3000Maximum delay in milliseconds
500GET /stream-settings HTTP/1.1
Host: device-ip:8080
Accept: */*
Current settings
{
"max_bitrate_kbps": 5000,
"buffer_size_kb": 3000,
"max_delay_ms": 500
}Persists new playback settings. They apply to the next streaming session, not the one currently running.
Playback settings, changeable between streaming sessions without re-uploading.
Maximum bitrate in kbps
5000Buffer size in KB
3000Maximum delay in milliseconds
500Settings saved
Request failed validation
Failed to persist settings
POST /stream-settings HTTP/1.1
Host: device-ip:8080
Content-Type: application/json
Accept: */*
Content-Length: 66
{
"max_bitrate_kbps": 5000,
"buffer_size_kb": 3000,
"max_delay_ms": 500
}{
"success": true,
"message": "text"
}Configuration
Environment Variables
Set these on the service in the device's Configuration tab. See Update Device Configuration.
MAX_FILE_SIZE
5368709120
Maximum upload size in bytes (5 GB)
RTSP_PORT
8554
RTSP server port
WEB_PORT
8080
Web UI and API port
LOG_LEVEL
INFO
Logging verbosity: DEBUG, INFO, WARNING, or ERROR
Upload Settings
These are applied during conversion, so changing them requires re-uploading the video.
target_fps
original
Target frame rate, 1 to 120. Omit to keep the original
crf_quality
23
Quality level, 0 to 51 (18 is high, 23 is medium, 28 is low)
max_width
original
Maximum width for downscaling, 320 to 7680. Omit to keep the original
Stream Settings
These are applied at playback and can be changed between streaming sessions from the CLI config menu or the /stream-settings endpoint.
max_bitrate_kbps
5000
Maximum bitrate in kbps, 100 to 100,000
buffer_size_kb
3000
Buffer size in KB, 100 to 50,000
max_delay_ms
500
Maximum delay in milliseconds, 50 to 5,000
Last updated
Was this helpful?