#!/bin/bash
#----------------------------------------------------------------------------
# BImage
# Copyright (C) 2007 Nathan Shearer
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published by
# the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to:
# The Free Software Foundation Inc.
# 51 Franklin Street
# Fifth Floor
# Boston, MA
# 02110-1301
# USA
COPYRIGHT="Copyright (C) 2007 Nathan Shearer"
VERSION="1.2.0.0"
function abdvde_cleanup
{
printf "\n"
if ! $DEBUG; then
rm -rf "$TMP"
fi
exit
}
function abdvde_cleanup_title
{
# if ! $DEBUG; then
rm -rf "$TMP/audio"*
rm -rf "$TMP/chapters.txt"
rm -rf "$TMP/mplayer"*
rm -rf "$TMP/subtitles"*
rm -rf "$TMP/tags.xml"
rm -rf "$TMP/temp"*
rm -rf "$TMP/video.avi"
sleep 1
# fi
}
function abdvde_create_mkv
{
unset MKVMERGE_ARGS
# video
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="--default-duration"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="0:${OUTPUT_FRAMERATE}fps"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="--noaudio"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="$TMP/video.avi"
# audio streams
for FILE in "$TMP/audio"*; do
if [ "$FILE" = "$TMP/audio*" ]; then
break
fi
LANGUAGE=`printf "$FILE" | sed -r "s/.*audio\\.[0-9]+\\.([a-z]+)/\\1/"`
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="--language"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="0:$LANGUAGE"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="$FILE"
done
# subtitle streams
for FILE in "$TMP/subtitles"*.idx; do
if [ "$FILE" = "$TMP/subtitles*.idx" ]; then
break
fi
LANGUAGE=`printf "$FILE" | sed -r "s/.*subtitles\\.[0-9]+\\.([a-z]+)\\.idx/\\1/"`
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="--language"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="0:$LANGUAGE"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="--stracks"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="0"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="$FILE"
done
# tags
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="--global-tags"
MKVMERGE_ARGS[${#MKVMERGE_ARGS[@]}]="$TMP/tags.xml"
printf "Muxing everything together: "
mkvmerge -o "$BASENAME.mkv" --chapters "$TMP/chapters.txt" "${MKVMERGE_ARGS[@]}" > /dev/null
printf "\"$BASENAME.mkv\" created.\n"
}
function abdvde_detect_crop
{
printf "Detecting crop widnow: "
WIDTH=0
HEIGHT=0
LEFT=0
TOP=0
if [ `printf "$LENGTH" | tr -d .` -lt 2000 ]; then
WIDTH=720
case "$FORMAT" in
"NTSC")
HEIGHT=480
;;
"PAL")
HEIGHT=576
;;
esac
else
for I in `seq 8 120`; do
OFFSET=$(( `printf "$LENGTH" | tr -d .` * $I / 128000 ))
TEMP=`mplayer dvd://${TITLE} -dvd-device "$INPUT" -vo null -nosound -benchmark -vf cropdetect=24:0 -ss ${OFFSET} -frames 4 2>/dev/null | grep crop= | tail -n 1 | grep -o -E "[0-9]+:[0-9]+:[0-9]+:[0-9]+"`
NEWWIDTH=`printf "$TEMP" | sed -r "s/([0-9]+):.+/\\1/"`
if printf "$NEWWIDTH" | grep -E "[0-9]+" > /dev/null; then
if [ $WIDTH -lt $NEWWIDTH ]; then
WIDTH=$NEWWIDTH
LEFT=`printf "$TEMP" | sed -r "s/[0-9]+:[0-9]+:([0-9]+):.+/\\1/"`
fi
fi
NEWHEIGHT=`printf "$TEMP" | sed -r "s/[0-9]+:([0-9]+):.+/\\1/"`
if printf "$NEWHEIGHT" | grep -E "[0-9]+" > /dev/null; then
if [ $HEIGHT -lt $NEWHEIGHT ]; then
HEIGHT=$NEWHEIGHT
TOP=`printf "$TEMP" | sed -r "s/[0-9]+:[0-9]+:[0-9]+:([0-9]+)/\\1/"`
fi
fi
done
fi
CROP="$WIDTH:$HEIGHT:$LEFT:$TOP"
printf "$CROP\n"
}
function abdvde_detect_telecine
{
unset TELECINE_METHOD
printf "Detecting telecine method: "
# foramt and framerate
case "$FORMAT" in
"NTSC")
mplayer -dvd-device "$INPUT" dvd://${TITLE} -vo null -nosound -quiet -benchmark 2>"$TMP/mplayer_output_2" > "$TMP/mplayer_output_1"
DEMUX_MPG_COUNT=`grep "demux_mpg" "$TMP/mplayer_output_1" | wc -l`
if [ "$DEMUX_MPG_COUNT" = "0" ]; then
FRAMES=$(( `printf "$LENGTH" | tr -d .` * 30000 / 1001000 ))
INPUT_FRAMERATE="30000/1001"
elif [ "$DEMUX_MPG_COUNT" = "1" ]; then
FRAMES=$(( `printf "$LENGTH" | tr -d .` * 24000 / 1001000 ))
INPUT_FRAMERATE="24000/1001"
else
FRAMES=$(( `printf "$LENGTH" | tr -d .` * 30000 / 1001000 ))
INPUT_FRAMERATE="VFR"
fi
;;
"PAL")
FRAMES=$(( `printf "$LENGTH" | tr -d .` * 25 ))
INPUT_FRAMERATE="25"
;;
esac
#detect telecine method
case "$INPUT_FRAMERATE" in
"24000/1001")
TELECINE_METHOD="24000/1001p soft telecined to 30000/1001t"
PROGRESSIVE_PERCENTAGE=100
printf "${TELECINE_METHOD}. Input is ${PROGRESSIVE_PERCENTAGE}%% progressive\n"
;;
"25")
TELECINE_METHOD="25p telecined to 25i"
PROGRESSIVE_PERCENTAGE="unknown"
printf "Unknown. Assuming ${TELECINE_METHOD}\n"
;;
"30000/1001")
# look for 24000/1001
mencoder dvd://"$TITLE" -dvd-device "$INPUT" -fps 30000/1001 -vf pullup,softskip,decimate -ofps 24000/1001 -nosound -ovc raw -of avi -o /dev/null 2>"$TMP/temp" >/dev/null
SKIPPED_FRAMES=`grep "Skipping frame" "$TMP/temp" | wc -l`
if [ $SKIPPED_FRAMES -eq 0 ]; then
TELECINE_METHOD="24000/1001p hard telecined to 30000/1001t"
PROGRESSIVE_PERCENTAGE=100
printf "${TELECINE_METHOD}. Input is ${PROGRESSIVE_PERCENTAGE}%% progressive\n"
# if less than $INTERLACE_TOLERANCE% is interlaced, than the video was likely edited after it was telecined
elif [ $SKIPPED_FRAMES -lt $(( $FRAMES * $INTERLACE_TOLERANCE / 100 )) ]; then
TELECINE_METHOD="24000/1001p hard telecined to 30000/1001t"
PROGRESSIVE_PERCENTAGE=$(( ( $FRAMES - $SKIPPED_FRAMES ) * 100 / $FRAMES ))
printf "${TELECINE_METHOD}. Input is ${PROGRESSIVE_PERCENTAGE}%% progressive\n"
# look for 30000/1001. $SKIPPED_FRAMES should equal $FRAMES / 5
elif [ $(( $SKIPPED_FRAMES * 500 / $FRAMES )) -gt $(( 100 - $INTERLACE_TOLERANCE )) ]; then
# is it 30000/1001i or 60000/1001f, hard to tell...
TELECINE_METHOD="30000/1001p telecined to 30000/1001i"
PROGRESSIVE_PERCENTAGE="unknown"
printf "Unknown. Assuming ${TELECINE_METHOD}\n"
fi
;;
"VFR")
# look for 24000/1001
mencoder dvd://"$TITLE" -dvd-device "$INPUT" -fps 30000/1001 -vf pullup,softskip,decimate -ofps 24000/1001 -nosound -ovc raw -of avi -o /dev/null 2>"$TMP/temp" >/dev/null
SKIPPED_FRAMES=`grep "Skipping frame" "$TMP/temp" | wc -l`
if [ $SKIPPED_FRAMES -eq 0 ]; then
TELECINE_METHOD="24000/1001p randomly soft and hard telecined to 30000/1001t"
PROGRESSIVE_PERCENTAGE=100
printf "${TELECINE_METHOD}. Input is ${PROGRESSIVE_PERCENTAGE}%% progressive\n"
# if less than $INTERLACE_TOLERANCE% is interlaced, than the video was likely edited after it was telecined
elif [ $SKIPPED_FRAMES -lt $(( $FRAMES * $INTERLACE_TOLERANCE / 100 )) ]; then
TELECINE_METHOD="24000/1001p randomly soft and hard telecined to 30000/1001t"
PROGRESSIVE_PERCENTAGE=$(( ( $FRAMES - $SKIPPED_FRAMES ) * 100 / $FRAMES ))
printf "${TELECINE_METHOD}. Input is ${PROGRESSIVE_PERCENTAGE}%% progressive\n"
fi
;;
esac
if [ "$TELECINE_METHOD" = "" ]; then
TELECINE_METHOD="unknown"
PROGRESSIVE_PERCENTAGE=$(( ( $FRAMES - $SKIPPED_FRAMES ) * 100 / $FRAMES ))
printf "Unknown. Assuming VFR. ${PROGRESSIVE_PERCENTAGE}%% is progressive material\n"
fi
}
function abdvde_dump_device
{
if [ -b "$INPUT" ]; then
printf "Dumping \"$INPUT\" to your hard drive..."
dd if="$INPUT" of="$TMP/dvd.iso" bs=2048 conv=noerror,sync 2>/dev/null
INPUT="$TMP/dvd.iso"
printf " done.\n"
fi
}
function abdvde_encode_video
{
unset MENCODER_ARGS
# inverse telecine
case "$TELECINE_METHOD" in
"24000/1001p soft telecined to 30000/1001t")
# 300.1
# ALPHA_DOG.1
# AUSTIN_POWERS_2.1
# BALLISTIC_ECKS_VS_SEVER.1
# BIGMAMA.1
# BIG_BULLY.1
# BLACKSHEEP.1
# BODY_OF_LIES.1
# BRAVHART.1
# CAPN_CORELLIS_MANDOLIN.1
# CONSTANTINE_DISC_1.1
# TIM_BURTONS_CORPSE_BRIDE.1
INPUT_FRAMERATE=""
MENCODER_FILTERS=""
OUTPUT_FRAMERATE="24000/1001"
;;
"24000/1001p hard telecined to 30000/1001t")
INPUT_FRAMERATE=""
MENCODER_FILTERS="filmdint=io=5:4:fast=0,softskip"
OUTPUT_FRAMERATE="24000/1001"
;;
"24000/1001p randomly soft and hard telecined to 30000/1001t")
# ALIEN_VS_PREDATOR.1
# AUSTIN_WS.1
# A_BEAUTIFUL_MIND.1
# BOOGEYMAN.1
# CABIN_FEVER.1
# CHEAPER_BY_THE_DOZEN.1
# CHILDREN_OF_MEN.1
# CHRISTMAS_WITH_THE_KRANKS.1
# FARSCAPE_S2_V1D1.5
# FARSCAPE_S2_V1D1.10
# GOLDMEMBER.2
# TEENAGE_DRAMA_QUEEN.1
INPUT_FRAMERATE=""
MENCODER_FILTERS="filmdint=io=5:4:fast=0,softskip"
OUTPUT_FRAMERATE="24000/1001"
;;
"25p telecined to 25i")
# RICHMAN_POORMAN_DISC1.3
# RICHMAN_POORMAN_DISC1.4
INPUT_FRAMERATE=""
MENCODER_FILTERS="filmdint=io=1:1:fast=0,softskip" # some interlacing sneaks through on frames with little movement
MENCODER_FILTERS="pullup,softskip" # this works much better
MENCODER_FILTERS="phase,softskip" # this works best, PAL guys have it easy!
OUTPUT_FRAMERATE="25"
;;
"30000/1001p telecined to 30000/1001i")
INPUT_FRAMERATE=""
MENCODER_FILTERS="filmdint=io=1:1:fast=0,softskip"
OUTPUT_FRAMERATE="30000/1001"
;;
"60000/1001f") # not currently used
;;
*)
INPUT_FRAMERATE=""
MENCODER_FILTERS="filmdint=io=1:4:=fast=0,softskip"
OUTPUT_FRAMERATE="120000/1001"
;;
esac
# crop
if [ "$MENCODER_FILTERS" = "" ]; then
MENCODER_FILTERS="crop=${CROP}"
else
MENCODER_FILTERS="${MENCODER_FILTERS},crop=${CROP}"
fi
# scale
MENCODER_FILTERS="${MENCODER_FILTERS},scale=-9:-9"
CWD=`pwd`
cd "$TMP"
printf "Encoding the video stream...\n"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="-dvd-device"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="$INPUT"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="dvd://${TITLE}"
if [ "$INPUT_FRAMERATE" != "" ]; then
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="-fps"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="$INPUT_FRAMERATE"
fi
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="-sws"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="9"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="-vf"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="$MENCODER_FILTERS"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="-ofps"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="$OUTPUT_FRAMERATE"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="-oac"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="copy"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="-ovc"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="x264"
MENCODER_ARGS[${#MENCODER_ARGS[@]}]="-x264encopts"
if echo "$X264_BITRATE" | grep -E -q "%"; then
X264_OPTIONS="bitrate="$(( $BITRATE * `echo "$X264_BITRATE" | tr -d "%"` / 100 ))":$X264_OPTIONS"
else
X264_OPTIONS="bitrate=$X264_BITRATE:$X264_OPTIONS"
fi
if $DEBUG; then
mencoder "${MENCODER_ARGS[@]}" qp=14:turbo=2:nob_pyramid:nodeblock:nocabac:me=dia:subq=0:threads=0 -of avi -o "$TMP/video.avi" $MENCODER_OPTIONS -msglevel all=1:statusline=5 2>/dev/null | tail -n +3 | head -n 1; printf "\n"
else
mencoder "${MENCODER_ARGS[@]}" $X264_OPTIONS:pass=1 -of avi -o /dev/null $MENCODER_OPTIONS -msglevel all=1:statusline=5 2>/dev/null | tail -n +3 | head -n 1; printf "\n"
mencoder "${MENCODER_ARGS[@]}" $X264_OPTIONS:pass=3 -of avi -o /dev/null $MENCODER_OPTIONS -msglevel all=1:statusline=5 2>/dev/null | tail -n +3 | head -n 1; printf "\n"
mencoder "${MENCODER_ARGS[@]}" $X264_OPTIONS:pass=2 -of avi -o "$TMP/video.avi" $MENCODER_OPTIONS -msglevel all=1:statusline=5 2>/dev/null | tail -n +3 | head -n 1; printf "\n"
fi
cd "$CWD"
# tag the video
printf "Creating tags... "
echo "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" > "$TMP/tags.xml"
echo "<!DOCTYPE Tags SYSTEM \"matroskatags.dtd\">" >> "$TMP/tags.xml"
echo "<Tags>" >> "$TMP/tags.xml"
echo "<Tag>" >> "$TMP/tags.xml"
echo "<Simple>" >> "$TMP/tags.xml"
echo "<Name>Source</Name>" >> "$TMP/tags.xml"
echo "<String>DVD</String>" >> "$TMP/tags.xml"
echo "<Simple>" >> "$TMP/tags.xml"
echo "<Name>Volume ID</Name>" >> "$TMP/tags.xml"
echo "<String>${VOLUMEID}</String>" >> "$TMP/tags.xml"
echo "</Simple>" >> "$TMP/tags.xml"
echo "<Simple>" >> "$TMP/tags.xml"
echo "<Name>Telecine Method</Name>" >> "$TMP/tags.xml"
echo "<String>${TELECINE_METHOD}</String>" >> "$TMP/tags.xml"
echo "</Simple>" >> "$TMP/tags.xml"
echo "<Simple>" >> "$TMP/tags.xml"
echo "<Name>Bitrate</Name>" >> "$TMP/tags.xml"
echo "<String>${BITRATE}</String>" >> "$TMP/tags.xml"
echo "</Simple>" >> "$TMP/tags.xml"
echo "</Simple>" >> "$TMP/tags.xml"
echo "</Tag>" >> "$TMP/tags.xml"
echo "<Tag>" >> "$TMP/tags.xml"
echo "<Simple>" >> "$TMP/tags.xml"
echo "<Name>Abdvde Version</Name>" >> "$TMP/tags.xml"
echo "<String>${VERSION}</String>" >> "$TMP/tags.xml"
echo "</Simple>" >> "$TMP/tags.xml"
echo "</Tag>" >> "$TMP/tags.xml"
echo "<Tag>" >> "$TMP/tags.xml"
echo "<Simple>" >> "$TMP/tags.xml"
echo "<Name>Mencoder Filters</Name>" >> "$TMP/tags.xml"
echo "<String>${MENCODER_FILTERS}</String>" >> "$TMP/tags.xml"
echo "</Simple>" >> "$TMP/tags.xml"
echo "</Tag>" >> "$TMP/tags.xml"
echo "<Tag>" >> "$TMP/tags.xml"
echo "<Simple>" >> "$TMP/tags.xml"
echo "<Name>x264encopts</Name>" >> "$TMP/tags.xml"
echo "<String>$X264_OPTIONS</String>" >> "$TMP/tags.xml"
echo "<Simple>" >> "$TMP/tags.xml"
echo "<Name>bitrate</Name>" >> "$TMP/tags.xml"
if echo "$X264_BITRATE" | grep -E -q "%"; then
echo "<String>"$(( $BITRATE * `echo "$X264_BITRATE" | tr -d "%"` / 100 ))"</String>" >> "$TMP/tags.xml"
else
echo "<String>$X264_BITRATE</String>" >> "$TMP/tags.xml"
fi
echo "</Simple>" >> "$TMP/tags.xml"
echo "<Simple>" >> "$TMP/tags.xml"
echo "<Name>passes</Name>" >> "$TMP/tags.xml"
echo "<String>3</String>" >> "$TMP/tags.xml"
echo "</Simple>" >> "$TMP/tags.xml"
echo "</Simple>" >> "$TMP/tags.xml"
echo "</Tag>" >> "$TMP/tags.xml"
echo "</Tags>" >> "$TMP/tags.xml"
printf "done\n"
}
function abdvde_extract_audio
{
printf "Extracting audio streams: "
for INDEX in `mplayer dvd://${TITLE} -dvd-device "$INPUT" -vo null -nosound -frames 10 2>/dev/null | grep "audio stream" | sed -r "s/audio stream: ([0-9]+).*/\\1/"`; do
STREAM="$INDEX"
INDEX=`mplayer dvd://${TITLE} -dvd-device "$INPUT" -vo null -nosound -frames 10 2>/dev/null | grep "audio stream: $INDEX"`
#AUTIO_FORMAT=`printf "$INDEX" | sed -r "s/.*format: (.+) language.*/\\1/"`
LANGUAGE=`printf "$INDEX" | sed -r "s/.*language: ([a-z]+) .*/\\1/"`
if [ "$LANGUAGE" = "unknown" ]; then
LANGUAGE="en"
fi
AID=`printf "$INDEX" | sed -r "s/.*([0-9]{3})\\./\\1/"`
mplayer dvd://${TITLE} -dvd-device "$INPUT" -aid ${AID} -dumpaudio -dumpfile "$TMP/audio.${STREAM}.${LANGUAGE}" 1>/dev/null 2>&1
if [ -s "$TMP/audio.${STREAM}.${LANGUAGE}" ]; then
printf "${LANGUAGE} "
else
rm -f "$TMP/audio.${STREAM}.${LANGUAGE}"
fi
done
printf "\n"
}
function abdvde_extract_chapters
{
printf "Extracting chapter information: "
dvdxchap -t ${TITLE} "$INPUT" > "$TMP/chapters.txt"
printf "done\n"
}
function abdvde_extract_subtitles
{
printf "Extracting subtitles:"
CWD=`pwd`
cd "$TMP"
if [ "$SUBTITLE_STREAMS" -ne 0 ]; then
poweriso extract "$INPUT" VIDEO_TS/VTS_01_0.IFO -od "$TMP" >/dev/null
mv "VTS_01_0.IFO" "abdvde.ifo"
for INDEX in `mplayer dvd://${TITLE} -dvd-device "$INPUT" -v -vo null -nosound -frames 10 2>/dev/null | grep "( sid )" | sed -r "s/subtitle \\( sid \\): ([0-9]).*/\\1/"`; do
SID="$INDEX"
INDEX=`mplayer dvd://${TITLE} -dvd-device "$INPUT" -v -vo null -nosound -frames 10 2>/dev/null | grep "subtitle ( sid ): $SID"`
LANGUAGE=`printf "$INDEX" | sed -r "s/.*language: ([a-z]+)/\\1/"`
if [ "$LANGUAGE" = "unknown" ]; then
LANGUAGE="en"
fi
mplayer dvd://${TITLE} -dvd-device "$INPUT" -dumpstream -dumpfile /dev/fd/3 3>&1 1>/dev/null 2>/dev/null | \
tccat -L | \
tcextract -x ps1 -t vob -a $(( 32 + $SID )) | \
subtitle2vobsub -o "subtitles."$(( 32 + $SID ))".$LANGUAGE" -i "abdvde.ifo" -a $(( 32 + $SID ))
printf " ${LANGUAGE}"
done
printf "\n"
else
printf " None found.\n"
fi
cd "$CWD"
# cleanup
rm -f "$TMP/abdvde.ifo"
}
function abdvde_get_info_1
{
mplayer -dvd-device "$INPUT" -msglevel identify=6 -frames 0 dvd:// 2>/dev/null > "$TMP/abdvde.dvd_info"
VOLUMEID=`grep "ID_DVD_VOLUME_ID" "$TMP/abdvde.dvd_info" | sed -r "s/ID_DVD_VOLUME_ID=(.+)/\\1/"`
printf "Volume ID: ${VOLUMEID}\n"
DISCID=`grep "ID_DVD_DISC" "$TMP/abdvde.dvd_info" | sed -r "s/ID_DVD_DISC=(.+)/\\1/"`
#printf "Disc ID: ${DISCID}\n"
TITLES=`grep "ID_DVD_TITLES" "$TMP/abdvde.dvd_info" | sed -r "s/ID_DVD_TITLES=([0-9]+)/\\1/"`
printf "This disc contains $TITLES titles:\n"
TITLE_LONGEST=0
TITLE_MOST_AUDIO_STREAMS=0
TITLE_MOST_SUBTITLE_STREAMS=0
for I in `seq 1 $TITLES`; do
mplayer -dvd-device "$INPUT" -msglevel identify=6 -frames 0 dvd://$I 2>/dev/null > "$TMP/abdvde.title_$I.info"
ANGLES=`grep ID_DVD_TITLE_${I}_ANGLES "$TMP/abdvde.title_$I.info" | sed -r "s/ID_DVD_TITLE_${I}_ANGLES=([0-9]+)/\\1/"`
CHAPTERS=`grep ID_DVD_TITLE_${I}_CHAPTERS "$TMP/abdvde.title_$I.info" | sed -r "s/ID_DVD_TITLE_${I}_CHAPTERS=([0-9]+)/\\1/"`
LENGTH=`grep ID_DVD_TITLE_${I}_LENGTH "$TMP/abdvde.title_$I.info" | sed -r "s/ID_DVD_TITLE_${I}_LENGTH=([0-9]+)(\\..*)?/\\1/"`
printf " Title $I: $ANGLES angles, $CHAPTERS chapters, $LENGTH seconds long\n"
AUDIO_STREAMS=`grep "number of audio channels on disk" "$TMP/abdvde.title_$I.info" | sed -r "s/number of audio channels on disk: ([0-9]+)[^0-9]*/\\1/"`
if [ $AUDIO_STREAMS -ne 0 ]; then
printf " $AUDIO_STREAMS audio streams:\n"
for J in `grep "audio stream: " "$TMP/abdvde.title_$I.info" | sed -r "s/audio stream: ([0-9]+).*/\\1/"`; do
AUDIO_STREAM="$J"
J=`grep "audio stream: $J" "$TMP/abdvde.title_$I.info"`
FORMAT=`printf "$J" | sed -r "s/.*format: (.+) language.*/\\1/"`
LANGUAGE=`printf "$J" | sed -r "s/.*language: ([a-z]+) .*/\\1/"`
AID=`printf "$J" | sed -r "s/.*([0-9]{3})\\./\\1/"`
printf " $LANGUAGE, $FORMAT\n"
done
fi
SUBTITLE_STREAMS=`grep "number of subtitles on disk" "$TMP/abdvde.title_$I.info" | sed -r "s/number of subtitles on disk: ([0-9]+)/\\1/"`
if [ $SUBTITLE_STREAMS -ne 0 ]; then
printf " $SUBTITLE_STREAMS subtitle streams:\n"
for J in `grep "( sid )" "$TMP/abdvde.title_$I.info" | sed -r "s/subtitle.+language: ([a-z]{2})/\\1/"`; do
printf " $J\n"
done
fi
# guess which title is likely the feature film
if [ $LENGTH -gt $TITLE_LONGEST ]; then
TITLES_TO_RIP=$I
TITLE_LONGEST=$LENGTH
TITLE_MOST_AUDIO_STREAMS=$AUDIO_STREAMS
TITLE_MOST_SUBTITLE_STREAMS=$SUBTITLE_STREAMS
elif [ $LENGTH -eq $TITLE_LONGEST ]; then
if [ $AUDIO_STREAMS -gt $TITLE_MOST_AUDIO_STREAMS -o $SUBTITLE_STREAMS -gt $TITLE_MOST_SUBTITLE_STREAMS ]; then
TITLES_TO_RIP=$I
TITLE_LONGEST=$LENGTH
TITLE_MOST_AUDIO_STREAMS=$AUDIO_STREAMS
TITLE_MOST_SUBTITLE_STREAMS=$SUBTITLE_STREAMS
fi
fi
done
}
function abdvde_get_info_2
{
SUBTITLE_STREAMS=`grep "number of subtitles on disk" "$TMP/abdvde.title_$TITLE.info" | sed -r "s/number of subtitles on disk: ([0-9]+)/\\1/"`
AUDIO_STREAMS=`grep "number of audio channels on disk" "$TMP/abdvde.title_$TITLE.info" | sed -r "s/number of audio channels on disk: ([0-9]+)[^0-9]*/\\1/"`
LENGTH=`grep "ID_DVD_TITLE_${TITLE}_LENGTH" "$TMP/abdvde.title_${TITLE}.info" | sed -r "s/.+=(.+)/\\1/"`
printf "Calculating video bitrate: "
if $DEBUG; then
BITRATE=8192
else
BITRATE=`mencoder dvd://$TITLE -dvd-device "$INPUT" -nosound -ovc copy -of rawvideo -o /dev/null 2>/dev/null | grep "Video stream" | sed -r "s/Video stream: *([0-9]+)\\..*/\\1/"`
fi
printf "$BITRATE\n"
ASPECT_RATIO=`mplayer dvd://$TITLE -dvd-device "$INPUT" -vo null -nosound -frames 4 2>/dev/null | grep "Movie-Aspect" | sed -r "s/^Movie-Aspect is ([0-9])\\.([0-9]+):.*/\\1\\2/"`
case `grep "ID_VIDEO_HEIGHT" "$TMP/abdvde.title_${TITLE}.info" | sed -r "s/.+=(.+)/\\1/" | sed -r "s/ID_VIDEO_HEIGHT=([0-9]+)/\\1/"` in
"480")
FORMAT="NTSC"
;;
"576")
FORMAT="PAL"
;;
esac
}
function abdvde_get_info_user
{
printf "\n"
if [ "$BATCH_MODE" != "" ]; then
case "$BATCH_MODE" in
"all")
BASENAME="$VOLUMEID"
TITLES_TO_RIP=`seq 1 $TITLES`
printf "Using \"$BASENAME\" as the base filename.\n"
;;
"longest")
BASENAME="$VOLUMEID"
printf "Using \"$BASENAME\" as the base filename.\n"
;;
*)
if ! printf "$TITLES_TO_RIP" | grep -E -q "( ?[0-9]+)+"; then
printf "$0: Titles must be a space separated list.\n"
exit 1
fi
BASENAME="$VOLUMEID"
TITLES_TO_RIP="$BATCH_MODE"
printf "Using \"$BASENAME\" as the base filename.\n"
;;
esac
else
BASENAME="$VOLUMEID"
read -p "Please enter the title(s) you want to rip [$TITLES_TO_RIP]: " USER_TITLE
case "$USER_TITLE" in
"");;
"*")
TITLES_TO_RIP=`seq 1 $TITLES`
;;
*)
TITLES_TO_RIP="$USER_TITLE"
;;
esac
printf "No more user input required.\n"
fi
}
function abdvde_help
{
printf "abdvde is a shell script which automates the process of ripping a DVD to your\n"
printf "hard drive.\n\n"
printf "Usage:\n"
printf " abdvde [options] [<input>]\n\n"
printf "Options:\n"
printf " -b [all|longest|title(s)]\n"
printf " Operate in batch mode. Do not ask the user for anything and rip\n"
printf " all, longest, or the specified title(s).\n"
printf " -h\n"
printf " Display this help message and exit.\n"
printf " -i <input>\n"
printf " Rip from <input> instead of /dev/dvd. <input> may be a device or an iso.\n"
printf " -I\n"
printf " Display information about the DVD and exit.\n"
#printf " -n N\n"
#printf " Add integer N to the niceness (default 20).\n"
printf " -v\n"
printf " Print the version and exit.\n\n"
printf "Examples:\n"
printf " abdvde -b longest\n"
printf " Rips the longest title on /dev/dvd\n"
printf " abdvde -b longest disc1.iso\n"
printf " Rips the longest titles on disc1.iso and disc2.iso\n"
exit
}
function abdvde_version
{
printf "abdvde $VERSION $COPYRIGHT\n"
exit
}
# defaults
DEBUG=false
INPUT=/dev/dvd
TMP="/tmp"
INTERLACE_TOLERANCE=5 # if less than 5% is interlaced, than the video was likely edited after it was telecined. Perform IVTC and encode CFR.
X264_OPTIONS="keyint=120:keyint_min=1:frameref=16:bframes=16:b_pyramid:direct_pred=auto:weight_b:partitions=all:8x8dct:subq=9:chroma_me:mixed_refs:nofast_pskip:threads=0:nointerlaced"
X264_BITRATE="50%" # this can also be an integer like "2048". Measured in Kb.
# load configuration
if [ -r /etc/abdvde/abdvde.conf ]; then
. /etc/abdvde/abdvde.conf
fi
if [ -r ~/.abdvde.conf ]; then
. ~/.abdvde.conf
fi
if $DEBUG; then
TMP="$TMP/abdvde"
else
TMP="$TMP/abdvde."`date +%s`
fi
mkdir -p "$TMP"
while getopts "b:hI:v" OPTION; do
case "$OPTION" in
"b") BATCH_MODE="$OPTARG";;
"h") abdvde_help;;
"I") abdvde_get_info_1; exit;;
#"n") NICE="$OPTARG";;
"v") abdvde_version;;
*) abdvde_help;;
esac
done
shift $(($OPTIND - 1))
if [ $# -gt 0 ]; then
INPUT=`readlink -f "$1"`
fi
#------------------------------------------------------------------------------
# prepare environment
trap abdvde_cleanup SIGINT SIGTERM
# ensure "$INPUT" can be read
if [ ! -r "$INPUT" ]; then
printf "$0: \"$INPUT\" cannot be read.\n"
exit 1
fi
# ensure there is a DVD in the drive
if [ -b "$INPUT" ]; then
eject -t "$INPUT" 2>/dev/null
if ! dd if="$INPUT" of=/dev/null bs=1 count=1 2>/dev/null; then
while ! dd if="$INPUT" of=/dev/null bs=1 count=1 2>/dev/null > /dev/null; do
printf "No medium found...\n"
sleep 10
done
filestat "$INPUT" 1>/dev/null 2>/dev/null
printf "\n"
fi
fi
#------------------------------------------------------------------------------
# begin execution
# collect information
abdvde_get_info_1
# VOLUMEID The Volume ID
# DISCID The Disc ID
# TITLES The number of titles on the DVD
# TITLE_LONGEST The longest title on the DVD
abdvde_get_info_user
# BASENAME The base filename to use
# TITLES_TO_RIP The title(s) to rip
abdvde_dump_device
for TITLE in $TITLES_TO_RIP; do
BASENAME="$VOLUMEID.$TITLE"
printf "\nRipping title $TITLE.\n"
abdvde_get_info_2
# AUDIO_STREAMS The number of audio streams
# SUBTITLE_STREAMS The number of subtitle streams
# LENGTH The length of TITLE in seconds
# FORMAT NTSC or PAL
abdvde_detect_telecine
# FRAMES The length of TITLE in frames
# TELECINE_METHOD The method used to telecine TITLE
abdvde_detect_crop
# WIDTH The width of the video.
# HEIGHT The height of the video.
# CROP The crop window.
abdvde_extract_audio
abdvde_extract_subtitles
abdvde_extract_chapters
abdvde_encode_video
# INPUT_FRAMERATE The framerate of TITLE
# OUTPUT_FRAMERATE The framerate of the original footage and encoded video
abdvde_create_mkv
abdvde_cleanup_title
done
abdvde_cleanup