Mencoder Encoding

From OESF

Jump to: navigation, search

Tutorial by Justin Hensley

taken from: http://www.cs.unc.edu/~hensley/zaurus/encode.html

This tutorial was developed using Redhat 9. It should be pretty much the same for people running other flavors of Linux.

Encoding a DVD

First, this document is designed to help people who own a DVD, re-encode it so that they can watch it on their Z. Please don't blame me if the MPAA stormtroopers come and arrest you for illegally copying a DVD. I do not condone that activity. Now that I've said that, on with the tutorial.

Mplayer is an amazing video player, and is very flexible. (As a sidebar, I've modified mplayer so that it can be used to display on UNC's high resolution, large-format display PixelFlex.) Mplayer includes a fairly powerful video encoder called mencoder. Mencoder has the concept of a output video codec (ovc). I've mainly used two of the available codecs: divx4 and lavc. If you haven't installed mplayer yet, please take a look at the getting an encoder page.


First, I'll show an example of how to encode a DVD, and then I'll talk a little more about some of the options. The following uses the lavc ovc:

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc lavc
   -lavcopts vcodec=mpeg4:vhq:vbitrate=150 -ofps 15 -sws 2

Or, if you would rather use the divx4 ovc:

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

This results in a file that is about 120 MB, which fits nicely on a 128MB compact flash card. The low video bitrate works best for movies without a lot of fast action.


Now let's go through and see what the different parts of the command do:

Tell mencoder to rip the first title on the dvd (the actual movie):

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

Set the audio sample rate to 24 kHz. (The input sample rate from the DVD is 48 kHz. I've found that the output sample rate needs to be an even divisor of the input sample rate. So, if you set srate to 22 kHz, the audio won't get transfered.):

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

Scale the video to a reasonable size for the Z. You shouldn't have to worry about calculating the correct output size, since mencoder will make sure that the movie's aspect ratio is kept:

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

Set the output file name:

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

Set the output audio codec (mp3 in this case):

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

Set the audio codec options. preset=15 tells lame to encode at an average bitrate of 15 kbps. mode=3 tells lame to use a single channel (mono, as opposed to stereo):

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

Set the output video codec (divx4 in this case):

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

Set the video codec options. br=150 tells the divx4 codec to encode at a bitrate of 150 kbps.

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

Set the output frames per second:

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

Use bi-cubic interpolation when scaling the video:

   mencoder dvd://1 -srate 24000 -vop scale=320:240 -o office_space.avi
   -oac mp3lame -lameopts preset=15:mode=3 -ovc divx4
   -divx4opts br=150 -ofps 15 -sws 2

This is by no means an exhaustive tutorial. A lot of what I did was to make the video small so that I could fit it on my 128MB compact flash card. You can get better results if you use two or three pass encoding. I'll try to add more information about that in the future, but I'm supposedly doing my PhD research right now.


Front-end bash script

By Vrejakti: Encoding AVIs for Zaurus Playback


Getting higher quality

Contributed by: Russil Wvong

Besides Justin Hensley's excellent tutorial, there's a number of guides to using MEncoder to encode video. In the MPlayer documentation, Chapter 14 is a detailed guide to getting higher quality using MEncoder.

Key points:

Video encoder works by dividing picture into 16x16 macro-blocks, compressing it using a quantizer. The lower the quantizer, the better the quality and the higher the bitrate. If you use two-pass variable-bit-rate coding, the encoder will use a higher quantizer for blocks that can be compressed easily.
Always use width and height that are divisible by 16.
Fully crop black borders: they require much more encoding, e.g. because of motion to and from edge of picture. Use mplayer -vf cropdetect to find out where to crop.
An extremely rough guideline: allow 0.25 bits per pixel. (For example, 640x240 at 12 fps = 1843200 pixels per second, which translates to 450 kb/s. In practice, an SL-C1000 running mplayer seems to be able to handle about 400 kb/s.)

The guide discusses the differences between progressive, telecined, and interlaced NTSC video. Progressive video was filmed at 24000/1001 fps, the usual frame rate for films, and stored without alteration; no special filtering is needed. Telecined video was filmed at 24000/1001 fps, then converted to 30000/1001 fps, e.g. for TV broadcast; use -vf pullup,softskip, before cropping or rescaling, and -ofps 24000/1001. Interlaced video, often used for TV, was filmed at 60000/1001 fps and then stored at 30000/1001 fps; use -vf pp=lb, after cropping and before scaling, and -ofps 30000/1001.

