This is a collection of working commandline examples to show how one could use FFMpeg and VLC for live transcoding of video streams. All examples have been tested on OSX 10.7.5 with FFMPeg 1.1.3 and VLC 2.0.5 in early 2013.
Documentation links
- FFMpeg, Muxers, Encoders, Protocols
- FFMPEG multiple outputs
- VLC Docu, Advanced Use
ffmpeg -v debug -y -re -i file.mp4 -vsync 1 -codec copy -bsf h264_mp4toannexb -f mpegts http://localhost:6666@listen
ffmpeg -v debug -fflags nobuffer -i tcp://127.0.0.1:6666 -r 15 -vsync 2 -copyts -copytb 1 -codec copy -map 0 -f segment -segment_time 2 -segment_list stream.m3u8 -segment_format mpegts -segment_list_flags +live stream-%09d.ts
Data path: Fake Source -> Server -> Web Clients
Start the video server with the command ./videoserver
and once a stream is recording visit the player page at server:/v1/videos/:id/play
where the id is the video streams unique identifier.
ffmpeg -v debug -y -re -i video.mp4 -vsync 1 -map 0 -codec copy -bsf h264_mp4toannexb -f mpegts -copytb 0 http://localhost:6666/v1/ingest/1/ts
ffmpeg -v debug -y -re -i video.mp4 -f mpegts -c:v libx264 -preset ultrafast -tune zerolatency -crf 20 -x264opts keyint=50:bframes=0:ratetol=1.0:ref=1 -profile baseline -maxrate 1200k -bufsize 1200k -c:a copy http://localhost:6666/v1/ingest/1/ts
/Applications/VLC.app/Contents/MacOS/VLC qtcapture:// -vvvv --no-drop-late-frames --no-skip-frames --sout='#transcode{vcodec=h264,fps=15,venc=x264{preset=ultrafast,tune=zerolatency,keyint=30,bframes=0,ref=1,level=30,profile=baseline,hrd=cbr,crf=20,ratetol=1.0,vbv-maxrate=1200,vbv-bufsize=1200,lookahead=0}}:standard{access=http{mime="video/MP2T"},mux=ts,dst=127.0.0.1:5555}' --qtcapture-width=640 --qtcapture-height=480 --live-caching=200 --intf=macosx
ffmpeg -v debug -y -i http://127.0.0.1:5555 -vsync 1 -map 0 -codec copy -r 15 -f mpegts -copytb 0 http://localhost:6666/v1/ingest/1/ts
ffmpeg -v debug -y -re -i video.mp4 -f h264 -c:v libx264 -preset ultrafast -tune zerolatency -crf 20 -x264opts keyint=50:bframes=0:ratetol=1.0:ref=1:repeat-headers=1 -profile baseline -maxrate 1200k -bufsize 1200k -an http://localhost:6666/v1/ingest/1/avc
-vvvv
--no-drop-late-frames
--no-skip-frames
--sout='#transcode{<params>}:standard{<params>}'
--mtu 8192
--qtcapture-width 640
--qtcapture-height 480
--live-caching 200 [ms] !important
--intf=macosx
--sout-x264-keyint=30
--sout-x264-bframes=0
--sout-x264-ref=1
--sout-x264-level=30
--sout-x264-profile=baseline
--sout-x264-hrd=cbr
--sout-x264-crf=20
--sout-x264-ratetol=1.0
--sout-x264-vbv-maxrate=1200 [kbit/s]
--sout-x264-vbv-bufsize=1200 [kbit/s]
--sout-x264-preset=ultrafast
--sout-x264-tune=zerolatency
--sout-x264-aud
--sout-x264-lookahead=0
--sout-transcode-venc x264
--sout-transcode-vcodec h264
--sout-transcode-vb 2000
--sout-transcode-fps 25
--sout-transcode-width W
--sout-transcode-height H
--sout-transcode-aenc
--sout-transcode-acodec mp4a
--sout-transcode-ab 64 [kbit/s]
--sout-transcode-channels 2
--sout-transcode-samplerate 44100
--sout-standard-mux=ts
--sout-ts-shaping 2000 [ms] minimum interval with constant bitrate in VBR stream
--sout-ts-use-key-frames limit shaping interval at key frames
--sout-ts-dts-delay=0
--sout-mux-caching=0
--clock-synchro=1
--sout-standard-access=udp
--sout-standard-dst IP:PORT
--sout-mux-caching=20 [ms]
--sout-udp-caching=0 [ms]
--sout-udp-group=10 send groups of 10 packets at a time
--sout-udp-late=100 [ms] ? drop packets arriving later than N ms
--sout-udp-raw ? dont wait until MTU is filled before sending
--sout-http-mime="video/MP2T"
VLC implements a streaming server and FFMpeg pulls raw data via HTTP. Note that VLC, unlike FFMpeg, is not able to send a live stream towards a HTTP server.
/Applications/VLC.app/Contents/MacOS/VLC qtcapture:// -vvvv --no-drop-late-frames --no-skip-frames --sout='#transcode{vcodec=h264,fps=15,venc=x264{preset=ultrafast,tune=zerolatency,keyint=30,bframes=0,ref=1,level=30,profile=baseline,hrd=cbr,crf=20,ratetol=1.0,vbv-maxrate=1200,vbv-bufsize=1200,lookahead=0}}:standard{access=http{mime="video/MP2T"},mux=ts,dst=127.0.0.1:5555}' --qtcapture-width=640 --qtcapture-height=480 --live-caching=200 --intf=macosx
ffmpeg -v debug -fflags nobuffer -i http://127.0.0.1:5555 -r 15 -vsync 2 -copyts -copytb 1 -codec copy -map 0 -f segment -segment_time 2 -segment_list test.m3u8 -segment_format mpegts -segment_list_flags +live teststream-%09d.ts
ffmpeg
automatically dies on ingest socket close.
VLC pushes TS stream to FFMpeg listening on UDP address/port.
ffmpeg -v debug -fflags nobuffer -i 'udp://127.0.0.1:5555?fifo_size=1000000&overrun_nonfatal=1' -r 15 -vsync 0 -copyts -copytb 1 -codec copy -map 0 -f segment -segment_time 2 -segment_list test.m3u8 -segment_format mpegts -segment_list_flags +live teststream-%09d.ts
/Applications/VLC.app/Contents/MacOS/VLC qtcapture://1 -vvvv --no-drop-late-frames --no-skip-frames --sout='#transcode{vcodec=h264,fps=15,venc=x264{preset=ultrafast,tune=zerolatency,keyint=30,bframes=0,ref=1,level=30,profile=baseline,hrd=cbr,crf=20,ratetol=1.0,vbv-maxrate=1200,vbv-bufsize=1200,lookahead=0}}:standard{access=udp,mux=ts,dst=127.0.0.1:5555}' --sout-mux-caching=0 --sout-udp-caching=0 --sout-udp-group=10 --clock-synchro=1 --sout-ts-shaping=2000 --sout-ts-use-key-frames --qtcapture-width=640 --qtcapture-height=480 --live-caching=200 --intf=macosx
FFMpeg finishes writing the last segment and finalises the m3u8 file on close. Signal 2 is recommended, but ctrl-c
worked for me as well.
# FFMpeg must be killed with signal 2 (I had to send the signal multiple times to be sure the correct thread received it)
kill -2 $PID
In this scenario VLC implements an RTSP server and FFMpeg connects to fetch the stream. Other interactions are possibel with RTSP/RTP, for example, having VLC send RTP over UDP to a multicast address and make FFMpeg join the multicast group. Signalling information in this scenario is passed via SDP (Session Description Protocol), a text based representation of technical details.
Status: FAILS
/Applications/VLC.app/Contents/MacOS/VLC -I dummy --ttl 12 qtcapture://1 -vvvv --no-drop-late-frames --no-skip-frames --sout='#transcode{vcodec=h264,vb=1200,fps=15,venc=x264{preset=ultrafast,tune=zerolatency,keyint=30,bframes=0,ref=1,level=30,profile=baseline,hrd=cbr,crf=20,ratetol=1.0,vbv-maxrate=1200,vbv-bufsize=1200,aud,lookahead=0,repeat-headers=1}}:rtp{name="Teststream1",sdp=rtsp://127.0.0.1:5555/teststream.sdp}' --sout-mux-caching=0 --sout-rtp-caching=0 --clock-synchro=1 --sout-ts-shaping=2000 --sout-ts-use-key-frames --qtcapture-width=640 --qtcapture-height=480 --live-caching=200 --intf=macosx --rtsp-host=127.0.0.1 --rtsp-port=5555
ffmpeg -v debug -fflags nobuffer -i rtsp://127.0.0.1:5555/teststream.sdp -r 15 -copyts -copytb 1 -codec copy -map 0 -f segment -segment_time 2 -segment_list test.m3u8 -segment_format mpegts -segment_list_flags +live teststream-%09d.ts
When packing raw H264 into RTP VLC does not insert SPS/PPS before every keyframe, so the resulting stream becomes unplayable. When requesting VLC to mux H264 into TS before packaging RTP, FFMpeg fails due to a RTSP handshake problem (SETUP failed: 459 Aggregate operation not allowed).
Not tested due to issue above FFMpeg should shut down as soon as the RTSP connection is closed (by streaming server sending a TEARDOWN message) or by TCP connection reset resulting from unintended server disconnect.
ffmpeg -v debug -fflags nobuffer -i pipe:0 -vsync 0 -copyts -copytb 1 -codec copy -map 0 -f segment -segment_time 2 -segment_list test.m3u8 -segment_format mpegts -segment_list_flags +live teststream-%09d.ts
Status: OK
/Applications/VLC.app/Contents/MacOS/VLC video.mp4 -vvvv --intf=rc --sout '#duplicate{dst=display,dst="transcode{vcodec=h264,vb=2000,fps=25,scale=1,width=640,height=480,acodec=mp4a,ab=128,channels=2,samplerate=44100,venc=x264{keyint=50,ref=1,ratetol=1.0}}:standard{access=udp,mux=ts,dst=127.0.0.1:5555}"'
# in a stream splitting example
duplicate{dst=file{mux=ts,dst='-'},dst=display}
Stream to local and pipe to media stream segmenter, which creates index file and can be streamed to iOS
vlc --ttl 12 qtcapture:// -vvv input_stream --sout="#transcode{venc=x264{keyint=60,idrint=2},vcodec=h264,vb=300,acodec=mp4a,ab=32,channels=2, samplerate=22050}:\
duplicate{dst=file{mux=ts,dst='-'},dst=display}" | mediastreamsegmenter -s 10 -D -f ./hls/live
ffmpeg -v debug -i ~/Movies/colorbars1.mp4 -i ~/Movies/colorbars2.mp4 -f mpegts -map 0:0 -map 1:0 -program title="this is muh first program":program_num=9001:st=0 -program title="program twooooo":program_num=9002:st=1 test.ts
For all the ffmpeg nerds out there, I've been poking at (what I think are) 'multiplexed' streams to try and get more of a handle on whats what with them and how I can play em/manipulate them. Maybe y'all know this already but this is where I'm at so far:
- Creating a video file that has multiple 'programs' in it. (emulating a vyvx stream with multiple programs?)
- Inspecting a stream/file to view the different program ID's (we would do this to a VyVx stream, or in this case, the test.ts file. We can see descriptions and Program ID's inside here (program ID's are the key)
.....
Input #0, mpegts, from 'test.ts':
Duration: 00:00:30.00, start: 1.440000, bitrate: 510 kb/s
Program 9001
Metadata:
service_name : this is muh first program
service_provider: FFmpeg
Stream #0:0[0x100]: Video: mpeg2video (Main) ([2][0][0][0] / 0x0002), yuv420p(tv, progressive), 320x240 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 90k tbn, 50 tbc
Program 9002
Metadata:
service_name : program twooooo
service_provider: FFmpeg
Stream #0:1[0x101]: Video: mpeg2video (Main) ([2][0][0][0] / 0x0002), yuv420p(tv, progressive), 320x240 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 90k tbn, 50 tbc
And finally, the main event... This is how you can pick out a program from a stream, and play it on your laptop. This is how we can play VyVx streams from the source directly on your laptop (no jillion-dollar multiviewer needed)
ffplay -vst p:9001 test.ts
And as a final bonus... When you use ffplay
and hit ctrl+c
, it cycles between program ID's, so you can see all the programs available in the stream! 😄