Update : Has any of the WLUG'ers have some NTSC DVDs I can please borrow. I have rewritten the script to work with NTSC DVDs, and it has worked perfectly on the only NTSC DVD in my collection. Cheers!
I have written a bash script that from a directory containing vob files, will make an extremely good looking XviD dvdrip. I'd really appreciate it if you would try it out and let me know if there are any bugs. I've had great success with it. At the moment it only works on a PAL DVD source, but it the future this will be updated to make perfect rips from an NTSC source. Will also be updated to make rips of DVD's containing tv-eps.
28/12/2006 Fixed : Bug causing all files to be hidden! 27/12/2006 Added : It should now be possible to encode to XviD directly from the DVD disc, provided the DVD only has CSS encryption and nothing too fancy :) If the Supplied dir argument is a mounted DVD (cannot be written to), then the $PWD will be used as our working directory, otherwise the vob dir will be used as our working directory. Added : Added some xvidenc options to set quantization type as H.263 and to make sure that qpel and gmc are not used as these can cause problems on standalone players. 26/12/2006 Added : Title and Output Filename options are now mandatory and the script will now detect if they are missing. Fixed : Listing .vob files now working. 25/12/2006 Added : Different range of possible resolutions for the output video, depending on whether we have a WS or FS source.
#!/bin/sh
#
#This is is a wrapper around the -identify functionality.
# It is supposed to escape the output properly, so it can be easily
# used in shellscripts by 'eval'ing the output of this script.
#
# Written by Tobias Diedrich <ranma+mplayer@tdiedrich.de>
# Licensed under GNU GPL.
if [ -z "$1" ]; then
echo "Usage: midentify <file> [<file> ...]"
exit 1
fi
mplayer -vo null -ao null -frames 0 -identify "$@" 2>/dev/null |
sed -ne '/^ID_/ {
s/[]()|&;<>`'"'"'\\!$" []/\\&/g;p
}'
RIGHT change_rectangle 2 +2 LEFT change_rectangle 2 -2 DOWN change_rectangle 3 +2 UP change_rectangle 3 -2 KP6 change_rectangle 0 +2 KP4 change_rectangle 0 -2 KP2 change_rectangle 1 +2 KP8 change_rectangle 1 -2 PGUP seek +60 PGDWN seek -60 q quit ESC quit ENTER pt_step 1 1 p pause SPACE pause f vo_fullscreen
So Here It Is:
#!/bin/bash
calculate_ar_error()
{
resized_ar=$(echo "scale=10;$1/$2" | bc )
ar_error=$(echo "scale=4; (($crop_ar - $resized_ar) / $resized_ar) * 100" | bc )
}
function best_mult16()
{
calculate_ar_error $1 $2
ar_error_1=$ar_error
calculate_ar_error $1 $3
ar_error_2=$ar_error
echo "AR Error $1 x $2 : ${ar_error_1}%"
echo "AR Error $1 x $3 : ${ar_error_2}%"
if [ `echo "${ar_error_2#-} < ${ar_error_1#-}" | bc ` -eq 1 ]; then
best_error=$ar_error_2
return 0;
else
best_error=$ar_error_1
return 1;
fi
}
function find_best_height()
{
#Find Closest Multiple of 16
perfect_height=$(echo "scale=10; $1 / $crop_ar" | bc)
round_down_mult16=$(echo "$perfect_height - ($perfect_height % 16)" | bc)
round_down_mult16=${round_down_mult16%%.*}
best_mult16 $1 $round_down_mult16 $(echo "$round_down_mult16 + 16" | bc)
if [ $? -eq 0 ]; then
best_height=$(expr $round_down_mult16 + 16)
else
best_height=$round_down_mult16
fi
echo "The Best height out of $round_down_mult16 and $(expr $round_down_mult16 + 16) is $best_height"
}
echo "Welcome to Staz's XviD Video Encoder"
echo "At the moment this can only be used to encode PAL DVD Movies to XviD"
echo "Email any bugs/fixes to ben.staz@gmail.com"
echo "-------------------------------------"
#Create Constants To Be Used In Script (Could use 'readonly foo==moo', 'declare -r foo=moo' or 'typeset -r foo=moo'
readonly CD_SIZE=716800
readonly PAL_MIN_RUNTIME_PER_CD=6000
readonly NTSC_MIN_RUNTIME_PER_CD=5220
readonly FILM_MIN_RUNTIME_PER_CD=6300
#First argument supplied is the directory containing the vobs.
if [ -d $1 ]; then
vob_dir=$1;
if [ "${vob_dir:0:1}" != "/" ]; then
echo "This vob dir is relevant to the PWD"
if [ "$vob_dir" == "." ]; then
vob_dir=${PWD}/
else
vob_dir=${PWD}/${vob_dir#./}
fi
else
echo "The vob dir is a full path."
fi
echo "Vob Dir : $vob_dir";
echo "Vob Files:"
for i in ${vob_dir}/*.[Vv][Oo][Bb] ;
do
echo $i;
done;
#Check if the supplied vob directory is a mounted DVD.
#The 2> /dev/null part avoids the 'unary operator' message when it is not a mounted DVD dir.
if [ `df -T $vob_dir | awk '$2 == "udf" || $2 == "iso9660" {print "0"}'` -eq 0 ]; then
echo "This is a mounted DVD. Will use ${PWD}/ as the working directory"
working_dir=${PWD}/
else
echo "Will use $vob_dir as the working directory"
working_dir=$vob_dir
fi 2> /dev/null
else
echo "Error : You did not supply a valid directory!"
fi;
shift;
#Set the default arguments (If user does not specify otherwise)
max_ar_error=3
echo "-------------------------------------"
echo " User Chosen Options"
echo "-------------------------------------"
#Following variables are used to make sure the two compulsory options (title and output) are supplied.
t=1
o=1
while test "$1" != "";
do
case $1 in
--list-titles|-l)
echo "-------------------------------------"
echo " Listing Titles"
echo "-------------------------------------"
lsdvd $vob_dir 2> /dev/null
echo "Choose a Title by using --title <n>"
echo "-------------------------------------"
exit
;;
--title|-t)
#TODO: WE WILL BE ABLE TO SUPPLY MULTIPLE TITLES HERE
t=0
echo "Chosen Title : $2"
title=$2
tmp=$(lsdvd -v $vob_dir 2> /dev/null )
length=$(echo "$tmp" | egrep -o '[0-9]{2}:[0-9]{2}:[0-9]{2}' | sed -n "${title}p")
ar=$(echo "$tmp" | egrep -o '[0-9]+/[0-9]+' | sed -n "${title}p")
echo "Title Length : $length"
echo "Title AR : $ar"
length_seconds=$(echo $length | { IFS='[:.]'; read h m s; echo "(${h##0} * 3600) + (${m##0} * 60) + ${s##0}" | bc; } )
echo "Length in Seconds : $length_seconds"
shift
;;
--max-ar-error|-e)
echo "Max AR % Error : ${2}%"
max_ar_error=$2
shift
;;
--output|-o)
o=0;
echo "Output File : $2"
output_file=$2
output_name=${2%.[Aa][Vv][Ii]}
shift
;;
*)
echo "Invalid Argument : $1"
echo "Will print usage in the future"
exit 1
;;
esac
shift
done
#Check that both the title and output options have been supplied.
if [ "$t" -eq 1 -o "$o" -eq 1 ] ; then
#Uh oh something is missing
echo "-------------------------------------"
echo "ERRORS!"
if [ "$t" -eq 1 ]; then
echo "You need To specify a Title. Usage : -t <title>"
fi
if [ "$o" -eq 1 ]; then
echo "You need to specify an Output File. Usage : -o <output file>"
fi
echo "-------------------------------------"
exit
fi
echo "-------------------------------------"
echo " Source Information"
echo "-------------------------------------"
#Calculate Source Video Format/Resolution/Framerate by parsing lsdvd's output.
video_format=$(lsdvd $vob_dir -v 2> /dev/null | egrep -o '(PAL|NTSC)' | tail -1 )
echo "Video Format......: $video_format"
case $video_format in
PAL)
frame_rate=25
source_width=720
source_height=576
min_runtime_per_cd=$PAL_MIN_RUNTIME_PER_CD
;;
NTSC)
frame_rate=29.97
source_width=720
source_height=480
min_runtime_per_cd=$NTSC_MIN_RUNTIME_PER_CD
;;
esac
echo "Source Resolution.: $source_width x $source_height"
echo "Source FrameRate..: $frame_rate"
echo "-------------------------------------"
echo " Crop Information"
echo "-------------------------------------"
#Calculate Cropping Values/Resolution based on parsed mplayer output.
crop_values=$(mplayer -dvd-device $vob_dir dvd://${title} -aid 128 -vf rectangle=720:576 -input conf=cropping.conf 2> /dev/null | egrep -o '[0-9]+:[0-9]+:[0-9]+:[0-9]+' | tail -1 )
echo "Crop Vals : $crop_values"
left_right_crop=$((source_width - $(echo "$crop_values" | cut -d ':' -f 1) ));
top_bottom_crop=$((source_height - $(echo "$crop_values" | cut -d ':' -f 2) ));
echo "Total Left/Right Cropping : $left_right_crop"
echo "Total Top/Bottom Cropping : $top_bottom_crop"
crop_ar=$(echo "scale=10;(($source_width - $left_right_crop) / $source_width) * ($source_height / ($source_height - $top_bottom_crop)) * ($ar)" | bc )
echo "Crop AR : $crop_ar"
found_a_res=0
if [ "$ar" == "16/9" ]; then
for width in $(seq 672 -16 512) ;
do
echo "-------------------------------------"
echo "Horizontal Resolution : $width"
echo "-------------------------------------"
find_best_height $width
if [ `echo "${best_error#-} < $max_ar_error" | bc` -eq 1 ]; then
final_width=$width
final_height=$best_height
found_a_res=1;
break;
fi
done;
elif [ "$ar" == "4/3" ]; then
for width in $(seq 576 -16 448) ;
do
echo "-------------------------------------"
echo "Horizontal Resolution : $width"
echo "-------------------------------------"
find_best_height $width
if [ `echo "${best_error#-} < $max_ar_error" | bc` -eq 1 ]; then
final_width=$width
final_height=$best_height
found_a_res=1;
break;
fi
done;
fi
#Check We Have Finally Came Up With a Resolution
if [ $found_a_res -eq 1 ]; then
echo "The Final Resolution is : $final_width x $final_height"
echo "The AR Error Is: ${best_error}%"
else
echo "Couldn't Find A Resolution!"
echo "Try Lowering the max AR Error %"
fi
echo "-------------------------------------"
#Work Out How Many CDS Our Encode Will Take Up
if [ "$length_seconds" -le "$min_runtime_per_cd" ]; then
num_cds=1;
else
num_cds=$(( ($length_seconds / $min_runtime_per_cd) + 1 ));
fi
echo "Number of CDS : $num_cds"
if [ $num_cds -eq 1 ]; then
#Now We Rip The DVD Audio Stream To PCM .wav (Uncompressed Audio)
mplayer -dvd-device $vob_dir dvd://${title} -aid 128 -vo null -vc dummy -mc 0 -ao pcm:file=${working_dir}${output_name}.wav
#Use Lame to Encode to VBR MP3 (-V 3 --vbr-new seems to result in a bitrate close to 128 which I am after)
lame -h -V 3 --vbr-new ${working_dir}${output_name}.wav ${working_dir}${output_name}.mp3
#Time To Apply Some Gain Or Else Our Movie Is Far Too Quiet!
#The switches will make sure that mp3gain applies the maximum gain possible WITHOUT any clipping
mp3gain -r -k ${working_dir}${output_name}.mp3
audio_format=mp3
else
echo "We are ripping to AC3 Audio NOW...."
tmp=$(mencoder -dvd-device $vob_dir dvd://${title} -aid 128 -oac copy -of rawaudio -ovc copy -mc 0 -o ${working_dir}${output_name}.ac3 2> /dev/null | grep 'audio stream: 0' | grep -o '(.*)' )
#I DONT KNOW THE OUTPUT OF MPLAYER IF THE AUDIO STREAM IS MONO. WILL HAVE TO FIND A DVD WITH A MONO AUDIO STREAM.
num_channels=$(echo "$tmp" | sed -e 's/(5.1)/6/' -e 's/(stereo)/2/' )
echo "Number Of Channels : $num_channels"
audio_format=ac3
fi
#Time To Calculate Overhead
echo "-------------------------------------"
echo "Overhead Calculations"
echo "-------------------------------------"
if [ "$audio_format" == "mp3" ]; then
frames_per_chunk=1
audio_overhead=$(echo "scale=10; ($length_seconds*1000) / (24*$frames_per_chunk)" | bc)
audio_size=$(du -k ${working_dir}${output_name}.mp3 | cut -f 1)
elif [ "$audio_format" == "ac3" ]; then
frames_per_chunk=2
audio_overhead=$(echo "scale=10; ($length_seconds*1000) / (32*$frames_per_chunk)" | bc)
audio_size=$(du -k ${working_dir}${output_name}.ac3 | cut -f 1)
fi
echo "Audio Overhead : ${audio_overhead%%.*}"
if [ $num_cds -ge 3 ]; then
#We will get an OPEN-DML .avi (with or without a legacy index?? will have to ask the mplayer devs)
overhead_kilobytes=$(echo "scale=10; (16 * $audio_overhead) / 1024" | bc )
else
#We will get a standard avi output.
echo "STANDARD AVI OUTPUT"
overhead_kilobytes=$(echo "scale=10; (24 * $audio_overhead) / 1024" | bc )
fi
echo "Total Overhead (Kilobytes) : ${overhead_kilobytes%.*}"
echo "-------------------------------------"
echo "Audio Size : $audio_size Kb's"
video_size=$(((num_cds*CD_SIZE) - audio_size - ${overhead_kilobytes%%.*} ))
echo "Video Size : $video_size kb's"
#We Now Have All The Info Needed To Start The XviD Encode.
#Note: -nosound disables processing the audio stream.
#First Pass
mencoder -dvd-device $vob_dir dvd://${title} -nosound -vf crop=${crop_values},scale=${final_width}:${final_height} -sws 9 -ovc xvid -passlogfile ${working_dir}${output_name}_2pass.log -xvidencopts pass=1:quant_type=h263:nogmc:noqpel:bitrate=-${video_size} -mc 0 -noskip -o /dev/null
pass1_filesize=$(echo "$(cat ${working_dir}${output_name}_2pass.log | awk '$6 ~ "^[0-9]" { total += $6; print $total} END { print total } ') / 1024" | bc)
echo "At a constant quantizer value of 2, the output filesize is $pass1_filesize Kb's in size"
#Here we can easily change the XviD encoding options.
xvidencopts=pass=2:quant_type=h263:min_pquant=1:min_iquant=1:min_bquant=1:nogmc:noqpel:bitrate=-${video_size}
#Second Pass:
mencoder -dvd-device $vob_dir dvd://${title} -nosound -vf crop=${crop_values},scale=${final_width}:${final_height} -sws 9 -ovc xvid -passlogfile ${working_dir}${output_name}_2pass.log -xvidencopts $xvidencopts -mc 0 -noskip -o ${working_dir}${output_name}_nosound.avi
#ITS MUXING TIME!!!
if [ "$audio_format" == "mp3" ]; then
mencoder ${working_dir}${output_name}_nosound.avi -ovc copy -oac copy -audiofile ${working_dir}${output_name}.mp3 -mc 0 -noskip -o ${working_dir}${output_name}.avi
else
#GET AC3 INFO AND THEN MUX
midentify ${working_dir}${output_name}.ac3 | sed -ne '/ID_AUDIO_BITRATE/p' -ne '/ID_AUDIO_RATE/p' | head -2 | awk -F '=' '{ print $2 }' | { read audio_bitrate; read audio_rate; mencoder ${working_dir}${output_name}_nosound.avi -ovc copy -oac copy -audiofile ${working_dir}${output_name}.ac3 -audio-demuxer 20 -rawaudio format=0x2000:channels=${num_channels}:rate=${audio_rate}:bitrate=${audio_bitrate} -mc 0 -noskip -o ${working_dir}${output_name}.avi; }
fi
#If We Encoded To 2CDS+ then we will want to split the encoded video into the appropriate number of parts.
if [ "$num_cds" -gt 1 ]; then
#Split into $num_cds parts
avisplit -i ${working_dir}${output_name}.avi -o ${working_dir}${output_name}-cd -s 700
counter=1;
for i in ${working_dir}${output_name}-cd-000[0-9].avi ;
do
mv $i ${working_dir}${output_name}-cd${counter}.avi;
counter=$((counter+1));
done;
fi
exit
Soon after typing this command mplayer will popup and start playing your chosen title from the DVD. You will notice the outline of a white rectangle that overlays the video. Basically what you want to do is to manipulate the rectangle so that it surrounds the video and crops out any black area around the video. Use the main arrow keys to move the entire rectangle and the numpad arrow keys to increase/decrease the width and height. What I recommend is.
No page links to PerfectDVDRips.