DVD9 to DVD5 

http://itdp.fh-biergarten.de/transcode-users/2004-02/txt00005.txt

#!/bin/sh

# Script to automatically convert DVD9 to DVD5 discs
# Preserving all subtitles, menus & audio tracks
# Supports both main feature & episodic DVDs
# Author: Rick Harris,  rickfharris@xxxxxxxxxxxx
#
# Required:
#       Eject                   -> http://eject.sourceforge.net/[]
#       Lsdvd                   -> http://acidrip.thirtythreeandathird.net[]
#       Mjpegtools              -> http://mjpeg.sourceforge.net/[]
#       Transcode (CVS)         -> http://zebra.fh-weingarten.de/~transcode/#cvs[]
#       Mplayer                 -> http://www.mplayerhq.hu[]
#       Xine (optional)         -> http://xine.sourceforge.net/[]
#       Dvdauthor (v0.6.9)      -> http://sourceforge.net/projects/dvdauthor/[]
#       Dvd+rw-tools            -> http://fy.chalmers.se/~appro/linux/DVD+RW/[]
#       Twice the disc size in free hard-drive space (approx. 15GB)
#
# Usage:
#       'cd' into any directory where the above hard-drive space is present
#       Insert DVD into DVD-Rom drive, do not mount it (this includes supermount)
#       Run ./dvd9todvd5.sh
#
#       Use the '--noclean' flag to disable removal of process files when finished
#
#       Use the '--omit-titleset' flag followed by a comma seperated list of titleset numbers
#       and title numbers that you wish to leave out.
#       Example: ./dvd9todvd5.sh --omit-titleset 02_003,11,08_004,15,04
#               to leave out titleset numbers:  2_title3, 11, 8_title4, 15 and 4
#
#       End result will be in the directory 'video/<disc_title>/DVD/'
#
#       Optionally, test with 'xine dvd:/full/path/to/video/<disc_title>/DVD/VIDEO_TS/'
#
#       Use 'growisofs -Z /dev/dvd -dvd-video DVD/' to burn to DVD5(4.7GB) Disc
#
# NOTE: Disc menus are currently experimental, and so are disabled by default.
#
#       If you want to enable them, then add the '--enable-menus' flag.
#
#       You will have to hand-edit the created 'dvdauthor.xml' to add in button commands,
#       as dvdunauthor does not currently do this.
#       eg. <button> jump menu 2; <button/>
#       However, you should still be able to access all the different Chapters, Titles, Subtitles
#       & Audio Tracks using your DVD Player's system menus if you choose not to --enable-menus.
#
#       DVDUnauthor has a built-in limit of 10 titlesets per Disc (some Discs have more)
#       Here is a patch that will disable this limit (for v0.6.9) ->
#       http://mightylegends.zapto.org/dvd/dvdunauthor.c.diff[]
#
# Most frequently asked question:
#       Q: How long does it take ?
#       A: Depends on your system specs, but as a guide, the whole process takes approx.
#          2.5 hours for an average 7GB DVD Disc with 1 main title that has
#          3 subtitles & 2 audio tracks on an AMD XP+ 1800 w/512MB RAM.
#          Able to remove the DVD Disc after the 1st hour approx.
#
# This script has only proven to work with DVDs that have been authored to comply
# with DVD standards. Any originally mis-authored or scratched DVDs usually fail.
# IE. No guarantees 8^)


DEV="/dev/dvd"
WORKDIR="video"
DISC_NAME=`lsdvd |grep "Disc Title"|cut -d " " -f 3`
MIN_SHRINK_SIZE="100000"        # 100MB  Minimum size of pre-processed .vobs to shrink
DVD_DIR="DVD"

CLEAN="yes"
MENUS="no"

case "$1" in
'--omit-titleset')
  OMIT_TITLE=$2
  ;;
'--noclean')
  CLEAN="no"
  ;;
'--enable-menus')
  MENUS="yes"
  ;;
esac

case "$2" in
'--omit-titleset')
  OMIT_TITLE=$3
  ;;
'--noclean')
  CLEAN="no"
  ;;
'--enable-menus')
  MENUS="yes"
  ;;
