FFmpeg x264 encoding guide

Preset files are available from the FFmpeg source code in the ffpresets subdirectory. Using the 0.5 release or current svn trunk of FFmpeg, running make install will install the preset files to ${prefix}/share/ffmpeg and just specifying -vcodec libx264 -vpre <preset> is sufficient for ffmpeg to find the preset.

Otherwise, you can either copy *.ffpreset from the FFmpeg source into ~/.ffmpeg/ or you can point to a preset file directly in the argument of -fpre in your command line.

Skip to the examples.

Basic FFmpeg Usage

To construct an ffmpeg command line, you need to understand a few fairly simple things. The basic command line format is:

ffmpeg [input options] -i [input file] [output options] [output file]

  • input options – these are usually mandatory information that is missing about the source file (for example, in the case of a sequence of image files this could be the frame rate), or the seek position corresponding to the desired start point of the stream
  • output options – audio and video filtering (alteration of the sample rate, number of channels, frame dimensions, frame rate), audio and video codecs and their corresponding options, container format and related options

Normally the minimum one should specify in an ffmpeg command line would be something like:

ffmpeg -i INFILE -acodec ACODEC -ab 96k -vcodec VCODEC -b 500k OUTFILE

…replacing the capitalised values as appropriate. When using x264, we need to add some extra bits as the defaults are bad.

x264 – Rate Control Choices

Firstly, you need to decide on a rate control method. This controls how bits are allocated within the stream. At a rudimentary level, you want the quality to remain constant but this implies that more complex frames use more bits and less complex frames use less bits.

Rate control methods available:

  • constant quantisation parameter – not recommended anymore unless you know you want it
  • constant rate factor – good for one pass when the priority is quality and file size/bit rate is not really a concern
  • one pass average bit rate – good for streaming purposes or targeting a bit rate when two-pass is unfeasible
  • two pass variable bit rate – good for targeting a bit rate when you have the time to spend on two passes (though the first pass can be quite fast) and are writing to a file

Or in prose, CQP mode is mostly deprecated by CRF as CRF maintains more constant quality which was usually the aim of someone using CQP mode. If you care more about quality than bit rate then I would recommend using one pass CRF to save yourself a bit of time. Evaluate various rate factors between about 25 and 15 (a lower value is higher quality and higher bit rate) until you find a quality level/approximate bit rate with which you’re happy and then you can use that value forever more. :)

One pass average bit rate is good if you need to aim for an approximate bit rate but don’t have time to run two passes. If you have the time then two passes are recommended as the bits will be better distributed to maintain constant quality.

To use one pass CQP:

-cqp <int>

To use one pass CRF:

-crf <float>

To use one pass ABR or two pass VBR:

-b BIT_RATE -bt BIT_RATE

x264 – FFmpeg Preset Choices

Secondly, you need to choose an appropriate preset from those available.

Presets available (for lossy compression):

  • quality related:
    • ultrafast
    • superfast
    • veryfast
    • faster
    • fast
    • medium – x264 CLI default
    • slow
    • slower
    • veryslow
    • placebo
  • first pass:
    • <preset from above>_firstpass – for example medium_firstpass
  • profile constraints:
    • baseline
    • main

Note: Profile constraint presets need to be specified with a second -vpre option after the quality/first pass preset, e.g. -vpre slower -vpre main

x264 – Recommended General Options

For all rate control methods you will probably want libx264 to select the number of threads to use to maximise its performance on your CPU(s):

-threads 0

Two-Pass Example

So if you wanted to encode using two-pass VBR, the command line would be something like:

ffmpeg -i INPUT -an -pass 1 -vcodec libx264 -vpre slow_firstpass -b BIT_RATE -bt BIT_RATE -threads 0 OUTPUT.mp4

Note: We don’t encode the audio in the first pass because we will not be using the data that was output.

ffmpeg -i INPUT -acodec libfaac -ab 128k -pass 2 -vcodec libx264 -vpre slow -b BIT_RATE -bt BIT_RATE -threads 0 OUTPUT.mp4

Single-Pass Constant Rate Factor (CRF) Example

Or for a single pass CRF encode:

ffmpeg -i INFILE -acodec libfaac -ab 96k -vcodec libx264 -vpre slow -crf 22 -threads 0 OUTPUT.mp4

