Handbrake Script
mythbrake.sh
#!/bin/sh
# Commercial Removal and transcode script for MythTV, updated 11/10/14
# Input arguments are passed to this user job from mythtv-setup
# Invoke using: postProcessRecording.sh %DIR% %FILE% %CHANID% %STARTTIMEUTC%
#
# Pre-requisites:
# 0. A working MythTV backend setup
# 1. HandBrakeCLI installed. If you need to install this on a Ubuntu system,
# try: sudo apt-get install handbrake-cli
# 2. Your MythTV database username and password:
# -- Add these to DBUSER and DBPASSWD lines below. Keep quotes.
#
# Script functions:
# 0. Invoked as a user-job after a MythTV recording completes
# 1. Query database to check if invoked for a commercial-free channel
# 2. If commercial-free channel, go to step 7
# 3. Flag commercials using "All" methods, copy flagged commercials to cutlist
# 4. Lossless transcode to remove commercials from the file
# 5. Rebuild the seek table. Clear cutlist
# 6. Update database to point to recording with no commercials
# 7. Remove stale bookmarking and seek information from the database
# 8. Use Handbrake to transcode recording to H.264 (MPEG-4):
# -- preserve original audio track (5.1, dts etc.)
# -- preserve subtitles
# -- Use x264 encoder for HD-quality video with much reduced file-size
# -- deinterlace video if necessary
# -- create .mp4 file format compatible with Roku or Apple/Android devices
# 9. Update database to point to the new .mp4 transcoded file
# 10. Rebuild seektable for new .mp4 transcoded file
# 11. Remove original recording and cleanup temp files
# Update these based on your setup
#
DBUSER="mythtv"
DBPASSWD="6jaw0P3s"
# Input arguments
#
VIDEODIR=$1 # %DIR%
INFILE=$2 # %FILE%
CHAN=$3 # %CHANID%
START=$4 # %STARTTIMEUTC%
# Locally generated variables
#
# Change extension to .mp4
#OUTFILE=`echo "$2" | sed s/\.mpg/\.mp4/g | sed s/\.ts/\.mp4/g`
OUTFILE=`echo "$2" | sed s/\.ts/\.mp4/g`
TEMPDIR="/tmp"
MYPID=$$
# Run at a lower priority
renice 19 $MYPID
ionice -c 3 -p $MYPID
# Sanity check usage and file existence
if [ -z "$VIDEODIR" -o -z "$INFILE" -o -z "$CHAN" -o -z "$START" ]; then
echo "Usage: $0 <VideoDir> <FileName> <ChannelID> <StartTime>\r" >> pp.log
exit 5
fi
if [ ! -f "$VIDEODIR/$INFILE" ]; then
echo "$0: File does not exist: $VIDEODIR/$INFILE\r" >> pp.log
exit 6
fi
# Work from a temporary directory
mkdir $TEMPDIR/postProcess-$MYPID
cd $TEMPDIR/postProcess-$MYPID
# Only go through commercial flagging if this isn't a commercial-free
# channel. This can be determined by querying the channel table.
COMMFREE=0
mkfifo sqlpipe.$MYPID # needed to preserve scope of COMMFREE variable
mysql --user=$DBUSER --password=$DBPASSWD mythconverg --column-names=0 -ss \
-e 'SELECT chanid FROM channel WHERE commmethod='-2';' > sqlpipe.$MYPID &
while read -r LINE
do
if [ "$CHAN" -eq "$LINE" ]; then
COMMFREE=1
echo "$0: Commercial-free channel. Skipping commercial flagging.\r" >> pp.log
fi
done < sqlpipe.$MYPID
if [ $COMMFREE -eq 0 ]; then
# Flag commercials, copy the flagged commercials to the cutlist, and
# transcode the video to remove the commercials from the file.
mythcommflag --chanid $CHAN --starttime $START --method 7 --quiet
ERROR=$?
if [ $ERROR -gt 126 ]; then
echo "Commercial flagging failed for ${INFILE} with error $ERROR\r" >> pp.log
exit $ERROR
fi
echo -n "$0: Generating cutlist for $INFILE...\r" > pp.log
mythutil --gencutlist --chanid $CHAN --starttime $START --quiet
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Copying cutlist failed for ${INFILE} with error $ERROR\r" >> pp.log
exit $ERROR
fi
echo -n "$0: Removing commercials... \r" >> pp.log
# Remove commercials in a .tmp file, replace original recording
echo "starting mythtranscode\r" >> pp.log
# mythtranscode --honorcutlist --mpeg2 --showprogress -i $VIDEODIR/$INFILE \
mythtranscode --mpeg2 --showprogress -i $VIDEODIR/$INFILE \
-o $TEMPDIR/postProcess-$MYPID/$INFILE.tmp --quiet
mv -f $TEMPDIR/postProcess-$MYPID/$INFILE.tmp $VIDEODIR/$INFILE
echo "replaced $INFILE.tmp with $INFILE. Rebuilding seek table...\r " >> pp.log
# This will rebuild the seek table
mythcommflag --chanid $CHAN --starttime $START --rebuild --quiet
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Rebuilding seek list failed for ${INFILE} with error $ERROR\r" >> pp.log
exit $ERROR
fi
# Remove the cutlist from the program
#
mythutil --clearcutlist --chanid $CHAN --starttime $START --quiet
ERROR=$?
# If successful, fix up the database to point to the transcoded mpeg-2 file
if [ $ERROR -eq 0 ]; then
echo "UPDATE recorded SET cutlist=0, \
filesize = $(ls -l $VIDEODIR/$INFILE | awk '{print $5}') \
WHERE basename = '$INFILE';" > update-db-$MYPID.sql
mysql --user=$DBUSER --password=$DBPASSWD mythconverg \
< update-db-$MYPID.sql
else
echo "Clearing cutlist failed for ${INFILE} with error $ERROR\r" >> pp.log
rm -f $VIDEODIR/$INFILE.tmp
exit $ERROR
fi
fi # ENDIF for channels with commercials
# Remove stale bookmarking and seeking info in the database
echo "DELETE FROM recordedseek WHERE chanid='$CHAN' AND \
starttime='$START';" > update-db-$MYPID.sql
mysql --user=$DBUSER --password=$DBPASSWD mythconverg < update-db-$MYPID.sql
echo "DELETE FROM recordedmarkup WHERE chanid='$CHAN' AND \
starttime='$START';" > update-db-$MYPID.sql
mysql --user=$DBUSER --password=$DBPASSWD mythconverg < update-db-$MYPID.sql
# Transcode the file to .mp4
echo "Transcoding $INFILE to $OUTFILE\r" >> pp.log
#HandBrakeCLI -i $VIDEODIR/$INFILE -o $VIDEODIR/$OUTFILE --format mp4 \
# --no-dvdnav --optimize --markers --encoder x264 \
# --h264-profile main --x264-preset medium --audio 1 --aencoder copy \
# --audio-fallback aac --arate Auto --ab 160 --maxWidth 1280 \
# --maxHeight 720 --loose-anamorphic --loose-crop --modulus 2 --decomb \
# --quality 20 --rate 30 --pfr --verbose 0 2 > hb-log$MYPID.txt
HandBrakeCLI -i $VIDEODIR/$INFILE -o $VIDEODIR/$OUTFILE -e x264 -q 21 -O \
-r 30 --pfr -x ref=6:bframes=5:vbv-maxrate=62000:vbv-bufsize=62000 \
-X 720 --decomb --loose-anamorphic --modulus 2 --x264-tune film \
# --x264-preset medium --h264-profile high --h264-level 4.1 -a 1,1 \
--x264-preset medium --h264-profile main --h264-level 4.1 -a 1,1 \
-E copy:ac3,faac -B auto,160 -R auto,auto -6 auto,dpl2 \
--audio-copy-mask aac,ac3,dtshd,dts,mp3 --audio-fallback ffac3 \
-f mp4 --verbose 1 2 > hb-log$MYPID.txt
# Update the database to point to the transcoded file
echo "UPDATE recorded SET basename='$OUTFILE', \
filesize = $(ls -l $VIDEODIR/$OUTFILE | awk '{print $5}'), \
transcoded='1' WHERE chanid='$CHAN' AND \
starttime='$START';" > update-db-$MYPID.sql
mysql --user=$DBUSER --password=$DBPASSWD mythconverg < update-db-$MYPID.sql
# Rebuild the seektable for new MP4 file
mythcommflag --chanid $CHAN --starttime $START --rebuild --quiet
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Rebuilding seek list failed for ${OUTFILE} with error $ERROR\r" >> pp.log
exit $ERROR
fi
# Cleanup
echo "Completed transcode! Cleaning up original recording and temp files.\r" >> pp.log
rm -f $VIDEODIR/$INFILE*
cd ..
rm -rf $TEMPDIR/postProcess-$MYPID
cd