esac

case "$3" in
'--omit-titleset')
  OMIT_TITLE=$4
  ;;
'--noclean')
  CLEAN="no"
  ;;
'--enable-menus')
  MENUS="yes"
  ;;
esac

case "$4" in
'--omit-titleset')
  OMIT_TITLE=$5
  ;;
'--noclean')
  CLEAN="no"
  ;;
'--enable-menus')
  MENUS="yes"
  ;;
esac


if [ ! -d $WORKDIR/$DISC_NAME ] ; then
mkdir -p $WORKDIR/$DISC_NAME && cd $WORKDIR/$DISC_NAME
else
cd $WORKDIR/$DISC_NAME
fi
if [ ! -d $DVD_DIR ] ; then
mkdir -p $DVD_DIR
fi
mount /dev/dvd $DVD_DIR -o ro,users
if [ -z `mount |grep $DVD_DIR` ] 2> /dev/null ;
then
eject $DEV
exit
else
DISC_SIZE=`du -s $DVD_DIR |awk '{print $1}'`
DIR_SIZE=`df ./ |grep /dev |awk '{print $4}'`
ACTUAL=`df -h ./ |grep /dev |awk '{print $4}'`
let PROCESS_SIZE=$DISC_SIZE/1024/1024*2
if [ $DIR_SIZE -lt $DISC_SIZE ] ; then
echo  -e '\e[1;31m'"Error: Only $ACTUAL free hard-drive space available"'\e[m'
echo  -e '\e[1;31m'"You will need at least $PROCESS_SIZE G free hard-drive space to convert this Disc"'\e[m'
umount $DVD_DIR
exit
fi
fi
umount $DVD_DIR


dvd_extract () {
if [ -e dvdauthor.xml ] ; then
sub_extract
else
echo -e '\e[1;33m'"Disc Title: $DISC_NAME"'\e[m'
echo ""
echo -e '\e[1;31mDe-crypting & Copying DVD to Hard-drive, please be patient...\e[m'
echo "Percentage updates every 1 minute"
dvdunauthor $DEV 1> /dev/null 2> /dev/null &
let PROGRESS=`du -s |awk '{print $1}'`
let DISC_SIZE_PROG=$DISC_SIZE-700
while [ $PROGRESS -lt $DISC_SIZE_PROG ]; do
let PROGRESS=`du -s |awk '{print $1}'`
PROG_PERCENT=$(bc -l << EOF
scale=3
($PROGRESS/$DISC_SIZE*100)
)
echo "$PROG_PERCENT% of copy completed"
sleep 60s
done
echo -e '\e[1;32mDone...\e[m'
sub_extract
fi
}


sub_extract () {
if [ $DISC_SIZE -le 4700000 ]; then
echo  -e '\e[1;31mDisc is not a DVD9 type, no conversion necessary\e[m'
echo  -e '\e[1;31mSkipping to DVD authoring\e[m'
if [ $MENUS = "yes" ]; then
dvd_author_menus
else
dvd_author
fi
fi
rm vobs.tmp 1> /dev/null 2> /dev/null
for i in `ls vob_*` ; do
let VOB_SIZE=`du -s $i |awk '{print $1}'`
VOB_NAME=`du -s $i |awk '{print $2}'`
if [ $VOB_SIZE -ge $MIN_SHRINK_SIZE ] ; then
echo $VOB_NAME >> vobs.tmp
fi
done
let VOB_COUNT=`wc -l vobs.tmp |awk '{print $1}'`
TITLE_NO=1
if [ -d subtitles ]; then
audio_extract
else
mkdir -p subtitles && cd subtitles
while [ $TITLE_NO -le $VOB_COUNT ]; do
VOB=`cat ../vobs.tmp |head -n $TITLE_NO |tail -n1`
VOB_ID=`cat ../vobs.tmp |head -n $TITLE_NO |tail -n1 |cut -d _ -f 2`
mplayer dvd://$VOB_ID -vo null -ao null -frames 0 -v 2>&1|grep sid|awk '{print $6"_"$8}' > $VOB-subs_lang.tmp
mplayer dvd://$VOB_ID -vo null -ao null -frames 0 -v 2>&1|grep sid|awk '{print $6}' > $VOB-subs_id.tmp
let SUB_NOS=`wc -l $VOB-subs_id.tmp |awk '{print $1}'`
LINE=1
while [ $LINE -le $SUB_NOS ]; do
LANG=`cat $VOB-subs_lang.tmp |head -n $LINE |tail -n1`
echo -e '\e[1;31m'"Extracting subtitle $LANG from $VOB"'\e[m'
SUB_ID=`cat $VOB-subs_id.tmp |head -n $LINE |tail -n1`
mkdir -p $VOB-sub-$LANG && cd $VOB-sub-$LANG
spuunmux -o $LANG -s $SUB_ID ../../../$DISC_NAME/$VOB 2> /dev/null
cd ../ && echo -e '\e[1;32mDone...\e[m'
let LINE=LINE+1
done
let TITLE_NO=TITLE_NO+1
done
cd ../
audio_extract
fi
}