What about scaling? For a DVD, the image first needs to be stretched to the correct aspect ratio (width / height). The uncropped source image is always 720:480 pixels (aspect ratio 1.5). The DVD also indicates whether the aspect ratio of the displayed image should be 1.78 (16:9), i.e. stretched horizontally by 1.78 / 1.5; or 1.33 (4:3), i.e. stretched vertically by 1.5 / 1.33. If the aspect ratio of the displayed image is incorrect, the displayed image will appear to be squeezed. Of course the cropped image won't have the same aspect ratio as the uncropped image, but it needs to be stretched by the same factor.

After that, the cropped and stretched image is scaled to the Zaurus's display, without altering its aspect ratio.

Section 14.4 describes how to do two-pass encoding with the Xvid video codec. Matt Gelhaus comments in passing that the Zaurus SL-C1000 can play back 640x480 video encoded with Xvid at 200 kb/s video and 64 kb/s audio. See the 2005 Doom9 video codec shootout for a discussion of the strengths and weaknesses of different codecs.



Here's some examples of command lines to encode various types of video, using Xvid. In each case the screen width is 640, the video bitrate is 300 kbit/s, and the audio bitrate is 128 kbit/s, which translates to about 200 Mbytes per hour of video.

A movie, encoded as progressive video. The frame rate is set to half (12000/1001 instead of 24000/1001). The cropped rectangle (in this case 720:352:0:62) will vary depending on the movie; you can obtain them using mplayer -vf cropdetect dvd://1.

   mencoder dvd://1 -o firstpass.avi -ofps 12000/1001
       -vf crop=720:352:0:62,scale=640:256 -force-avi-aspect 640:256
       -ovc xvid -xvidencopts pass=1:bitrate=300
       -oac mp3lame -lameopts abr:br=128
   mencoder dvd://1 -o output.avi -ofps 12000/1001
       -vf crop=720:352:0:62,scale=640:256 -force-avi-aspect 640:256
       -ovc xvid -xvidencopts pass=2:bitrate=300
       -oac mp3lame -lameopts abr:br=128

In this case the aspect ratio for the uncropped display image is 1.78, and the cropped image is 720:352. First the width needs to be stretched by 1.78 / 1.5, so the cropped and stretched image is 854:352. Then the width is scaled to 640 pixels, and to preserve the aspect ratio of 854:352, the height is scaled to width / aspect = 263 pixels, which is rounded off to 256; so the scaled image is 640:256.

A movie broadcast on TV, encoded as telecined video.

   mencoder dvd://1 -o firstpass.avi -ofps 12000/1001
       -vf pullup,softskip,crop=704:464:10:8,scale=640:480 -force-avi-aspect 640:480
       -ovc xvid -xvidencopts pass=1:bitrate=300
       -oac mp3lame -lameopts abr:br=128
   mencoder dvd://1 -o output.avi -ofps 12000/1001
       -vf pullup,softskip,crop=704:464:10:8,scale=640:480 -force-avi-aspect 640:480
       -ovc xvid -xvidencopts pass=2:bitrate=300
       -oac mp3lame -lameopts abr:br=128

In this case the aspect ratio is 1.33, and the cropped image is 704:464. The height is stretched by 1.5 / 1.33, so the cropped and stretched image is 704:523. Then the width is scaled to 640 pixels, and the height is scaled to width / aspect = 475 pixels, or 480 when rounded off.

A TV program, encoded as interlaced video. The frame rate is set to one third (10000/1001 instead of 30000/1001); you could also set it to one half (15000/1001) instead.

   mencoder dvd://1 -o firstpass.avi -ofps 10000/1001
       -vf crop=720:480:0:0,pp=lb,scale=640:480 -force-avi-aspect 640:256
       -ovc xvid -xvidencopts pass=1:bitrate=300
       -oac mp3lame -lameopts abr:br=128
   mencoder dvd://1 -o output.avi -ofps 10000/1001
       -vf crop=720:480:0:0,pp=lb,scale=640:480 -force-avi-aspect 640:256
       -ovc xvid -xvidencopts pass=2:bitrate=300
       -oac mp3lame -lameopts abr:br=128

