LinHES Forums
http://forums.linhes.org/

Script to Transcode Recordings to H264
http://forums.linhes.org/viewtopic.php?f=11&t=19208
Page 1 of 1

Author:  Luthair [ Fri Nov 14, 2008 11:09 pm ]
Post subject:  Script to Transcode Recordings to H264

I've often wanted to transcode recordings with x264 and have them remain as a recording. Recently I finally wrote a script which seems to work well.

It uses a bitrate of 1000, I don't know if this is optimal, but a 30 minute show once commercials a removed results in a file of ~170mb (for me about 1/5th the size of the original). My original plan had been to use matroska as the container, however the MythTV playback seemed much better using mp4. I find the script requires approximately 1.5x the original runtime for transcoding (X2 4050+ 1gb RAM).

A few things to note:
- I don't believe the script removes commercials based on commercial flagging, a cutlist must be created.
- Temporary files are stored in /myth/tmp/ if a cutlist is present you will need space for the original mpeg too
- I've attempted to incorporate error handling, but I don't know if I've been successful (it hasn't failed, yet)
- Since this is an early version, the script does not remove the old file, it is simply renamed to ${CHAN}_${START}.mpg.old (see above, I didn't want it to fail, and take a recording with it)

I'm curious to know if this works for others, or if anyone has suggestions.

Code:
#!/bin/sh
# Transcode a MythTV recording to
# Usage:  transcode_mp4  %STARTTIME%    %CHANID%   "%DIR%/%FILE%"   %JOBID%

# Constants?
DBUSERNAME="mythtv"
DBPASSWORD="mythtv"
DBHOST="localhost"
TEMP="/myth/tmp/"
TVDIR="/myth/tv/"

starttime="$(date +%s)"

# Variables to improve readability
# Don't change these!
CHAN=$1
START=$2
FILE=$3
JOBID=$4
ERROR=0
BASENAME="${CHAN}_${START}"
STATUSFILE="${TEMP}${BASENAME}_status.log"

sql_command()
# Arg 1 - command to execute
{
   mysql -u $DBUSERNAME --password=$DBPASSWORD -h $DBHOST mythconverg -e "$1"
}

update_comment()
# Arg 1 -comment to set
{
   sql_command "update jobqueue set comment=\"$1\" where id=\"$JOBID\";"
}

set_status()
# Arg 1 - status
{
   sql_command "update jobqueue set status=\"$1\" where id=\"$JOBID\";"
}

# -- Slightly modified from myth2x264 --
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
       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`
           update_comment "$prog_percent% Completed @ $current_FPS fps"
       fi
       sleep 10
   done
}

cut_commercials()
{
   update_comment "Removing commercials"
   CUTLIST=`mythcommflag --getcutlist -c $CHAN -s $START | grep 'Cutlist:' | cut -d \  -f 2`

   if [ -n "$CUTLIST" ]; then
      /usr/bin/nice -n19 mythtranscode -c $CHAN -s $START --outfile "${TEMP}${BASENAME}.mpg" --mpeg2 --honorcutlist
   else
      ln -s "${FILE}" "${TEMP}${BASENAME}.mpg"
   fi
}

transcode_video()
{
    (/usr/bin/nice -n19 mencoder "${TEMP}${BASENAME}.mpg" -o /dev/null -vf softskip,harddup -oac mp3lame -lameopts abr:br=92 -ovc x264 -x264encopts pass=1:bitrate=1000:turbo=2:me=umh:me_range=16:nodct_decimate:nointerlaced:8x8dct:nofast_pskip:trellis=1:partitions=p8x8,b8x8,i8x8,i4x4:mixed_refs:bime:keyint=300:keyint_min=30:frameref=3:bframes=14:b_adapt:b_pyramid:weight_b:direct_pred=auto:subq=5:nobrdo:chroma_me:cabac:deblock:nossim:nopsnr:threads=auto -passlogfile "${TEMP}${BASENAME}.log" > $STATUSFILE 2>&1; ERROR=$?) &
   check_background_progress "2"

   cat /dev/null > $STATUSFILE
   
   if [ $ERROR -eq 0 ]; then
      (/usr/bin/nice -n19 mencoder "${TEMP}${BASENAME}.mpg" -o "${TEMP}${BASENAME}.mp4" -vf softskip,harddup -oac mp3lame -lameopts abr:br=92 -ovc x264 -x264encopts pass=2:bitrate=1000:me=umh:me_range=16:nodct_decimate:nointerlaced:8x8dct:nofast_pskip:trellis=1:partitions=p8x8,b8x8,i8x8,i4x4:mixed_refs:keyint=300:keyint_min=30:frameref=3:bframes=14:bime:b_adapt:b_pyramid:weight_b:direct_pred=auto:subq=5:nobrdo:chroma_me:cabac:deblock:nossim:nopsnr:threads=auto -passlogfile "${TEMP}${BASENAME}.log" > $STATUSFILE 2>&1; ERROR=$?) &
      check_background_progress "2 + 50"

   fi
}

switch_files()
{
   FILESIZE="${TEMP}${BASENAME}.mp4"
   mv "${TEMP}${BASENAME}.mp4" "${TVDIR}${BASENAME}.mp4"
   sql_command "UPDATE recorded SET basename='${BASENAME}.mp4', filesize = '${FILESIZE}' WHERE chanid = '${CHAN}' AND starttime = '${START}';"
   mv "${FILE}" "${FILE}.old"
   /usr/bin/nice -n19 mythcommflag --clearcutlist -c $CHAN -s $START
   /usr/bin/nice -n19 mythcommflag --rebuild -c $CHAN -s $START
}

cleanup()
{
   update_comment "Cleanup"

   rm "${TEMP}${BASENAME}.log"
   rm "${TEMP}${BASENAME}.mpg"
   rm "${TEMP}${BASENAME}.mpg.map"
   rm "${STATUSFILE}"
}

#----- Main ------
cut_commercials
transcode_video

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

if [ $ERROR -eq 0 ]; then
    hours=$((seconds / 3600))
    seconds=$((seconds % 3600))
    minutes=$((seconds / 60))
    seconds=$((seconds % 60))
   switch_files
   set_status 272
    update_comment "Encode Successful. Encoding Time: $hours hour(s) $minutes minute(s) $seconds second(s)"
else
   set_status 304
   update_comment "Encode Failed.  Exit status: $ERROR"
fi

cleanup

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/