v0.9
This commit is contained in:
		
						commit
						bd87bacacb
					
				
					 1 changed files with 553 additions and 0 deletions
				
			
		
							
								
								
									
										553
									
								
								burnSubs
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										553
									
								
								burnSubs
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,553 @@
 | 
				
			||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					set -e
 | 
				
			||||||
 | 
					set -o nounset
 | 
				
			||||||
 | 
					set -o errexit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					################################################################################
 | 
				
			||||||
 | 
					# burnSubs
 | 
				
			||||||
 | 
					# version 0.9.1
 | 
				
			||||||
 | 
					#################3
 | 
				
			||||||
 | 
					# Wishlist:
 | 
				
			||||||
 | 
					#   queue encodes
 | 
				
			||||||
 | 
					#   finish TODOs
 | 
				
			||||||
 | 
					#	list subtitles flag
 | 
				
			||||||
 | 
					#	finish help flag
 | 
				
			||||||
 | 
					#	audio recode flag
 | 
				
			||||||
 | 
					################################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function machineSetup() {
 | 
				
			||||||
 | 
						# Default setup
 | 
				
			||||||
 | 
						export FF_ENC="libx264"
 | 
				
			||||||
 | 
						export FF_HW=""
 | 
				
			||||||
 | 
						export FILT_PFX=""
 | 
				
			||||||
 | 
						export FILT_SFX=""
 | 
				
			||||||
 | 
						CRF=${OPTS_CRF:-23}
 | 
				
			||||||
 | 
						export FF_STD="-preset myTranscoderPreset -crf $CRF -tune animation \
 | 
				
			||||||
 | 
							-preset medium -movflags +faststart"
 | 
				
			||||||
 | 
						export FF_EXT="-profile:v high -level 4.0"
 | 
				
			||||||
 | 
						# Handle the time limit argument used for testing if it was passed
 | 
				
			||||||
 | 
						if [[ "${OPTS_TIMELIMIT}" != "null" ]]; then
 | 
				
			||||||
 | 
							export LIM_TIME="-t ${OPTS_TIMELIMIT}"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							export LIM_TIME=""
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# The default extraProc function. This should be overridden by each encoder
 | 
				
			||||||
 | 
						# as required. For example, to set bitrate after a video has been parsed.
 | 
				
			||||||
 | 
						function extraProc() {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Use the machine hostname to set the default encoding options based upon
 | 
				
			||||||
 | 
						# my preferences.
 | 
				
			||||||
 | 
						echo "Machine identification:"
 | 
				
			||||||
 | 
						if [[ "${OPTS_FORCESOFT}" == "true" ]]; then
 | 
				
			||||||
 | 
							echo "   > Hostname: $(hostname)"
 | 
				
			||||||
 | 
							export OPTS_ENC="allsoft"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							if [[ "$(hostname)" == "Kusanagi" ]]; then
 | 
				
			||||||
 | 
								echo "   > Hostname: 草薙素子"
 | 
				
			||||||
 | 
								export OPTS_ENC="nvidia"
 | 
				
			||||||
 | 
								echo "FIX FFMPEG!"
 | 
				
			||||||
 | 
								#export FFMPEG="/opt/ffmpeg-nvenc/bin/ffmpeg"
 | 
				
			||||||
 | 
								export LD_LIBRARY_PATH="/opt/ffmpeg-nvenc/lib"
 | 
				
			||||||
 | 
								export FF_EXT="${FF_EXT} -pix_fmt yuv420p"
 | 
				
			||||||
 | 
							elif [[ "$(hostname)" == "grad-heo-lappy" ]]; then
 | 
				
			||||||
 | 
								echo "   > Hostname: $(hostname)"
 | 
				
			||||||
 | 
								export OPTS_ENC="vaapi"
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								echo "   > Hostname: $(hostname)"
 | 
				
			||||||
 | 
								export OPTS_ENC="allsoft"
 | 
				
			||||||
 | 
								export FF_EXT="${FF_EXT} -pix_fmt yuv420p"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						# Configure audio filtergraph if needed.
 | 
				
			||||||
 | 
						if [[ "${OPTS_TRANS_AUDIO}" == true ]]; then
 | 
				
			||||||
 | 
							FILT_AUDIO="-c:a aac"
 | 
				
			||||||
 | 
							if [[ "${OPTS_LPF_AUDIO}" == true ]]; then
 | 
				
			||||||
 | 
								FILT_AUDIO="-filter:a highpass=f=7 ${FILT_AUDIO}"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if [[ "$(hostname)" == "Ram-the-Red" ]]; then
 | 
				
			||||||
 | 
								FILT_AUDIO="${FILT_AUDIO} -strict -2"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							FILT_AUDIO="-c:a copy"
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Configure the encoder based upon the specific encoder chain required
 | 
				
			||||||
 | 
						## NVIDIA GPU Encode/Decode
 | 
				
			||||||
 | 
						if [[ "$OPTS_ENC" == "nvidia" ]]; then
 | 
				
			||||||
 | 
							echo "   > Using nVidia Encoder"
 | 
				
			||||||
 | 
							echo "   >>> full hardware"
 | 
				
			||||||
 | 
							# NVIDIA GPU encoding options
 | 
				
			||||||
 | 
							export FF_ENC="h264_nvenc"
 | 
				
			||||||
 | 
							# Assuming h264 input video
 | 
				
			||||||
 | 
							# TODO: Handle non h264 input streams
 | 
				
			||||||
 | 
							#export FF_HW="-hwaccel cuvid -c:v h264_cuvid"
 | 
				
			||||||
 | 
							#export FF_HW="-hwaccel cuvid"
 | 
				
			||||||
 | 
							# Frame count lookahead
 | 
				
			||||||
 | 
							export FF_EXT="${FF_EXT} -rc-lookahead 30"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						## Intel CPU Encode/Decode
 | 
				
			||||||
 | 
						elif [[  "$OPTS_ENC" == "vaapi" ]]; then
 | 
				
			||||||
 | 
							echo "   > Using VAAPI."
 | 
				
			||||||
 | 
							# apt install libvdpau-va-gl1
 | 
				
			||||||
 | 
							#export FF_BIN="/opt/ffmpeg/bin/ffmpeg"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# Full hardware
 | 
				
			||||||
 | 
							if [[ "${OPTS_FORCEPARTSOFT}" == "false" ]]; then
 | 
				
			||||||
 | 
								echo "   >>> full hardware"
 | 
				
			||||||
 | 
								# Full hardware decode/encode
 | 
				
			||||||
 | 
								export FF_HW="-hwaccel vaapi -hwaccel_device \
 | 
				
			||||||
 | 
									/dev/dri/renderD128 -hwaccel_output_format vaapi"
 | 
				
			||||||
 | 
								export FF_ENC="h264_vaapi"
 | 
				
			||||||
 | 
								export FILT_PFX="scale_vaapi,hwmap=mode=read+write+direct,format=nv12,"
 | 
				
			||||||
 | 
								export FILT_SFX=",hwmap"
 | 
				
			||||||
 | 
								# Override the extra options used for this encoder
 | 
				
			||||||
 | 
								export FF_EXT="-profile:v 100 -level 40"
 | 
				
			||||||
 | 
							# Mixed software hardware
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								echo "   >>> hardware decode"
 | 
				
			||||||
 | 
								echo "     > software encode"
 | 
				
			||||||
 | 
								# software encode, hardware decode only
 | 
				
			||||||
 | 
								export FF_HW="-hwaccel vaapi -hwaccel_device /dev/dri/renderD128"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							# Disable this shit
 | 
				
			||||||
 | 
							# set the bitrate based upon the old video size.
 | 
				
			||||||
 | 
							if [[ $(false) ]]; then
 | 
				
			||||||
 | 
								function extraProc() {
 | 
				
			||||||
 | 
									echo -n "   > determine video size: "
 | 
				
			||||||
 | 
									LEN_COMPLEX=$("$JQ" '.streams[0].tags.DURATION' \
 | 
				
			||||||
 | 
										"${STREAMS_ALL}" | tr -d '"')
 | 
				
			||||||
 | 
									LEN_SECONDS=$("$DATE" -u +'%s' -d "1970-01-01 $LEN_COMPLEX")
 | 
				
			||||||
 | 
									# shellcheck disable=SC2016
 | 
				
			||||||
 | 
									VIDEO_SIZE_KBYTES=$("$FFPROBE"  -select_streams v -show_entries \
 | 
				
			||||||
 | 
										packet=size -of default=nokey=1:noprint_wrappers=1 \
 | 
				
			||||||
 | 
										-i "${INPUT_VIDEO}" | "$AWK" '{s+=$1} END {print s/1024.0}')
 | 
				
			||||||
 | 
									KBITRATE=$("$PYTHON3" -c \
 | 
				
			||||||
 | 
										"print('%.0f' % (1.0*8.0*$VIDEO_SIZE_KBYTES/$LEN_SECONDS))")
 | 
				
			||||||
 | 
									export FF_EXT="-b:v ${KBITRATE}K "
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						# Full Software encoding/decoding. No hardware assistance.
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							echo "   > Using default full software chain."
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						sleep 1
 | 
				
			||||||
 | 
						echo "====> Starting <===="
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setupBins() {
 | 
				
			||||||
 | 
						# The first argument is the "default" binary name, and the second
 | 
				
			||||||
 | 
						# is the variable where that binary's path is stored. Using *export* to
 | 
				
			||||||
 | 
						# override the variable before "setupBins" is called will let you specify
 | 
				
			||||||
 | 
						# a specific instance of the binary to use instead.
 | 
				
			||||||
 | 
						setAndValidateBin "ffmpeg" "FFMPEG"
 | 
				
			||||||
 | 
						setAndValidateBin "ffprobe" "FFPROBE"
 | 
				
			||||||
 | 
						setAndValidateBin "jq" "JQ"
 | 
				
			||||||
 | 
						setAndValidateBin "python3" "PYTHON3"
 | 
				
			||||||
 | 
						setAndValidateBin "awk" "AWK"
 | 
				
			||||||
 | 
						setAndValidateBin "date" "DATE"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Used by the above function to evaluate overrides if they are set, and
 | 
				
			||||||
 | 
					# otherwise to simply return the existing binary as an absolute path.
 | 
				
			||||||
 | 
					function setAndValidateBin() {
 | 
				
			||||||
 | 
						binaryVariable="$2"
 | 
				
			||||||
 | 
						# shellcheck disable=SC2086
 | 
				
			||||||
 | 
						eval binaryCurrentValue="\${$binaryVariable:-}"
 | 
				
			||||||
 | 
						if [[ "" == "$binaryCurrentValue" ]]; then
 | 
				
			||||||
 | 
							binaryCurrentValue="$1"
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Try to extract the results of the current binary as an absolute path
 | 
				
			||||||
 | 
						binaryCurrentValue=$(readlink -f "$(which "$binaryCurrentValue")") || /bin/true
 | 
				
			||||||
 | 
						# And fail if we don't have it
 | 
				
			||||||
 | 
						if [[ ! -x "$binaryCurrentValue" ]]; then
 | 
				
			||||||
 | 
							echo "ERROR: Required binary '$1' not found."
 | 
				
			||||||
 | 
							exit
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						# shellcheck disable=SC2086
 | 
				
			||||||
 | 
						eval export $binaryVariable="$binaryCurrentValue"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The fall back cleanup function to remove the shit in temp. Set to trap in
 | 
				
			||||||
 | 
					# the setup temp function further on.
 | 
				
			||||||
 | 
					function doCleanup() {
 | 
				
			||||||
 | 
						# On eject return to where we started, and frag the cleanup directory
 | 
				
			||||||
 | 
						cd "$WD"
 | 
				
			||||||
 | 
						if [[ "$OPTS_DEBUG" == "false" ]]; then
 | 
				
			||||||
 | 
							echo "=> Cleaning up."
 | 
				
			||||||
 | 
							rm -r "$TMP"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							echo "tmp dir: $TMP"
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						alertUser
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# All we do is note that we'll have to move around, and this helps us keep our
 | 
				
			||||||
 | 
					# bearings and avoid polluting the working directory.
 | 
				
			||||||
 | 
					function setupTemp() {
 | 
				
			||||||
 | 
						echo "=> Performing Setup:"
 | 
				
			||||||
 | 
						# The FFMPEG calls require all of the files to actually exist on disk. To
 | 
				
			||||||
 | 
						# accommodate this, we setup a temporary working directory to dump the files
 | 
				
			||||||
 | 
						# and we will remove it's contents when things are done. This provides a
 | 
				
			||||||
 | 
						# location for the font files to be placed, as well as a location for the
 | 
				
			||||||
 | 
						# raw subtitles files.
 | 
				
			||||||
 | 
						trap doCleanup EXIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						export WD="$PWD"
 | 
				
			||||||
 | 
						export TMP=$(mktemp -d /tmp/transFont.XXXX)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function dumpFonts() {
 | 
				
			||||||
 | 
						# Dumb font dump
 | 
				
			||||||
 | 
						cd "$FONTDIR"
 | 
				
			||||||
 | 
						"$FFMPEG" -dump_attachment:t "" -i "${INPUT_VIDEO}" -vn -an \
 | 
				
			||||||
 | 
							-f null /dev/null 2>/dev/null || /bin/true
 | 
				
			||||||
 | 
						cd "$WD"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setupFonts() {
 | 
				
			||||||
 | 
						echo "   > setting up fonts..."
 | 
				
			||||||
 | 
						# Simply setup an encode specific font configuration setup. This will direct
 | 
				
			||||||
 | 
						# the system to use any font files that we have provided in $TMP/font_files
 | 
				
			||||||
 | 
						# then fall back to the system configuration afterwards.
 | 
				
			||||||
 | 
						export FONTDIR="${TMP}/font_files"
 | 
				
			||||||
 | 
						FC_DIR="${TMP}/fontconfig"
 | 
				
			||||||
 | 
						FC_FILE="${FC_DIR}/fonts.conf"
 | 
				
			||||||
 | 
						mkdir "${FONTDIR}"
 | 
				
			||||||
 | 
						mkdir "${FC_DIR}"
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							echo '<?xml version="1.0"?>';
 | 
				
			||||||
 | 
							echo '<!DOCTYPE fontconfig SYSTEM "fonts.dtd">';
 | 
				
			||||||
 | 
							echo '<fontconfig>';
 | 
				
			||||||
 | 
							echo '	<dir>'"${FONTDIR}"'</dir>';
 | 
				
			||||||
 | 
							echo '	<include>/etc/fonts/fonts.conf</include>';
 | 
				
			||||||
 | 
							echo '</fontconfig>'
 | 
				
			||||||
 | 
						} > "${FC_FILE}"
 | 
				
			||||||
 | 
						# This export line presents the configuration override to FFMPEG later on.
 | 
				
			||||||
 | 
						export FONTCONFIG_FILE="${FC_FILE}"
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						dumpFonts
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setupPreset() {
 | 
				
			||||||
 | 
						echo "   > setting up preset..."
 | 
				
			||||||
 | 
						# The preset system provides a way to specify specific encoding options.
 | 
				
			||||||
 | 
						# This can easily be removed as desired.
 | 
				
			||||||
 | 
						presetName="$1"
 | 
				
			||||||
 | 
						# And include the ffmpeg preset
 | 
				
			||||||
 | 
						export FFMPEG_DATADIR="${TMP}/ffmpeg"
 | 
				
			||||||
 | 
						FFMPEG_PRESET_FILE="${FFMPEG_DATADIR}/${FF_ENC}-${presetName}.preset"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mkdir "${FFMPEG_DATADIR}"
 | 
				
			||||||
 | 
						{	
 | 
				
			||||||
 | 
							# This preset is for the roku
 | 
				
			||||||
 | 
							echo 'coder=1'
 | 
				
			||||||
 | 
							echo 'flags=+loop'
 | 
				
			||||||
 | 
							echo 'cmp=+chroma'
 | 
				
			||||||
 | 
							echo 'partitions=+parti8x8+parti4x4+partp8x8+partb8x8'
 | 
				
			||||||
 | 
							echo 'me_method=umh'
 | 
				
			||||||
 | 
							echo 'subq=8'
 | 
				
			||||||
 | 
							echo 'me_range=16'
 | 
				
			||||||
 | 
							echo 'g=250'
 | 
				
			||||||
 | 
							echo 'keyint_min=25'
 | 
				
			||||||
 | 
							echo 'sc_threshold=40'
 | 
				
			||||||
 | 
							echo 'i_qfactor=0.71'
 | 
				
			||||||
 | 
							echo 'b_strategy=2'
 | 
				
			||||||
 | 
							echo 'qcomp=0.6'
 | 
				
			||||||
 | 
							echo 'qmin=10'
 | 
				
			||||||
 | 
							echo 'qmax=51'
 | 
				
			||||||
 | 
							echo 'qdiff=4'
 | 
				
			||||||
 | 
							echo 'bf=4'
 | 
				
			||||||
 | 
							echo 'refs=4'
 | 
				
			||||||
 | 
							echo 'directpred=3'
 | 
				
			||||||
 | 
							echo 'trellis=1'
 | 
				
			||||||
 | 
							echo 'flags2=+wpred+mixed_refs+dct8x8+fastpskip'
 | 
				
			||||||
 | 
						} > "${FFMPEG_PRESET_FILE}"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function parseStreams() {
 | 
				
			||||||
 | 
						# Most MKV files will only have a single subtitle file. In the case we have
 | 
				
			||||||
 | 
						# multiple subtitles we wish to handle conversion gracefully. To do so, we
 | 
				
			||||||
 | 
						# extract all of the track information (the first ffprobe call), then use
 | 
				
			||||||
 | 
						# the json parsing tool jq to extract subtitle data for styled subtitles.
 | 
				
			||||||
 | 
						#
 | 
				
			||||||
 | 
						# 
 | 
				
			||||||
 | 
						STREAMS_ALL="${TMP}/streams.json"
 | 
				
			||||||
 | 
						export STREAMS_SUB="${TMP}/subs.json"
 | 
				
			||||||
 | 
						"$FFPROBE" -v error -of json -show_streams "${INPUT_VIDEO}" 2>/dev/null > "${STREAMS_ALL}"
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						# Extract subtitles
 | 
				
			||||||
 | 
						#$item.codec_type == "subtitle" \&\& 
 | 
				
			||||||
 | 
						# shellcheck disable=SC2016
 | 
				
			||||||
 | 
						"$JQ" 'reduce .streams[] as $item ([]; if ($item.codec_name == "ass") then [.[],$item] else . end) | reduce .[] as $item ([]; [.[],{t:($item.tags.title),i:($item.index),lang:$item.tags.language, disposition:$item.disposition}]) | reduce .[] as $item ([]; [.[],{t:($item.t // ($item.lang + "-" + ($item.i | tostring))),i:$item.i,lang:$item.lang,disposition:$item.disposition}])' "${STREAMS_ALL}" > "${STREAMS_SUB}"
 | 
				
			||||||
 | 
						export SUB_COUNT=$("$JQ" 'length' "${STREAMS_SUB}")
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function listSubtitles() {
 | 
				
			||||||
 | 
						# TODO: 
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function selectSubs() {
 | 
				
			||||||
 | 
						# TODO: handle multiple subtitle files
 | 
				
			||||||
 | 
						# TODO: verify the the subtitle index is legal
 | 
				
			||||||
 | 
						if [[ $SUB_COUNT -eq 0 ]]; then
 | 
				
			||||||
 | 
							echo "   > ERROR: No subtitles! Todo!"
 | 
				
			||||||
 | 
							export SUBTITLE_INDEX=-1
 | 
				
			||||||
 | 
						elif [[ $SUB_COUNT -eq 1 ]]; then
 | 
				
			||||||
 | 
							export SUBTITLE_INDEX=$($JQ '.[].i' "$STREAMS_SUB")
 | 
				
			||||||
 | 
							SUBTITLE_NAME=$($JQ '.[].t' "$STREAMS_SUB")
 | 
				
			||||||
 | 
							echo "   > subtitles: [${SUBTITLE_INDEX}] ${SUBTITLE_NAME}"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							echo "   > ERROR: Multiple subtitles! Todo!"
 | 
				
			||||||
 | 
							export SUBTITLE_INDEX=-1
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function extractSubs() {
 | 
				
			||||||
 | 
						echo "   > extracting subtitles"
 | 
				
			||||||
 | 
						export SUBTITLE_FILE="${TMP}/ripped.ass"
 | 
				
			||||||
 | 
						extractIndex="$1"
 | 
				
			||||||
 | 
						"$FFMPEG" -i "${INPUT_VIDEO}" -map 0:"${extractIndex}" -vn -an -c:s copy -c:a copy \
 | 
				
			||||||
 | 
							"$SUBTITLE_FILE" 2>/dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function doTranscode() {
 | 
				
			||||||
 | 
						echo "=> Starting transcode:"
 | 
				
			||||||
 | 
						# shellcheck disable=SC2086
 | 
				
			||||||
 | 
						echo "$FFMPEG" ${FF_HW} -i "${INPUT_VIDEO}" -sn ${LIM_TIME} \
 | 
				
			||||||
 | 
							-filter:v "${FILT_PFX}ass=${SUBTITLE_FILE}${FILT_SFX}" \
 | 
				
			||||||
 | 
							${FILT_AUDIO} -c:v "${FF_ENC}" ${FF_STD} ${FF_EXT}	\
 | 
				
			||||||
 | 
							"${OUTPUT_VIDEO}"
 | 
				
			||||||
 | 
						if [[ "$OPTS_DRYRUN" == true ]]; then
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						# shellcheck disable=SC2086
 | 
				
			||||||
 | 
						"$FFMPEG" ${FF_HW} -i "${INPUT_VIDEO}" -sn ${LIM_TIME} \
 | 
				
			||||||
 | 
							-filter:v "${FILT_PFX}ass=${SUBTITLE_FILE}${FILT_SFX}" \
 | 
				
			||||||
 | 
							${FILT_AUDIO} -c:v "${FF_ENC}" ${FF_STD} ${FF_EXT}	\
 | 
				
			||||||
 | 
							"${OUTPUT_VIDEO}"
 | 
				
			||||||
 | 
						export FINAL_STATUS=$?
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function runExtraProc() {
 | 
				
			||||||
 | 
						if [[ "$FF_ENC" == "$1" ]]; then
 | 
				
			||||||
 | 
							extraProc
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function klobberCheck() {
 | 
				
			||||||
 | 
						if [[ -e "${OUTPUT_VIDEO}" ]]; then
 | 
				
			||||||
 | 
							if [[ "$OPTS_KLOBBER" == "true" ]]; then
 | 
				
			||||||
 | 
								echo "   > klobbering old file '${OUTPUT_VIDEO}'"
 | 
				
			||||||
 | 
								rm -v "${OUTPUT_VIDEO}"
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								echo "   > refusing to klobber old file '${OUTPUT_VIDEO}'"
 | 
				
			||||||
 | 
								exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function alertUser() {
 | 
				
			||||||
 | 
						# if the function isn't available, then define an empty function to
 | 
				
			||||||
 | 
						# reject the message into the void
 | 
				
			||||||
 | 
						if ! which notify-send >/dev/null; then
 | 
				
			||||||
 | 
							function notify-send() { return; }
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if [[ $FINAL_STATUS -ne 0 ]]; then
 | 
				
			||||||
 | 
							notify-send -u normal --icon error "🗙 Transcode failed!" \
 | 
				
			||||||
 | 
								"$(basename "${INPUT_VIDEO}")\n🞩🞩🞩🞩🞩\n$(basename "${OUTPUT_VIDEO}")"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							notify-send -u normal --icon ${NOTIFY_ICON} "✔ Transcode finished" \
 | 
				
			||||||
 | 
								"$(basename "${INPUT_VIDEO}")\n↓↓↓↓↓\n$(basename "${OUTPUT_VIDEO}")"
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# And verify arguments
 | 
				
			||||||
 | 
					######
 | 
				
			||||||
 | 
					# Defaults
 | 
				
			||||||
 | 
					OPTS_KLOBBER=false
 | 
				
			||||||
 | 
					OPTS_LISTSUBS=false
 | 
				
			||||||
 | 
					OPTS_SELSUB=-1
 | 
				
			||||||
 | 
					OPTS_LISTSUBS=false
 | 
				
			||||||
 | 
					OPTS_FORCESOFT=false
 | 
				
			||||||
 | 
					OPTS_FORCEPARTSOFT=false
 | 
				
			||||||
 | 
					OPTS_ENC="allsoft"
 | 
				
			||||||
 | 
					OPTS_TIMELIMIT=null
 | 
				
			||||||
 | 
					OPTS_DRYRUN=false
 | 
				
			||||||
 | 
					OPTS_DEBUG=false
 | 
				
			||||||
 | 
					OPTS_LPF_AUDIO=false
 | 
				
			||||||
 | 
					OPTS_TRANS_AUDIO=false
 | 
				
			||||||
 | 
					unset OPT_CRF
 | 
				
			||||||
 | 
					# this is the --icon flag passed to notify-send at the end of the transcode
 | 
				
			||||||
 | 
					NOTIFY_ICON="face-tired"
 | 
				
			||||||
 | 
					# preinitalized final ffmpeg status to assumed error
 | 
				
			||||||
 | 
					FINAL_STATUS=1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Argument Parsing
 | 
				
			||||||
 | 
					#	Input/Output videos (non-flagged arguments)
 | 
				
			||||||
 | 
					#	optional:
 | 
				
			||||||
 | 
					#		-k		do clobber output
 | 
				
			||||||
 | 
					#		-s #	subtitle track
 | 
				
			||||||
 | 
					#		-l		list subtitle tracks of input files		
 | 
				
			||||||
 | 
					#		--soft	force software encoder
 | 
				
			||||||
 | 
					#		-d		debug, don't cleanup
 | 
				
			||||||
 | 
					###
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					######
 | 
				
			||||||
 | 
					# Reformat and organize the input strings
 | 
				
			||||||
 | 
					OPT_STRING=$(getopt -o 'hkls:dt:' --long 'help,psoft,soft,dry,crf:,audio,audiofix' -- "$@")
 | 
				
			||||||
 | 
					# reassign them as positional arguments
 | 
				
			||||||
 | 
					eval set -- "$OPT_STRING"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					while true; do
 | 
				
			||||||
 | 
						case "$1" in
 | 
				
			||||||
 | 
							"-t")
 | 
				
			||||||
 | 
								OPTS_TIMELIMIT="$2"
 | 
				
			||||||
 | 
								echo ">> !! limiting encode to time '$OPTS_TIMELIMIT'"
 | 
				
			||||||
 | 
								shift 2
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"-k")
 | 
				
			||||||
 | 
								OPTS_KLOBBER=true
 | 
				
			||||||
 | 
								echo ">> !! klobber when encoding time comes."
 | 
				
			||||||
 | 
								shift
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"-l")
 | 
				
			||||||
 | 
								OPTS_LISTSUBS=true
 | 
				
			||||||
 | 
								echo ">> !! list subtitles and exit"
 | 
				
			||||||
 | 
								shift
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"-s")
 | 
				
			||||||
 | 
								OPTS_SELSUB="$2"
 | 
				
			||||||
 | 
								#TODO: verify legal subtitle track number convention"
 | 
				
			||||||
 | 
								echo "TODO: verify legal subtitle track number convention" 
 | 
				
			||||||
 | 
								echo ">> !! Selecting subtitle track #${OPTS_SELSUB}"
 | 
				
			||||||
 | 
								shift 2
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"--psoft")
 | 
				
			||||||
 | 
								OPTS_FORCEPARTSOFT=true
 | 
				
			||||||
 | 
								echo ">> !! forcing software encoding."
 | 
				
			||||||
 | 
								shift
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"--audio")
 | 
				
			||||||
 | 
								OPTS_LPF_AUDIO=true
 | 
				
			||||||
 | 
								OPTS_TRANS_AUDIO=true
 | 
				
			||||||
 | 
								echo ">> !! low pass filter audio to AAC."
 | 
				
			||||||
 | 
								shift
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"--audiofix")
 | 
				
			||||||
 | 
								OPTS_TRANS_AUDIO=true
 | 
				
			||||||
 | 
								echo ">> !! no filter audio to AAC."
 | 
				
			||||||
 | 
								shift
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"--soft")
 | 
				
			||||||
 | 
								OPTS_FORCESOFT=true
 | 
				
			||||||
 | 
								echo ">> !! forcing software decoding/encoding."
 | 
				
			||||||
 | 
								shift
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"--crf")
 | 
				
			||||||
 | 
								OPTS_CRF="$2"
 | 
				
			||||||
 | 
								echo ">> !! CRF Override CRF='$OPTS_CRF'"
 | 
				
			||||||
 | 
								shift 2
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"-d")
 | 
				
			||||||
 | 
								OPTS_DEBUG=true
 | 
				
			||||||
 | 
								echo ">> !! debug enabled."
 | 
				
			||||||
 | 
								echo ">>      temp files will not be cleaned up."
 | 
				
			||||||
 | 
								shift
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"--dry")
 | 
				
			||||||
 | 
								OPTS_DRYRUN=true
 | 
				
			||||||
 | 
								echo ">> !! dry run. No encode."
 | 
				
			||||||
 | 
								shift
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"--")
 | 
				
			||||||
 | 
								shift # all arguments parsed
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							"-h" | "--help")
 | 
				
			||||||
 | 
								# TODO: Display help
 | 
				
			||||||
 | 
								shift # all arguments parsed
 | 
				
			||||||
 | 
								echo "TODO: HELP!" # Display HELP
 | 
				
			||||||
 | 
								exit
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
							*)
 | 
				
			||||||
 | 
								echo "Arg: $1"
 | 
				
			||||||
 | 
								echo "Internal Error!" >&2
 | 
				
			||||||
 | 
								exit
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						esac
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Now parse POSITIONAL ARGUMENTS
 | 
				
			||||||
 | 
					if [[ $# -ne 2 ]]; then
 | 
				
			||||||
 | 
						echo "ERROR: Incorrect number of positional arguments. Expected 2, got $#"
 | 
				
			||||||
 | 
						echo "       $0 [args] <input> <output>"
 | 
				
			||||||
 | 
						exit
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						INPUT_VIDEO="$(readlink -f "$1")"
 | 
				
			||||||
 | 
						OUTPUT_VIDEO="$2"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############
 | 
				
			||||||
 | 
					# Configure the encoder based upon the hostname
 | 
				
			||||||
 | 
					machineSetup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############
 | 
				
			||||||
 | 
					# Check and validate the binaries we use to parse and setup the encoding chain
 | 
				
			||||||
 | 
					setupBins
 | 
				
			||||||
 | 
					# Setup the temp space for working files
 | 
				
			||||||
 | 
					setupTemp
 | 
				
			||||||
 | 
					# Extract embedded fonts and configure fontconfig
 | 
				
			||||||
 | 
					setupFonts
 | 
				
			||||||
 | 
					# Export the preset file used for the Roku
 | 
				
			||||||
 | 
					setupPreset myTranscoderPreset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############
 | 
				
			||||||
 | 
					# Parse stream data to identify subtitles
 | 
				
			||||||
 | 
					parseStreams
 | 
				
			||||||
 | 
					# Now! If OPTS_LISTSUBS is defined, then we branch to list subs and exit.
 | 
				
			||||||
 | 
					if [[ "$OPTS_LISTSUBS" == "true" ]]; then
 | 
				
			||||||
 | 
						listSubtitles
 | 
				
			||||||
 | 
						exit	
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					# ask the user for the subtitle file if more than one is available
 | 
				
			||||||
 | 
					selectSubs
 | 
				
			||||||
 | 
					# extract the selected subtitle file
 | 
				
			||||||
 | 
					extractSubs $SUBTITLE_INDEX
 | 
				
			||||||
 | 
					# Set the bitrate if that function wasn't disabled
 | 
				
			||||||
 | 
					runExtraProc "h264_vaapi"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If we're clobbering, now is the time to do the clobbering
 | 
				
			||||||
 | 
					klobberCheck
 | 
				
			||||||
 | 
					# Kickoff the transcode
 | 
				
			||||||
 | 
					doTranscode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# cleanup automatically executes after the done message is cleared
 | 
				
			||||||
 | 
					echo "done."
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue