FFmpeg – the swiss army knife of Internet Streaming – part IV
This is the fourth and last part of a short series dedicated to FFmpeg (First, Second and Third part).
In this conclusive article I will focus on the support for RTMP that makes FFmpeg an excellent tool for enhancing the capabilities of the Adobe Flash Streaming Ecosystem.
FFmpeg introduced a strong support for RTMP streaming with the release 0.5 by the inclusion of the librtmp (rtmpdump) core. An RTMP stream can be used both as an input and/or as an output in a command line.
The required syntax is:
rtmp_proto://server[:port][/application][/stream] options
where rtmp_proto can be: “rtmp“, “rtmpt“, “rtmpte“, “rtmps“, “rtmpte“, “rtmpts” and options contain a list of space-separated options in the form key=val (more info here).
Using some of the parameters that we have seen in the first three parts of the series, it’s possible to do a lot of things that the standard Flash Streaming Ecosystem cannot offer. Sometimes there are minor bugs but generally speaking the rtmplib works well and helps FMS to fill the gap with some advanced feature of Wowza Server (like re-purposing of rtp/rtsp stream, TS-stream and so on). FFmpeg works with FMS as well as Wowza Server and RED5, so in the article I will use FMS as a generic term to mean any “RTMP-server”.
1. STREAM A FILE TO FMS AS IF IT WERE LIVE
With the help of FFmpeg it is possible for example to stream a pre-encoded file to FMS as if it were a live source. This can be very useful for test purpose but also to create pseudo-live channels.
ffmpeg -re -i localFile.mp4 -acodec copy -vcodec copy -f flv rtmp://server/live/streamName
The -re option tells FFmpeg to read the input file in realtime and not in the standard as-fast-as-possible manner. With -acodec copy and -vcodec copy I’m telling FFmpeg to copy the essences of the input file without transcoding, then to package them in an FLV container (-f flv) and send the final bitstream to an rtmp destination (rtmp://server/live/streamName).
The input file must have audio and video codec compatible with FMS, for example H.264 for video and AAC for audio but any supported codecs combination should work.
Obviously it would be also possible to encode on the fly the input video. In this case remember that the CPU power requested for a live encoding can be high and cause loss in frame rate or stuttering playback on subscribers’ side.
In which scenario can be useful a command like that ?
For example, suppose to have created a communication or conference tool in AIR. One of the partecipants at the conference could fetch a local file and stream it to the conference FMS to show, in realtime, the same file to other partecipants. Leveraging the “native process” feature of AIR it is simple to launch a command line like the one above and do the job. In this scenario, probably you will have to transcode the input, or check for the compatibility of codecs analyzing the input up front (remember ffmpeg -i INPUT trick we spoke about in the second article).
2. GRAB AN RTMP SOURCE
Using a command like this:
ffmpeg -i rtmp://server/live/streamName -acodec copy -vcodec copy dump.flv
It’s possible to dump locally the content of a remote RTMP stream. This can be useful for test/audit/validation purpose. It works for both live and on-demand content.
3. TRANSCODE LIVE RTMP TO LIVE RTMP
One of the more interesting scenario is when you want to convert a format to a different one for compatibility sake or to change the characteristics of the original stream.
Let’s suppose to have a Flash Player based app that do a live broadcast. You know that until FP11, Flash can only encode using the old Sorenson spark for video and NellyMoser ASAO or Speex for audio. You may use a live transcoding command to enhance the compression of the video transcoding from Sorenson to H.264:
ffmpeg -i rtmp://server/live/originalStream -acodec copy -vcodec libx264 -vpre slow -f flv rtmp://server/live/h264Stream
This could be useful to reduce bandwidth usage especially in live broadcasting where latency it’s not a problem.
The next release of FMS will also offer support for the Apple HTTP Live Streaming (like Wowza already do). So it will be possible to use FMS to stream live to iOS device. But FMS does not transcode the stream essence, it performs only a repackaging or repurposing of the original essences. But FFmpeg can help us to convert the uncompliant Sorenson-Speex stream to a H.264-AAC stream in this way:
ffmpeg -i rtmp://server/live/originalStream -acodec libfaac -ar 44100 -ab 48k -vcodec libx264 -vpre slow -vpre baseline -f flv rtmp://server/live/h264Stream
See also the point 4 and 5 to know how to generate a multibitrate stream to be compliant with Apple requirements for HLS. This approach will be useful also with FP11 that encode in H.264, but generate only one stream.
Another common scenario is when you are using FMLE to make a live broadcast. The standard windows version of FMLE supports only MP3 and not AAC for audio encoding (plug-in required). This may be a problem when you want to use your stream also to reach iOS devices with FMS or Wowza (iOS requires AAC for HLS streams). Again FFmpeg can help us:
ffmpeg -i rtmp://server/live/originalStream -acodec libfaac -ar 44100 -ab 48k -vcodec copy -f flv rtmp://server/live/h264_AAC_Stream
On the other hand, I have had the opposite problem recently with an AIR 2.7 apps for iOS. AIR for iOS does not support by now H.264 or AAC streaming with the classical netStream object, but I needed to subscribe AAC streams generated for the desktops. FFmpeg helped me in transcoding AAC streams to MP3 for the AIR on iOS app.
Again, you probably know that Apple HLS requires an audio only AAC stream with a bitrate less than 64Kbit/s for the compliance of video streaming apps, but at the same time you probably want to offer an higher audio quality for your live streaming (on desktop fpo istance). Unfortunately FMLE encode at multiple bitrates only the video track while use a unique audio preset for all bitrates. With FFmpeg is possible to generate a dedicated audio only stream in AAC with bitrate less than 64Kbit/s.
4. GENERATE BASELINE FOR LOW-END DEVICES
Very similarly, if you want to be compliant with older iOS versions or other mobile devices (older BB for istance) you need to encode in Baseline profile, but at the same time you may want to leverage high profile for desktop HDS. So you could use FMLE to generate high profile streams, with high quality AAC and then generate server side a baseline set of multi-bitrate streams for HLS and/or low end devices compatibility.
This command read from FMS the highest quality of a multi bitrate set generated by FMLE and starting from that generate 3 scaled down versions in baseline profile for HLS or Mobile. The last stream is an audio only AAC bitstream at 48Kbit/s.
ffmpeg -re -i rtmp://server/live/high_FMLE_stream -acodec copy -vcodec x264lib -s 640×360 -b 500k -vpre medium -vpre baseline rtmp://server/live/baseline_500k -acodec copy -vcodec x264lib -s 480×272 -b 300k -vpre medium -vpre baseline rtmp://server/live/baseline_300k -acodec copy -vcodec x264lib -s 320×200 -b 150k -vpre medium -vpre baseline rtmp://server/live/baseline_150k -acodec libfaac -vn -ab 48k rtmp://server/live/audio_only_AAC_48k
5. ENCODE LIVE FROM LOCAL GRABBING DEVICES
FFmpeg can use also a local AV source, so it’s possible to encode live directly from FFmpeg and bypass completely FMLE. I suggest to do that only in very controlled scenarios because FMLE offers precious, addictional functions like auto-encoding adjust to keep as low as possible the latency when the bandwidth between the acquisition point and the server is not perfect.
This is an example of single bitrate:
ffmpeg -r 25 -f dshow -s 640×480 -i video=”video source name”:audio=”audio source name” -vcodec libx264 -b 600k -vpre slow -acodec libfaac -ab 128k rtmp://server/application/stream_name
Join this command line and the previous and you have a multi-bitrate live encoding configuration for desktop and mobile.
6. ENCODE SINGLE PICTURES WITH H.264 INTRA COMPRESSION
H.264 has a very efficient Intra compression mode, so it is possible to leverage it for picture compression. I have estimated an improvement of around 50% in compression compared to JPG. Last year I have discussed estensively the possibility to use this kind of image compression to protect professional footage with FMS and RTMPE. Here you find the article, and this is the command line:
ffmpeg.exe -i INPUT.jpg -an -vcodec libx264 -coder 1 -flags +loop -cmp +chroma -subq 10 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -flags2 +dct8x8 -trellis 2 -partitions +parti8x8+parti4x4 -crf 24 -threads 0 -r 25 -g 25 -y OUTPUT.mp4
Change -crf to modulate encoding quality (and compression rate).
CONCLUSIONS
With this article, this short series on FFmpeg comes to an end.
There are a lot of other scenarios where using FFmpeg with FMS (or Wowza) can help you creating new exciting services for you projects and overcome the limitations of the current Flash Video Ecosystem, so now it’s up to you. Try to mix my examples and post comments about new ways of customization that you have found of your RTMP delivery system.
I’ll speak about this topic also during my presentation at MAX 2011, http://bit.ly/qvKjP0, so I’m looking forward to chat of advanced FFmpeg usage and Encoding optimizations with someone of you in Los Angeles.




You may find this handy for compiling bleeding-edge ffmpeg static binaries: https://github.com/pyke369/sffmpeg
Thank you
pyke3698,
This is awesome!!! I was able to download and build ffmpeg within an hour on my CentOS 5.6 server.
My first attempt failed due to missing “librtmp” so I removed “–enable-librtmp” from ffmpeg.
Also, I was able to update to libvpx to 0.9.7.
Two questions if you feel like answering…
1) How can I correct the librtmp issue?
2) How can I use “GIT” to get latest libraries?
Thanks so much to you and Sonnati with FFMPEG.
zhi
“yum -y install pkgconfig*” fixed the librtmp problem.
-zhi
@Zhi Feel free to send me pull requests on github.com if you feel something need to be amended/enhanced.
If I understand correctly, I can use ffmpeg to read data from a webcam and stream it? I’m hoping to port this into .NET Gadgeteer. Thanks!
Hi,
I’m testing FFMPEG to grab single (or a series of) still frames from an rtmp source. It works, but it can take upwards of 2 minutes before ffmpeg starts saving the stills. I’m at a loss as to why this is, as the streams come straight down in any regular player.
Example:
ffmpeg -i “rtmp://108.9.128.3/rtplive playpath=point_of_rocks.stream” image%d.jpg
Any ideas of options to help speed this up?
Thanks!
Same issue here, no luck so far,using RED5. However, their test app oflaDemo works great ie I can stream from a camera and send to other clients. Just can’t get ffmpeg to read in the rtmp, ie using rtmp://localhost/oflaDemo/mytestname Running Ubuntu 11.04, with red5 v1.0 and ffmpeg installed via default methods (ie apt-get install). I also have compiled my own bleeding edge ffmpeg but no differences Okay here’s a log (hope you all don’t get angry… its not too long
../ffmpeg/ffmpeg -loglevel verbose -re -i “rtmp://localhost/oflaDemo/quandt” -acodec copy -vcodec copy -y a.flv
Parsing…
Parsed protocol: 0
Parsed host : localhost
Parsed app : oflaDemo
RTMP_Connect1, … connected, handshaking
HandShake: Type Answer : 03
HandShake: Server Uptime : 16205
HandShake: FMS Version : 0.0.0.0
HandShake: Handshaking finished….
RTMP_Connect1, handshaked
Invoking connect
HandleClientBW: client BW = 64000 0
HandleCtrl, received ctrl. type: 0, len: 6
HandleCtrl, Stream Begin 0
RTMP_ClientPacket, received: invoke 161 bytes
(object begin)
Property:
Property:
Property: NULL
Property:
(object begin)
Property:
Property:
Property:
Property:
Property:
(object end)
(object end)
HandleInvoke, server invoking
HandleInvoke, received result for method call
sending ctrl. type: 0×0003
Invoking createStream
RTMP_ClientPacket, received: bytes read report
RTMP_ClientPacket, received: invoke 29 bytes
(object begin)
Property:
Property:
Property: NULL
Property:
(object end)
HandleInvoke, server invoking
HandleInvoke, received result for method call
SendPlay, seekTime=0, stopTime=0, sending play: quandt
Invoking play
sending ctrl. type: 0×0003
RTMP_ClientPacket, received: invoke 131 bytes
(object begin)
Property:
Property:
Property: NULL
Property:
(object begin)
Property:
Property:
Property:
Property:
Property:
(object end)
(object end)
HandleInvoke, server invoking
HandleInvoke, onStatus: NetStream.Play.StreamNotFound
Closing connection: NetStream.Play.StreamNotFound
rtmp://localhost/oflaDemo/quandt: Operation not permitted
Hi,
Great post.
I’m trying to follow the examples and to transmit local flv file to FMS and then to watch with ffplayer.
ffmpeg -loglevel verbose -re -i host.flv -acodec copy -vcodec copy -f flv rtmp://server_address/live/test
ffplay -loglevel verbose rtmp://server_address/live/test
on the ffplay side I’m getting: Closing connection: NetStream.Play.StreamNotFound.
Will appreciate advice.
Thanks,
Ofer
Hi,
Does the step 4, “4. GENERATE BASELINE FOR LOW-END DEVICES” actually allow you to stream to an iPad for example?
I’m trying to find out how to use ffmpeg to do live streaming out to mobile devices
You need to encode in multibitrate (HLS) to be compliant with Apple’s AppStore requirements.
I’ll update soon the FFmpeg codebase with multibitrate support and more.
That’s great, I really appreciate the help. Is there a need to utilize another program to do any segmenting or can it be done straight from ffmpeg to the mobile devices?
I’m hoping to use ffmpeg rtmp to take an already encoded stream and push it to one of the “free” (ad-based) video systems. I have been working unsuccessfully on ustream (FMS) and find others on the net who agree. It seems that the results on justin.tv and livestream are better with ffmpeg rtmp. Any ideas out there? Is there some portion of rtmp ‘keepalive’ that ffmpeg is missing?
More poking around the web indicates this is due to SWF Verification on the RTMP connection. It looks like other open source projects have implemented support for this with the ability to specify a token/hash. Most folks are just looking to download/play content from a RTMP server, whereas I need to push RTMP to ustream. The main reason I’m inclined to use ffmpeg is that my source is already encoded, so I’m just using “-vcodec copy”. I don’t know if any other piece of software can push RTMP without touching the encoding. Any help out there? Is there a better forum for this discussion?
Is there any more documentation on this, and when will the codebase with this support be available?
I think this could help many of you:
if the input url is of a live rtmp – it needs to be enclosed in quotes and be followed by a live=1, for example:
ffmpeg -i “rtmp://server-ip/appname/streamname live=1″
Otherwise it gives you the “StreamNotFound” error.
I found this out when I saw somebody use it like that as a parameter for ffplay, so I tried it for ffmpeg and it worked!
I’ve seen this as well, but have not been able to make it work against RED5, was your testing against ustream or other site? Or a red5 site?
hi i have flv file generated using wowza, it is videoless audio file
how can i convert it into mp3 using ffmpeg? appreciate if you can give me the command…
from:
ffmpeg -re -i /home/alacret/Escritorio/test3.ogv -acodec copy -vcodec copy -f flv rtmp://localhost:9001/live/streamName
rtmp://localhost:9001/live/streamName: Operation not permitted
I got the message
RTMP_Connect0, failed to connect socket. 111 (Connection refused)
your flash media server is runing on port 9001 ? (default is 1935)
in general this seems to be a wrong port error
ps. sometimes you should write output in this way
-f flv “rtmp://localhost:9001/live/streamName live=1″
it seems to be – wrong port error, maybe 1935 instead of 9001
and sometimes you should write output from ffmpeg in this way:
-f flv “rtmp://localhost:1935/live/streamName live=1″
or
-f flv “rtmp://localhost:9001/live/streamName live=1″
if you use custom port, which is 9001 in this example
hi friends
i have a doubt in ffmpeg with rtmp
i want to edit the video which is getting from rtmp server and save to same rtmp server
i try the bellow but not working
ffmpeg -i rtmp://server1/vod/sample.flv -flags gray rtmp://server1/vod/fmsgrayout.flv
you are using an insufficient number of parameters. Try to encode at least the video track in h264 or ad “-acodec copy -f flv” before the output
Hi,
First of all great tutorial! it was really useful to me.
I have problem with ffmpeg that I can’t fix. I’m making a video from jpeg images. I need to use a frame rate between 7-9. The problem is that doesn’t matter how much I change the frame rate (25fps or 7fps) the movie lenght remains the same. That means that ffmpeg skips some input images in order to keep that length. Therefore, I need ffmpeg to include the entire image sequence and move the final output video length.
I’m using ffmpeg 0.7.11 and the following command line:
ffmpeg -i proves/img/img%d.jpg -r 7 -b 1200k -vcodec libx264 -flags +loop -me_method hex -g 250 -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -bf 3 -b_strategy 1 -i_qfactor 0.71 -cmp +chroma -subq 8 -me_range 16 -coder 1 -sc_threshold 40 -flags2 +bpyramid+wpred+mixed_refs+dct8x8+fastpskip -keyint_min 25 -refs 3 -trellis 1 -directpred 1 -partitions -parti8x8-parti4x4-partp8x8-partp4x4-partb8x8 -threads 0 -acodec libfaac -ar 44100 -ab 96k -y proves/8.mp4
Is there something I’m missing or I should change in order to let ffmpeg keep all the input frames and make the movie longer (and more heavy)?
Many thanks!