audio_extract () {
TITLE_NO=1
if [ -d audio ] ; then
vob_shrink
else
mkdir -p audio && cd audio
while [ $TITLE_NO -le $VOB_COUNT ]; do
VOB=`cat ../vobs.tmp |head -n $TITLE_NO |tail -n1`
VOB_ID=`cat ../vobs.tmp |head -n $TITLE_NO |tail -n1 |cut -d _ -f 2`
mplayer dvd://$VOB_ID -vo null -ao null -frames 0 -v 2>&1 |grep "audio stream" |grep language |cut -d ] -f 2 > $VOB-audio_track.tmp
tcprobe -i ../$VOB 2>&1 |grep "audio track" > $VOB-audio_id.tmp
let AUD_NOS=`wc -l $VOB-audio_id.tmp |awk '{print $1}'`
LINE=1
STREAM_ID=0
while [ $LINE -le $AUD_NOS ]; do
TRACK=`cat $VOB-audio_track.tmp |head -n $LINE |tail -n1`
echo -e '\e[1;31m'"Extract$TRACK from $VOB"'\e[m'
AUD_ID=`cat $VOB-audio_id.tmp |head -n $LINE |tail -n1 |awk '{print $4}'`
AUD_TYPE=`cat $VOB-audio_track.tmp |head -n $LINE |tail -n1 |cut -d : -f 3|awk '{print $1}'`
tcextract -i ../$VOB -a $AUD_ID -x $AUD_TYPE -t vob > $VOB-audio-$STREAM_ID.$AUD_TYPE
let STREAM_ID=STREAM_ID+1
echo -e '\e[1;32mDone...\e[m'
let LINE=LINE+1
done
let TITLE_NO=TITLE_NO+1
done
cd ../
vob_shrink
fi
}


vob_shrink () {
eject $DEV
echo -e '\e[1;33mIt is now safe to remove the DVD disc\e[m'
echo -e '\e[1;33mAll other processing will be done from the Hard-drive\e[m'
QUANT_FACT=$(bc -l << EOF
scale = 3
($DISC_SIZE/4300000)
EOF
)
for VOB in `cat vobs.tmp` ; do
echo -e '\e[1;31m'"De-muxing $VOB ready for shrinking"'\e[m'
tcextract -i $VOB -x mpeg2 -t vob > $VOB.m2v
rm $VOB
echo -e '\e[1;31m'"Resizing $VOB using a factor of $QUANT_FACT"'\e[m'
tcrequant -i $VOB.m2v -f $QUANT_FACT -o $VOB-quant.m2v
rm $VOB.m2v
echo -e '\e[1;32mDone...\e[m'
done
sub_merge
}


