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.
UPDATE, 2010-01-10: see this article for more details related to high-bitrate MPEG-2 encoding.
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. You can see the artifacts in the following images (click on the images to see the full-size versions, where the artifacts are very obvious):
View the MPEG-2 clip.
Note: this example in this article uses a snapshot of the ffmpeg subversion code from September 10, 2009.
Here’s the command line I started with:
1 2 3 4 5 6 7 |
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.mpg |
First, we’ll go through these options and then we’ll talk about what I changed to get better results.
Video options
Let’s go through the various options to control the video encoding.
1 |
-vcodec mpeg2video |
This instructs ffmpeg to use MPEG-2 video encoding
1 |
-pix_fmt yuv420p |
For 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)
1 |
-me_method epzs |
ffmpeg’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.
1 |
-threads 4 |
ffmpeg’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.
1 |
-r 29.97 |
MPEG-2 must be either 25 or 29.97 frames per second; no other frame rates will work.
1 |
-g 15 |
use a GOP size of 15, a very standard GOP size
1 |
-s 704x396 |
Output a frame size of 704×396
1 |
-b 2500k -bt 300k |
2.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 options
Now a look at the audio options:
1 |
-acodec mp2 |
use 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)
1 |
-ac 2 -ab 192k -ar 44100 |
Output 2-channnel audio at 192Kbps and a 44100 Hz sampling rate.
1 |
-async 1 |
Use audio/video sync method 1 (I always use this audio sync method).
Output options
Finally, have a look at the output options:
1 |
-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 quality
Now 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-frames
Adding B-frames seemed to give the most bang for the buck.
1 |
-bf 2 |
this 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)
Stills:
Sample video:
Rate distortion optimal quantization
1 |
-trellis 2 |
rate-distortion optimal quantization; this cleans up the bulk of the artifacting that remained after enabling B-frames.
Stills:
Sample video:
Pel ME Compare Function
1 |
-cmp 2 -subcmp 2 |
Explicitly 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.
Stills:
Sample video:
GOP Size
1 |
-g 45 |
use 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.
Stills:
Sample video:
Final command-line
Here is the final command I used:
1 2 3 4 5 6 7 |
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.mpg |
please is there a way to intergrate all you said in a web app ?
sorry i am still a new to this and i have been given a school projet realtime streaming and i intend to use ffmpeg for realtime encoding and display it with a web app.but for the moment i am stuck after multiple reseach in the internet.
please i realy need help
This article is pretty old and really doesn’t apply to current ffmpeg versions. You also wouldn’t use MPEG2 for a streaming application.
You want to encode to h264, and you probably want to stream via HLS, which is supported by almost all current browsers (either directly or with Javascript extensions) with the exception of MSIE 11 and below. For MSIE, you need to use RTMP streaming along with a flash-based player.
I think this article is a good overview of how to do that.