When playing back the encoded video using mplayer, if you find that the video and audio are out of sync, you can use the -delay parameter to adjust the synchronization of the video and audio. Getting the parameter value right is a matter of trial and error.



I've written a bash script (running on Ubuntu) to do the scaling calculations. Its inputs are the size of the source image, the aspect ratio of the displayed image, the cropped rectangle, and the size of the target display; its output is the size of the scaled image. bash doesn't support floating-point arithmetic directly, so the script uses bc to do its calculations.

Pseudo-code:

sourceAspect    := sourceWidth / sourceHeight
croppedAspect   := croppedWidth / croppedHeight
stretchedAspect := croppedAspect * (displayAspect / sourceAspect)

targetAspect := targetWidth / targetHeight
if (stretchedAspect > targetAspect)
    scaledWidth  := targetWidth
    scaledHeight := targetWidth / stretchedAspect
else
    scaledHeight := targetHeight
    scaledWidth  := targetHeight * stretchedAspect
endif

The script:

#!/bin/bash
#
# zscale -s sourceWidth:sourceHeight
#        [ -a aspectRatio ]
#        [ -c croppedWidth:croppedHeight:croppedLeft:croppedTop ]
#        -t targetWidth:targetHeight
#

usage() {
    echo >&2 "Usage: $0 -s sourceWidth:sourceHeight
[ -a aspectRatio ]
[ -c croppedWidth:croppedHeight:croppedLeft:croppedTop ]
-t targetWidth:targetHeight"
}

while getopts s:a:c:t: option
do
    case "$option" in
    s)      SOURCE="$OPTARG";;
    a)      ASPECT="$OPTARG";;
    c)      CROPPED="$OPTARG";;
    t)      TARGET="$OPTARG";;
    [?])    usage
            exit 1;;
    esac
done
shift $(($OPTIND - 1))

if [[ -z $SOURCE || -z $TARGET ]] ; then
    usage
    exit 1
fi

#
# If cropped rectangle is not specified, use source rectangle
#
if [[ -z $CROPPED ]] ; then
    CROPPED=$SOURCE:0:0
fi

croppedWidth=${CROPPED%%:*}
remainder=${CROPPED#*:}
croppedHeight=${remainder%%:*}
croppedAspect=`echo "scale=10; $croppedWidth / $croppedHeight" | bc`

#
# Stretch cropped rectangle based on aspect ratio
#
if [[ ! -z $ASPECT ]] ; then
    sourceWidth=${SOURCE%:*}
    sourceHeight=${SOURCE#*:}
    sourceAspect=`echo "scale=10; $sourceWidth / $sourceHeight" | bc`
    croppedAspect=`echo "scale=10; $croppedAspect * $ASPECT / $sourceAspect" | bc`
fi

#
# Scale cropped rectangle to target size.
# If aspect > targetAspect, fill the width; otherwise, fill the height.
#
targetWidth=${TARGET%:*}
targetHeight=${TARGET#*:}
targetAspect=`echo "scale=10; $targetWidth / $targetHeight" | bc`
if [[ $croppedAspect > $targetAspect ]] ; then
    scaledWidth=$targetWidth
    scaledHeight=`echo "scale=10; $scaledWidth / $croppedAspect" | bc`
else
    scaledHeight=$targetHeight
    scaledWidth=`echo "scale=10; $scaledHeight * $croppedAspect" | bc`
fi

#
# Round off an integer value to a multiple of 16.
#
round16 () {
    echo "($1 + 8) / 16 * 16" | bc
}

echo `round16 $scaledWidth`:`round16 $scaledHeight`

I've also written a bash script, zmovie, that I use as a front end. It attempts to auto-detect the aspect ratio and cropping parameters. It uses ~/.zmovierc as a configuration file.

#!/bin/bash
#
# zmovie -- encode video for Zaurus using MEncoder
# See http://www.oesf.org/index.php?title=Mencoder_Encoding
#

# Set up reasonable defaults.
APPNAME=`basename "$0"`
CONFNAME=."$APPNAME"rc
IN=dvd://1
INTERLACED=0
TELECINED=0
CROPSTART=600
CROPFRAMES=10
OPTIONS="-alang en -slang en"
OUT=out.avi
MAXSIZE=640:480
FPS=12000/1001
VBITRATE=300
ABITRATE=128

# Import configuration file, possibly overriding defaults.
[ -r ~/"$CONFNAME" ] && . ~/"$CONFNAME"

usage() {
    echo >&2 "Usage: $0 [-c none | -c w:h:x:y ] [-i] [-t] [-f fps] [-o out] [file]"
}

while getopts o:c:a:itf: option
do
    case "$option" in
    o)      OUT="$OPTARG";;
    c)      CROP="$OPTARG";;
    i)      INTERLACED=1;;
    t)      TELECINED=1;;
    f)      FPS="$OPTARG";;
    [?])    usage
            exit 1;;
    esac
