Created
July 26, 2010 07:58
-
-
Save dmoo1790/490296 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# MYTHCUTNZ Version 0.1 | |
# This script tries to transcode and/or cut myth recordings. | |
# Why? LATM AAC audio used in most NZ broadcasts causes problems for | |
# programs like ffmpeg when you try to edit/cut them. | |
# Uses cvlc to transcode the LATM AAC audio if the recording has no AC3 audio. | |
# If the recording does have AC3 audio then cvlc is not used. | |
# Uses ffmpeg to cut the recording using cut list and/or commercial skip list. | |
# Updates the myth database with sql calls except for rebuilding the seek table. | |
# Output files may NOT be easily editable again. | |
OVERWRITE=0 | |
OUTPUT_DIR="" | |
CHANID=-9999 | |
STARTTIME="" | |
USECUTS=1 | |
USECOMMFLAGS=1 | |
outfile="11test.mpg" | |
rec_dir="" | |
basename="" | |
USER="root" | |
PASS="" # Change this to "-p your_password" if necessary | |
USAGE="$0 -c channel_id -s starttime [-d dir] [-f filename] [-o directory] [-h] [-Z] [-n] [-N] | |
-h Help/usage | |
-c Channel ID (required, %CHANID% from Mythtv) | |
-s Start time (required, %STARTTIME% from Mythtv) | |
-d Directory where the recording is store (optional, %DIR% from Mythtv) | |
-f Recording file name (optional, %FILE% from Mythtv) | |
-o Output directory (optional, recording directory if not specified) | |
-Z Overwrite original recording (optional, default is false, ignored if -o specified) | |
-n Don't edit the recording using the cut list (optional, default is use cut list) | |
-N Don't edit the recording using the commercial flag list (optional, default is use comm flags) | |
Example usage to cut a recording using the cut list and commercial skip list and overwrite original | |
mythcutnz -c %CHANID% -s %STARTTIME% -Z | |
Example usage to cut a recording only using the cut list and save the file to a different directory | |
mythcutnz -c %CHANID% -s %STARTTIME% -o /your/directory/ -N | |
Warning: The end files may not be editable with ffmpeg and/or playable in vlc. Keep the original | |
recording if you think you may want to do further edits or conversions in future. This script does | |
NOT delete the original recording. It is renamed with the extension \".old\"." | |
while getopts "c:s:o:d:f:hZnN" opt | |
do | |
case $opt in | |
c ) | |
CHANID="$OPTARG" | |
;; | |
s ) | |
STARTTIME="$OPTARG" | |
;; | |
d ) | |
rec_dir="$OPTARG" | |
;; | |
f ) | |
basename="$OPTARG" | |
;; | |
h ) | |
echo "Usage: $USAGE" >&2 | |
exit 0 | |
;; | |
o ) | |
OUTPUT_DIR="$OPTARG" | |
;; | |
Z ) OVERWRITE=1 # Will be reset to false if -o directory is specified | |
;; | |
n ) | |
USECUTS=0 | |
;; | |
N ) | |
USECOMMFLAGS=0 | |
;; | |
? ) | |
echo "Invalid option: -$OPTARG" >&2 | |
echo "Usage: $USAGE" >&2 | |
exit -1 | |
;; | |
esac | |
done | |
if [ "$OUTPUT_DIR" != "" ]; then | |
OVERWRITE=0 | |
fi | |
if [ $CHANID == -9999 -o "$STARTTIME" == "" ]; then | |
echo "Channel ID and/or Start Time missing" >&2 | |
echo "Usage: $USAGE" >&2 | |
exit -1 | |
fi | |
############################################################################# | |
# Find where the recording is stored if not specified with -d and -f options | |
############################################################################# | |
if [ "$rec_dir" == "" -o "$basename" == "" ]; then | |
storage_dirs=`echo "select dirname from storagegroup;" | mysql -N -u $USER $PASS mythconverg` | |
basename=`echo "select basename from recorded where chanid=$CHANID and starttime=\"$STARTTIME\";" \ | |
| mysql -N -u $USER $PASS mythconverg` | |
#echo $basename | |
#echo $storage_dirs | |
found=0 | |
for f in $storage_dirs; do | |
if [ -e "$f$basename" ]; then | |
rec_dir=$f | |
found=1 | |
fi | |
done | |
echo $rec_dir$basename | |
if [ $found == 0 ]; then | |
echo "Can't find recording, aborting" >&2 | |
exit -1 | |
fi | |
fi | |
# Set output directory to recording directory if not specified with -o option | |
if [ "$OUTPUT_DIR" == "" ]; then | |
OUTPUT_DIR=$rec_dir | |
fi | |
############################################################################# | |
# Get recording video and audio streams with ffmpeg | |
############################################################################# | |
declare -a STREAMS # STREAMS is a 1 dimensional array storing stream info from ffmpeg | |
AUDIO_STREAM="" | |
VIDEO_STREAM="" | |
STREAMS=( `ffmpeg -i $rec_dir$basename 2>&1 | awk '/Stream #/ {print $3 " " $4 " " $2}'` ) | |
i=0 | |
count=${#STREAMS[@]} | |
while [ $i -lt $count ] | |
do | |
# echo ${STREAMS[$i]} | |
case ${STREAMS[$i]} in | |
"Audio:") | |
if [ ${STREAMS[$i+1]} == "ac3," ]; then | |
STREAM=${STREAMS[$i+2]} | |
AUDIO_STREAM=${STREAM:1:3} | |
fi | |
;; | |
"Video:") | |
STREAM=${STREAMS[$i+2]} | |
VIDEO_STREAM=${STREAM:1:3} | |
;; | |
esac | |
let i=i+3 | |
done | |
############################################################################# | |
# If ffmpeg didn't find an AC3 audio stream then transcode the file with cvlc | |
############################################################################# | |
if [ "$AUDIO_STREAM" == "" ]; then | |
thefile=$OUTPUT_DIR$basename".tmp" | |
ionice -c3 cvlc $rec_dir$basename --sout "#transcode{acodec=a52, ab=384, channels=2, samplerate=48000} \ | |
:std{mux=ps, access=file, dst="$thefile"}" vlc://quit > /dev/null | |
MAPPING="" | |
else | |
thefile=$rec_dir$basename | |
MAPPING="-map "$VIDEO_STREAM" -map "$AUDIO_STREAM | |
fi | |
############################################################################# | |
# Edit the recording based on cuts and/or commercial flags | |
############################################################################# | |
if [ $USECUTS == 1 -o $USECOMMFLAGS == 1 ]; then | |
MARKTYPES="" | |
if [ $USECUTS == 1 ]; then | |
MARKTYPES="0,1" | |
if [ $USECOMMFLAGS == 1 ]; then | |
MARKTYPES=$MARKTYPES",4,5" | |
fi | |
else | |
MARKTYPES=$MARKTYPES"4,5" | |
fi | |
# Get the cuts from recordedmarkup table and store in an array | |
cuts=( `echo "select type,mark from recordedmarkup where chanid=$CHANID and starttime=\"$STARTTIME\" \ | |
and type in ($MARKTYPES) order by mark" | mysql -N -u $USER $PASS mythconverg` ) | |
outfile=$OUTPUT_DIR$basename".new" | |
i=0 | |
part=1 | |
totaltime=0 | |
pieces=${#cuts[@]} | |
let pieces=pieces-3 | |
#k=0 | |
#while [ $k -lt $pieces ]; do | |
# echo ${cuts[k]} | |
# let k++ | |
#done | |
# Figure out divisor for frames to time calculations | |
TBC=( `ffmpeg -i $thefile 2>&1 | awk '/tbc/ {print $(NF-1)}'` ) | |
echo $"tbc = "$TBC | |
if [ $TBC == 100 ]; then | |
FPS=50 | |
else | |
if [ $TBC == 50 ]; then | |
FPS=25 | |
else | |
FPS=25 # Guess | |
fi | |
fi | |
while [ $i -le $pieces ]; do | |
if [ ${cuts[i]} == 0 -o ${cuts[i]} == 5 ]; then # Look for a cut end, i.e., the start of a segment we want to keep | |
# Convert cut points from frames to seconds | |
cutstart=`echo "scale=3; ${cuts[i+1]}/$FPS" | bc -l` | |
cutlength=`echo "scale=3; ${cuts[i+3]}/$FPS-$cutstart" | bc -l` | |
# Cut length needs to be updated to match timestamp update | |
cutlength2=`echo "scale=3; $cutlength+$totaltime" | bc -l` | |
echo $cutstart" "$cutlength" "$cutlength2" "${cuts[i+1]}" "${cuts[i+3]} | |
# Cut the segment and update the timestamps with ffmpeg | |
ionice -c3 ffmpeg -y -async 1 -itsoffset $totaltime -ss $cutstart -t $cutlength2 -i "$thefile" \ | |
-vcodec copy -acodec copy $MAPPING tmp.mpg | |
if [ $part -gt 1 ]; then # Concatenate this segment to existing file | |
ionice -c3 cat tmp.mpg >> "$outfile" | |
ionice -c3 rm tmp.mpg | |
else | |
ionice -c3 mv tmp.mpg "$outfile" | |
fi | |
# Total time updated so that timestamps for next segment can be updated | |
totaltime=`echo "scale=3; $totaltime+$cutlength" | bc -l` | |
# Increment loop counter by 4 since array has cut start/end pairs plus cut types | |
let i+=4 | |
let part++ | |
else | |
# Skips the case where the first cut point is a cut start, i.e., when start of recording is deleted | |
let i+=2 | |
fi | |
done | |
else | |
mv $thefile $OUTPUT_DIR$basename".new" | |
fi | |
############################################################################# | |
# Reset the cut list, seek table, etc. for final file | |
############################################################################# | |
if [ $OVERWRITE == 1 ]; then | |
# Don't delete original. Just rename. | |
mv $rec_dir$basename $rec_dir$basename".old" | |
mv $OUTPUT_DIR$basename".new" $OUTPUT_DIR$basename | |
# Delete tmp file if it exists | |
if [ -e $OUTPUT_DIR$basename".tmp" ]; then | |
ionice -c3 rm $OUTPUT_DIR$basename".tmp" | |
fi | |
# Clear the seek table | |
echo "delete from recordedseek where chanid=$CHANID and starttime=\"$STARTTIME\";" | mysql -u $USER $PASS mythconverg | |
# Clear the markup table | |
echo "delete from recordedmarkup where chanid=$CHANID and starttime=\"$STARTTIME\";" | mysql -u $USER $PASS mythconverg | |
# Clear bookmark, cutlist, commflagged flags | |
echo "update recorded set bookmark=0, cutlist=0, commflagged=0 where chanid=$CHANID and starttime=\"$STARTTIME\";" | mysql -u $USER $PASS mythconverg | |
# Update file size | |
FILESIZE=`du -b $OUTPUT_DIR$basename | awk '{print $1}'` | |
echo "update recorded set filesize=$FILESIZE where chanid=$CHANID and starttime=\"$STARTTIME\";" | mysql -u $USER $PASS mythconverg | |
# Rebuild the seek table with mythtranscode (mythcommflag does not seem to work) | |
ionice -c3 mythtranscode -c $CHANID -s "$STARTTIME" --buildindex | |
# Fix the seek table if necessary. Seems mythtranscode has a bug which causes frame numbers (marks) to get doubled. | |
# Something to do with fields per sec vs frames per sec??? Bug in ffmpeg??? | |
if [ $FPS == 25 ]; then | |
echo "update recordedseek set mark=mark/2 where chanid=$CHANID and starttime=\"$STARTTIME\" order by mark;" | mysql -u $USER $PASS mythconverg | |
fi | |
# Seems to be flaky using mythcommflag to fix things | |
# ionice -c3 mythcommflag -f $OUTPUT_DIR$basename --clearcutlist | |
# ionice -c3 mythcommflag -f $OUTPUT_DIR$basename --clearskiplist | |
# ionice -c3 mythcommflag -f $OUTPUT_DIR$basename --rebuild | |
else | |
# Don't accidentally overwrite an existing file | |
if [ -e $OUTPUT_DIR$basename ]; then | |
i=1 | |
while [ -e $OUTPUT_DIR$basename"."$i".mpg" ]; do | |
let i++ | |
done | |
mv $OUTPUT_DIR$basename $OUTPUT_DIR$basename"."$i".mpg" | |
else | |
mv $OUTPUT_DIR$basename".new" $OUTPUT_DIR$basename | |
fi | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment