Gnuritas

jun 20, 2014

Video Processing and Encoding

For a couple of years there have been a number of great open-source programs around for encoding video, both in Windows and (Ubuntu) Linux. Some of them provide a nice graphical user interface, but the best ones are still commandline tools, such as ffmpeg and MEncoder. They are extremely flexible, but unfortunately also have a bewildering number of commandline options. This page lists a few invocations I regularly use.

Extracting DVD titles

To extract a single title from a DVD, first copy the DVD to harddisk:

dvdbackup -M

Next, use totem or vlc (under Plackback->Title) to find out the number of the title you want. For our example we’ll assume that the DVD files are in a directory called DVD_VOLUME/ and that we want the second title. Finally, copy the title to a separate file using mencoder:

mencoder -dvd-device DVD_VOLUME/ "dvd://2" -ovc copy -oac copy -of mpeg -o title_2.mpeg

This will create an MPEG2 file containing just the title you specified. You can of course select a different container format with the -of parameter, or a codec other than copy to transcode the file. To leave out audio, use -nosound instead of -oac copy.

Cutting/selecting part of a video

With the options -ss and -endpos you can tell mencoder to process only a part of the input file. Note that mencoder can currently only split streams on keyframes, and the position used with -endpos is relative to the start of the output, not the input (so it’s perhaps more logical to think of it as “duration”). Here’s an example:

mencoder -ss 05:30 -endpos 12:45 -oac copy -ovc copy input.avi -o output.avi

You may want to consider avidemux for a more user-friendly alternative (which is also more flexible when it comes to cutting frames) .

Fast MPEG-4 encoding with FFmpeg

I recently needed to rapidly transcode a HDTV-quality H.264 file into MPEG4, so I could play it decently on an ancient Xbox. The following worked very well, and finished the job in no-time on my multi-core machine:

ffmpeg -i input.mp4 -vcodec mpeg4 -threads 2 -b 1500k -acodec libmp3lame -ab 160k output.avi

Or if the audio was already fine:

ffmpeg -i input.mp4 -vcodec mpeg4 -threads 2 -b 1500k -acodec copy output.avi

Encoding DVD-compliant MPEG-2 video

Check out Eric Olson’s page on this subject, and his automated encoding script. I could not get it to encode MP2 audio under Ubuntu Lucid out-of-the-box, so I used twolame to encode the audio separately. For authoring a DVD, I found DVDStyler to work quite nicely, at least once you figure out the somewhat awkward user-interface… But at least it doesn’t try to re-encode your videos when they’re already in the right format.

See also:

Extracting audio from a video file

You can do this with FFMPEG by specifying -vn to disable video. You can use any output format and codec, but for best results don’t reencode (-acodec copy) and choose an output file-format that matches the audio codec used in the video file. You can use e.g. mplayer or ffprobe to check whether the audio track is AAC (use .aac / .m4a / .mp4 for output), MP3 (use .mp3), MP2 (use .mp2), PCM (use .wav or .flac) or something else. If in doubt, use FLAC output for lossless encoding without huge files. Use -acodec pcm_s16le if you want uncompressed .wav files. Some examples:

ffmpeg -i input.flv -vn -acodec copy output.m4a

ffmpeg -i input.avi -vn output.flac

Note that you can tag MPEG-4 files using neroAacTag.

Encoding interlaced PAL DV to H.264

If you want to archive interlaced 4:3 PAL DV material without wasting too much disk-space or losing too much quality, try encoding it to interlaced H.264. Use a recent version of x264, e.g. from ppa:jon-severinsson/ffmpeg or ppa:motumedia/mplayer-daily. If quality is important, try the following:

x264 --bff --sar 12:11 --threads auto --preset veryslow --crf 20 -o output.mp4 input.avi

Increase the CRF to 23-25 for smaller but slightly lower-quality files, and change the preset to slower, slow or medium to increase the encoding speed at the cost of some quality and/or size.

x264 does not encode audio, so you’ll need to encode it separately (e.g. ffmpeg -i input.avi -vn output.flac)
and then multiplex. For audio encoding, you could also use an external encoder, such as the Nero AAC encoder or LAME (for mp3).

Multiplexing with ffmpeg is easy, for example:

ffmpeg -i video.mp4 -i audio.m4a/mp3/flac/wav -vcodec copy -acodec copy output.mp4

You’ll probably want to combine the entire operation into a shell-script. Something like:

#!/bin/bash

in=$1
out=$2
subdir=

if [ -z "$1" ]; then
  echo "Usage: $0 infile [outfile]"
  exit
fi

if [ -z "$out" ]; then
  out="${in%avi}mp4"
fi

if [ "$subdir" ]; then
  if [ ! -d $subdir ] 
    then mkdir -p $subdir
  fi

  out=$subdir/$out
fi

if [ -e $out ]; then
  echo "Error: outfile $out already exists (or is same as infile)"
  exit
fi

echo Encoding $in to $out

