#! /bin/bash
#testcommand for media player
#parameters: command [filename] [...]
#  test
#  play filename xsize ysize
#return -1 if any error (no output!)
#this script is prepared for tools writing to stdout or requiring a file name
#  for tools writing to stdout simple create a new convertXXX function
#    that sends the tool to background and sets MPID to the pid
#  for tools requiring a filename call createFifo first, then
#    also create a function that sends the tool in background
#  after starting the conversion tool call waitFkt, this will kill the conversion
#  tool and the fifo reader if we are killed or if one of the tools finishes

#set -x

# fifo or temp file (use temp file on slow systems - needs space!)
USE_FIFO=0
#delay for slow systems befor pplaying starts on client side
PREBUFFER_DELAY=10
#whether to use mencoder or ffmpeg
USE_MENCODER=
#limit mencoder quality (or ffmpeg quality)
MENENCODER_LOW=1
#the locaton of the fifo
#WARNING: if USE_FIFO = 0 this is a real file - needs sufficient space!
FIFO=/tmp/vdrfifo$$
#the default DVD device
DVD=/dev/sr0
#tempfile used during dvd listing
TMPF=/tmp/dvd$$


log() {
  echo >/dev/null
  echo "$$:`date `:$*" >> /tmp/test1.log
}

#determine the sleepfunction to be used
#return SLEEPCMD

setSleepFunction() {
  type usleep > /dev/null 2>&1
  if [ $? = 0 ] ; then
    SLEEPCMD="usleep 100000"
  else
    SLEEPCMD="sleep 1"
  fi
  log "sleepcommand=$SLEEPCMD"
}


trapfkt() {
  log "trap received"
  if [ "$MPID" != "" ] ; then
    log killing MPID=$MPID
    kill $MPID > /dev/null 2>&1
    kill -9 $MPID > /dev/null 2>&1
  fi
  if [ "$FPID" != "" ] ; then
    log killing FPID=$FPID
    kill $FPID > /dev/null 2>&1
    kill -9 $FPID > /dev/null 2>&1
  fi
  if [ -p $FIFO -o -f $FIFO ] ; then
    log removing tmpf/fifo $FIFO
    rm -f $FIFO
  fi
  if [ -p $TMPF ] ; then
    rm -f $TMPF
  fi
}

#create a fifo or tempfile
createFifo() {
  if [ $USE_FIFO = 1 ] ; then
    log creating fifo $FIFO
    mkfifo $FIFO >/dev/null 2>&1 || exit 1
  else
    log creating tmpfile $FIFO
    rm -f $FIFO
    touch $FIFO
  fi
}

#start a reader for the fifo
startReader() {
  if [ "$MPID" != "" ] ; then
    tail --pid=$MPID -f $FIFO 2>&1 &
    FPID=$!
  else
    tail -f $FIFO 2>&1 &
    FPID=$!
  fi
  log readerPid=$FPID
}


initialDelay() {
  if [ "$PREBUFFER_DELAY" != "" ] ; then
    log waiting $PREBUFFER_DELAY seconds to prebuffer
    nrwait=` expr $PREBUFFER_DELAY \* 1 ` 
    while [ $nrwait -gt 0 ] 
    do
      sleep 1
      nrwait=`expr $nrwait - 1` 
    done
  fi
  log starting
}

#filename syntax: filename#title,title,...
#or             : filename#title:chap-chap
convertDVD() {
  dvfn=`echo "$1" | sed 's/#[^#]*$//'`
  dvti=`echo "$1" | sed 's/.*#//'`
  dvchap=`echo $dvti | sed -n 's/.*://p'` 
  if [ "$dvchap" != "" ] ; then
    dvcp="dvd://"`echo $dvti | sed 's/:.*//'`
    dvchap="-chapter $dvchap"
  else
    for dvxti in ` echo $dvti | tr ',' ' '` 
    do
       dvcp="$dvcp dvd://$dvxti"
    done
  fi
  #echo mencoder  -dvd-device "$dvfn" -of mpeg -oac copy -ovc copy -o $FIFO $dvchap $dvcp > /dev/null 2>&1 &
  mencoder  -dvd-device "$dvfn" -of mpeg -oac lavc -ovc copy -vf harddup -srate 48000 -af lavcresample=48000 -lavcopts acodec=mp2:abitrate=192 -o $FIFO $dvchap $dvcp  > /dev/null 2>&1 &
  MPID=$!
}


