====== VOB to AVI using Mencoder (Next Gen) ====== This is a recode and enhancement of my first [[vob_to_avi_using_mencoder|vob2avi shell script]]. Pretty much does the same. #!/bin/bash function init() { if [ "$INIT_DONE" ]; then echo "+ init: done already" >&2; return; fi key="$IN $OPTS" echo "::: init: initializing with key '$key'" >&2 ; # hash=`echo "$key" | md5sum | cut -f1 -d' '` hash=`echo "OPTS $OPTS" | sed 's/[^[:alnum:]]/_/g' ` echo "+ init: hash is '$hash'" >&2 ; basedir=`dirname "$IN"` basename=`basename "$IN"` export TMPDIR="$basedir/$basename.$hash.vob2avi" echo "+ init: TMPDIR is '$TMPDIR'" >&2 ; mkdir -p "$TMPDIR" INIT_DONE="yes" echo "+ init: done" >&2 ; } function setupaudio() { if [ "$DUMMYMODE" ]; then whiptail --title "ERROR" --msgbox "audio setup can not be done in DUMMY MODE!" 7 75 ; return fi init demux echo "::: setupaudio: setting up audio track configuration for '$IN'" >&2 ; pushd "$TMPDIR" > /dev/null find "." | egrep "audio_0x[a-f0-9]+.vob" | while read track; do track=`basename $track` while true; do tagfile=`mktemp` if \ whiptail --title "choose action for track $track" --menu "" 24 75 17\ listen "Listen to this track" \ remove "Do not include this track in final avi" \ include "Include this track in final avi" \ first "Make this the first audio track" \ 2>$tagfile then \ tag=`cat $tagfile` rm -f $tagfile echo "+ setupaudio: user voted for menu item $tag with $track" >&2 ; case "$tag" in listen) kaffeine $track ;; remove) newaids=`cat aids | grep -v $track` echo -e "$newaids" > aids break ;; include) echo $track >> aids break ;; first) newaids=`cat aids | grep -v $track` echo $track > aids echo -e "$newaids" >> aids break ;; esac else rm -f $tagfile break; fi done done popd >/dev/null } function demux() { if [ "$DUMMYMODE" ]; then whiptail --title "ERROR" --msgbox "demuxing can not be done in DUMMY MODE!" 7 75 ; return fi init if [ -f "$TMPDIR/demux_done" ]; then echo "+ demux: done already" >&2 ; return fi echo "::: demux: demultiplexing '$IN'" >&2 ; info=`info` videoids=`echo -e "$info" | egrep "^ID_VIDEO_ID=" | sort | uniq | cut -f2 -d"="` audioids=`echo -e "$info" | egrep "^ID_AUDIO_ID=" | sort | uniq | cut -f2 -d"="` subtitleids=`echo -e "$info" | egrep "^ID_SUBTITLE_ID=" | sort | uniq | cut -f2 -d"="` #echo -e "$info";return pushd "$TMPDIR" > /dev/null flagfile="demux_lock" rm -f "$flagfile" fifos="" for id in $videoids; do id=`printf "0x%02x" $(($id + 224))` echo "+ demux: found video ID#$id" >&2 ; fifo="video_$id.fifo" mkfifo "$fifo" fifos="$fifos $fifo" ( #wait for flagfile while [ ! -f "$flagfile" ]; do sleep 1; done ; tcdemux -i "$fifo" -A $id > "video_$id.vob" ) & done for id in $audioids; do id=`printf "0x%02x" $id` echo "+ demux: found audio ID#$id" >&2 ; fifo="audio_$id.fifo" mkfifo "$fifo" fifos="$fifos $fifo" ( #wait for flagfile while [ ! -f "$flagfile" ]; do sleep 1; done ; tcdemux -i "$fifo" -A $id > "audio_$id.vob" ) & done for id in $subtitleids; do id=`printf "0x%02x" $(($id + 32))` echo "+ demux: found subtitle ID#$id" >&2 ; fifo="subtitle_$id.fifo" mkfifo "$fifo" fifos="$fifos $fifo" ( #wait for flagfile while [ ! -f "$flagfile" ]; do sleep 1; done ; tcdemux -i "$fifo" -A $id > "subtitle_$id.vob" ) & done touch "$flagfile" pv -N "demuxing" "$IN" | tee $fifos >/dev/null rm -f "$flagfile" rm -f $fifos popd > /dev/null touch "$TMPDIR/demux_done" echo "+ demux: done" >&2 ; exit 0 } function info() { if [ "$DUMMYMODE" ]; then echo "ERROR: info called in DUMMY MODE" >&2 exit -1 fi init if [ -f "$TMPDIR/info" ]; then echo "+ info: done already" >&2 cat "$TMPDIR/info" return fi echo "::: info: initializing" >&2 echo "+ info: identifying $IN with mplayer" >&2 res=`mplayer -ao null -vo null -frames 1 -identify "$IN" 2>&1` echo "+ info: identifying $IN with tcprobe" >&2 res="$res"`tcprobe -H 100 -i "$IN" 2>&1` echo "+ info: saving info" >&2 echo -e "$res" > "$TMPDIR/info" echo "+ info: done" >&2 } function testencode() { echo "::: test-encoding '$1'" >&2 ; vob="$1" #-ss 10:00 ripaudio "$vob" "-frames 2500" encode "$vob" "-frames 2500" audiomerge "$vob" mplayer -vo xv -fs "$vob.avi" } function ripaudio() { echo "::: ripping audio from '$1'" >&2 ; vob="$1" opts="$2" info "$vob" | grep "ID_AUDIO_ID" | cut -f2 -d"=" > "${vob}.aids" cat "${vob}.aids" | while read aid; do mencoder "$vob" $opts -oac copy -aid $aid -ovc frameno -o "${vob}_audio_${aid}.avi" done } function audiomerge() { echo "::: encoding '$1'" >&2 ; vob="$1" aids=`cat "${vob}.aids"` cp -f "${vob}.avi" "${vob}_merged.avi" for aid in $aids; do track=0 if [ -f "${vob}_audio_${aid}.avi" ]; then echo "::: merging lang ${vob}_audio_${aid}.avi as track $track" >&2 ; aviindex -i "${vob}_audio_${aid}.avi" -f -o "${vob}_merged.avi.idx" avimerge -i "${vob}_merged.avi" -o "${vob}.avi.tmp" -p "${vob}_audio_${aid}.avi" -A $aid -x "${vob}_merged.avi.idx" mv -f "${vob}.avi.tmp" "${vob}_merged.avi" track=$(($track + 1)) rm -f "${vob}_merged.avi.idx" fi done } function encode() { echo "::: encoding '$1'" >&2 ; # unlink frameno.avi 2> /dev/null vob="$1" opts="$2" crop=`cropdetect "$vob"` scale=`scaledetect "$vob"` vfopts=pp=de,crop=$crop,scale=$scale lavcopts=vcodec=mpeg4:vhq:vqmin=2:vbitrate=2000 # mencoder "$vob" $opts -oac copy -alang English -ovc frameno -o "${vob}_audio_en.avi" # mencoder "$vob" $opts -oac copy -alang Hungarian -ovc frameno -o "${vob}_audio_hu.avi" mencoder "$vob" $opts -oac copy -ovc lavc -lavcopts $lavcopts:vpass=1 -vf $vfopts -o "/dev/null" mencoder "$vob" $opts -oac copy -ovc lavc -lavcopts $lavcopts:vpass=2 -vf $vfopts -o "$vob.avi" # unlink frameno.avi 2> /dev/null unlink divx2pass.log 2> /dev/null } function scaledetect() { echo "::: scale-detecting '$1'" >&2 ; vob="$1" scalecache="$vob.scale" if [ -f "$scalecache" ]; then echo "+ reading scale data from $scalecache" >&2 scale=`cat "$scalecache"` echo "+ final scale parameters: $scale" >&2 echo "$scale" return fi info=`info "$vob"` #echo -e "$info" #exit 0 res=`echo -e "$info" | egrep "^VIDEO:" | egrep -o "[0-9]+x[0-9]+"` case "$res" in 720x576) echo "+ video has PAL resolution, this is good" >&2 aspect=`echo -e "$info" | egrep "^Movie-Aspect" | egrep -o "[0-9.]+:[0-9.]+" | tr ':' '/'` #aspect="4/3" ow="720" oh="576" ;; *) echo "+ video has $res resolution, this is BAD - UNIMPLEMENTED" >&2 exit -1 ;; esac echo "+ video has $aspect aspect with $res resolution" >&2 crop=`cropdetect "$vob"` w=`echo $crop | cut -f1 -d":"` h=`echo $crop | cut -f2 -d":"` echo "+ cropped video has resolution ${w}x${h}" >&2 # original width: nw=$ow nh=`echo "scale=4;(1/($aspect))*($ow/$oh)*($w/$ow)*$h" | bc | cut -f1 -d'.'` # cropped width: #nw=$w #nh=`echo "scale=4;(1/($aspect))*($ow/$oh)*$h" | bc | cut -f1 -d'.'` scale="${nw}:${nh}" echo "+ storing final parameters to: $scalecache" >&2 echo $scale > "$scalecache" echo "+ final scale parameters: $scale" >&2 echo $scale echo "+ scale detect done." >&2 } function cropdetect() { echo "::: crop-detecting '$1'" >&2 ; vob="$1" cropcache="$vob.crop" if [ -f "$cropcache" ]; then echo "+ reading crop data from $cropcache" >&2 bestcrop=`cat "$cropcache"` echo "+ final parameters: $bestcrop" >&2 echo $bestcrop return fi # info "$vob" # exit 0 echo "+ crop detecting movie with mplayer..." >&2 crops=`mktemp` for x in 2 5 10 20 30 50 100; do mplayer -vo null -ao null -frames 5 -ss $x:00 -vf cropdetect "$vob" 2>/dev/null | grep "\[CROP\]" | egrep -o "[0-9]+:[0-9]+:[0-9]+:[0-9]+" done > $crops cropss=`mktemp` cat $crops | while read crop; do x=`echo $crop | cut -f3 -d":"` y=`echo $crop | cut -f4 -d":"` xl=`echo $crop | cut -f1 -d":"` yl=`echo $crop | cut -f2 -d":"` echo $(( xl*yl)) $crop done > $cropss rm -f $crops bestcrop=`cat $cropss | sort -n | tail -n1 | cut -f2 -d' '` rm -f $cropss echo "+ best crop guessed by mplayer: $bestcrop" >&2 inputconf=`mktemp` echo "W change_rectangle 0 1" >> $inputconf echo "w change_rectangle 0 -1" >> $inputconf echo "E change_rectangle 1 1" >> $inputconf echo "e change_rectangle 1 -1" >> $inputconf echo "S change_rectangle 2 1" >> $inputconf echo "s change_rectangle 2 -1" >> $inputconf echo "D change_rectangle 3 1" >> $inputconf echo "d change_rectangle 3 -1" >> $inputconf cropfile=`mktemp` echo "+ fine tuning with mplayer... (use keys: wWeEsSdD)" >&2 mplayer "$vob" -input conf=$inputconf -vf rectangle=$bestcrop 2>/dev/null | egrep -o "[0-9]+:[0-9]+:[0-9]+:[0-9]+" > $cropfile rm -f $inputconf bestcrop=`tail -n1 $cropfile` rm -f $cropfile echo "+ storing final parameters to: $cropcache" >&2 echo $bestcrop > "$cropcache" echo "+ final crop parameters: $bestcrop" >&2 echo $bestcrop echo "+ crop detect done." >&2 } #encode dvd.DVD_VIDEO.1216721459.01.vob 720:430:0:72 720:405 BANNER=`basename $0`" - GPLv3 - (c) 2008 by Erno Rigo " # try to get to our input file if [ -z "$1" ]; then searchpath=`pwd` else if [ -d "$1" ]; then searchpath="$1" else IN="$1" fi fi if [ ! -z "$searchpath" ]; then echo "::: searching for INPUT candidates in $searchpath... " >&2 files=`find "$searchpath" -type f | egrep ".*[.](vob|mpeg|VOB|MPEG|Vob|Mpeg|mpg|MPG)$" 2>/dev/null` opts=`echo -e "$files" | while read file; do echo "$file" "."; done` menutag=`mktemp` if \ whiptail --noitem --backtitle "$BANNER" --title "select INPUT file" \ --menu "" 24 75 17 -- \ "[Dummy mode]" "dummy"\ $opts \ 2>"$menutag";\ then echo "::: selected tag: "`cat "$menutag"` >&2 IN=`cat "$menutag"` rm -f "$menutag" else echo "::: exiting on user request" >&2 rm -f "$menutag" exit 0; fi fi if [ ! -f "$IN" ]; then IN="Dummy mode!" DUMMYMODE="yes" else # calculate absolute path for IN pushd `dirname "$IN"` > /dev/null IN=`cd -`"/"`basename "$IN"` popd > /dev/null fi OPTS="$2" if [ ! -z "$3" ]; then $3 exit 0 fi # MAIN MENU LOOP while true; do menutag=`mktemp` echo "::: entering main menu" >&2 if \ whiptail --backtitle "IN: '$IN'" --title "main menu" \ --menu "OPTS: '$OPTS'" 24 75 16 -- \ "demux" "- Demultiplex INPUT" \ "setupaudio" "- Setup audio tracks to be included in OUTPUT" \ 2>"$menutag"; \ then tag=`cat "$menutag"` rm -f "$menutag" echo "::: selected tag: $tag" >&2 $tag else echo "::: exiting on user request" >&2 rm -f "$menutag" exit 0; fi done # END MAIN MENU LOOP exit 0 opts=`cat< $optsf longopts=`cat $optsf` rm -f $optsf TEMP=`getopt -o "" --long $longopts -n "$0" -- "$@"` if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi # Note the quotes around `$TEMP': they are essential! eval set -- "$TEMP" while true ; do case "$1" in --encode) echo "Option encode, argument $2" ; shift 2 ;; --cropdetect) cropdetect "$2" ; shift 2 ;; --scaledetect) scaledetect "$2" ; shift 2 ;; --prepare) testencode "$2" ; shift 2 ;; --ripaudio) ripaudio "$2" ; shift 2 ;; --audiomerge) audiomerge "$2" ; shift 2 ;; --demux) demux "$2" ; shift 2 ;; --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;; esac done #echo "Remaining arguments:" #for arg do echo '--> '"\`$arg'" ; done {{tag>util mplayer video encode transcode avi dvd mpeg bash}} ~~LINKBACK~~