Accessing local host rtsp with Brev Launchpad

Please provide the following information when creating a topic:

  • Hardware Platform (GPU model and numbers): Brev, NVIDIA L40s (48Gib)
  • Issue Type( questions, new requirements, bugs):
    • Unable to access localhost rtsp ip address
  • How to reproduce the issue ? (This is for bugs. Including the command line used and other details for reproducing)
    • Replicate the file structure and files from the section below Supporting files to replicate
      • make sure to include a video in the folder videos-to-stream
    • Run the following docker commands
      • docker compose down --remove-orphans
        docker compose pull
        docker compose up
        
      • or if the command doesn’t exist

        • docker-compose down --remove-orphans
          docker-compose pull
          docker-compose up
          
    • start the container up, paste the URL rtsp://localhost:8554/live/mystream
      • docker compose up                                                                                          16:48:57
        [+] Running 4/4
         ✔ Network rtsp-stream_default                                                                                                                             Created       0.0s 
         ✔ Container mediamtx                                                                                                                                      Created       0.0s 
         ✔ Container video-streamer                                                                                                                                Created       0.0s 
         ! streamer The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested               0.0s 
        Attaching to mediamtx, video-streamer
        mediamtx        | 2025/08/18 21:49:01 INF MediaMTX v1.14.0
        mediamtx        | 2025/08/18 21:49:01 INF configuration loaded from /mediamtx.yml
        mediamtx        | 2025/08/18 21:49:01 INF [RTSP] listener opened on :8554 (TCP)
        mediamtx        | 2025/08/18 21:49:01 INF [RTMP] listener opened on :1935
        mediamtx        | 2025/08/18 21:49:01 INF [HLS] listener opened on :8888
        mediamtx        | 2025/08/18 21:49:01 INF [WebRTC] listener opened on :8889 (HTTP), :8189 (ICE/UDP)
        mediamtx        | 2025/08/18 21:49:01 INF [SRT] listener opened on :8890 (UDP)
        video-streamer  | [streamer] publishing to rtmp://mediamtx:1935/live/mystream
        video-streamer  | 
        video-streamer  | ================= STREAM ENDPOINTS =================
        video-streamer  | Publish (internal, streamer -> MediaMTX):
        video-streamer  |   rtmp://mediamtx:1935/live/mystream
        video-streamer  | 
        video-streamer  | View (from this host):
        video-streamer  |   RTSP (TCP): rtsp://localhost:8554/live/mystream
        video-streamer  |   HLS:        http://localhost:8888/live/mystream
        video-streamer  | 
        video-streamer  | ffplay (RTSP over TCP):
        video-streamer  |   ffplay -rtsp_transport tcp rtsp://localhost:8554/live/mystream
        video-streamer  | ====================================================
        video-streamer  | 
        
        • The url can be found from the line
          • video-streamer  | View (from this host):
            video-streamer  |   RTSP (TCP): rtsp://localhost:8554/live/mystream
            
  • Requirement details (This is for new requirement. Including the logs for the pods, the description for the pods)
    • We get the following error (will upload screenshot in follow up post)
      • ERROR: Could not connect to the RTSP URL or there is no video stream from the RTSP URL
        

Supporting files to replicate

file structure

.
├── docker-compose.yml
├── mediamtx.yml
├── stream.sh
└── videos-to-stream
    └── Insert-Your-Video-To-Stream.mp4

docker-compose.yml