sub_merge () {
for VOB in `cat vobs.tmp` ; do
AUD_SUBS=`ls audio/$VOB-audio-*`
echo -e '\e[1;31m'"Merging audio track(s) into $VOB"'\e[m'
mplex -f8 -o $VOB.mpg $VOB-quant.m2v $AUD_SUBS 1> /dev/null 2> /dev/null
rm $VOB-quant.m2v
echo -e '\e[1;32mDone...\e[m'
done
TITLE_NO=1
let VOB_COUNT=`wc -l vobs.tmp |awk '{print $1}'`
while [ $TITLE_NO -le $VOB_COUNT ]; do
VOB=`cat vobs.tmp |head -n $TITLE_NO |tail -n1`
let SUB_NOS=`wc -l subtitles/$VOB-subs_id.tmp |awk '{print $1}'`
LINE=1
while [ $LINE -le $SUB_NOS ]; do
cd subtitles
LANG=`cat $VOB-subs_lang.tmp |head -n $LINE |tail -n1`
SUB_ID=`cat $VOB-subs_id.tmp |head -n $LINE |tail -n1`
cd $VOB-sub-$LANG
echo -e '\e[1;31m'"Merging subtitle $LANG into $VOB"'\e[m'
spumux -s $SUB_ID $LANG.xml < ../../$VOB.mpg > $VOB-temp.mpg 2> /dev/null
rm ../../$VOB.mpg
mv $VOB-temp.mpg ../../$VOB.mpg
cd ../../ && echo -e '\e[1;32mDone...\e[m'
let LINE=LINE+1
done
mv $VOB.mpg $VOB
let TITLE_NO=TITLE_NO+1
done
if [ $MENUS = "yes" ] ; then
dvd_author_menus
else
dvd_author
fi
}


omit_title () {
if [ -n $OMIT_TITLE ] ; then

for i in `echo $OMIT_TITLE |awk -F"," '{for (i=1; i<=NF; i++) print $i}' |grep _` ; do echo "vob_"$i"t.vob" >> omit_vobs.tmp ; done
for i in `echo $OMIT_TITLE |awk -F"," '{for (i=1; i<=NF; i++) print $i}' |grep -v _` ; do echo "vob_"$i"_001t.vob" >> omit_vobs.tmp ; done

for i in `cat omit_vobs.tmp` 2> /dev/null ; do
let TITLE_START=`sed -n "/"$i"/{=;p;q}" dvdauthor.xml |head -n1`-3
sed -e "$TITLE_START,/\/titleset/d" dvdauthor.xml > dvdauthor-temp.xml
mv dvdauthor-temp.xml dvdauthor.xml
done
else
return 1
fi
}


sub_xml () {
if [ -d subtitles ] ; then
cd subtitles
if [ -z `ls -dv */` 2> /dev/null ] ; then
cd ../
return 1
else
cp ../dvdauthor.xml dvdauthor-sub.xml
for i in `ls -dv */` 2> /dev/null ; do
VOB=`echo $i |cut -d - -f1`
LANG=`echo $i |cut -d _ -f4 |cut -d / -f1`
XML_LINE=`grep -C1 $VOB dvdauthor-sub.xml |awk '{print $1}' |head -n1`
let INSERT_NO=`sed -n "/$VOB/{=;p;q}" dvdauthor-sub.xml |head -n1`-1
INSERT="$INSERT_NO"i
if [ $XML_LINE = "<pgc>" 2> /dev/null ] ; then
sed "$INSERT\<subpicture lang=\"$LANG\" />" dvdauthor-sub.xml > output.xml
mv output.xml dvdauthor-sub.xml
fi
done
mv dvdauthor-sub.xml ../dvdauthor.xml
cd ../
fi
return 1
else
return 1
fi
}

