dockerportforwardingdocker-network

MediaMTX RTSP container not proxying feeds


Please note: Even with port forwarding flags added this probelm persists, and so the other SO answers are not helping me here. I understand I am asking about the ope source MediaMTX RTSP server here, but I believe this is a pure Docker question at heart; and as such, can be answered by anyone with Docker networking experience regardless of their experience with MediaMTX.


I am on a Mac laptop here. I am running MediaMTX via docker like so:

docker run --rm -it -p 8554:8554 bluenviron/mediamtx:latest
2023/10/16 15:05:22 INF MediaMTX v1.2.0
2023/10/16 15:05:22 INF configuration loaded from /mediamtx.yml
2023/10/16 15:05:22 INF [RTSP] listener opened on :8554 (TCP), :8000 (UDP/RTP), :8001 (UDP/RTCP)
2023/10/16 15:05:22 INF [RTMP] listener opened on :1935
2023/10/16 15:05:22 INF [HLS] listener opened on :8888
2023/10/16 15:05:22 INF [WebRTC] listener opened on :8889 (HTTP)
2023/10/16 15:05:22 INF [SRT] listener opened on :8890 (UDP)

I can confirm that it is running:

docker ps
CONTAINER ID   IMAGE                        COMMAND       CREATED          STATUS          PORTS     NAMES
ef27229a41c4   bluenviron/mediamtx:latest   "/mediamtx"   19 seconds ago   Up 18 seconds             goofy_franklin

And telnet see it just fine:

telnet localhost 8554
Trying ::1...
Connected to localhost.
Escape character is '^]'.

But when I go to publish (write/stream) an MP4 to it via ffmpeg I get broken pipe errors:

ffmpeg -re -stream_loop -1 -i fireplace.mp4 -c copy -f rtsp rtsp://localhost:8554/mystream     
ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers
  built with Apple clang version 14.0.0 (clang-1400.0.29.202)
  configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/6.0_1 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
  libavutil      58.  2.100 / 58.  2.100
  libavcodec     60.  3.100 / 60.  3.100
  libavformat    60.  3.100 / 60.  3.100
  libavdevice    60.  1.100 / 60.  1.100
  libavfilter     9.  3.100 /  9.  3.100
  libswscale      7.  1.100 /  7.  1.100
  libswresample   4. 10.100 /  4. 10.100
  libpostproc    57.  1.100 / 57.  1.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'fireplace.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf59.27.100
  Duration: 00:00:11.27, start: 0.000000, bitrate: 522 kb/s
  Stream #0:0[0x1](und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, smpte170m/bt470bg/smpte170m, progressive), 368x640, 448 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
      encoder         : Lavc59.37.100 libx264
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 64 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
Output #0, rtsp, to 'rtsp://localhost:8554/mystream':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf60.3.100
  Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, smpte170m/bt470bg/smpte170m, progressive), 368x640, q=2-31, 448 kb/s, 30 fps, 30 tbr, 90k tbn (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
      encoder         : Lavc59.37.100 libx264
  Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 64 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
av_interleaved_write_frame(): Broken pipe00:00:09.60 bitrate=N/A speed=   1x    /s speed=N/A    
[out#0/rtsp @ 0x128f15b00] Error muxing a packet
[out#0/rtsp @ 0x128f15b00] Error writing trailer: Broken pipe
frame=  305 fps= 30 q=-1.0 Lsize=N/A time=00:00:10.10 bitrate=N/A speed=   1x    
video:560kB audio:80kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Conversion failed!

When I run that command I get this output in the container logs:

2023/10/19 23:26:43 INF [RTSP] [conn 192.168.65.1:22506] opened
2023/10/19 23:26:43 INF [RTSP] [session f1b1b628] created by 192.168.65.1:22506
2023/10/19 23:26:43 INF [RTSP] [session f1b1b628] is publishing to path 'mystream', 2 tracks (H264, MPEG-4 Audio)
2023/10/19 23:26:50 INF [RTSP] [session f1b1b628] destroyed: torn down by 192.168.65.1:22506
2023/10/19 23:26:50 INF [RTSP] [conn 192.168.65.1:22506] closed: EOF
2023/10/19 23:26:53 INF [RTSP] [conn 192.168.65.1:22507] opened
2023/10/19 23:26:53 INF [RTSP] [session b7be9e08] created by 192.168.65.1:22507
2023/10/19 23:26:53 INF [RTSP] [session b7be9e08] is publishing to path 'mystream', 2 tracks (H264, MPEG-4 Audio)
2023/10/19 23:27:03 INF [RTSP] [conn 192.168.65.1:22507] closed: terminated
2023/10/19 23:27:03 INF [RTSP] [session b7be9e08] destroyed: session timed out

So it appears that ffmpeg is able to connect to the RTSP server, but not able to actually send anything to it.

Can anyone spot where I might be going awry?


Solution

  • Use the following:

    docker run --rm -it --network=host -p 8554:8554

    ffmpeg -re -stream_loop -1 -i fireplace.mp4 -c copy -f rtsp -rtsp_transport tcp rtsp://localhost:8554/mystream

    View the stream with:

    ffplay -rtsp_transport tcp rtsp://localhost:8554/mystream

    Explanation:

    Since you are running this on a mac, you are likely using Docker Desktop. The Docker Desktop documentation has this to say about host networking:

    The host networking driver only works on Linux hosts, and is not supported on Docker Desktop for Mac, Docker Desktop for Windows, or Docker EE for Windows Server.

    Since you are running docker run --rm -it --network=host -p 8554:8554 bluenviron/mediamtx:latest, the --network=host option will override any port assignments you provide in the command. Since this mode is not functional on Docker Desktop for mac, this means that your container will not be reachable.

    To fix this, you will need to explicitly forward the ports you wish to use. I was able to get the following to work on a mac:

    docker run --rm -it -p 8554:8554 bluenviron/mediamtx:latest <- Starts the server

    To test that this is working, I stream a continuous series of gray frames over the RTSP server with the following command:

    ffmpeg -readrate 1 -f lavfi -i color=c=gray -vf "fps=25,format=yuv420p" -c:v libx264 -f rtsp -rtsp_transport tcp rtsp://localhost:8554/mystream

    -readrate 1 limits ffmpeg from sending frames too fast, since the framerate we get with this synthetic video could cause issues.

    -f lavfi -i color=c=gray generates gray frames continuously so we don't need to rely on any specific video for testing purposes

    -vf "fps=25,format=yuv420p" sets the video format (25 FPS and 420p resolution)

    -c:v libx264 sets the codec to H264, one of the supported codecs for mediamtx's RTSP stream, per their documentation.

    -f rtsp -rtsp_transport tcp sets the output format and transport protocol. Note that your command above is missing -rtsp_transport tcp, which I found to be necessary in the same setup (macOS/docker/ffmpeg). This is likely something you will need to add to your own ffmpeg command.

    I was able to confirm that this stream was functional by viewing it with ffmpeg using the following command:

    ffplay -rtsp_transport tcp rtsp://localhost:8554/mystream

    Edit for stream capture, per request:

    To capture the output of your stream back into a local file, you can use the following command:

    ffmpeg -rtsp_transport tcp -i rtsp://localhost:8554/mystream -c copy fp-copy.mp4

    Since your original command will infinitely loop the fireplace.mp4 file you have, this will continue to capture until your disk is full. To limit it to a specific duration, you can use the -t option on your output like so:

    ffmpeg -rtsp_transport tcp -i rtsp://localhost:8554/mystream -c copy -t 60 fp-copy.mp4

    This will copy the first 60 seconds from the time you start streaming. Increase it to whatever duration you would like.

    You can also limit by file size instead of duration. To do that, use:

    ffmpeg -rtsp_transport tcp -i rtsp://localhost:8554/mystream -c copy -fs 100M fp-copy.mp4

    This will limit the output to 100MB.

    Note that the first few seconds of your captured output may be black. This comes from the period where ffmpeg is establishing a connection to the RTSP stream.

    If you don't want to go through the trouble of trimming out this segment with an external tool, you can modify the command to:

    ffmpeg -rtsp_transport tcp -i rtsp://localhost:8554/mystream -vf "trim=start=10,setpts=PTS-STARTPTS" -af "atrim=start=10,asetpts=PTS-STARTPTS" -t 20 fp-copy.mp4

    This new -vf option will trim the first 10 seconds from both audio and video. Note that this is incompatible with the -c copy option, but it seems to work fine all the same.