H.264 web video encoding tutorial with FFmpeg
Web is full of articles about encoding videos with FFmpeg, however most of them are obsolete and use old non-working FFmpeg parameters. So here’s my guide for encoding web videos using recent FFMpeg versions for Flash and HTML5.
Step 1: Get a new build of FFmpeg
Most distribution builds are very old, buggy and have numerous issues. Don’t use them.
Ubuntu users: UbuntuForums has a great guide for compiling newest FFMpeg build. I strongly suggest you use a stable FFmpeg build (that’s 0.9 at the moment) instead of git master. Don’t forget libx264 for H.264 and libvpx for VP8/WEBM if you want that support.
Windows users: Zeranoe has great static builds of FFmpeg for Windows with libx264 and libvpx included. Use those for encoding.
OS X users: MacPorts should be able to compile and install FFmpeg with libvpx and libx264. As I don’t use any machines with OS X you’ll have to check for yourself.
If you already know what “bitrates, profiles etc.” are and just want the command lines skip to step 4 or sample command lines.
Step 2: Choose resolution, bitrate and profile
Now you’ll have to decide on two things – the resolution, bitrate and profile you want those videos in.
Resolution gives “sharpness” to the overall image. If you choose a low resolution, the video will be small and it will be blurry when users will put it full-screen. Typically people use 360p (that’s a shorthand naming made popular by HD televison, meaning picture has height of 360 with width corresponding to wanted aspect ratio), 480p, 720p and 1080p resolutions, as those correspond to common screen sizes, which avoids excessive blurriness.
Contrary to popular belief, resolution does not affect file size.
Bitrate tells the encoder about how many bits should each second of video have. It directly determines file size of the video along with the quality. Set too low, it will cause the video to look very blocky (especially in fast-moving scenes) and set too high will make your files excessively large.
When choosing bitrate you need to remember, it is directly connected to resolution – storing pictures of certain resolution requires more bits, so if you want higher resolution videos, you’ll have to choose higher bitrate for them to not look like garbage.
A rule of thumb to calculate file size from bitrate is:
filesize (in MB) = (bitrate in Mbit/s * 8) * (video length in seconds)
Some general resolution/bitrate guidelines that we’ve found to work well at Viidea:
| Resolution | Bitrate | Approximate size of 10 min video |
|---|---|---|
| 320p (for mobile phones) | 180 kbit/s | ~13 MB |
| 360p | 300 kbit/s | ~22 MB |
| 480p | 500 kbit/s | ~37 MB |
| 576p (SD) | 850 kbit/s | ~63 MB |
| 720p (HD) | 1000 kbit/s | ~75 MB |
The values in the table were optimized for lecture-type content recorded with SD cameras, so if you want to encode something more dynamic (like Transformers ;) ) I suggest you bump the bitrate up a little.
Profile constrains H.264 to a subset of features – higher profiles require more CPU power to decode and are able to generate better looking videos at same bitrate. You should always choose the best profile your target devices support.
Basic support matrix for devices:
| Device | Max supported profile |
|---|---|
| Desktop browsers iPhone 4S, iPad 2 Tegra Android tablets Xbox 360, Playstation 3 | High profile |
| iPhone 3GS, iPhone 4, iPad high-end Android phones | Main profile |
| iPhone, iPhone 3G medium/low-end Android devices other embedded players | Baseline profile |
Remember, most devices also have a maximum resolution and bitrate they can handle. That is usually expressed in as a H.264 level and can be set in FFmpeg with -level parameter (this will make FFmpeg abort encoding of videos which couldn’t be played on the device).
Step 3: Choose audio format and bitrate
For audio, the choice is a lot simpler – if you want to encode for mobile devices I strongly suggest you use AAC+, which has a very noticeable improvement of audio quality at the same bitrate. Sadly, libaacplus in FFmpeg, doesn’t support encoding to higher bitrates than 64 kbps. With that in mind, AAC+ is perfect for podcasts, lectures and other speech content, since it retains quality even at low bitrates (difference between “normal” LC-AAC at 96 kbit/s vs. AAC+ at 64kbit/s is practically not noticeable).
Otherwise, rule of thumb is to take around 128 kbit/s for standard quality material and 192kbit/s for something more complex.
Step 4: Encode!
So, you made all the hard choices and now it’s time to encode your video. FFmpeg command line to encode a standard web video looks like this:
ffmpeg -i input_file.avi -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -vf scale=-1:480 -threads 0 -acodec libfdk_aac -b:a 128k output_file.mp4
You can also encode the video in two-passes, which gives the added benefit of quality increase and more accurate file size for given bitrate:
1st pass:
ffmpeg -i input_file.avi -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -vf scale=-1:480 -threads 0 -pass 1 -an -f mp4 /dev/null
2nd pass:
ffmpeg -i input_file.avi -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -vf scale=-1:480 -threads 0 -pass 2 -acodec libfdk_aac -b:a 128k -f mp4 output_file.mp4
Scary isn’t it?
Warning: ffmpeg command line arguments are position sensitive – make sure you don’t mix up the order. Good rule of thumb to prevent mistakes is to keep the order of Download: options
ffmpeg [input options] -i [input filename] -vcodec [video options] -acodec
Let’s break down all those parameters:
-i [input file] - this specifies the name of input file
-vcodec libx264 – tells FFmpeg to encode video to H.264 using libx264 library
-vprofile high – sets H.264 profile to “High” as per Step 2. Other valid options are baseline, main
-preset slow – sets encoding preset for x264 – slower presets give more quality at same bitrate, but need more time to encode. “Slow” is a good balance between encoding time and quality.
Other valid options are: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo (never use this one)
-b:v - sets video bitrate in bits/s
-maxrate and -bufsize – forces libx264 to build video in a way, that it could be streamed over 500kbit/s line considering device buffer of 1000kbits. Very useful for web – setting this to bitrate and 2x bitrate gives good results.
-vf scale – applies “scale” filter, which resizes video to desired resolution. “720:480″ would resize video to 720×480, “-1″ means “resize so the aspect ratio is same.”
Usually you set only height of the video, so for 380p you set “scale=-1:380″, for 720p “scale=-1:720″ etc.
-threads 0 – tells libx264 to choose optimal number of threads to encode, which will make sure all your processor cores in the computer are used
-acodec libfdk_aac – tells FFmpeg to encode audio to AAC using libfdk-aac library
-b:a - sets audio bitrate in bits/s
-pass [1|2] – tells FFmpeg to process video in multiple passes and sets the current pass
-an – disables audio, audio processing has no effect on first pass so it’s best to disable it to not waste CPU
That’s basically all there is to it.
Some sample command lines:
“Standard” web video (480p at 500kbit/s):
ffmpeg -i input_file.avi -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -vf scale=-1:480 -threads 0 -acodec libfdk_aac -b:a 128k output_file.mp4
360p video for older mobile phones (360p at 250kbit/s in baseline profile):
ffmpeg -i inputfile.avi -vcodec libx264 -vprofile baseline -preset slow -b:v 250k -maxrate 250k -bufsize 500k -vf scale=-1:360 -threads 0 -acodec libfdk_aac -b:a 96k output.mp4
480p video for iPads and tablets (480p at 400kbit/s in main profile):
ffmpeg -i inputfile.avi -vcodec libx264 -vprofile main -preset slow -b:v 400k -maxrate 400k -bufsize 800k -vf scale=-1:480 -threads 0 -acodec libfdk_aac -b:a 128k output.mp4
High-quality SD video for archive/storage (PAL at 1Mbit/s in high profile):
ffmpeg -i inputfile.avi -vcodec libx264 -vprofile high -preset slower -b:v 1000k -vf scale=-1:576 -threads 0 -acodec libfdk_aac -b:a 196k output.mp4
If you’re interested in encoding WebM instead of H.264, read the next article :)
Your High-quality preset has an error in the command line, where it says -vg -1:576 it should say -vf scale=-1:576
Apart from that, great post! :)
(whoops! corrected my correction!)
Your High-quality preset has an error in the command line, where it says -vf -1:576 it should say -vf scale=-1:576
Apart from that, great post! :)
Yes of course! Fixed the mistake, thanks for letting me know ;)
Excellent, I was just looking for some useful information on what encoding settings to use for html5-compatible video (mp4/webm), but there are so many poor and undocumented examples out there. I’m glad google got me here :)
Thanks for this, very helpful.
I do not have the libvo_aacenc library. Are there any alternatives?
Yeah, people usually use libfaac instead of libvo_aacenc.
I replaced:
-acodec libvo_aacenc
With:
-acodec aac -strict experimental
I recommend against using the built-in FFmpeg encoder – it still commonly produces broken AAC audio. Use libfaac if licensing allows it or libvo_aacenc if it doesn’t.
For OSX users, ffmpeg is also easily available through Homebrew.
$ Brew install ffmpeg
Thanks for your advice.
I’m using -acodec libvorbis as I can’t get libfaac or vo-aacenc.
Could you reccomend some presets for 720p and 1080p web video. I think I’m running into some issues when trying to up the -maxrate and -bufsize.
Thanks
Sorry to clarify,
“width or height not divisible by 2″
When using the scale with -1:720
I think it is a ffmpeg bug
This page is very helpful. Thank you so much!
Hello,
I’m trying to make a movie from jpg images using the h264 vcodec, but it keeps on giving me errors. Do you know if h264 allow images as an input?
Many thanks!
Antony, video is allergic to odd numbers. That is not a bug.
If you want a challenge then script FFMPEG to do your bidding.
I have a script that I cannot distribute (copyright hell right now) that can do the following:
1) Encode video by default to a .150 bit per pixel density. I can override that on the command line. More info on bit per pixel here:
http://www.streaminglearningcenter.com/articles/choosing-your-streaming-resolution-and-data-rate.html
2) Detect crop. Can be overridden.
3) Encode to baseline, main or high profile.
4) Detect interlaced content and some primitive telecine / pulldown detection. Can be overridden.
5) Resize the video to a specified width. Default is no resize. Make sure to check that the output video is evenly divisible. If it isn’t add one to the width and/or height.
6) Override output frames per second.
7) Change the bitrate of the audio. All audio is forced to stereo on purpose or it will not stream to devices.
8) Encode a time limited section of the video.
9) Defaults to a keyframe interval of 10 seconds. That can be overridden.
You will need to do a lot of math and calculations to pull that off but the command line version of MediaInfo can help out tons.
Note that a lot of the content you will run across will be broken in ways you have never imagined before.
If you are on 0.7.x, you may have to use -profile instead of -vprofile if you get a Undefined constant or missing ‘(‘ error.
If you’re dealing with different video types, you definitely want to do some scripting.
I just had some problems with converting a video based on the web settings (vf -scale = -1:480). I got this error message:
Error while opening encoder for output stream #0:0 – maybe incorrect parameters such as bit_rate, rate, width or height.
I realized that it was because the height was higher than the original video and wouldn’t work with the way I had my settings (iOS, etc.)
I’m just posting it just in case anyone else had the same problem and was confused. Thanks for the doc, Jernej!
great post …
Im encoding video files for so many years now, not as a pro but when needed here and there. I have never managed to fully grasp the relation between the resolution & bitrate and their effect on the file size until now.
So basically, if the picture is fuzzy & blurry, the resolution is too low and if I see pixelation on the picture it is because of the low bitrate. And resolution do not have a direct effect on the file size, but of course higher resolution will require higher bitrates.
Your post was very informative for me. I would like to ask you a question if you dont mind.
I never change the aspect ratio when encoding, even if the source have some weird, non-standart ratio, I just keep the source aspect ratio intact. Mainly because Im scared to have some stretched objects. Also, Im scared to have some negative effects on the file size, encoding time and the picture quality.
The same goes for the frame rate as well. When Im thinking about it, lowering the frame rate from 30 to 23 might make the file size smaller (neve tried it though) but again I dont know if that will have a negative effect on the encoding time and picture quality.
I would appreciate it if you can shed some light on these two subjects as well.
Thanks…
Needed some guidance. We are converting videos recorded from Apple IOS and Android device. And this converted videos are being accessed by IOS, android devices and from Website using Strobe Media Playback.
We are using following command to convert video:
ffmpeg -i -s 480*800 -vcodec libx264 -acodec aac -strict experimental -ac 2 -r 25 -ab 44100 .mp4
The issue come when uploading from the IOS device that orientation changes.
By removing the “-s 480*800″ the orientation issue solved, but android devices stopped playing the converted videos.
Is there any way that the converted video plays well in IOS, ANdroid devices and Web.
Thanks.
Hi all!
I also trying to produce some video-clips with ffmpeg out of lots of pics from my webcam …
Codes:
/usr/local/vencode/bin/ffmpeg -r 8 -f image2 -i www/xxx/Alarm%5d.jpg -s 500×375 -b 1035k -y www/xxx/Videos/Sa_Fahrt_1.mp4
/usr/local/vencode/bin/ffmpeg -r 8 -f image2 -i www/xxx/Alarm%5d.jpg -s 500×375 -b 1035k -y www/xxx/Videos/Sa_Fahrt_1.ogv
It works great in FireFox 14.0.1 and also in Opera (Next) 12.50 internal!
But there are different problems in following browsers!
Safari 5.1.7:
Complete slow and not loading(!?!) playing the videos!
Safari on Mac 5.0.5:
green videos with a lot of lareg pixels
IE9:
Only showing the flowplayer in the comp. compatibility modus
But not loading my videos?!?
Chrome 21.011.xx:
Only playing the older, short videos, but not loading the new ones!?!
(Fahrt 1 and Fahrt 6 are new from today!)
They are not working, the others yes …?!?
iPad3-browser:
Sometimes not loading the posters of the videos!
Only shows black screen with the PALY-Button … Sometimes!
My samples you can find here:
=>> =>> http://www.automower-webcam.com/onboard-zeitraffer_mi.php
Thanks a lot for helping me
I think there is a problem with the wrong size, resolution and/or the bit-rate:
“-s 500×375 -b 1035k”
Nils
Hi all!
I also trying to produce some video-clips with ffmpeg out of lots of pics from my webcam …
Codes:
/usr/local/vencode/bin/ffmpeg -r 8 -f image2 -i www/xxx/Alarm%5d.jpg -s 500×375 -b 1035k -y www/xxx/Videos/Sa_Fahrt_1.mp4
/usr/local/vencode/bin/ffmpeg -r 8 -f image2 -i www/xxx/Alarm%5d.jpg -s 500×375 -b 1035k -y www/xxx/Videos/Sa_Fahrt_1.ogv
It works great in FireFox 14.0.1 and also in Opera (Next) 12.50 internal!
But there are different problems in following browsers!
Safari 5.1.7:
Complete slow and not loading(!?!) playing the videos!
Safari on Mac 5.0.5:
green videos with a lot of lareg pixels
IE9:
Only showing the flowplayer in the comp. compatibility modus
But not loading my videos?!?
Chrome 21.011.xx:
Only playing the older, short videos, but not loading the new ones!?!
(Fahrt 1 and Fahrt 6 are new from today!)
They are not working, the others yes …?!?
iPad3-browser:
Sometimes not loading the posters of the videos!
Only shows black screen with the PALY-Button … Sometimes!
My samples you can find here:
=>> =>> http://www.automower-webcam.com/onboard-zeitraffer_mi.php
Thanks a lot for helping me
I think there is a problem with the wrong size, resolution and/or the bit-rate:
“-s 500×375 -b 1035k”
Nils
What changes in the command line below FFmepg to work with the latest version (0.11.1)?
This is because the command line below is not working.
ffmpeg -i video_input.mp4 -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -vf scale=-1:480 -threads 0 -acodec libvo_aacenc -b:a 64k video_output.mp4
Thanks
What changes in the command line below FFmepg to work with the latest version (0.11.1)?
This is because the command line below is not working in Windows Server.
ffmpeg -i video_input.mp4 -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -vf scale=-1:480 -threads 0 -acodec libvo_aacenc -b:a 64k video_output.mp4
Thanks
What changes in the command line below FFmepg to work with the latest version (0.11.1)?
This is because the command line below is not working in Windows Server.
ffmpeg -i video_input.mp4 -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -vf scale=-1:480 -threads 0 -acodec libvo_aacenc -b:a 64k video_output.mp4
Thanks
Excellent! Thanks a lot man.
Hey thanks, great Post!
-vf scale=-1:480
If you are getting “Error while opening encoder for output stream #0:0 – maybe incorrect parameters such as bit_rate, rate, width or height”
check your frame size. my src = 1280×720 , ffmpeg reports “width not divisible by 2 (853×480)”
change to
-vf scale=850:480
resolves the error
(maybe solution to poster above.)
-vf scale=-1:480
If you are getting “Error while opening encoder for output stream #0:0 – maybe incorrect parameters such as bit_rate, rate, width or height”
check your frame size. my src = 1280×720 , ffmpeg reports “width not divisible by 2 (853×480)”
change to
-vf scale=850:480
resolves the error
(maybe solution to poster above.)
@Joana I found this tutorial yesterday for making slideshow videos. http://svnpenn.github.com/2012/ffmpeg-slideshow/
If you want to maintain the aspect-ratio, and don’t want to specify width, let ffmpeg calculate the width for you?
-vf scale=”trunc(oh*a/2)*2:480″
Above scale filter would make ffpeg calcualte right width for 480 (height) by maintaining source aspect ratio. Yeah, you won’t get any divide by 2 errors here.
If you want to height to be calculated automatically, which is rare case:
-vf scale=”640:trunc(ow*a*2)/2″
HTH
cheers
-abdul
All the samples here can’t create .mp4 for blackberry.
I’ve tried the 360 and 480 and my bb pays the audio but says the video is in an unsupported format
Linux users can improve audio quality with NeroAccenc and can install it from a terminal with the following commands
sudo wget ftp://ftp6.nero.com/tools/NeroDigitalAudio.zip
sudo unzip NeroDigitalAudio.zip -d nero
sudo cd nero/linux
sudo install -D -m755 neroAacEnc /usr/local/bin
after install run this to see if neroaacenc installed properly
neroAacEnc
to strip a .wav file from your movie then convert it to a .m4a use this command from the terminal
ffmpeg -y -i mymovie.mov -threads 0 audio.wav
neroAacEnc -q 0.3 -if audio.wav -of OUTPUT.M4a
then you can inject the .m4a back into your rendered video file like this from the terminal
ffmpeg -i output.mp4 -vcodec copy -threads 0 -an withoutaudio.mp4
ffmpeg -i withoutaudio.mp4 -vcodec copy -i OUTPUT.M4a -acodec copy -threads 0 final.mp4
hi,
Thanks for the tutorial. Can i use the same command to encode flv video?
ffmpeg -i input_file.avi -vcodec libx264 -vprofile high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -vf scale=-1:480 -threads 0 -acodec libvo_aacenc -b:a 128k output_file.mp4(flv)
Thanks,
Richard
The “Sample command lines” use both the -ba and -a:b options.
What’s the difference?
Both “-b:a” and “-ab” mean exactly the same.
“-ab” is an old deprecated parameter being phased out in less ambiguous “:” style.
Hi
You guys all seem pretty comfortable with using libfdk_aac.
Well, I’d be too if ffmpeg didn’t cut it short on my Linux Mint 13-based ffmpeg with a final ‘unknown encoder libfdk_aac’. So, contrary to what I thought, I haven’t got the whole range of audio libraries installed on my system. I know how silly that kind of question can appear to people in the knowing, but the Web is opaque to my queries about libfdk_acc at the moment.
Anybody having a clue to share?
Um, libfdk_aac is so new that most distros don’t package their ffmpeg with that lib support (that’s the reason why this guide starts with your own compile – distro packages are mostly hopelessly obsolete).
So if you want to use libfdk_aac, you need to grab it from its github page, compile it and then compile ffmpeg with “–enable-libfdk-aac” yourself.
Official Ubuntu compilation guide on ffmpeg wiki will tell you how to do that on Mint 13.
Got it, with thanks.