-
What does FFmpeg’s ’-target pal-dvd’ actually do, and how can we modify it to fit output onto a single-layer DVD?
This isn’t really a programming task, but more something that’s bugged me so I decided to do some digging for an answer. FFmpeg has a command-line parameter -target, which allows you to specifically say that your output is for things like DVD, or VCD. The targets then include prefixes for display type/TV format. You end up with -target pal-dvd etc. The same goes for NTSC with ntsc-dvd. You get the idea.
The man page doesn’t detail what these options actually do though, other than some vague message about it setting options for you, and my current issue is with pal-dvd making files around 6 GiB in size, i.e. far bigger than the 4.38-ish GiB that we can fit on a single-layer DVD. So what options is it setting behind the scenes, and what can be changed to reduce the file size?
The -fs (maximum file size) option can be a little misleading, doing nothing more than truncating the output stream when it reaches the limit. It doesn’t alter the actual bit rate at which we’re encoding. But we should look at what options we’re setting with -target to both understand what’s going on generally, and to see what bit-rate options are being set so we can take back control.
Downloading the latest repo commit (7e5cbb3), a little look inside ffmpeg.c eventually reveals a function:
static int opt_target(OptionsContext *o, const char *opt, const char *arg)
That looks very promising. Inside this is the following code. Don’t forget that in C (and a few other languages), if two strings match strcmp returns 0, which is the same as boolean false. That’s why we can say if (!strcmp(x,y))
else if(!strcmp(arg, "dvd")) { opt_video_codec(o, "c:v", "mpeg2video"); opt_audio_codec(o, "c:a", "ac3"); parse_option(o, "f", "dvd", options); parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options); parse_option(o, "r", frame_rates[norm], options); parse_option(o, "pix_fmt", "yuv420p", options); opt_default("g", norm == PAL ? "15" : "18"); opt_default("b:v", "6000000"); opt_default("maxrate", "9000000"); opt_default("minrate", "0"); //1500000; opt_default("bufsize", "1835008"); //224*1024*8; opt_default("packetsize", "2048"); // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack. opt_default("muxrate", "10080000"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8 opt_default("b:a", "448000"); parse_option(o, "ar", "48000", options); }This gives us all of the options that -target [pal|ntsc]dvd sets. Let’s look at them one by one:
- -c:v and -c:a - These are setting MPEG2 and AC3 as video and audio codecs respectively. You could probably swap this out to -c:a pcm_s16le if you wanted PCM instead.
- -f dvd - Force FFmpeg to package the output stream as a DVD-VOB-style file.
- -s [720x576|720x480]] - The prefix of the target is set as norm earlier on in some omitted code, and this uses it to set the PAL video size of 720x576px or x480px if NTSC.
- -r [25|29.97] - Frame rate. Again, looked up in an array. 25fps for PAL, 29.97 for NTSC. Well, actually, 29.9700299… for NTSC, which is defined as (30000/1001). Not sure whether a terminal will let you pass in a computed value like this. Perhaps a script could work it out then pass it in.
- -pix_fmt yuv420p - Set the colour space and pixel format appropriately. Don’t ask.
- -g [15|18] - The GOP size, i.e. the number of frames following and including each I-frame. PAL = 15, NTSC = 18 here, although I would expect to see PAL = 12, NTSC = 15. In almost every case this will make no difference whatsoever, so why not go with what FFmpeg settled on?
- -b:v 6000000 - Ah, setting the video bit rate to 6Mbps. This is probably what we’ll need to change ;-) More on this in a minute.
- -maxrate 9000000 - Setting an upper limit on video bit rate. The spec allows us to make DVDs with a total A/V rate of around 9.8Mbps. When we look at the audio rate below, a nice round number of 9Mbps is probably sensible here, but for best compatibility I’d probably set it to around 8Mbps or a little lower.
- -minrate 0 - You can see that the minimum video bit rate has a comment next to it, suggesting 1.5Mbps may be a more sensible value here. Spec has somewhere around 1Mbps as minimum.
- -bufsize 1835008 - VBV size. How much a reader is required to buffer in memory for playback. Defined in spec, so leave this alone.
- -packetsize 2048 - The code has a nice little explanation that DVD packet size is identical to sector size. Great, we’ll just set that then.
- -muxrate 10080000 - We can support a maximum of 10.08Mbps *payload* bitrate in the standard (though as before, A/V is less) so it makes sense that we set the upper mux rate limit to this.
- -b:a 448000 - An audio bit rate of 448kbps seems potentially a little high for most purposes. You could likely reduce this if you don’t need such quality, but it still beats PCM for file size. Regardless, you’ll need this value to calculate your video bit rate later, so make a note of whatever you set it to.
- -ar 48000 - An audio frequency of 44.8kHz is pretty standard on DVDs. If you change your bit rate significantly, perhaps ensure that your chosen frequency is available at it for AC3. Generally you’ll leave this alone.
Great, so we’ve rifled through the options and have a general understanding about what the target parameter is setting. The main thing we’re going to want to change is our (average) bit rate. To do this, we need to work out what we can set it to, given the audio rate, the length of content we’re encoding, and what our file size restriction is.
There’s a nice calculator for this over at 3ivx that has fields for just this. For simplicity’s sake, you may choose to enter 4400MB as the file size, equivalent to just under 4.3GB, giving us room for a) overheads, and b) any overshoot by the encoder, though this should be mitigated by a 2-pass encode that we’ll do. My footage to encode is 2:11:52, and I’ll set the audio bit rate as 448kbps. This gives me a video bit rate of just over 4100kbps.
Now for the two-pass encoding. In a first pass, the encoder will analyse the source video to determine what parts require higher bit rates, and save this information to a temporary log file. If you don’t do this, a single-pass encode will allow a little leeway each side of the average, but will be less than optimal. A second pass then uses the previously generated information to best distribute the file size across the source during an encode.
We need to call ffmpeg twice, once for each pass. We don’t need all of the parameters we found above when doing the first pass. In all honesty, I’m not sure what of the parameters below can also be omitted. But, say your input file is input.avi and your calculated bit rate is 4100k, the line below will perform the first pass and generate your log file. Note that for both of the commands below you can probably just use -target pal-dvd and override the parameters you want to change by appending them afterwards. I suspect that -an for example will overwrite any audio settings that the target parameter sets.
ffmpeg -i input.avi -c:v mpeg2video -f dvd -s 720x576 -r 25 -pix_fmt yuv420p -g 15 -b:v 4100k -maxrate 8000000 -minrate 0 -bufsize 1835008 -packetsize 2048 -pass 1 -an -y NUL
Note that the output here is NUL on a Windows system. Unix users can replace it with /dev/null. The parameter -an is used to specify no audio output (saves any processing), and -y just says it’s fine to overwrite the output, which is null anyway.
The second pass is the actual encoding. Here’s the command for 4100k encoding, from input.avi to output.mpg:
ffmpeg -i input.avi -c:v mpeg2video -c:a ac3 -f dvd -s 720x576 -r 25 -pix_fmt yuv420p -g 15 -b:v 4100k -maxrate 8000000 -minrate 0 -bufsize 1835008 -packetsize 2048 -muxrate 10080000 -b:a 448000 -ar 48000 -pass 2 output.mpg
I actually had a 6ch AC3 stream of about 384kbps that I was able to copy using -acodec copy instead of re-encoding here. My output file ended up at about 4.21GiB, which is less than the calculations said it would be but not by much. Still, less is better than more in terms of fitting it on media. Next comes authoring the DVD.
If you have Nero or some program like that, your MPEG file is now compatible and should be burnable with no transcoding. If you want to do it through the command line (perhaps as part of a script), grab yourself dvdauthor. The latest win32 binaries are in this directory. They’re a little old, but they should do the job. Otherwise, there’s source files for the most recent version, and they’re dotted around the net precompiled too. Make a .xml file with the following in it, replacing output.mpg with whatever your file is called:
<dvdauthor> <vmgm /> <titleset> <titles> <pgc> <vob file="output.mpg" /> </pgc> </titles> </titleset> </dvdauthor>Now call it from the command line with the following to create a directory called outdir with your DVD files in, where your XML file is struct.xml.
dvdauthor -o outdir -x struct.xml
Voila! A set of DVD files ready for burning. Check that it works, then you can delete your intermediate MPEG file.
-
acceptable-stain liked this
cinecharlie reblogged this from todayiwantedtoprogram
cinecharlie liked this
alecitas-blog liked this
jacksonloner liked this
todayiwantedtoprogram posted this