aud_xml () {
if [ -d audio ] ; then
cd audio
cp ../dvdauthor.xml dvdauthor-aud.xml
for i in `ls -vr *audio_track*` ; do
TRACK_NO=1
VOB=`echo $i |cut -d - -f1`
TRACKS_TOTAL=`cat $VOB-audio_track.tmp |wc -l |awk '{print $1}'`
while [ $TRACK_NO -le $TRACKS_TOTAL ]; do
FORMAT=`cat $VOB-audio_track.tmp |head -n $TRACK_NO |tail -n1 |awk '{print $6}'`
TYPE=`cat $VOB-audio_track.tmp |head -n $TRACK_NO |tail -n1 |awk '{print $7}'`
LANG=`cat $VOB-audio_track.tmp |head -n $TRACK_NO |tail -n1 |awk '{print $9}'`
if [ $LANG = "unknown" ] ; then
LANG="en"
fi
if [ $TYPE = "(5.1)" ] ; then
TYPE="dolby=\"surround\""
else
if [ $TYPE = "(stereo)" ] ; then
TYPE="channels=\"2\""
fi
fi
XML_LINE=`grep -C1 $VOB dvdauthor-aud.xml |awk '{print $1}' |head -n1`
let INSERT_NO=`sed -n "/$VOB/{=;p;q}" dvdauthor-aud.xml |head -n1`-1
INSERT="$INSERT_NO"i
if [ $XML_LINE = "<pgc>" 2> /dev/null ] ; then
sed "$INSERT\<audio format=\"$FORMAT\" lang=\"$LANG\" $TYPE />" dvdauthor-aud.xml > output.xml
mv output.xml dvdauthor-aud.xml
fi
let TRACK_NO=TRACK_NO+1
done
done
mv dvdauthor-aud.xml ../dvdauthor.xml
cd ../
return 1
else
return 1
fi
}


dvd_author_menus () {
omit_title
sub_xml
aud_xml
dvdauthor -o $DVD_DIR -x dvdauthor.xml
echo -e '\e[1;35mYou have chosen to --enable-menus\e[m'
echo -e '\e[1;35m'"You will now have to hand-edit the created 'dvdauthor.xml' by looking at the menu's"'\e[m'
echo -e '\e[1;35m.png images in an image-viewer & assigning menu button commands to the relevant menu'
echo -e '\e[1;35mRun the ./submenu.sh script to extract the menu images & have it tell you\e[m'
echo -e '\e[1;35mhow many buttons you need to assign for each .vob\e[m'
echo -e '\e[1;35mLooking in the *.vob.xml files should also give you a clue\e[m'
echo "#!/bin/sh" >> submenu.sh
echo "rm *.png 1> /dev/null 2> /dev/null" >> submenu.sh
echo "rm *.vob.xml 1> /dev/null 2> /dev/null" >> submenu.sh
echo "for i in *m.vob ; do spuunmux -o $i $i; done" >> submenu.sh
echo "for i in *.vob.xml ; do echo -e "Number of buttons in $i: \c" && cat $i |grep button |wc -l ; done" >> submenu.sh
chmod +x submenu.sh
echo -e '\e[1;33m'"Run 'dvdauthor -o $DVD_DIR -x dvdauthor.xml' when you are done to author the DVD structure"'\e[m'
echo -e '\e[1;33m'"Use 'xine dvd:`pwd`/$WORKDIR/$DISC_NAME/$DVD_DIR/VIDEO_TS/' to test before burning"'\e[m'
echo -e '\e[1;31m'"Create image & burn to DVD5 (4.7GB) Disc with 'growisofs -Z /dev/dvd -dvd-video $DVD_DIR/'"'\e[m'
return 0
exit
}


dvd_author () {
omit_title
sub_xml
aud_xml
echo -e '\e[1;31mCreating new DVD file structure\e[m'
mv dvdauthor.xml dvdauthor-temp.xml
sed -e '/menus/,/\/menus/d' dvdauthor-temp.xml > dvdauthor.xml
rm dvdauthor-temp.xml
dvdauthor -o $DVD_DIR -x dvdauthor.xml
echo -e '\e[1;32m'"Newly converted DVD can be found in $WORKDIR/$DISC_NAME/$DVD_DIR/"'\e[m'
echo -e '\e[1;33m'"Create image & burn to DVD5 (4.7GB) Disc with 'growisofs -Z /dev/dvd -dvd-video $WORKDIR/$DISC_NAME/$DVD_DIR/'"'\e[m'
clean_up
}


clean_up () {
if [ $CLEAN = "yes" ] ; then
rm -rf subtitles 1> /dev/null 2> /dev/null
rm -rf audio 1> /dev/null 2> /dev/null
rm * 1> /dev/null 2> /dev/null
cd ../../
else
echo -e '\e[1;31mSkipping clean-up\e[m'
echo -e '\e[1;31mProcess files have been left intact\e[m'
cd ../../
fi
exit
}

dvd_extract