#!/bin/sh
# convert recording to x264 encoded avi
# version 0.6

# usage:
# first parameter must be %DIR%/%FILE% of the recording
# second parameter must be the desired base name of the output
# third parameter must be %CHANID% if you set USECUTLIST=Y
# fourth parameter must be %STARTTIME% if you set USECUTLIST=Y
# fifth parameter must be %JOBID% for the User Job status to be updated in MythTV
# in the mythtv setup screen invoke this script like this:
# MYTHTV User Job Command:
# /usr/LH/bin/myth2x264 "%DIR%/%FILE%" "%TITLE% - %SUBTITLE%" "%CHANID%" "%STARTTIME%" "%JOBID%"

# options:
RESOLUTION=960:544 	# to keep the source resolution use -1 or to scale down use xxx:xxx (ie 960:544)
BITRATE=2500		# use negative bitrate to set output file size in KB (ie. -700000)
USECUTLIST=Y		# Y or N

# where the converted video is stored
OUT_DIR=/myth/video

# database settings
BACKEND_HOSTNAME=${BACKEND_HOSTNAME:-"localhost"}
DBUSERNAME=${DBUSERNAME:-"mythtv"}
DBPASSWORD=${DBPASSWORD:-"mythtv"}
SQLCMD="mysql -u $DBUSERNAME --password=$DBPASSWORD -h $BACKEND_HOSTNAME mythconverg -e"

#------FUNCTIONS---------------
update_comment()
# Arg_1 = COMMENT
{
if [ $NO_JOBID = 0 ]; then
    `$SQLCMD "update jobqueue set comment=\"$1\" where id=\"$JOBID\";"`
fi
}

update_status()
# Arg_1 = status code
{
if [ $NO_JOBID = 0 ]; then
    `$SQLCMD "update jobqueue set status=\"$1\" where id=\"$JOBID\";"`
fi
}

check_background_progress()
# check mencoder progress in background
# Arg_1 = PROGRESS CALCULATION
{
while [ `tail -1 $STATUSFILE | grep -c "^x264 \[info\]: kb/s:"` = 0 ]
do
    sleep 10
    check_myth_jobcmds
    current_status=`tail -1 $STATUSFILE | grep "([ 0-9]\{1,\}%)"`
    prog_percent=`echo "$current_status" | sed 's_.*(\([ 0-9][ 0-9]\)%).*_\1_'`
    current_FPS=`echo "$current_status" | sed 's_.*\([ 0-9][ 0-9].[ 0-9][ 0-9]\)fps.*_\1_'`
    if [ -n "$prog_percent" ]; then
        prog_percent=`expr $prog_percent / $1`
        echo "$prog_percent% Completed @ $current_FPS fps"
        update_comment "$prog_percent% Completed @ $current_FPS fps"
    fi
    sleep 10
done
}

check_myth_jobcmds()
# check the myth database for stop pause or resume commands
{
if [ $NO_JOBID = 0 ]; then
    CURRENT_CMD=`$SQLCMD "select cmds from jobqueue where id=\"$JOBID\";" | sed '/[0-9]/!d'`
    case "$CURRENT_CMD" in
	# JOB_RUN
	0) ;;
	# JOB_PAUSE
	1) update_status 6
	   kill -s STOP $mencoder_pid ;;
	# JOB_RESUME
	2) update_status 4
       `$SQLCMD "update jobqueue set cmds=\"0\" where id=\"$JOBID\";"`
       kill -s CONT $mencoder_pid ;;
	# JOB_STOP
	4) update_status 5
	   `$SQLCMD "update jobqueue set cmds=\"0\" where id=\"$JOBID\";"`
       kill -9 $mencoder_pid $command_pid
       clean_up_files
       echo "Encode Cancelled" >> $LOGFILE
       update_status 320
 	   exit ;;
    esac
fi
}

get_mencoder_pid()
{
process_name=""
i1=1
while [ "$process_name" != "found" ]; do
   if [ "`ps $mencoder_pid | grep mencoder | sed 's_.*\(mencoder\).*_\1_'`" = "mencoder" ]; then
      process_name="found"
   else
      mencoder_pid=`expr $mencoder_pid + 1`
   fi
   i1=`expr $i1 + 1`
   if [ $i1 -gt 20 ]; then
      break
   fi
done
}

clean_up_files()
# clean up left over files
{
unlink $TMPFILE 2> /dev/null
unlink $TMPCUTFILE 2> /dev/null
unlink $TMPCUTFILE.map 2> /dev/null
unlink $TWOPASSFILE 2> /dev/null
unlink $TWOPASSFILE.tmp 2> /dev/null
unlink $STATUSFILE 2> /dev/null
unlink $MENCODER_RETURN_CODE 2> /dev/null
unlink $MENCODER_RETURN_CODE_2 2> /dev/null
}

