Difference between revisions of "User:Iamlindoro"
From MythTV Official Wiki
Iamlindoro (talk | contribs) m |
Iamlindoro (talk | contribs) (Revert to the old version which uses a script instead of the avidemux patch) |
||
Line 1: | Line 1: | ||
− | + | Here is a script that allows lossless cutting of HD-PVR content. Set this script as executable, and as a userjob. It works on the cutlist, so get that set before running. You could technically swap --getcutlist for --getskiplist and this would probably work as an auto-commercial-removal, but that is an insanely bad idea. | |
− | |||
− | |||
− | |||
− | |||
PS, Discussion pages are for suggesting changes, don't just edit someone's user page. :) | PS, Discussion pages are for suggesting changes, don't just edit someone's user page. :) | ||
Line 35: | Line 31: | ||
# | # | ||
− | mythcommflag --getcutlist- | + | |
− | nice -n 9 avidemux2_cli --force-alt-h264 --autoindex --rebuild-index --nogui --force-smart --load "$ | + | test -f /etc/mythtv/mysql.txt && . /etc/mythtv/mysql.txt |
+ | test -f ~/.mythtv/mysql.txt && . ~/.mythtv/mysql.txt | ||
+ | |||
+ | mysqlconnect="mysql -N -h$DBHostName -u$DBUserName -p$DBPassword $DBName" | ||
+ | export mysqlconnect | ||
+ | |||
+ | RECDIR=$1 | ||
+ | BASENAME=$2 | ||
+ | |||
+ | chanid=`echo "select chanid from recorded where basename=\"$BASENAME\";" | | ||
+ | $mysqlconnect` | ||
+ | |||
+ | starttime=`echo "select starttime from recorded where basename=\"$BASENAME\";" | | ||
+ | $mysqlconnect` | ||
+ | |||
+ | if test "$chanid" = "" || test "$starttime" = "" ; then | ||
+ | echo "Recording not found in MythTV database, aborted." | ||
+ | exit 1 | ||
+ | fi | ||
+ | |||
+ | cat > $RECDIR/$BASENAME.cut << EOF | ||
+ | //AD <- Needed to identify// | ||
+ | |||
+ | var app = new Avidemux(); | ||
+ | |||
+ | //** Video ** | ||
+ | // 01 videos source | ||
+ | app.load("/$RECDIR/$BASENAME"); | ||
+ | app.clearSegments(); | ||
+ | EOF | ||
+ | |||
+ | CUTLIST=`mythcommflag --getcutlist -f /$RECDIR/$BASENAME |grep Cutlist| sed 's/Cutlist//g' | sed 's/-/ /g' |sed 's/,/-/g' | sed 's/: 0 //'| sed 's/: /-/'`- | ||
+ | FIRSTFRAME=`echo "select MIN(mark) from recordedseek where chanid=$chanid and starttime='$starttime';" | $mysqlconnect` | ||
+ | LASTFRAME=`echo "select MAX(mark) from recordedseek where chanid=$chanid and starttime='$starttime';" | $mysqlconnect` | ||
+ | |||
+ | for i in ${CUTLIST} | ||
+ | do | ||
+ | |||
+ | # Get exact frame cut number from Myth | ||
+ | |||
+ | STARTKEYFRAME=`echo $i | cut -d '-' -f 1` | ||
+ | ENDKEYFRAME=`echo $i | cut -d '-' -f 2` | ||
+ | |||
+ | # Turn those framenumbers into nearest keyframe prior to cutpoint. | ||
+ | |||
+ | START=`echo "select mark from recordedseek where mark < $STARTKEYFRAME and chanid=$chanid and starttime='$starttime' order by mark DESC LIMIT 1;" | $mysqlconnect || continue` | ||
+ | END=`echo "select mark from recordedseek where mark < $ENDKEYFRAME and chanid=$chanid and starttime='$starttime' order by mark DESC LIMIT 1;" | $mysqlconnect || continue` | ||
+ | |||
+ | if [ .${START}. = .. ] | ||
+ | then START=0 | ||
+ | fi | ||
+ | if [ ${START} -ge $LASTFRAME ] | ||
+ | then | ||
+ | continue | ||
+ | fi | ||
+ | |||
+ | if [ .${END}. = .. ] | ||
+ | then END=$LASTFRAME | ||
+ | fi | ||
+ | |||
+ | LENGTH=$((${END} - ${START} )) | ||
+ | |||
+ | if [ ${LENGTH} -le 0 ] | ||
+ | then | ||
+ | echo LENG $LENGTH | ||
+ | continue | ||
+ | fi | ||
+ | |||
+ | cat >> $RECDIR/$BASENAME.cut << EOF | ||
+ | app.addSegment(0,${START},${LENGTH}); | ||
+ | EOF | ||
+ | count=$((${count} + 1)) | ||
+ | done | ||
+ | |||
+ | cat >> $RECDIR/$BASENAME.cut << EOF | ||
+ | app.markerA=$FIRSTFRAME; | ||
+ | app.markerB=$LASTFRAME; | ||
+ | app.rebuildIndex(); | ||
+ | |||
+ | //** Postproc ** | ||
+ | app.video.setPostProc(3,3,0); | ||
+ | |||
+ | app.video.setFps1000(59940); | ||
+ | |||
+ | //** Filters ** | ||
+ | |||
+ | //** Video Codec conf ** | ||
+ | app.video.codec("Copy","CQ=4","0 "); | ||
+ | |||
+ | //** Audio ** | ||
+ | app.audio.reset(); | ||
+ | app.audio.codec("copy",128,0,""); | ||
+ | app.audio.normalizeMode=0; | ||
+ | app.audio.normalizeValue=0; | ||
+ | app.audio.delay=0; | ||
+ | app.audio.mixer("NONE"); | ||
+ | app.setContainer("MATROSKA"); | ||
+ | setSuccess(1); | ||
+ | //app.Exit(); | ||
+ | |||
+ | //End of script | ||
+ | EOF | ||
+ | |||
+ | CORENAME=`basename $BASENAME .mpg` | ||
+ | |||
+ | # Run through AVIDemux. Don't know how the audio sync will be. | ||
+ | # | ||
+ | |||
+ | nice -n 9 avidemux2_cli --force-alt-h264 --autoindex --rebuild-index --nogui --force-smart --load "$RECDIR/$BASENAME" --run $RECDIR/$BASENAME.cut --save "$RECDIR/$CORENAME.avi" --quit 2> /dev/null | ||
# Move the AVI file into a Matroska. | # Move the AVI file into a Matroska. | ||
# Failure to do this will result in broken seeking. | # Failure to do this will result in broken seeking. | ||
− | ffmpeg -i $ | + | ffmpeg -i $RECDIR/$CORENAME.avi -acodec copy -vcodec copy $RECDIR/$CORENAME.mkv |
# Do a little cleanup. | # Do a little cleanup. | ||
− | rm $ | + | rm $RECDIR/$CORENAME.avi |
− | rm $ | + | rm $RECDIR/$BASENAME.idx |
− | rm $ | + | rm $RECDIR/$BASENAME.cut |
</pre></code> | </pre></code> | ||
Revision as of 19:52, 15 July 2009
Here is a script that allows lossless cutting of HD-PVR content. Set this script as executable, and as a userjob. It works on the cutlist, so get that set before running. You could technically swap --getcutlist for --getskiplist and this would probably work as an auto-commercial-removal, but that is an insanely bad idea.
PS, Discussion pages are for suggesting changes, don't just edit someone's user page. :)
#!/bin/sh -e
#
# Written by Robert McNamara
# (robert DOT mcnamara ATSIGN gmail DOT com)
#
# Requires:
#
# AVIDemux 2.4 SVN revision 4445 or later (current 10/7/08)
# Working MythTV setup (To steal the cutlist from)
# FFMpeg (to fix indexing and drop into an MKV)
#
# First thing's first. This is only currently working on 720p files.
# Because of some issues with AVIDemux (which are being worked on),
# 1080i won't work at all (as Myth and AVIDemux seem to reckon frame
# counts differently).
#
# This script works at the keyframe level only. I strongly advise
# you to set cutpoints approximately one second into actual program
# material to avoid accidentally inserting commercials.
#
# The output MKV file will be in your recordings directory.
#
# Basic user job setup is:
#
# h264cut %DIR% %FILE%
#
test -f /etc/mythtv/mysql.txt && . /etc/mythtv/mysql.txt
test -f ~/.mythtv/mysql.txt && . ~/.mythtv/mysql.txt
mysqlconnect="mysql -N -h$DBHostName -u$DBUserName -p$DBPassword $DBName"
export mysqlconnect
RECDIR=$1
BASENAME=$2
chanid=`echo "select chanid from recorded where basename=\"$BASENAME\";" |
$mysqlconnect`
starttime=`echo "select starttime from recorded where basename=\"$BASENAME\";" |
$mysqlconnect`
if test "$chanid" = "" || test "$starttime" = "" ; then
echo "Recording not found in MythTV database, aborted."
exit 1
fi
cat > $RECDIR/$BASENAME.cut << EOF
//AD <- Needed to identify//
var app = new Avidemux();
//** Video **
// 01 videos source
app.load("/$RECDIR/$BASENAME");
app.clearSegments();
EOF
CUTLIST=`mythcommflag --getcutlist -f /$RECDIR/$BASENAME |grep Cutlist| sed 's/Cutlist//g' | sed 's/-/ /g' |sed 's/,/-/g' | sed 's/: 0 //'| sed 's/: /-/'`-
FIRSTFRAME=`echo "select MIN(mark) from recordedseek where chanid=$chanid and starttime='$starttime';" | $mysqlconnect`
LASTFRAME=`echo "select MAX(mark) from recordedseek where chanid=$chanid and starttime='$starttime';" | $mysqlconnect`
for i in ${CUTLIST}
do
# Get exact frame cut number from Myth
STARTKEYFRAME=`echo $i | cut -d '-' -f 1`
ENDKEYFRAME=`echo $i | cut -d '-' -f 2`
# Turn those framenumbers into nearest keyframe prior to cutpoint.
START=`echo "select mark from recordedseek where mark < $STARTKEYFRAME and chanid=$chanid and starttime='$starttime' order by mark DESC LIMIT 1;" | $mysqlconnect || continue`
END=`echo "select mark from recordedseek where mark < $ENDKEYFRAME and chanid=$chanid and starttime='$starttime' order by mark DESC LIMIT 1;" | $mysqlconnect || continue`
if [ .${START}. = .. ]
then START=0
fi
if [ ${START} -ge $LASTFRAME ]
then
continue
fi
if [ .${END}. = .. ]
then END=$LASTFRAME
fi
LENGTH=$((${END} - ${START} ))
if [ ${LENGTH} -le 0 ]
then
echo LENG $LENGTH
continue
fi
cat >> $RECDIR/$BASENAME.cut << EOF
app.addSegment(0,${START},${LENGTH});
EOF
count=$((${count} + 1))
done
cat >> $RECDIR/$BASENAME.cut << EOF
app.markerA=$FIRSTFRAME;
app.markerB=$LASTFRAME;
app.rebuildIndex();
//** Postproc **
app.video.setPostProc(3,3,0);
app.video.setFps1000(59940);
//** Filters **
//** Video Codec conf **
app.video.codec("Copy","CQ=4","0 ");
//** Audio **
app.audio.reset();
app.audio.codec("copy",128,0,"");
app.audio.normalizeMode=0;
app.audio.normalizeValue=0;
app.audio.delay=0;
app.audio.mixer("NONE");
app.setContainer("MATROSKA");
setSuccess(1);
//app.Exit();
//End of script
EOF
CORENAME=`basename $BASENAME .mpg`
# Run through AVIDemux. Don't know how the audio sync will be.
#
nice -n 9 avidemux2_cli --force-alt-h264 --autoindex --rebuild-index --nogui --force-smart --load "$RECDIR/$BASENAME" --run $RECDIR/$BASENAME.cut --save "$RECDIR/$CORENAME.avi" --quit 2> /dev/null
# Move the AVI file into a Matroska.
# Failure to do this will result in broken seeking.
ffmpeg -i $RECDIR/$CORENAME.avi -acodec copy -vcodec copy $RECDIR/$CORENAME.mkv
# Do a little cleanup.
rm $RECDIR/$CORENAME.avi
rm $RECDIR/$BASENAME.idx
rm $RECDIR/$BASENAME.cut
This is a script that will correct broken MPEG-2 TSs from firewire or DVB. The script replaces the original recording with a file that will work with mythtranscode rather than crashing it.
#!/bin/sh
#
#
# mpeg2fixup.sh
#
# Written in 2008 by Robert McNamara. Please redistribute freely and without
# restriction. (robert DOT mcnamara ATSIGN g m a i l DOTCOM)
#
# Script to clean up Firewire and DVB recordings that kill mythtranscode.
# It appears the bogus PTS information makes mythtrascode lossless transcoding
# fail with error 232 (Unknown). It complains about a deadlock.
#
# This solution is not the most elegant in the world, but it *does* work and
# ultimately permits Myth to successfully lossless-transcode the files.
#
# There are two prerequisites for this script. The first is the xport
# transport stream demuxer. It is only distributed for Windows but it compiles
# fine on linux. Get the following file:
#
# http://www.w6rz.net/xport.zip
#
# And unzip it. Compile it with "cc -o xport xport.c" and copy the resulting
# file to somewhere in your path (in my case, /usr/bin).
#
# You will also need a copy of ffmpeg with AC3 and MPEG-2 support.
#
# In essence, this script demuxes the file recorded from DVB/Firewire, and
# remuxes the streams with ffmpeg into a "clean" MPEG container. It copies the
# existing recording file to the same location with extension .tmp and inserts
# the new file in its place. Commercial flags and cutlists are cleared, and
# commflagging is run on the new file. In my limited testing, Myth can now
# successfully transcode the resulting file losslessly.
#
# Here's how it should be set up as a userjob:
#
# mpeg2fixup.sh "%DIR%" "%FILE%"
#
# I set the script to work within /tmp. If you don't want it to do that,
# change the first variable below.
#
# Even on a powerful processor (I run this on a Q6600) you can expect this to cost
# you 10 or so minutes of processing time for each hourlong show. It's the price
# you pay to preserve quality and end up with lossless-transcode-able files.
WORKINGDIR=/tmp
DIR=$1
FILE=$2
# Make the directory to work in:
mkdir "$WORKINGDIR/$FILE"
cd "$WORKINGDIR/$FILE"
# First step is dumping the PIDs to files
xport "$DIR/$FILE" 1 1 1
# Once we're done with that, let's mux everything into a new file.
ffmpeg -i bits0001.mpv -i bits0001.mpa -vcodec copy -acodec copy "$WORKINGDIR/$FILE/$FILE"
# Let's move the old file out of the way, and the new file into its place.
mv "$DIR/$FILE" "$DIR/$FILE.old"
mv "$WORKINGDIR/$FILE/$FILE" "$DIR/$FILE"
# Now we need to clear the cutlist on the file, rebuild its seektable, and rerun commflagging.
mythcommflag --clearcutlist -f "$DIR/$FILE"
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Clearing cutlist failed for $FILE with error $ERROR"
exit $ERROR
fi
# *Don't* rebuild the seektable traditionally or you will end up with screwed up times and it will be uneditable.
# Use mythtranscode on lossless/buildindex mode instead.
mythtranscode --mpeg2 --infile "$DIR/$FILE" --buildindex --showprogress
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Rebuilding seektable failed for $FILE with error $ERROR"
exit $ERROR
fi
# Commercial Flagging. This mostly sucks on my broken recordings, you can comment it out if
# you wish. I find that I basically have to go in and manually set cutpoints anyway.
mythcommflag -f "$DIR/$FILE"
ERROR=$?
if [ $ERROR -ne 0 ]; then
echo "Commercial flagging failed for ${FILENAME} with error $ERROR"
exit $ERROR
fi
# Remove the contents of the working directory
rm -rf "$WORKINGDIR/$FILE"
# If you want to remove the old recording, uncomment the last line:
# rm "$DIR/$FILE.old"