x264 Encoding Guide

Updated: May 29, 2011.

If you've found this guide helpful, please consider making a donation.

To get started you need to install the latest version of mplayer, x264, ffmpeg and neroAacEnc.

Using FFmpeg or mencoder to handle everything is convenient but you gain more control and get better results by breaking down the steps and using the best tool for that specific job.

Encoding the video

In order for x264 to encode the video stream we must first decode our source video stream with mplayer, convert it to a (lossless) yuv4mpeg stream, or y4m for short, and pipe it to x264 as input. 

    Step 1a
      $ mplayer -nosound -benchmark -vo yuv4mpeg:file=>(x264 --demuxer y4m --crf 20 --threads auto --output output.264 - 2>x264.log) star-wars.mkv

      The above command is a very basic example just to show how the process works. It's not intended to be used.

      In this command we specify mplayer's input file star-wars.mkv, convert the input video stream to y4m and pipe the stream to a subshell running x264 with -vo yuv4mpeg:file=>(x264 ...), ignore the audio -nosound (we'll deal with audio encoding in Step 2) and perform faster than realtime -benchmark. At the same time running in a subshell we have x264 with --demuxer y4m to correctly demux the stdin from mplayer, --crf 20 to enable constant quality mode, --threads auto enables parallel encoding, --output output.264 outputs the raw h264/avc bytestream to output.264 (this is the encoded video), - is the pipe that mplayer is feeding y4m to and x264 is reading as input, 2>x264.log sends the terminal output from x264 to x264.log (you can open another terminal and monitor x264's progress with tail -f x264.log).

      For more info see x264 --fullhelp | less and man mplayer.

    Step 1b
      Here's another example that's more advanced. This is how I encode video for my iPhone.

      $ mplayer -nosound -benchmark -sws 9 -vf dsize=480:320:0,scale=0:0,expand=480:320,dsize=1.5 -vo yuv4mpeg:file=>(x264 --demuxer y4m --crf 20 --preset slow --profile baseline --level 30 --vbv-bufsize 10000 --vbv-maxrate 10000 --threads auto --output output.264 - 2>x264.log) star-wars.mkv

      In the above command I set the lanczos scaler algorithm with -sws 9 to be used when scaling the video down. It's slower than mplayer's default scaler but if quality is your main concern then I recommend using it. -vf dsize=480:320:0,scale=0:0,expand=480:320,dsize=1.5 is the video filter chain that scales the video to 480x320 while maintaining the original aspect ratio and adds padding to the top and bottom or left and right and sets the aspect ratio to 1.5 (480/320).

    Step 1c
      Let's say you want to encode some anime for your phone, ps3 or whatever but you need to hardsub the subtitles because your device doesn't support loading softsubs and you haven't learned Japanese yet, slacker. In case you don't know, hardsubbing is encoding the subtitles into the video stream.

      $ mplayer -nosound -benchmark -fontconfig -font 'Sans:style=Bold' -subfont-outline 2 -subfont-text-scale 2.1 -sub-bg-alpha 0 -subfont-blur 0 -sub-bg-color 0 -sws 9 -vf dsize=480:320:0,scale=0:0,expand=480:320,dsize=1.5 -vo yuv4mpeg:file=>(x264 --crf 20 --preset slow --profile baseline --level 30 --vbv-bufsize 10000 --vbv-maxrate 10000 --threads auto --output output.264 video.y4m 2>x264.log) anime.mkv

      You can adjust the size of the font by increasing/decreasing the value in -subfont-text-scale 2.1. If you want to use a different font, you can get a list by running fc-list | sort | less.

      Note: If you want to hardsub advanced sub station styled subtitles, or ass for short, remove all the -sub* options along with -font 'Sans:style=Bold' and add -ass. Most of the time I think they look like ass, har har.

    Step 1d
      Deinterlace PAL dv, double the frame, scale to 4/3 aspect ratio and pipe to x264. MPlayer can't change the frame rate so we use mencoder. The results will look pretty good!

      mencoder input.PAL.dv -of rawvideo -ofps 50 -ovc raw -vf yadif=3,mcdeint=2:1:10,scale=768:576,format=i420 -nosound -really-quiet -o - 2>/dev/null | x264 --demuxer raw --crf 20 --threads auto --fps 50 --input-res 768x576 --output output.264 -

    x264 levels and profiles

      Most devices only support up to specific level and one or more profiles. Levels define the max macroblocks per second, max frame size (macroblocks) and max video bit rate. Profiles define the h264 capabilities that can be used, such as b frames and CABAC. The H264 wikipedia page lists all the levels and profiles. Update: x264 now has presets and profile settings. x264 --fullhelp | less for more info.

        iPhone, iPod 5.5G
          --level 30 --profile baseline --vbv-bufsize 10000 --vbv-maxrate 10000

          --level 1.3 --no-cabac --vbv-bufsize 768 --vbv-maxrate 768

          --level 2.1 --vbv-bufsize 4000 --vbv-maxrate 4000

          --level 30 --no-cabac --vbv-bufsize 10000 --vbv-maxrate 10000

          --level 3.1 --no-cabac --vbv-bufsize 14000 --vbv-maxrate 14000

          --level 4.1 --vbv-bufsize 62500 --vbv-maxrate 62500

Encoding the audio

The audio will be handled much like the video. mplayer will be used to convert the audio to wav and pipe it to neroAacEnc inside the subshell.
    Step 2

    $ mplayer -nocorrect-pts -vo null -vc null -ao pcm:fast:file=>(neroAacEnc -ignorelength -lc -q 0.6 -if - -of audio.mp4 2>nero.log) start-wars.mkv

    The flag -nocorrect-pts gets around the "Too many buffered pts" bug in mplayer, -vo null -vc null ignores the video, -ao pcm:fast:file=>(neroAacEnc ...) pipes the wav to the subshell running neroAacEnc and start-wars.mkv is our input. Inside the subshell we set -ignorelength because neroAacEnc is reading from a pipe, -lc forces the use of the LC AAC profile (supported by most devices), -q 0.6 enables target quality mode (vbr), -if - specifies the pipe from mplayer as the input, -of audio.mp4 outputs the encoded aac audio to audio.mp4, 2>nero.log sends the console output to nero.log (open another terminal and run tail -f nero.log to monitor its progress).

    See neroAacEnc -help 2>&1 | less and man mplayer for more info.

Muxing into the container

    Step 3

    Remember to use the fps from your source video.

    $ MP4Box -fps 25 -add output.264 -add audio.mp4 star-wars.mp4