services:
  mediamtx:
    image: bluenviron/mediamtx:latest
    container_name: mediamtx
    environment:
      MTX_RTSPTRANSPORTS: tcp   # RTSP over TCP (Docker Desktop/macOS friendly)
    volumes:
      - ./mediamtx.yml:/mediamtx.yml:ro  # file sits at /mediamtx.yml
    # NOTE: no "command": the image entrypoint is already "mediamtx",
    # and it will pick up /mediamtx.yml automatically as the default conf
    ports:
      - "8554:8554/tcp"   # RTSP
      - "1935:1935/tcp"   # RTMP (publisher input)
      - "8888:8888/tcp"   # HLS (optional)
    restart: unless-stopped

  streamer:
    image: ghcr.io/jrottenberg/ffmpeg:6.1-alpine   # this one is multi-arch (arm64 OK)
    container_name: video-streamer
    depends_on:
      - mediamtx
    environment:
      RTMP_URL: rtmp://mediamtx:1935/live
      STREAM_KEY: mystream
      # COPY_MODE: "true"  # uncomment to try stream-copy (no re-encode)
    volumes:
      - ./videos-to-stream:/videos:ro
      - ./stream.sh:/stream.sh:ro
    entrypoint: ["/bin/sh", "/stream.sh"]
    restart: unless-stopped

stream.sh

#!/bin/sh
set -eu

# Inputs / defaults
APP="${APP:-live}"
KEY="${STREAM_KEY:-mystream}"

PUBLIC_HOST="${PUBLIC_HOST:-localhost}"
RTSP_PORT="${RTSP_PORT:-8554}"
HLS_PORT="${HLS_PORT:-8888}"
RTMP_PORT="${RTMP_PORT:-1935}"

# Internal publish URL (inside Docker network)
SERVER="${RTMP_URL:-rtmp://mediamtx:${RTMP_PORT}/${APP}}"

print_urls() {
  echo ""
  echo "================= STREAM ENDPOINTS ================="
  echo "Publish (internal, streamer -> MediaMTX):"
  echo "  rtmp://mediamtx:${RTMP_PORT}/${APP}/${KEY}"
  echo ""
  echo "View (from this host):"
  echo "  RTSP (TCP): rtsp://${PUBLIC_HOST}:${RTSP_PORT}/${APP}/${KEY}"
  echo "  HLS:        http://${PUBLIC_HOST}:${HLS_PORT}/${APP}/${KEY}"
  echo ""
  echo "ffplay (RTSP over TCP):"
  echo "  ffplay -rtsp_transport tcp rtsp://${PUBLIC_HOST}:${RTSP_PORT}/${APP}/${KEY}"
  echo "===================================================="
  echo ""
}

echo "[streamer] publishing to ${SERVER}/${KEY}"
print_urls

# tiny wait so mediamtx can start
sleep 2

stream_file() {
  f="$1"
  echo "[streamer] streaming: $f"
  if [ "${COPY_MODE:-false}" = "true" ]; then
    # Try copy; fallback to transcode if incompatible
    ffmpeg -nostdin -hide_banner -loglevel warning -re -i "$f" \
      -c:v copy -c:a aac -ar 48000 -ac 2 -b:a 160k \
      -f flv "${SERVER}/${KEY}" \
    || ffmpeg -nostdin -hide_banner -loglevel warning -re -i "$f" \
      -c:v libx264 -preset veryfast -tune zerolatency -pix_fmt yuv420p \
      -c:a aac -ar 48000 -ac 2 -b:a 160k \
      -f flv "${SERVER}/${KEY}"
  else
    # Always (light) transcode to H.264/AAC
    ffmpeg -nostdin -hide_banner -loglevel warning -re -i "$f" \
      -c:v libx264 -preset veryfast -tune zerolatency -pix_fmt yuv420p \
      -c:a aac -ar 48000 -ac 2 -b:a 160k \
      -f flv "${SERVER}/${KEY}"
  fi
}