x264 --bff --sar 12:11 --threads auto --preset slow --crf 21 -o tmp-video.m4v $in
ffmpeg -i $in -vn tmp-audio.wav
neroAacEnc -q 0.75 -if tmp-audio.wav -of tmp-audio.m4a
ffmpeg -i tmp-video.m4v -i tmp-audio.m4a -acodec copy -vcodec copy $out

rm tmp-video.m4v tmp-audio.wav tmp-audio.m4a

Generating black video to match an audio track

FFMpeg is capable of adding a silent audio track to a video, or if you provide an audio track that is shorter than the video, FFMpeg allows you to pad the audio with silence to match the video length (using -apad -shortest). Sometimes however, you may need to do it the other way around: generate blank video to match a longer audio track. Unfortunately this can not be easily accomplished with FFMpeg. So far, the only method I’ve found is to manually split the audio track into two parts, generate a blank video sequence for the additional audio, and concatenate the two. This is far from ideal. Nonetheless, this is how you can generate a blank video sequence to match an audio track:

ffmpeg -i audio.m4a -f lavfi -i color=black:1280x720 -r 30 -vcodec libx264 -preset slow -crf 24 -acodec copy -shortest output.mp4

The above example will generate a 30fps 1280x720 black video sequence, encode it as H.264 and multiplex it with the audio.

Concatenating video files

This is another operation that is easy with MEncoder but quite hard with FFMpeg (depending on the version you’re using). As of FFMpeg 1.1, there are several official ways to concatenate videos. To concatenate MPEG4-files (or any MPEG-format) on Linux, you can also use cat, as long as you convert the files to MPEG Transport Streams before concatenating. This example works for H.264 video with AAC audio in an MPEG4-container:

ffmpeg -i video1.mp4 -acodec copy -vcodec copy -vbsf h264_mp4toannexb video1.ts
ffmpeg -i video2.mp4 -acodec copy -vcodec copy -vbsf h264_mp4toannexb video2.ts
cat video1.ts video2.ts >videofull.ts
ffmpeg -i videofull.ts -isync -acodec copy -vcodec copy -absf aac_adtstoasc videofull.mp4

Encoding PAL DV to MPEG-4 video

Note: The below is a bit outdated, it needs to be updated…

I use Kino to capture DV video from my camcorder over FireWire. As I have a rather cheap camcorder, the result tends to be somewhat noisy. I compress it using MEncoder, and I usually set it co constant quality (vqscale=4, use a value of 3 or 2 for better quality), switch on noise reduction (nr=600) and some high-quality options (mbd=2:trell=yes:v4mv=yes), and I apply a deinterlacing filter to the source (-vf-add kerndeint). I force the fourcc identifier to MP4V, because not all players recognise the default FMP4 identifier. Also, you have to explicitly provide the aspect ratio (4:3 for PAL) for it to be stored in the AVI output header.

mencoder -ovc lavc -lavcopts vcodec=mpeg4:mbd=2:trell=yes:v4mv=yes:nr=600:vqscale=4:aspect=4/3 -oac mp3lame -lameopts vbr=3 -vf-add kerndeint -ffourcc MP4V -o mpeg4-output.avi dv-input.avi

Kino usually splits the DV stream into multiple files, so after compression I join them together again using:

mencoder -oac copy -ovc copy -of avi -force-avi-aspect 4/3 -o merged-output.avi fragment1.avi fragment2.avi fragment3.avi

Note that of course you can already join multiple fragments during the encoding step. Also, use of variable bitrate (VBR or ABR) in the MP3 audio stream may sometimes cause your audio and video to go out of sync. To prevent that you can use something like -lameopts cbr:br=160:mode=0 to force stereo audio with a constant bitrate (128, 160 or 192 kbps should be fine) instead of a variable one.

To get a smaller file, you could consider using either multipass encoding or encoding with a more advanced codec such as H.264. For multipass encoding, leave out the vqscale option and run mencoder several times, providing the options vpass=1:turbo, vpass=2, etc. for each pass.

To encode as an H.264 AVI file with AAC audio, you should be able to use something like:

mencoder -ovc x264 -x264encopts threads=auto:subq=5:8x8dct:frameref=2:bframes=3:weight_b:crf=24 -force-avi-aspect 4/3 -vf hqdn3d,kerndeint,scale -oac faac -o output-h264.avi input-dv.avi

Increase the crf value to get a smaller file, or decrease it for higher quality. It’s probably a good idea to convert the AVI file to an IsoMedia (MPEG-4 part 14) stream afterwards, e.g. using MP4Box from the Ubuntu gpac package.:

mplayer -dumpvideo -dumpfile output-h264.h264 output-h264.avi
mplayer -dumpaudio -dumpfile output-h264.aac output-h264.avi
MP4Box -add output-h264.avi -new output-h264.mp4

Unfortunately MP4Box complains about the video stream (Cannot find H264 start code), I’m not sure why.

Update (2012-09-08):
Recent versions of ffmpeg can also be used to convert (or encode directly to) mp4.

If it does work, the result should play fine using something like MPlayer or VLC, but unfortunately not with Quicktime 7. To make the file playable by Quicktime 7, reduce the encoding options in the mplayer commandline to:

-x264encopts threads=auto:subq=5:frameref=2:crf=24

See also