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?
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.