done
shift $(($OPTIND - 1))

if [[ ! -z "${1}" ]] ; then
    IN=$1
fi

# Run mplayer to get the parameters of the source video.
mplayer $IN $OPTIONS -ss $CROPSTART -frames $CROPFRAMES -vf cropdetect -identify -quiet -vo null -ao null 2>&1 > /tmp/zmovie.$$

# Get the source size.
sourceWidth=`cat /tmp/zmovie.$$ | grep ID_VIDEO_WIDTH`
sourceWidth=${sourceWidth#ID_VIDEO_WIDTH=}
sourceHeight=`cat /tmp/zmovie.$$ | grep ID_VIDEO_HEIGHT`
sourceHeight=${sourceHeight#ID_VIDEO_HEIGHT=}
SIZE=$sourceWidth:$sourceHeight

# Get the aspect ratio.
if [[ -z $ASPECT ]] ; then
    ASPECT=`cat /tmp/zmovie.$$ | grep Movie-Aspect | grep -v undefined`
    ASPECT=${ASPECT#Movie-Aspect is }
    ASPECT=${ASPECT%:1 - prescaling*}
fi

# Get the output of -vf cropdetect.
if [[ -z $CROP ]] ; then
    CROP=`cat /tmp/zmovie.$$ | grep CROP | tail -1`
    CROP=${CROP#* crop=}
    CROP=${CROP%%\).*}
fi

# Invoke zscale to do the scaling calculations.
zs=
if [[ ! -z $ASPECT ]] ; then
    zs="$zs -a $ASPECT"
fi
if [[ ! -z $CROP && $CROP != "none" ]] ; then
    zs="$zs -c $CROP"
fi
SCALE=`zscale -s $SIZE $zs -t $MAXSIZE`

# Specify video filters:  inverse telecine, crop, de-interlace, scale,
# in that order.
VFILTER=
if [[ $TELECINED == 1 ]] ; then
    VFILTER="$VFILTER pullup softskip"
fi
if [[ ! -z $CROP && $CROP != "none" && $CROP != $SIZE:0:0 ]] ; then
    VFILTER="$VFILTER crop=$CROP"
fi
if [[ $INTERLACED == 1 ]] ; then
    VFILTER="$VFILTER pp=lb"
fi
if [[ ! -z $SCALE ]] ; then
    VFILTER="$VFILTER scale=$SCALE"
fi
if [[ ! -z $VFILTER ]] ; then
    VFILTER=`echo $VFILTER | sed "s/ /,/g"`
    VFILTER="-vf $VFILTER"
fi

# Run mencoder.
VCODING="-ovc xvid -xvidencopts pass=1"
ACODING="-oac mp3lame -lameopts abr:br=$ABITRATE"

COMMAND="mencoder $IN -ofps $FPS $VFILTER -force-avi-aspect $SCALE $VCODING $ACODING $OPTIONS -o /tmp/firstpass.avi"
echo "`date`: $COMMAND"
$COMMAND -quiet > /tmp/mencoder.log 2>&1

VCODING="-ovc xvid -xvidencopts pass=2:bitrate=$VBITRATE"

COMMAND="mencoder $IN -ofps $FPS $VFILTER -force-avi-aspect $SCALE $VCODING $ACODING $OPTIONS -o $OUT"
echo "`date`: $COMMAND"
$COMMAND -quiet >> /tmp/mencoder.log 2>&1

echo "`date`: encoding complete"
exit 0
Personal tools