listDVD() {
  bn=`basename "$1"` 
  #mx=`lsdvd "$1" | sed -n 's/^Title: *\([0-9]*\).*/\1,/p'|tr -d '\012'` 
  #lsdvd "$1" | sed -n 's?^ *Title: *\([0-9][0-9]*\) *, *Length: *\(.*\) *Chapters.*?'$bn' - T \1, \2;'$1'#\1.dvd-title@'$bn' - T \1 Menu;'$1'#\1.dvd-chapter?p' | tr '@' '\012'
  rm -f $TMPF
  lsdvd "$1" | sed -n 's?^ *Title: *\([0-9][0-9]*\) *, *Length: *\(.*\) *Chapters.*?\1 \2?p' |  while read dvti dvlen
  do
    dvlen=`echo $dvlen | sed 's/\..*//'`
    if [ "$dvlen" != "00:00:00" ] ; then
      echo "$bn - T $dvti - $dvlen;$1#$dvti.dvd-title"
      echo "$bn - T $dvti - [Menu];$1#$dvti.dvd-chapter"
      allti="$allti,$dvti"
      echo $allti > $TMPF
    fi
  done
  allti="`cat $TMPF`"
  rm -f $tmpf
  echo "$bn - All;$1#$allti.dvd-title"
}
listDVDChapter() {
  bn=`basename "$1" | sed 's/#[^#]*$//'`
  fn=`echo "$1" | sed 's/\.dvd-chapter *$//' | sed 's/#[^#]*$//'`
  ti=`echo "$1" | sed 's/.*#//' | sed 's/\.dvd-chapter *$//'`
  echo "$bn - T $ti - All;$fn#$ti.dvd-title"
  mx=`lsdvd "$fn" | sed -n 's?^ *Title: *'$ti' *, *Length:.*Chapters: *\([0-9]*\).*?\1?p'`
  lsdvd -c "$fn" | sed -n '/^Title: *'$ti'/,/^ *$/p' | sed -n 's?^[ 	]*Chapter: *\([0-9][0-9]*\) *, *Length: *\([0-9.:]*\).*?'$bn' - T '$ti' - C \1, \2;'$fn'#'$ti':\1'-$mx'.dvd-title?p' 
}


