H264 commercial remover and remuxer
From MythTV Official Wiki
| Author | Ian Thiele |
| Description | This script uses mythcommflag, ffmpeg, and mkvmerge to remove commercials from an h264 encoded input file and outputs them into an mkv container. |
| Supports |
Usage
/path/h264cut.sh /path/to/file
Disclaimer
I wrote this specifically to get a friend's .mpg files, that were encoded with h.264 from a hd-pvr, commercial-free and into a Matroska container. I have little,read: no, knowledge of video encoding, containers, and whatnot. Built this just from ffmpeg and mkvmerge man pages. Might work for you, might not. That said, feel free to take it and modify it to your needs, etc., etc.
Update
Added a little database bookkeeping and logfile support. Will stop broken seeking when playing inside myth. Also confirmed that this works with files from both a hdr-pvr and hdhomerun.
#!/bin/bash
# Ian Thiele
# icthiele@gmail.com
#Uses mythcommflag, ffmpeg, and mkvmerge to cut commercials out of h.264 encoded mpg files#
workdir="/tmp/h264cut"
if [ -z "`ls ${workdir}`" ]; then
mkdir -p ${workdir}
fi
if [ ! -f $1 ]; then
echo "file doesn't exist, aborting."
exit 1
fi
#see if we have the DB info
test -f /etc/mythtv/mysql.txt && . /etc/mythtv/mysql.txt
test -f ~/.mythtv/mysql.txt && . ~/.mythtv/mysql.txt
#let's make sure we have a sane environment
if [ -z "`which ffmpeg`" ]; then
echo "FFMpeg not present in the path. Adjust environment or install ffmpeg"
exit 1
elif [ -z "`which mkvmerge`" ]; then
echo "mkvmerge is not present in the path. Adjust environment or install mkvtoolnix"
exit 1
fi
#connect to DB
mysqlconnect="mysql -N -h$DBHostName -u$DBUserName -p$DBPassword $DBName"
export mysqlconnect
#deteremine directory and filename
RECDIR=`dirname $1`
BASENAME=`basename $1`
tmp=`basename $BASENAME .mpg`
logfile=/store/LeBaugh/mythold/${BASENAME}.log
>${logfile}
#determine chanid and starttime from recorded table
chanid=`echo "select chanid from recorded where basename=\"$BASENAME\";" | $mysqlconnect`
starttime=`echo "select starttime from recorded where basename=\"$BASENAME\";" | $mysqlconnect`
#determine FPS (frames per second) from db, which is used to determine the seek time to extract video clips
fps=$(echo "scale=10;`echo "select data from recordedmarkup where chanid=$chanid AND starttime='$starttime' and type=32" | $mysqlconnect` / 1000.0" | bc)
if [ -z "$chanid" ] || [ -z "$starttime" ]
then
echo "Recording not found in MythTV database, script aborted."
exit 1
elif [ -z "$fps" ]
then
echo "Frames per second value not found in MythTV database, script aborted."
exit 1
fi
#lets make sure we have a cutlist before we proceed
if [ -z "`mythcommflag --getcutlist -c $chanid -s "$starttime" | grep Cutlist | sed 's/Cutlist: $//'`" ]; then
echo "no cutlist found....generating new cutlist"
mythcommflag -c $chanid -s "$starttime" --gencutlist &>${logfile}
fi
#cutlist provides a list of frames in the format start-end,[start1-end1,....] to cut
#we swap this list so that it provides the ranges of video we want in the format
# start-end start1:end1 ....
CUTLIST=`mythcommflag -c $chanid -s "$starttime" --getcutlist | grep Cutlist | sed 's/Cutlist: //' | \
sed 's/-/ /g' | sed 's/^\|$/-/g' | sed 's/,/-/g'`
clipcount=0
for i in ${CUTLIST}
do
start=`echo $i | sed 's/ //g' | sed 's/^\(.*\)-.*$/\1/'`
end=`echo $i | sed 's/ //g' | sed 's/^.*-\(.*\)$/\1/'`
#if $start is empty, deal with it
if [ -z $start ]; then
#set $start to 0
start=0
if [ $start -eq $end ]; then
continue
fi
fi
#convert start into time in seconds (divide frames by frames per second)
start=$(echo "scale=8; $start / $fps" | bc -l)
#if $end is not null, we can do things
if [ -n "$end" ]; then
clipcount=$((++clipcount))
end=$(echo "scale=8; $end / $fps" | bc -l)
duration=`echo "$end - $start" | bc -l`
ffmpeg -i ${RECDIR}/${BASENAME} -acodec copy -vcodec copy -f matroska -ss $start -t $duration \
${workdir}/${tmp}_${clipcount}.mkv &>>${logfile}
elif [ -z "$end" ]; then
clipcount=$((++clipcount))
ffmpeg -i ${RECDIR}/${BASENAME} -acodec copy -vcodec copy -f matroska -ss ${start} \
${workdir}/${tmp}_${clipcount}.mkv &>>${logfile}
fi
done
mergestr=""
for i in `ls ${workdir}/${tmp}_* | sort`
do
if [ -z "$mergestr" ]; then
mergestr="$i"
continue
fi
mergestr="$mergestr +$i"
done
mkvmerge --append-mode track $mergestr -o ${RECDIR}/${tmp}.mkv &>>${logfile}
#clear out the old cutlist
mythcommflag --clearcutlist -c $chanid -s "$starttime" &>>${logfile}
#we'll need a new filesize to update the db with
filesize=$(du ${RECDIR}/${tmp}.mkv | awk '{print $1}')
#update db with new filesize and filename
cat <<EOF | $mysqlconnect
UPDATE
recorded
SET
cutlist = 0,
filesize = ${filesize},
basename = "${tmp}.mkv"
WHERE
chanid = ${chanid} AND
starttime = "${starttime}";
EOF
#delete the old commercial skip info
cat <<EOF | $mysqlconnect
DELETE FROM
recordedmarkup
WHERE
chanid = ${chanid} AND
starttime = "${starttime}" AND
(type = 4 OR type = 5);
EOF
cat <<EOF | $mysqlconnect
DELETE FROM
recordedseek
WHERE
chanid = ${chanid} AND
starttime = "${starttime}";
EOF
mv ${RECDIR}/${BASENAME} /store/LeBaugh/mythold/${BASENAME}.old
#cleanup $workdir
rm -rf ${workdir}/*${tmp}*