|
|
- #!/bin/bash
-
- #Is a 'slave' script to run an ffmpeg (and ffprobe) command. Generally it will
- #take a file specified on the 'host' machine that has a list of files; copy a
- #version down locally, transcode it, then replace the original file on the
- #'host', and remove the temporary files.
- #
- #You will need to have both FFMPEG and FFPROBE installed (and will need
- #to pray to St. Isidore... good luck if you encounter issues.
-
- #Default operations, change if necessary
- FFBIN="/usr/bin/" #if unusual install or a specific version
- HostName="localhost" #if localhost then will do locally (removes ssh/scp cmds)
- hostFile="/tmp/transcode/list.txt"
- tmpDIR="$PWD/tmpTranscode"
- workDIR="$PWD/transcode"
-
- #DEFINE FUNCTIONS
- function encode {
- local tmpFL=$1
- local outFL=$2
- $FFBIN/ffmpeg -hide_banner -loglevel error -stats -re -i "$tmpFL" -map 0 \
- -map_metadata 0 -c copy \
- -c:v libx265 -preset slow -x265-params crf=23 \
- -use_wallclock_as_timestamps 1 \
- -map_chapters 0 -max_muxing_queue_size 9999 "$outFL"
- }
-
- function burnSubs {
- local inFL=$1
- local tmpFL=$2
- local outFL=$3
- local track=$4
-
- #EVIDTNELY NECESSARY SO THAT FILES AREN'T 198+ HRS IN LEN. AT THE END
- local DURATION=$( ffprobe -loglevel error -show_entries format=duration \
- -of default=noprint_wrappers=1:nokey=1 "$inFL" )
-
- $FFBIN/ffmpeg -hide_banner -loglevel error -stats -i "$inFL" \
- -filter_complex "[0:v][0:s:$track]overlay[v]" -map "[v]" \
- -map 0:a -c:a copy -map 0:s -map -0:s:$track -c:s copy \
- -map_metadata 0 -map_chapters 0 -max_muxing_queue_size 9999 \
- -t $DURATION "$tmpFL"
-
- rm "$inFL" #SAVE SPACE
-
- encode "$tmpFL" "$outFL"
- }
-
- #MAIN FUNCTION BEGINS
- mkdir -p "$tmpDIR"
- mkdir -p "$workDIR"
-
- if [ -n "$1" ]
- then
- numIter=$1
- iterLim="true"
- else
- numIter=20
- iterLim="false"
- fi
-
- if ! command -v $FFBIN/ffprobe &> /dev/null
- then
- echo "Need to have ffprobe (and ffmpeg) installed"
- exit 1
- fi
- if ! command -v $FFBIN/ffmpeg &> /dev/null
- then
- echo "Need to have ffmpeg (and ffprobe) installed"
- exit 1
- fi
- if ! command -v bc &> /dev/null
- then
- echo "Need to have bc installed (foreign audio scan)"
- exit 1
- fi
-
- i=0 #Total number of loops
- j=0 #Failed to obtain job
- k=0 #ffmpeg failed
- declare -a langs #Subtitle Languages
-
- while [ $numIter -gt 0 ] && [ $j -lt 50 ] && [ $k -lt 60 ]
- do
- if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
- then
- filePATH=$( ssh $HostName "head -n1 $hostFile;sed -i -e '1d' $hostFile" )
- else
- filePATH=$( head -n1 $hostFile;sed -i -e '1d' $hostFile )
- fi
- if [ -n "$filePATH" ]
- then
- j=0
- fileNAME=$( basename "$filePATH" )
- #PULL DOWN FILE
- if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
- then
- scp $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )" "$tmpDIR"
- else
- rsync -a --progress "$filePATH" "$tmpDIR/"
- fi
-
- #RUN FFMPROBE/FFMPEG
- echo "DOING $fileNAME"
- unset langs
-
- #DETERMINE THE NUMBER OF ENGLISH SUBTITLES (BURNING BEHAVIOUR)
- for line in $( $FFBIN/ffprobe -loglevel error -select_streams s -show_entries\
- stream=index:stream_tags=language -of csv=p=0 \
- "$tmpDIR"/"$fileNAME" )
- do
- langs+=("$line")
- done
- unset line
- engCounter=0
- if [ ${#langs[@]} -gt 1 ]
- then
- #DETERMINE NUMBER OF ENGLISH-CONTAINING SUBTITLES
- unset streamNUMBERS
- declare -a streamNUMBERS
- for language in "${langs[@]}"
- do
- if grep -iq "eng" <<< $language
- then
- let ++engCounter
- delim=","
- unset addNumber
- addNumber=( "${language%%"$delim"*}" )
- streamNUMBERS+=($addNumber)
- fi
- done
- if [ $engCounter -lt 2 ]
- then
- #ONLY ONE ENG. SUB TRACK
- echo "ONE ENG. SUB TRACK"
- encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
- else
- #TEST SUBTITLE TYPE; IF NOT PGS SKIP IT; FEEL FREE TO FILL IN
- if grep -qi "pgs" <<< $( $FFBIN/ffprobe -loglevel error -select_streams s \
- -show_entries stream=codec_name \
- -of csv=p=0 "$tmpDIR"/"$fileNAME" )
- then
- # MORE THAN ONE SUB TRACK; HAVE TO FIGURE OUT WHICH TO BURN
- unset streamFRAMES
- declare -a streamFRAMES
- #Presuming the one to burn-in is the one with less frames
- unset minFrames
- unset maxFrames
- unset indexITER
- unset minINDEX
- minFrames=0
- maxFrames=0
- indexITER=0
- minINDEX=0
-
- for index in ${streamNUMBERS[@]}
- do
- SUBINDEX=$(expr $index - ${streamNUMBERS[0]})
- currFrames=$( $FFBIN/ffprobe -loglevel error -select_streams s:$SUBINDEX \
- -show_entries stream_tags=NUMBER_OF_FRAMES-eng -of csv=p=0 \
- "$tmpDIR/$fileNAME")
- if [ $indexITER -lt 1 ]
- then
- minFrames=$currFrames
- maxFrames=$currFrames
- minINDEX=$index
- let ++indexITER
- elif [ $currFrames -lt $minFrames ]
- then
- minFrames=$currFrames
- minINDEX=$index
- let ++indexITER
- elif [ $currFrames -gt $maxFrames ]
- then
- maxFrames=$currFrames
- let ++indexITER
- fi
- done
- unset SUBTITLEINDEX
- SUBTITLEINDEX=$(expr $minINDEX - ${streamNUMBERS[0]})
- #TEST FRAMES IN SUB TRACK, IF < 15% MAX MOST LIKELY ISN'T FOR. AUD.
- #15% as LOTR dir. comm included, blows up the max number for them...
- currFrames=$( $FFBIN/ffprobe -loglevel error -select_streams s:$SUBTITLEINDEX \
- -show_entries stream_tags=NUMBER_OF_FRAMES-eng -of csv=p=0 \
- "$tmpDIR/$fileNAME")
- if [ $( echo "($currFrames / $maxFrames) < 0.25"|bc -l ) -gt 0 ]
- then
- echo "BURNING STREAM $SUBTITLEINDEX (STREAM $minINDEX) from $fileNAME"
- burnSubs "$tmpDIR/$fileNAME" "$tmpDIR/TMP$fileNAME" "$workDIR/$fileNAME" $SUBTITLEINDEX
- else
- echo "MIN. SUB TRACK ($SUBTITLEINDEX [$minINDEX])) DUR. > 25% FILM, NOT BURNING"
- encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
- fi
-
-
- else
- #TODO expand foreign scan for more than pgs subtitles Need ass and
- #subtitles filters; don't know how to differentiate at present time.
- #I'm actually kinda missing a good example; I'm sure they're in there
- #but I don't know which ones they are lol; lmk if you know one.
- echo "NOT A PGS SUBTITLE TYPE; PASSING ALL THROUGH, FUTURE DEV."
- encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
- fi
- fi
- else
- #ONE OR FEWER SUB TRACKS
- encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME"
- fi
-
- if [ $? != 0 ] || [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
- then
- #RUN FAILED (EITHER NONZERO EXIT OR THE FILE IS 0 BYTES LARGE)
- if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
- then
- ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
- else
- echo "$filePATH">>$hostFile
- fi
- let ++k
- echo "RUN ($fileNAME) FAILED ($k/60)"
- if [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
- then
- rm "$workDIR"/"$fileNAME"
- fi
- else
- #UPLOAD AND REMOVE THE TRANSCODED FILE
- if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
- then
- scp "$workDIR/$fileNAME" $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )"
- else
- rsync -a --progress "$workDIR/$fileNAME" "$filePATH"
- fi
- if [ $? != 0 ]
- then
- echo "UPLOAD OF $filePATH FAILED; EXITING"
- if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
- then
- ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
- else
- echo "$filePATH">>$hostFile
- fi
- exit 1
- else
- rm "$workDIR"/"$fileNAME"
- fi
- k=0
-
- fi
- #REMOVE THE TEMP FILE (if necessary)
- if ls "$workDIR"/"$fileNAME"
- then
- rm "$workDIR"/"$fileNAME"
- else
- echo "Workdir already cleaned"
- fi
- if ls "$tmpDIR"/"$fileNAME"
- then
- rm "$tmpDIR"/"$fileNAME"
- elif ls "$tmpDIR"/"TMP$fileNAME"
- then
- rm "$tmpDIR"/"TMP$fileNAME"
- else
- echo "Already removed $tmpDIR/$fileNAME?"
- fi
-
- else
- echo "OUT OF FILES!? (try number $j/50) ... sleeping 1 min"
- let ++j
- sleep 60
- fi
-
- #Increment if required
- if [ $iterLim == "true" ]
- then
- let --numIter
- fi
- let ++i
- echo "Done LOOP NUMBER $i!"
- done
-
- exit 0
|