#-------MAIN SCRIPT------------

# check if %JOBID% is passed from command line
JOBID=$5
if [ -z "$JOBID" ]; then
    NO_JOBID=1
else
    NO_JOBID=0
fi

# create temp filename so multiple instances won't conflict
TMPNAME=toX264-$$
TMPFILE=/myth/tmp/$TMPNAME.avi
TMPCUTFILE=/myth/tmp/$TMPNAME.mpg
MENINPUTFILE=$1
TWOPASSFILE=/myth/tmp/$TMPNAME-2pass.log
STATUSFILE=/myth/tmp/$TMPNAME-status.log
MENCODER_RETURN_CODE=/myth/tmp/$TMPNAME-mencoder_return_code
MENCODER_RETURN_CODE_2=/myth/tmp/$TMPNAME-mencoder_return_code_2

# log file location
LOGFILE=/var/log/mythtv/myth2x264.log
CDate="`date`"
echo "" >> $LOGFILE
echo $CDate >> $LOGFILE
echo "File to encode: $MENINPUTFILE     Name: $2" >> $LOGFILE

# start timer
beforetime="$(date +%s)"

check_myth_jobcmds

# check if using cutlist
if [ $USECUTLIST = Y ]; then
    MYTHCOMMFRAMES=`mythcommflag --getcutlist -f $MENINPUTFILE | grep 'Cutlist:' | cut -d \  -f 2`
    if [ -n "$MYTHCOMMFRAMES" ]; then
        echo "Extracting Cutlist..." >> $LOGFILE
        update_comment "Extracting Cutlist"
        /usr/bin/nice -n19 /usr/bin/mythtranscode --chanid "$3" --starttime "$4" --outfile "$TMPCUTFILE" --mpeg2 --honorcutlist
        MENINPUTFILE=$TMPCUTFILE
    fi
fi

# run mencoder in background to do 1st pass conversion
echo "Encoding 1st Pass at $RESOLUTION..." >> $LOGFILE
( /usr/bin/nice -n19 /usr/bin/mencoder $MENINPUTFILE -passlogfile $TWOPASSFILE \
-oac copy -ovc x264 -vf lavcdeint,scale=$RESOLUTION \
-x264encopts threads=auto:pass=1:turbo=1:subq=1:frameref=1:bframes=3:bitrate=$BITRATE \
-o /dev/null > $STATUSFILE 2>&1 ; echo $? > $MENCODER_RETURN_CODE ) &
mencoder_pid=$!
command_pid=$mencoder_pid
get_mencoder_pid

check_background_progress "2"

# run mencoder in background to do 2nd pass conversion
echo "Encoding 2nd Pass at $RESOLUTION..." >> $LOGFILE
( /usr/bin/nice -n19 /usr/bin/mencoder $MENINPUTFILE -passlogfile $TWOPASSFILE \
-oac copy -ovc x264 -vf lavcdeint,scale=$RESOLUTION \
-x264encopts threads=auto:pass=2:subq=5:8x8dct:frameref=3:bframes=3:b_pyramid:weight_b:bitrate=$BITRATE \
-o "$TMPFILE" > $STATUSFILE 2>&1 ; echo $? > $MENCODER_RETURN_CODE_2 ) &
mencoder_pid=$!
command_pid=$mencoder_pid
get_mencoder_pid

check_background_progress "2 + 50"

ERROR=$?

# make output filename unique
OUTPUTFILE=$OUT_DIR/$2.avi
i=1
while [ -e "$OUTPUTFILE" ]
do
    OUTPUTFILE=$OUT_DIR/$2-$i.avi
    i=`expr $i + 1`
done

# move temp file to output location
chown mythtv "$TMPFILE" && mv "$TMPFILE" "$OUTPUTFILE"

# stop timer
aftertime="$(date +%s)"
seconds="$(expr $aftertime - $beforetime)"

if [ $ERROR -eq 0 ]; then
    echo "File Encoded Successfully: $OUTPUTFILE" >> $LOGFILE
    hours=$((seconds / 3600))
    seconds=$((seconds % 3600))
    minutes=$((seconds / 60))
    seconds=$((seconds % 60))
    echo "Encoding took $hours hour(s) $minutes minute(s) $seconds second(s) @ $current_FPS fps." >> $LOGFILE
    update_status 272
    update_comment "Encode Successful. Encoding Time: $hours hour(s) $minutes minute(s) $seconds second(s)"
else
    update_status 304
    update_comment "Encode Failed.  Exit status: $ERROR"
    echo "ERROR: $ERROR" >> $LOGFILE
fi

clean_up_files