Related Reading

Also, see my x264 <-> FFmpeg option mapping and an externally maintained list of mappings with descriptions of what the options mean.

Those of you looking for the iPod/PSP information, I felt it was a little out of place here and have subsequently moved them to their own pages. | iPod guide | PSP guide |

86 Responses to FFmpeg x264 encoding guide

  1. Pingback: FFmpeg x264/mp4 Video Encoding auf Debian Lenny » Server » Debian Root

  2. akinso says:

    i have a very basic problem… and im a newbie so it becomes a big problem !!

    i want to write a code to just grab the basic info such as file type encoder bit rate duration .. etc !!! but again i want to use the ffmpeg library but not the application…how to use the avcodec lib !!!

  3. rob says:

    You may be interested in ffprobe. To use the library, you need to include the relevant public API headers in your C code and link the resultant binary for that code against the appropriate libraries. You can find more information about the FFmpeg APIs in the header files, the documentation on ffmpeg.org and in #ffmpeg on irc.freenode.net

  4. Pingback: iPad Streaming Video and More

  5. Pingback: Install FFMPEG correctly on ubuntu 9.0.4 ­ www.chaoman.com

  6. Pingback: Visualizing Your Project History with Gource — Takashi Yoshida's Blog

  7. Pingback: Vladimir Arvat » Blog Archive » FFmpeg and x264

  8. Pingback: Mythic Logos : ffmpeg

  9. Pingback: Weekly Digest for June 20th — Hello. My name is Václav Vančura.

  10. Pingback: Encoding Videos for a NWZ-E345 Sony Walkman (codecs already found)

  11. bmaxwell says:

    This page has been very helpful, thanks for having it up!

    I’m having a weird problem and I’m only finding scattered references to it on the web.
    I’m transcoding Flash flv files to x264 mp4 for use in HTML5 video tag stuff. All is well except in Safari where the video looks very dark.

    The file itself is fine, I can play it in VLC or the Chrome browser and it looks totally normal, but in Safari (which I guess uses quicktime for html5 video tag stuff) it looks dark. Another oddball thing to this is that if I open the new video file in the newest version of the Quicktime Player App (v 10.0) it looks fine (I’m guessing Safari uses a different version of quicktime as a plug in).

    I came across some people posting about the Quicktime gamma issue saying that flipping the “-flags2 +dct8x8″ to “-flags2 -dct8x8″ would fix it, but that didn’t do anything.

    I’ve been playing around with many different settings for ffmpeg x264 (using different presets, etc) and it never changes.

    Here’s my latest ffmpeg command:
    vid_options = “-vcodec libx264 -r 23.98 -b 1000k -flags +loop+mv4 -cmp 256 -partitions +parti4x4+parti8x8+partp4x4+partp8x8+partb8x8 -me_method umh -subq 7 -trellis 1 -refs 5 -bf 3 -flags2 +bpyramid+wpred+mixed_refs-dct8x8 -coder 1 -me_range 16 -g 40 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -qmin 10 -qmax 51 -qdiff 4 -vf ‘movie=0:png:#{WATERMARK} [logo]; [in][logo] overlay=10:main_h-overlay_h-10:1 [out]‘”

    system “/usr/local/bin/ffmpeg -i #{self.source_file} -an -pass 1 #{vid_options} -y #{self.watermark_file}”

    system “/usr/local/bin/ffmpeg -i #{self.source_file} -acodec libfaac -ab 128k -async 1 -pass 2 #{vid_options} -y #{self.watermark_file}”

    I’m using the newest dev version of FFMPEG that has libavfilter working so I can get a watermark on the video.

    Any help would be greatly appreciated, thanks!

  12. rob says:

    Please use the presets for encoding with x264 and only tweak options afterwards after you’re sure the changes do what you want. -flags +mv4 is redundant for libx264 and I don’t think -cmp 256 will do anything either, but I’m not certain on that one.

    I suspect the gamma issue is due to how the decoder that Safari is using is interpreting the colour space standard used for encoding. I know you aren’t conducting any benchmark, but point 1. “Screw up your colorspace conversions” from this article should explain a bit about what might be going on there.

    There may be a way to figure out what VLC and Chrome are assuming (Chrome uses a multi-threaded version of FFmpeg for decoding h.264) for decoding your video and indicate it to x264 so that it gets coded in the bitstream and respected (hopefully) by the decoder Safari is using. By default it isn’t written so the decoder has to decide. The options of interest are: -color_primaries, -color_trc and -colorspace but honestly I’m not sure what settings you need to use.

    However, Alexander Strange has said that maybe if you have Perian installed, Safari is using Perian for decoding and while he thinks he got that colourspace stuff right, maybe there are bugs in it. If you have Perian, try temporarily removing it and trying the video in Safari again. If Perian is the issue, please report the problem back to Alex.

    I hope that helps to at least point you in the right direction. :)

  13. Pingback: HOWTO: Install and use the latest FFmpeg and x264

  14. Robert,

    I’m quite interested in using x264 to encode some old football games that are taking up many gigabytes on my hard drive. But most of these games are in 1080i format, and I don’t want to try to deinterlace them in software—they look great when displayed using mplayer’s ‘bobdeint’ option, and I want to keep them interlaced. I’ve tried using the option -top -1, but the results I get are just OK. (This is with the ‘hq’ preset.) Any suggestions?

  15. rob says:

    I think you need to set ‘-flags +ildct’ so that it uses interlaced encoding modes in x264. If you need to specify the field order then FFmpeg will need hacking to pass this to x264. :)

  16. Felix says:

    Hi Rob,

    your site is really informative. Thanks!

    I noticed that you answered a comment on this thread just this morning, so am taking the opportunity to lay my troubles on you! :-)

    I have just purchased a Panasonic SD60 (1920/50i) recording in AVCHD 17Mbps VBR. I am using Ubuntu 10.04 on a quad core Opteron 2.1 GHZ system.

    The included Panasonic software, of course, only runs on Windows so I am trying to work out the best workflow for my movies on Linux.

    The first decision is what formats I need to have for direct viewing on the pc, editing and viewing on other devices in the future.

    The AVCHD MTS format that the camera produces seems to be very good at putting a high quality file in a small amount of space, but when playing it requires too much processing power and also displays interlace artifacts when I pause it.

    Therefore I need to convert it to something that the PC can play. I also need to keep a hiqh quality copy for future editing requirements. (This might as well be the original MTS due to its quality/space ratio)

    I have been testing the following:
    * Convert to DNXHD because apparently it is a good format for editing software, also the conversion removes the interlacing, and produces a format that can be played OK on my cpu. However, if I ask VLC to rotate the image through 90 degrees whilst playing (if I have turned the camera sideways) then the cpu cannot cope. (I guess I should do this during the ffmpeg conversion?)
    The resulting DNXHD file is at least twice the size of the original MTS file.

    ffmpeg -i $ORIGINAL -vcodec dnxhd -b 90Mb -deinterlace -acodec libmp3lame -r 25 $DNXHD
    (Btw using threads 0 when running this conversion causes the resulting file to be junk. I will report this if you think it is interesting)

    * Stage 2 convert to x264

    ffmpeg -i $DNXHD -an -pass 1 -vcodec libx264 -vpre slow_firstpass -b 36Mb -bt 36Mb -threads 0 $FINAL
    ffmpeg -i $DNXHD -y -acodec libmp3lame -pass 2 -vcodec libx264 -vpre slow -b 36Mb -bt 36Mb -threads 0 $FINAL

    The resulting x264 file is still twice the size of the original MTS and only 5% smaller than the DNXHD file. Also it displays blockiness when the image changes quickly.

    I suppose the desired benefit of an x264 file would be compatibility with many playback devices, and web video services that the other formats may not offer.

    To summarise, my goal would be to convert to HQ format suitable for viewing on PC, pausable without interlace artifacts, in a reasonable file size – if possible this would be a format that is widely compatible.

    Can you suggest a solution?

    Many, many, thanks

  17. Felix says:

    Rob,

    apparently 90Mb is not enough for top quality DNxHD.
    See http://www.itbroadcastanddigitalcinema.com/ffmpeg_howto.html#Encoding_VC-3

    I will try encoding the DNxHD at 180Mb and see what the results are.

  18. Felix says:

    Well, having encoded the DNxHD at 180Mb I now have a 754MB file for a 34 second video!
    When I play this there are a couple of freezes which may be caused by insufficeint CPU power, or may be part of the encoded video.
    I have then converted this to x264, using the previous command but with -b and -bt of 50Mb.
    This produces a file full of blockiness and incapble of playing back smoothly. it freezes half way through or when you try to jump ahead.

    I think I will now give up with using DNxHD as an intermediate file and experiment going directly from AVCHD to x264 either interlaced or non-interlaced.

    Still hope that you can give me some pointers! :-)

  19. Felix says:

    For viewing on a PC I am getting pretty good results with a single stage conversion from MTS to MPEG4:

    ffmpeg -y -an -i 00001.MTS -f avi -vcodec mpeg4 -b 8000000 -deinterlace -s 1280×720 00001.avi

    (This is without sound : -an)

    In what way is x264 better than MPEG4?

    Also, a question – looking at the ffmpeg x264 presets I notice that the following are present:

    libx264-baseline.ffpreset libx264-medium.ffpreset
    libx264-default.ffpreset libx264-medium_firstpass.ffpreset
    libx264-faster.ffpreset libx264-normal.ffpreset
    libx264-faster_firstpass.ffpreset libx264-placebo.ffpreset
    libx264-fast.ffpreset libx264-placebo_firstpass.ffpreset
    libx264-fast_firstpass.ffpreset libx264-slower.ffpreset
    libx264-fastfirstpass.ffpreset libx264-slower_firstpass.ffpreset
    libx264-hq.ffpreset libx264-slow.ffpreset
    libx264-ipod320.ffpreset libx264-slow_firstpass.ffpreset
    libx264-ipod640.ffpreset libx264-slowfirstpass.ffpreset
    libx264-lossless_fast.ffpreset libx264-superfast.ffpreset
    libx264-lossless_max.ffpreset libx264-superfast_firstpass.ffpreset
    libx264-lossless_medium.ffpreset libx264-ultrafast.ffpreset
    libx264-lossless_slower.ffpreset libx264-ultrafast_firstpass.ffpreset
    libx264-lossless_slow.ffpreset libx264-veryfast.ffpreset
    libx264-lossless_ultrafast.ffpreset libx264-veryfast_firstpass.ffpreset
    libx264-main.ffpreset libx264-veryslow.ffpreset
    libx264-max.ffpreset libx264-veryslow_firstpass.ffpreset

    Many of these offer a firstpass option, but the following do not:
    baseline, default, hq, ipod, lossless, main, max, normal.

    Can these be used in 2 pass mode?

    Secondly, the following presets with very similar names exist:

    libx264-slow_firstpass.ffpreset libx264-slowfirstpass.ffpreset
    libx264-fast_firstpass.ffpreset libx264-fastfirstpass.ffpreset

    Are these all meant to exist?

    Thanks

  20. rob says:

    Felix: your first order of business should be to compile both FFmpeg and x264 from source, or at least get recent versions of them.

    Some of those presets you listed are outdated. If you read the guide, you will see which ones are not. If want to do two-pass encoding with x264, I would recommend using the fastfirstpass variant of your chosen preset for the first pass of encoding and then the normal variant in the second pass, as per the guide.

    As for deinterlacing – FFmpeg’s deinterlacing just blends as far as I know. There are much better quality deinterlacers available such as yadif an mcdeint. See this link for details. mplayer -vf pp=fd is the same as ffmpeg … -deinterlace …

    Your first port of call should be to try ffmpeg-mt for decoding – it offers multi-threaded H.264 decoding and so you may be able to play back your 1080i/50 AVCHD files in realtime without conversion.

    git clone git://gitorious.org/~astrange/ffmpeg/ffmpeg-mt.git
    cd ffmpeg-mt
    git clone git://git.ffmpeg.org/libswscale/
    and then compile your ffmpeg as usual. Then to use it, use ffplay -threads 4 <input file> But maybe you’ll want the better deinterlacers that are in mplayer. There are guides around the web for compiling a version of mplayer with ffmpeg-mt.

    Also, one thing to note. When converting, unless you have a good reason to go via some lossless format it is always better to encode directly to your desired output format than to use an intermediate lossy format. Unless you have to for editing purposes.

    I hope that helps. :)

  21. johnbuuck says:

    The only ffpreset files I have seen have been for x264 encoding. I have tried putting ffmpeg options in an ffpreset file for use with other codecs and always get an invalid syntax error. Can you confirm that ffpreset files only work for x264 encoding? If not, could you give an example of an ffpreset file used for flv encoding?

  22. rob says:

    Can you show me both the preset file you’ve created and the FFmpeg command line that are being problematic? I may be able to advise you once I see that.

  23. prince1248 says:

    Hi Rob,
    I’m trying to use FFMPEG to encode a live webcam stream over RTP. Is it possible to give RTP input directly to FFMPEG? Given below is the command that I’m using :

    ffmpeg -i rtp://172.16.0.100:1234 -acodec libfaac -ab 96k -vcodec libx264 -b 500kb -crf 22 -threads 0 OUTPUT.ts
    Using the above command i see nothing happening. Please help.
    Thanks,
    Suman.R

  24. prince1248 says:

    I’m using Vlc player and RTP protocol to capture the webcam video and then trying to input the RTP address to FFMPEG as given in the above post of mine.
    Thanks,
    Suman.R

  25. rob says:

    RTP is supported:

    $ ffmpeg -protocols | grep rtp
    IO. rtp

    For your stream, what is the output of:
    $ ffmpeg -i rtp://ip:port

    That should give a summary of the input.

  26. Suman Ramineni says:

    Hi Rob,
    Thanks for the reply.
    Here is the actual scenario i’m working on. The webcam is connected to the windows machine. On the windows machine i’m using vlc and RTP to capture the stream and using vlc unicast i’m sending the stream to the server which is a Linux machine .Given below is the generated stream output string for vlc:
    :sout=#transcode{vcodec=h264,vb=800,scale=1,acodec=mp4a,ab=128,channels=2,samplerate=44100}:rtp{dst=Server ip,port=5004,mux=ts}
    On the Linux server i have ffmpeg which takes the stream as input and pipe the ffmpeg output to a segmenter so that the stream can be split into small intervals and a playlist file can be obtained that can be used to play on iPhone.
    Coming to ur suggestion when i did $ ffmpeg -i rtp://ip:port for my stream i got the following on the console:
    FFmpeg version 0.6, Copyright (c) 2000-2010 the FFmpeg developers
    built on Jul 27 2010 18:33:04 with gcc 4.1.2 20080704 (Red Hat 4.1.2-48)
    configuration: –enable-gpl –enable-nonfree –enable-pthreads –enable-libfaac –enable-libfaad –enable-libmp3lame –enable-libx264
    libavutil 50.15. 1 / 50.15. 1
    libavcodec 52.72. 2 / 52.72. 2
    libavformat 52.64. 2 / 52.64. 2
    libavdevice 52. 2. 0 / 52. 2. 0
    libswscale 0.11. 0 / 0.11. 0
    Its just the information of the ffmpeg installation.I cant see anything more than this.
    Sorry if i’m not so clear in my explanation. I’m pretty new to this. Any help will be appreciated.
    Thanks,
    Suman.R

  27. rob says:

    I meant to issue the following command in your terminal:

    ffmpeg -i rtp://172.16.0.100:1234

    Assuming that the server’s IP and port are still correct.

  28. Suman Ramineni says:

    Hi rob,
    I understood what you are saying and i did just that
    ffmpeg -i rtp://Myserver ip(174.121.223.170):Portnumber(5004)
    But i dont see anything apart from the ffmpeg installation information.
    Thanks,
    Suman

  29. Suman Ramineni says:

    and do we have to follow any set of rules while selecting the port number????? I’m just using random numbers!!!!!

  30. rob says:

    The port should be configured by the server (VLC). I don’t know if they have any defaults but check the VLC configuration.

  31. Rob,

    For the time being I’ve given up on deinterlacing, but I have a new problem which I think is purely an ffmpeg problem. I’ve got about 20GB worth of MPEG2-TS split into approximately 30 files. My goal is to transcode this material at 3 or 4 Mb/s to fit it onto a single DVD. (I have temporarily given up on retaining interlaced 1080i content; I’m reducing 1080i content to 720p and using the ffmpeg -deinterlace option. The results are good enough for now.)

    Here’s my difficulty: the source of the MPEG2-TS files is an ATSC broadcast stream, and it’s carrying two video streams and 3 audio streams. The numbering of streams is not always consistent, so if I have files a.ts and b.ts, it’s quite possible that the video I want is stream 0 in the first file and stream 2 in the second file. I thought I would be able to use ffmpeg’s -map option to say just what stream to take from what input file, but it doesn’t work the way I thought. And indeed, I can’t find any way to get this done. Do you know either (a) how to specify which streams to take from each of multiple input files, or (b) if I transcode each file separately, how to concatenate a bunch of .mkv files with h264 video and faac audio, without having to re-encode? (The thought of concatenating the MPEG-2 TS files gives me shivers, as it sucks up an extra 20GB and a fair amount of time as well.)

  32. rob says:

    What was the problem with using the ildct flag for encoding in an interlaced fashion (MBAFF – Macroblock-Adaptive Frame Field coding) with libx264?

    If you need to select streams, you’ll have to process each individually, which sucks. Unless you can ffmpeg -i INFILE for each file and consistently identify the streams you want in some way such that you could script it. The way the -map option works is as follows: each -map option picks the specified stream from the input and makes it the next stream in the output counting from 0. So, -map 0.5 -map 0.2 -map 0.4 will do (if 1.x represents stream x of the output) 0.5 -> 1.0, 0.2 -> 1.1 and 0.4 -> 1.2.

    I was wondering if the streams were consistently flagged in some way, I mean, your TV must know which to select somehow. Why are there two video streams? I’m not sure but perhaps ffmpeg only deals with one video stream by default, maybe you’re lucky and it chooses the right one.

    I’m not sure FFmpeg’s mpeg-ts muxer is so good yet either which is a shame as MPEG2-TS is probably the best format for concatenating, theoretically. If you can get the streams to be just the streams you want in some consistent fashion (i.e. in the same order in all files) then you can do cat file01.ts file02.ts file03.ts ... | ffmpeg -i - ....

  33. Suman Ramineni says:

    Hi Rob,
    I have found out a solution for my streaming problem. Now I’m actually able to catch the webcam stream using ffmpeg on the server and save the output .ts fil. Here is the modified command that worked for me
    ffmpeg -i rtp://174.121.223.170?localport=1234 -acodec libfaac -ar 48000 -ab 64k -vcodec libx264 -vpre slow -b 128k -s 320×240 -f mpegts output.ts
    However,the quality of the output .ts file is pretty bad. I can hardly see my webcam stream playing. Can you please suggest me the bitrates and other values that are to be used for better quality of the picture?
    Thanks,
    Suman.R

  34. rob says:

    Well the command line looks OK, but add ‘-threads 0′ to use libx264 in multi-threaded mode so it can capitalise on the cores you have. Depending on your system and what else the system is doing, it may well be that the encoding can’t keep up.

    Ideally you would want to ‘dump’ the rtp streams to a file without transcoding while you’re capturing and then transcode later. But if you have to transcode on-the-fly and -threads 0 doesn’t solve it, try a faster preset. And you probably want to use a higher bitrate for the video, perhaps try something around ~250kbps and see if that’s good enough quality.

  35. keith says:

    Thanks for the great guide Rob!

    I was wondering if you could explain how the different presets correspond with the MIME types which should be used for the generated videos. It looks like there are two parts to the video component of the complete MIME type: profile and AVC level (http://wiki.whatwg.org/wiki/Video_type_parameters).

    If I am using the “hq” preset to encode a video, does that correspond to the H.64 “High” profile? How do I determine what the AVC level is?

    Any insight would be greatly appreciated.

    Thanks :)

  36. rob says:

    The presets don’t constrain the H.264 Profile, except for the main and baseline presets. Unless you’re specifying the main or baseline presets, you’re using High Profile. The level is dependent on the resolution, frame rate and bit rate. See here for more details.

    It’s not so easy to find out what the level is after you’ve encoded a file, but you can apply restrictions and set the level at encode-time using the -bufsize -maxrate and -level options.

Leave a Reply