# Loop through the folder forever
while true; do
  found=false
  for f in /videos/*; do
    [ -f "$f" ] || continue
    found=true
    stream_file "$f"
  done
  if [ "$found" = false ]; then
    echo "[streamer] no files found in /videos; add files to ./videos-to-stream/"
    sleep 5
  else
    echo "[streamer] loop complete; starting over..."
  fi
done

mediamtx.yml

paths:
  all:
    source: publisher

Could you try to use the ip of your host instead of the localhost field?

You can also try to set the VSS_SKIP_INPUT_MEDIA_VERIFICATION to 1 in the .env file. Please refer to our skip-input-media-verification to learn about this parameter.

1 Like

My team and I tried it for one of my colleagues public Ip address. It didn’t work when running it from our laptop

I can only post 1 image at a time, so I will make follow up posts

We tried with this config to use a custom public_host as you suggested

# docker-compose.yml
services:
  mediamtx:
    image: bluenviron/mediamtx:latest
    container_name: mediamtx
    environment:
      MTX_RTSPTRANSPORTS: tcp   # RTSP over TCP (Docker Desktop/macOS friendly)
    volumes:
      - ./mediamtx.yml:/mediamtx.yml:ro  # file sits at /mediamtx.yml
    # NOTE: no "command": the image entrypoint is already "mediamtx",
    # and it will pick up /mediamtx.yml automatically as the default conf
    ports:
      - "8554:8554/tcp"   # RTSP
      - "1935:1935/tcp"   # RTMP (publisher input)
      - "8888:8888/tcp"   # HLS (optional)
    restart: unless-stopped

  streamer:
    image: ghcr.io/jrottenberg/ffmpeg:6.1-alpine   # this one is multi-arch (arm64 OK)
    container_name: video-streamer
    depends_on:
      - mediamtx
    environment:
      RTMP_URL: rtmp://mediamtx:1935/live
      STREAM_KEY: mystream
      PUBLIC_HOST: "0.0.0.0"
      # COPY_MODE: "true"  # uncomment to try stream-copy (no re-encode)
    volumes:
      - ./videos-to-stream:/videos:ro
      - ./stream.sh:/stream.sh:ro
    entrypoint: ["/bin/sh", "/stream.sh"]
    restart: unless-stopped
 
# stream.sh
set -eu

# Inputs / defaults
APP="${APP:-live}"
KEY="${STREAM_KEY:-mystream}"

PUBLIC_HOST="${PUBLIC_HOST:-localhost}"
RTSP_PORT="${RTSP_PORT:-8554}"
HLS_PORT="${HLS_PORT:-8888}"
RTMP_PORT="${RTMP_PORT:-1935}"

# Internal publish URL (inside Docker network)
SERVER="${RTMP_URL:-rtmp://mediamtx:${RTMP_PORT}/${APP}}"

print_urls() {
  echo ""
  echo "================= STREAM ENDPOINTS ================="
  echo "Publish (internal, streamer -> MediaMTX):"
  echo "  rtmp://mediamtx:${RTMP_PORT}/${APP}/${KEY}"
  echo ""
  echo "View (from this host):"
  echo "  RTSP (TCP): rtsp://${PUBLIC_HOST}:${RTSP_PORT}/${APP}/${KEY}"
  echo "  HLS:        http://${PUBLIC_HOST}:${HLS_PORT}/${APP}/${KEY}"
  echo ""
  echo "ffplay (RTSP over TCP):"
  echo "  ffplay -rtsp_transport tcp rtsp://${PUBLIC_HOST}:${RTSP_PORT}/${APP}/${KEY}"
  echo "===================================================="
  echo ""
}

echo "[streamer] publishing to ${SERVER}/${KEY}"
print_urls

# tiny wait so mediamtx can start
sleep 2

stream_file() {
  f="$1"
  echo "[streamer] streaming: $f"
  if [ "${COPY_MODE:-false}" = "true" ]; then
    # Try copy; fallback to transcode if incompatible
    ffmpeg -nostdin -hide_banner -loglevel warning -re -i "$f" \
      -c:v copy -c:a aac -ar 48000 -ac 2 -b:a 160k \
      -f flv "${SERVER}/${KEY}" \
    || ffmpeg -nostdin -hide_banner -loglevel warning -re -i "$f" \
      -c:v libx264 -preset ultrafast -tune zerolatency -pix_fmt yuv420p \
      -maxrate 2500k -bufsize 5000k -g 50 -keyint_min 25 \
      -c:a aac -ar 48000 -ac 2 -b:a 160k \
      -f flv "${SERVER}/${KEY}"
  else
    # Optimized transcode settings for smoother streaming
    ffmpeg -nostdin -hide_banner -loglevel warning -re -i "$f" \
      -c:v libx264 -preset ultrafast -tune zerolatency -pix_fmt yuv420p \
      -maxrate 2500k -bufsize 5000k -g 50 -keyint_min 25 \
      -x264-params "nal-hrd=cbr:force-cfr=1" \
      -c:a aac -ar 48000 -ac 2 -b:a 160k \
      -f flv "${SERVER}/${KEY}"
  fi
}

# Loop through the folder forever
while true; do
  found=false
  for f in /videos/*; do
    [ -f "$f" ] || continue
    found=true
    stream_file "$f"
  done
  if [ "$found" = false ]; then
    echo "[streamer] no files found in /videos; add files to ./videos-to-stream/"
    sleep 5
  else
    echo "[streamer] loop complete; starting over..."
  fi
done

Since it didn’t work, we tried uploading the docker-compose.yml and stream.sh file to the jupyterlab [brev]. Even when we run it, the brev launchpad app still couldn’t access the RTSP stream even though it is running in the same network.

When we changed the .env file to include the variable defined above, it still didn’t change

When running ffprobe, we get this resposne

ffprobe -v error -rtsp_transport tcp -show_streams -of compact=p=0:nk=1 rtsp://0.0.0.0:8554/live/mystream
 

0|h264|H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10|Constrained Baseline|video|[0][0][0][0]|0x0000|1280|720|1280|720|0|0|1:1|16:9|yuv420p|31|tv|bt709|bt709|bt709|left|progressive|1|false|0|N/A|25/1|25/1|1/90000|90000|1.000000|N/A|N/A|N/A|N/A|8|N/A|N/A|N/A|0|0|0|0|0|0|0|0|0|0|0|0
1|aac|AAC (Advanced Audio Coding)|LC|audio|[0][0][0][0]|0x0000|fltp|48000|2|stereo|0|N/A|0/0|0/0|1/48000|0|0.000000|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|0|0|0|0|0|0|0|0|0|0|0|0

This is the ffprobe output when we run it locally

ffprobe -v error -rtsp_transport tcp -show_streams -of compact=p=0:nk=1 rtsp://0.0.0.0:8554/live/mystream
 
0|h264|H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10|Constrained Baseline|video|[0][0][0][0]|0x0000|1280|720|1280|720|0|0|0|1:1|16:9|yuv420p|31|tv|bt709|bt709|bt709|left|progressive|1|false|0|N/A|25/1|25/1|1/90000|16108|0.178978|N/A|N/A|N/A|N/A|8|N/A|N/A|N/A|52|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0
1|aac|AAC (Advanced Audio Coding)|LC|audio|[0][0][0][0]|0x0000|fltp|48000|2|stereo|0|0|N/A|0/0|0/0|1/48000|5753|0.119854|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|2|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0

When running the server from local

When running the docker compose file

This is our .env file, as you can see the variable is set to 1

FFprobe on jupyterlab (brev instance)

ffprobe from the local server

If you can only access it locally but not through ip, try turning off the host’s firewall (not docker)

sudo ufw disable

Is this something I run on launchpad or on my laptop? If I need to run this on my the laptop, I don’t think my IT will allow me to run this command.

I can try with launchpad once we get some more credits in the meantime while I wait.

I’m referring to Launchpad.
I tried your docker-compose.yml file.

The mediamtx and vss containers are running on the same host.

For vss, the localhost refers to the container’s network, not mediamtx’s. However, since you’ve mapped the mediamtx port to the host.

Please use rtsp://hostip:8554/live/mystream, through host ip, I can access the rtsp stream in vss