#convert AVI to mpeg2, using mencoder see
#http://www.wiki.csoft.at/index.php/MEncoder_Scripts
convertAVI_Mencoder() {
  #additional video encoding options to lower CPU usage
  if [ "$MENENCODER_LOW" = 1 ] ; then
    addOpts=":brd_scale=4:dia=-2:vfdct=1"
  else
    addOpts=
  fi
  if [ -f "$1.rot" ] ; then
	log found rotation marker for "$1"
 	rt=`cat "$1.rot"` 
        case "$rt" in
	270|-90)
		RTOP="-vf-add rotate=2"
		;;
	*)
		RTOP="-vf-add rotate=1"
		;;
	esac
  fi
  sz=$2:$3
  if [ "$RTOP" != "" ] ; then
    sz=$3:$2
  fi
  log "starting mencoder  -oac lavc -ovc lavc -of mpeg -ofps 25 -mpegopts format=mpeg:tsaf:vframerate=25 -vf harddup -srate 48000 -af lavcresample=48000 -lavcopts vcodec=mpeg2video:vrc_buf_size=1835:vrc_maxrate=4000:vbitrate=1000:keyint=15:acodec=mp2:abitrate=192$addOpts $RTOP -vf-add expand=$sz::::: -really-quiet -o $FIFO $1" 
  mencoder  -oac lavc -ovc lavc -of mpeg -ofps 25 -mpegopts format=mpeg:tsaf:vframerate=25 -vf harddup -srate 48000 -af lavcresample=48000 -lavcopts vcodec=mpeg2video:vrc_buf_size=1835:vrc_maxrate=4000:vbitrate=1000:keyint=15:acodec=mp2:abitrate=192$addOpts $RTOP -vf-add expand=$sz::::: -really-quiet -o $FIFO "$1" 2> /dev/null &
  MPID=$!
}
convertAVI_ffmpeg() {
  ifmt=`ffmpeg -i "$1" -fs 1 -target pal-dvd -y /dev/null 2>&1 | sed -n 's/.*Video[^,]*,[^,]*, *\([0-9][0-9]*x[0-9[0-9]*\).*/\1/p' | head -1` 
  log "read format $ifmt for $1"
  ix=${ifmt/x*}
  iy=${ifmt/*x}
  if [ "$ifmt" != "" -a "$ix" != "" -a "$iy" != "" -a "$2" != "" -a "$3" != "" ] ; then
    log "ifmt=$ifmt, ix=$ix,iy=$iy"
    xpad=$(( ( $2 - $ix ) / 2 ))
    ypad=$(( ( $3 - $iy ) / 2 ))
    log computed padding $xpad $ypad
    if [ "$xpad" -ge 0 -a "$ypad" -ge 0 ] ; then
    padding="-padtop $ypad -padbottom $ypad -padleft $xpad -padright $xpad"
    log "padding set to $padding"
    fi
  fi
  if [ "$3" = 576 ] ; then
    fr=25
  else
    fr=29
  fi
  if [ "$MENENCODER_LOW" == "" ] ; then
	HBR="-bufsize 1835000 -maxrate 4000000"
  else
	HDR=""
  fi
  log ffmpeg -i "$1" -f dvd -r $fr -b 3000000 $HBR -vcodec mpeg2video -y -acodec mp2 -ar 48000 -ab 192k -ac 2 $padding $FIFO 
  ffmpeg -i "$1" -f dvd -r $fr -b 3000000 $HBR -vcodec mpeg2video -y -acodec mp2 -ar 48000 -ab 192k -ac 2 $padding $FIFO  > /dev/null 2>&1 &
  MPID=$!
}


convertAVI() {
  if [ "$USE_MENCODER" != "" ] ; then
    convertAVI_Mencoder "$1" "$2" "$3"
  else
    convertAVI_ffmpeg "$1" "$2" "$3"
  fi
}
#convert WAV to mpeg using lame
convertWAV() {
lame -v -b 192 -S "$1" - - 2>&1 &
MPID=$!
}

#convert pictures using GraphicsMagic
convertPicture(){
  if [ "$2" != "" -a "$3" != "" ] ; then
    fopt="-geometry ${2}x$3"
    rot=`gm identify -format '%[EXIF:Orientation]' "$1"` 
    [ "$rot" = 3 ] && rtopt=" -rotate 180"
    [ "$rot" = 8 ] && rtopt=" -rotate 270"
    [ "$rot" = 6 ] && rtopt=" -rotate 90"
  fi
  log gm convert $rtopt $fopt  "$1" jpeg:- 
  gm convert $rtopt $fopt  "$1" jpeg:- 2>&1 &
  MPID=$!
}

#cat data
catData() {
  cat "$1" 2>&1 &
  MPID=$!
}

#convert a playlist
#handle http:// as audio-url
convertList() {
  cat "$1" 2>&1 | sed 's?^ *http:\(.*\)?/http:\1.http-audio?'
}

#get a HTTP url via wget
getHTTP() {
  wget -q -O - "$1" 2>&1 &
  MPID=$!
}


#put in background to kill children and remove fifo
#in case we are killed by -9
#will be alive as long as the pid p1 is alive, afterwards kills other pids
#p1 my pid, p2 fifo, p3... other pids
bgclean() {
  opid=$1
  shift || exit 1
  fifo=$1
  shift || exit 1
  log bg: started $opid $fifo $*
  while [ 1 = 1 ]
  do
    kill -0 $opid > /dev/null 2>&1
    if [ $? != 0 ] ; then
      if [ "$fifo" != "" ] ; then
        log bg: remove $fifo
        rm -f $fifo
      fi
      for pid in $*
      do
        log bg: kill $pid
        kill -9 $pid > /dev/null 2>&1
      done
      log bg: exiting
      exit 0
    fi
    sleep 1
  done
}

 
  



#wait until the cat/converter has been stopped
#p1 != "" - use initial delay
waitFkt() {
  bgclean $$ $FIFO $MPID $FPID < /dev/null > /dev/null 2>&1 &
  if [ "$1" != "" ] ; then
    initialDelay
  fi
  setSleepFunction
  log start waiting for MPID=$MPID and FPID=$FPID
  while [ 1 = 1 ]
  do
  dokill=0
  if [ "$MPID" != ""  -a "$FPID" = "" ] ; then
    kill -0 $MPID >/dev/null 2>&1 || dokill=1
  fi
  if [ "$FPID" != "" ] ; then
    kill -0 $FPID >/dev/null 2>&1 || dokill=1
  fi
  if [ $dokill = 1 ] ; then
    log "killing MPID=$MPID FPID=$FPID"
    kill -9 $MPID > /dev/null 2>&1
    MPID=""
    kill -9 $FPID > /dev/null 2>&1
    FPID=""
  fi
  if [ "$FPID" = "" -a "$MPID" = "" ] ; then
    log leaving waitFkt
    break
  fi
  eval $SLEEPCMD
  done
}
 
log started with param "$*"
if [ "$1" = "" ] ; then
  echo invalid call
  exit 1
fi
trap trapfkt 0 1 2 3 4 5 6 7 8 10 11 12 13 14 15

case $1 in
  check)
  exit 0
  ;;
  play)
  exts=`echo "$2" | sed 's/.*\.//'` 
  if [ "$exts" = "" ] ; then
    exit 1
  fi
  fname=`echo "$2" | sed 's/\.[^.]*$//'`
  case $exts in
    xmpg)
    #mpeg2 test
    nname="$fname.mpg"
    cat "$nname" &
    MPID=$!
    waitFkt
    ;;
    xjpg)
    #jpeg test
    nname="$fname.jpg"
    [ "$nname" = "" ] && exit 1
    [ ! -f "$nname" ] && exit 1
    convertPicture "$nname" $3 $4
    waitFkt
    ;;
    xmp3)
    #mp3 test
    nname="$fname.mp3"
    cat "$nname" &
    MPID=$!
    waitFkt
    ;;
    #real converting functions
    bmp|BMP|tiff|TIFF|png|PNG|jpg|JPG|jpeg|JPEG)
    convertPicture "$2" $3 $4
    waitFkt
    ;;
    AVI|avi|mpeg|MPEG|mpg|MPG|wmv|WMV|flv|FLV)
    createFifo
    convertAVI "$2" $3 $4
    startReader
    waitFkt 1
    ;;
    WAV|wav)
    convertWAV "$2"
    waitFkt
    ;;
    xdir)
    catData "$2"
    waitFkt
    ;;
    m3u|dir)
    convertList "$2"
    waitFkt
    ;;
    http-audio)
    fn=`echo "$2" | sed 's/\.[^.]*$//' | sed 's?^ */??'`
    getHTTP "$fn"
    waitFkt
    ;;
    dvd-device)
    dv=`cat "$2"`
    if [ "$dv" = "" ] ; then
      dv=$DVD
    fi
    listDVD $dv "$2" $3 $4
    waitFkt
    ;;
    iso)
    listDVD "$2" $3 $4
    waitFkt
    ;;
    dvd-chapter)
    listDVDChapter "$2" $3 $4
    waitFkt
    ;;
    dvd-title)
    createFifo
    convertDVD "$fname" $3 $4
    startReader
    waitFkt
    ;;
    *)
    exit 1
    ;;
  esac
  ;;
  *)
  exit 1
  ;;
esac


