[Blog] An introduction to encoding and pushing with ffmpeg
Hello everyone, Balder here. This time I'd like to talk doing your own encodes and stream pushes. There's a lot of good options out there on the internet, both paid and open source. To cover them would require several posts, so instead I'll just talk about the one I like the most: ffmpeg.
Ffmpeg, the swiss army knife of streaming
Ffmpeg is an incredibly versatile piece of software when it comes to media encoding, pushing and even restreaming other streams. Ffmpeg is purely command line, which is both its downside and strength. It'll allow you to use it in automation on your server, which can be incredibly handy for any starting streaming platform. The downside is that as you'll have to do this without a graphical interface, the learning curve is quite high, and if you don't know what you're doing you can worsen the quality of your video or even make it unplayable. Luckily the basic settings are really forgiving for starting users, and as long as you keep the original source files you're quite safe from mistakes.
So what can ffmpeg do?
Anything related to media really: there's little that ffmpeg can't do. If you have a media file/stream you'll be able to adjust the codecs however you want, change the media format and record it to a file or push it towards a media server. A big benefit to this is that it allows you to bypass known problems/issues that certain protocols or pushing methods have. We use it mostly as an encoder and pushing application ourselves; it's deeply involved in all of our tests.
The basics of ffmpeg
Ffmpeg has too many options to explain easily to new users, so we'll go over the bare minimum required to encode and push streams with ffmpeg. Luckily ffmpeg has a wide community and information on how to do something is easily found through your preferred search engine. Every ffmpeg command will follow the following syntax:
ffmpeg input(s) [codec options] output(s)
Input is given by
-i Input.file/stream_url. The input can be a file or a stream, of course you'll have to verify the input you're filling in exists or is a valid url, but that's how far the difficulty goes. A special mention goes to the "-re" option to read a file in real-time: it'll allow you to use a media file as "live” source if you wish to test live streaming without having a true live source available.
A huge array of options is available here, however we'll only cover two things: Copying codecs and changing codecs to H264 for video and AAC for audio. As H264/AAC are the most common codecs at the moment there's a good chance you already have these in your files, otherwise re-encoding them to H264/AAC with the default settings of ffmpeg will almost certainly give you what you want. If not feel free to check out the ffmpeg documentation here. To specify the video or audio codec, use
-c:v for video or
-c:a for audio. Lastly, you can use
-c to choose all codecs in the file/stream at once.
Copying codecs (options)
The copying of codecs couldn't be easier with ffmpeg. You only need to use
-c copy to copy both the video and audio codecs. Copying the codecs allows you to ingest a media file/stream and record it or change it to a different format. You can also only copy a specific codec like this:
-c:v copy for video and
-c:a copy for audio. The neat thing about using the copy option is that it will not re-encode your media data, making this an extremely fast operation.
Encoding to H264/AAC (options)
Ffmpeg allows you to change the video and audio track separately. You can copy a video track while only editing the audio track if you wish. Copying is always done with the
copy codec. An encode to H264/AAC is done by using the option
-c:a aac -strict -2 -c:v h264. Older versions of ffmpeg might require the equivalent old syntax
-acodec aac -strict -2 -vcodec h264 instead.
The output of ffmpeg can either be a file or a push over a stream url. To record it to a file use
outputfile.ext; almost any media type can be chosen by simply using the right extension. To push over a stream use
-f FORMAT STREAM_URL. The most commonly used format for live streaming will be RTMP, but RTMP streams internally use the FLV format. That means you'll have to use
-f flv rtmp://SERVERIP:PORT/live/STREAMNAME for this. Other stream types may auto-select their format based on the URL, similar to how this works for files.
- FLV file Input to MP4 file, copy codecs
ffmpeg -i INPUT.flv -c copy OUTPUT.mp4
In all the examples below we'll assume you do not know the codecs and will want to replace them with H264/AAC.
- RTMP stream Input to FLV file, reencode
ffmpeg -i rtmp://IP:PORT/live/STREAMNAME -c:a aac -strict -2 -c:v h264 OUTPUT.flv
- MP4 file Input to RTMP stream, reencode
ffmpeg -re -i INPUT.mp4 -c:a aac -strict -2 -c:v h264 -f flv rtmp://IP:PORT/live/STREAMNAME
- HLS stream input to RTMP stream, reencode
ffmpeg -i http://IP:PORT/hls/STREAMNAME/index.m3u8 -c:a aac -strict -2 -c:v h264 -f flv rtmp://IP:PORT/live/STREAMNAME
- MP4 file input to RTSP stream, reencode
ffmpeg -re -i INPUT.mp4 -c:a aac -strict -2 -c:v h264 -f rtsp -rtsp_transport tcp rtsp://IP:PORT/STREAMNAME
- HLS stream input to RTSP stream, reencode
ffmpeg -i http://IP:PORT/hls/STREAMNAME/index.m3u8 -c:a aac -strict -2 -c:v h264 -f rtsp -rtsp_transport tcp rtsp://IP:PORT/STREAMNAME
- RTSP stream input over TCP to RTMP stream, copy
*Using ffmpeg to ingest over TCP instead of UDP makes sure you don't have the packet loss problem that UDP has and gives a better and more stable picture for your stream.
-rtsp_transport tcp -i CameraURL -c copy -f flv rtmp://IP:PORT/live/STREAMNAME
Creating a multibitrate stream from a single input
This one is a bit advanced, but often asked for so I've opted to include it. In order to fully understand the command you'll need some explanation however. It's important to keep in mind that you will need to tell ffmpeg how many video/audio tracks you want and which track should be used as source for the options later on. First you start with mapping and selecting input tracks then you describe the encoder settings per track.
ffmpeg -i INPUT -map a:0 -map v:0 -map v:0 -c:a:0 copy -c:v:0 copy -c:v:1 h264 -b:v:1 250k -s:v:1 320x240 OUTPUT
To explain all of those options in more detail:
INPUTcan be either a file or a stream for input
OUTPUTcan be either a file or a stream for output
-map a:0selects the first available audio track from the source
-map v:0selects the first available video track from the source
-map v:0selects the first available video track from the source a second time
-c:a:0 copytells ffmpeg to copy the audio track without re-encoding it
-c:v:0 copytells ffmpeg to copy the video track without re-encoding it
-c:v:1 h264tells ffmpeg to also re-encode the video track in h264
-b:v:1 250ktells ffmpeg that this second video track should be 250kbps
-s:v:1 320x240tells ffmpeg that this second video track should be at 320x240 resolution
You can keep adding video tracks or audio tracks by adding
-map v:0 or
-map a:0 just be sure to set the encoder options for every track you add. You can select the second input video or audio track with
-map v:1 or
-map a:1 and so forth for additional tracks.
Well that was it for the basics when using ffmpeg. I hope it helps you when you want to try and get yourself familiarized with it. The next blog will be released in the same month as the IBC, with all the new exciting developments being shown we think it's a good idea to go back to the basics of OTT so we'll be releasing Jaron’s presentation "What is OTT anyway?" given at last year's IBC2016, covering the basics of OTT at a level for people that are just getting started with streaming.