MPEG-2 encoding with ffmpeg
I’ve done some significant experimentation with different options for encoding MPEG-2 video from a live video source with ffmpeg. The objective was to create video that was approximately 3 Mbps at a “decent” resolution; this video would be manually edited and then converted to Web quality. By “decent”, I mean a high enough resolution so that the video can survive the transcode to Web resolutions without too many re-encoding artifacts. When encoding a live source, performance is critical; if ffmpeg can’t keep up with the live frames being captured, you may as well not even try to encode the video; your live capture buffers will quickly fill up and bring down your encoding system. Obviously, you can’t use any sort of two-pass encoding, either.
In my tests of real-time encoding, I encountered one particular transition that was very difficult for ffmpeg to encode without artifacts. I use this as a worst-case scenario for testing various settings of the MPEG-2 encoder.
Here’s the command line I started with:
ffmpeg -i test.mp4 \ -vcodec mpeg2video -pix_fmt yuv420p -me_method epzs -threads 4 \ -r 29.97 -g 15 -s 704x396 -b 2500k -bt 300k \ -acodec mp2 -ac 2 -ab 192k -ar 44100 \ -async 1 \ -y \ -f vob output.mpgFirst, we’ll go through these options and then we’ll talk about what I changed to get better results.
Video optionsLet’s go through the various options to control the video encoding.
-vcodec mpeg2videoThis instructs ffmpeg to use MPEG-2 video encoding
-pix_fmt yuv420pFor convenience, I wanted to be able to play the video in QuickTime (with the MPEG-2 Playback Component). I found that QuickTime could not play yuv422p MPEG-2 (YUV 4:2:2 Planar), but it can handle yuv420p (YUV 4:2:0 Planar)
-me_method epzsffmpeg’s mpeg2video encoder only supports “zero” and “epzs” as motion estimation methods; you could omit this option and go with the default, but as a word of warning, if you are outputting to one or more additional codecs (e.g. MPEG-4), you might be using another motion estimation method, and without an explicit motion estimation method specified for the mpeg2video encoder, ffmpeg will try to use the same motion estimation method used by the other codec, and it will fail. Better to be safe here and explicitly specify the me_method.
-threads 4ffmpeg’s mpeg2video encoder does not do automatic thread detection, so I set this to 4 because I’m working on a 4-core machine; you could omit this option, but if you’re outputting to one or more codecs, and you’re using -threads 0 with another codec, ffmpeg will try to use the automatic thread detection on the MPEG-2 output, and it will fail.
-r 29.97MPEG-2 must be either 25 or 29.97 frames per second; no other frame rates will work.
-g 15use a GOP size of 15, a very standard GOP size
-s 704x396Output a frame size of 704×396
-b 2500k -bt 300k2.5 Mbps with tolerance of 300k; the mpeg2video codec requires that the tolerance be “large enough” for the bitrate (so you can’t set a 10k tolerance on a 3Mbps bitrate, for example); a larger tolerance had some effect on video quality, but nothing near the -bf 2 effect.
Audio optionsNow a look at the audio options:
-acodec mp2use MPEG-1 layer II audio (you could use ac3, mp3, or libfaac instead, but that might cause some compatibility issues — I don’t believe that DVD VOBs can contain AAC audio, for example)
-ac 2 -ab 192k -ar 44100Output 2-channnel audio at 192Kbps and a 44100 Hz sampling rate.
-async 1Use audio/video sync method 1 (I always use this audio sync method).
Output optionsFinally, have a look at the output options:
-f vob 'test-vob-b3000-bt500-704x396-yuv420p-g45-bf2-trellis2-cmp2.mpg'Use the VOB output format; don’t be tempted to use the mpeg2video format — you won’t get any audio track.
Improving the qualityNow lets look at how we can improve the quality, especially during that horrible transition. The command-line options here are the result of a lot of experimentation.
B-framesAdding B-frames seemed to give the most bang for the buck.
-bf 2this inserts two B-frames between each P frame; ffmpeg’s default is to use no B-frames at all; Using B-frames made very noticeable differences in video quality while also reducing file size (many artifacts were removed).
Rate distortion optimal quantization -trellis 2rate-distortion optimal quantization; this cleans up the bulk of the artifacting that remained after enabling B-frames.
Pel ME Compare Function -cmp 2 -subcmp 2Explicitly specify the full pel me compare function, sub pel me compare function; this seems to pick up any tiny bits of artifacting after -trellis 2; important to note that on its own, this does not make the video quality improvement that -trellis 2 does.
GOP Size -g 45use a GOP size of 45; this made a noticeable improvement in the quality. The impact is comparable to the impact I saw from adding -trellis 2 to the command-line options.
I’ve seen recommendations about going up to -g 100, but I’ve also read that some decoders might have trouble with very large GOP sizes, which could make it hard/impossible to use the resulting video with some editors.
Final command-lineHere is the final command I used:
ffmpeg -i test.mp4 \ -vcodec mpeg2video -pix_fmt yuv420p -me_method epzs -threads 4 \ -r 29.97 -g 45 -bf 2 -trellis 2 -cmp 2 -subcmp 2 -s 704x396 -b 2500k -bt 300k \ -acodec mp2 -ac 2 -ab 192k -ar 44100 \ -async 1 \ -y \ -f vob output.mpgSursa
2011-03-31 21:46:04