decided to actually go through git as was doing too many scripts... uses ffmpeg to transcode a list of files into AV1 format.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

309 lines
9.1 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. #!/bin/bash
  2. #Is a 'slave' script to run an ffmpeg (and ffprobe) command. Generally it will
  3. #take a file specified on the 'host' machine that has a list of files; copy a
  4. #version down locally, transcode it, then replace the original file on the
  5. #'host', and remove the temporary files.
  6. #
  7. #You will need to have both FFMPEG and FFPROBE installed (and will need
  8. #to pray to St. Isidore... good luck if you encounter issues.
  9. #Default operations, change if necessary
  10. FFBIN="/usr/bin/" #if unusual install or a specific version
  11. HostName="localhost" #if localhost then will do locally (removes ssh/scp cmds)
  12. hostFile="/tmp/transcode/list.txt"
  13. workDIR="$PWD/transcode"
  14. tmpDIR="$PWD/tmpTranscode"
  15. #DEFINE FUNCTIONS
  16. function encode {
  17. local inFL=$1
  18. local outFL=$2
  19. local burn=$3
  20. if [ $burn -gt -1 ]
  21. then
  22. inline="-i "$tmpDIR/dummy.mkv""
  23. vidline="-map 1:v:0"
  24. subline="-map -0:s:$burn"
  25. else
  26. unset inline
  27. vidline="-map 0:v:0"
  28. unset subline
  29. fi
  30. $FFBIN/ffmpeg -hide_banner -loglevel error -stats \
  31. -i "$inFL" $inline \
  32. -map_metadata 0 \
  33. $vidline \
  34. -c:v libsvtav1 -crf 28 -preset 6 -pix_fmt yuv420p10le \
  35. -svtav1-params \
  36. "enable-overlays=1:\
  37. tune=0:\
  38. keyint=10s" \
  39. -map 0:a? -acodec aac \
  40. -map 0:s? -scodec copy $subline \
  41. -use_wallclock_as_timestamps 1 -max_interleave_delta 0 \
  42. -map_chapters 0 -max_muxing_queue_size 9999 -y "$outFL"
  43. }
  44. function burnSubs {
  45. local inFL=$1
  46. local outFL=$2
  47. local track=$3
  48. #EVIDTNELY NECESSARY SO THAT FILES AREN'T 198+ HRS IN LEN. AT THE END
  49. local DURATION=$( $FFBIN/ffprobe -loglevel error -show_entries format=duration \
  50. -of default=noprint_wrappers=1:nokey=1 "$inFL" )
  51. $FFBIN/ffmpeg -hide_banner -stats -i "$inFL" \
  52. -map_metadata -1 \
  53. -filter_complex "[0:v][0:s:$track]overlay[v]" -map "[v]" \
  54. -filter_complex_threads 1 \
  55. -an -sn \
  56. -max_muxing_queue_size 4096 \
  57. -t $DURATION -y "$tmpDIR/dummy.mkv"
  58. if ! [ $? -eq 0 ]
  59. then
  60. echo "Sub Burn Failed"
  61. return 10
  62. else
  63. encode "$inFL" "$outFL" $track
  64. fi
  65. }
  66. #MAIN FUNCTION BEGINS
  67. mkdir -p "$tmpDIR"
  68. mkdir -p "$workDIR"
  69. if [ -n "$1" ]
  70. then
  71. numIter=$1
  72. iterLim="true"
  73. else
  74. numIter=20
  75. iterLim="false"
  76. fi
  77. if ! command -v $FFBIN/ffprobe &> /dev/null
  78. then
  79. echo "Need to have ffprobe (and ffmpeg) installed"
  80. exit 1
  81. fi
  82. if ! command -v $FFBIN/ffmpeg &> /dev/null
  83. then
  84. echo "Need to have ffmpeg (and ffprobe) installed"
  85. exit 1
  86. fi
  87. if ! command -v bc &> /dev/null
  88. then
  89. echo "Need to have bc installed (foreign audio scan)"
  90. exit 1
  91. fi
  92. i=0 #Total number of loops
  93. j=0 #Failed to obtain job
  94. k=0 #ffmpeg failed
  95. declare -a langs #Subtitle Languages
  96. while [ $numIter -gt 0 ] && [ $j -lt 50 ] && [ $k -lt 60 ]
  97. do
  98. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  99. then
  100. filePATH=$( ssh $HostName "head -n1 $hostFile;sed -i -e '1d' $hostFile" )
  101. else
  102. filePATH=$( head -n1 $hostFile;sed -i -e '1d' $hostFile )
  103. fi
  104. if [ -n "$filePATH" ]
  105. then
  106. j=0
  107. fileNAME=$( basename "$filePATH" )
  108. #PULL DOWN FILE
  109. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  110. then
  111. scp $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )" "$tmpDIR"
  112. else
  113. rsync -a --progress "$filePATH" "$tmpDIR/"
  114. fi
  115. #RUN FFMPROBE/FFMPEG
  116. echo "DOING $fileNAME"
  117. unset langs
  118. #DETERMINE THE NUMBER OF ENGLISH SUBTITLES (BURNING BEHAVIOUR)
  119. for line in $( $FFBIN/ffprobe -loglevel error -select_streams s -show_entries\
  120. stream=index:stream_tags=language -of csv=p=0 \
  121. "$tmpDIR"/"$fileNAME" )
  122. do
  123. langs+=("$line")
  124. done
  125. unset line
  126. engCounter=0
  127. if [ ${#langs[@]} -gt 1 ]
  128. then
  129. #DETERMINE NUMBER OF ENGLISH-CONTAINING SUBTITLES
  130. unset streamNUMBERS
  131. declare -a streamNUMBERS
  132. for language in "${langs[@]}"
  133. do
  134. if grep -iq "eng" <<< $language
  135. then
  136. let ++engCounter
  137. delim=","
  138. unset addNumber
  139. addNumber=( "${language%%"$delim"*}" )
  140. streamNUMBERS+=($addNumber)
  141. fi
  142. done
  143. if [ $engCounter -lt 2 ]
  144. then
  145. #ONLY ONE ENG. SUB TRACK
  146. echo "ONE ENG. SUB TRACK"
  147. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME" -1
  148. else
  149. #TEST SUBTITLE TYPE; IF NOT PGS SKIP IT; FEEL FREE TO FILL IN
  150. if grep -qi "pgs" <<< $( $FFBIN/ffprobe -loglevel error -select_streams s \
  151. -show_entries stream=codec_name \
  152. -of csv=p=0 "$tmpDIR"/"$fileNAME" )
  153. then
  154. # MORE THAN ONE SUB TRACK; HAVE TO FIGURE OUT WHICH TO BURN
  155. unset streamFRAMES
  156. declare -a streamFRAMES
  157. #Presuming the one to burn-in is the one with less frames
  158. unset minFrames
  159. unset maxFrames
  160. unset indexITER
  161. unset minINDEX
  162. minFrames=0
  163. maxFrames=0
  164. indexITER=0
  165. minINDEX=0
  166. for index in ${streamNUMBERS[@]}
  167. do
  168. SUBINDEX=$(expr $index - ${streamNUMBERS[0]})
  169. currFrames=$( $FFBIN/ffprobe -loglevel error -select_streams s:$SUBINDEX \
  170. -show_entries stream_tags=NUMBER_OF_FRAMES-eng -of csv=p=0 \
  171. "$tmpDIR/$fileNAME")
  172. if [ $indexITER -lt 1 ]
  173. then
  174. minFrames=$currFrames
  175. maxFrames=$currFrames
  176. minINDEX=$index
  177. let ++indexITER
  178. elif [ $currFrames -lt $minFrames ]
  179. then
  180. minFrames=$currFrames
  181. minINDEX=$index
  182. let ++indexITER
  183. elif [ $currFrames -gt $maxFrames ]
  184. then
  185. maxFrames=$currFrames
  186. let ++indexITER
  187. fi
  188. done
  189. unset SUBTITLEINDEX
  190. SUBTITLEINDEX=$(expr $minINDEX - ${streamNUMBERS[0]})
  191. #TEST FRAMES IN SUB TRACK, IF < 15% MAX MOST LIKELY ISN'T FOR. AUD.
  192. #15% as LOTR dir. comm included, blows up the max number for them...
  193. currFrames=$( $FFBIN/ffprobe -loglevel error -select_streams s:$SUBTITLEINDEX \
  194. -show_entries stream_tags=NUMBER_OF_FRAMES-eng -of csv=p=0 \
  195. "$tmpDIR/$fileNAME")
  196. if [ $( echo "($currFrames / $maxFrames) < 0.25"|bc -l ) -gt 0 ]
  197. then
  198. echo "BURNING STREAM $SUBTITLEINDEX (STREAM $minINDEX) from $fileNAME"
  199. burnSubs "$tmpDIR/$fileNAME" "$workDIR/$fileNAME" $SUBTITLEINDEX
  200. else
  201. echo "MIN. SUB TRACK ($SUBTITLEINDEX [$minINDEX])) DUR. > 25% FILM, NOT BURNING"
  202. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME" -1
  203. fi
  204. else
  205. #TODO expand foreign scan for more than pgs subtitles Need ass and
  206. #subtitles filters; don't know how to differentiate at present time.
  207. #I'm actually kinda missing a good example; I'm sure they're in there
  208. #but I don't know which ones they are lol; lmk if you know one.
  209. echo "NOT A PGS SUBTITLE TYPE; PASSING ALL THROUGH, FUTURE DEV."
  210. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME" -1
  211. fi
  212. fi
  213. else
  214. #ONE OR FEWER SUB TRACKS
  215. encode "$tmpDIR/$fileNAME" "$workDIR/$fileNAME" -1
  216. fi
  217. if [ $? != 0 ] || [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
  218. then
  219. #RUN FAILED (EITHER NONZERO EXIT OR THE FILE IS 0 BYTES LARGE)
  220. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  221. then
  222. ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
  223. else
  224. echo "$filePATH">>$hostFile
  225. fi
  226. let ++k
  227. echo "RUN ($fileNAME) FAILED ($k/60)"
  228. if [ $( stat -c%s "$workDIR/$fileNAME" ) -eq 0 ]
  229. then
  230. rm "$workDIR"/"$fileNAME"
  231. fi
  232. else
  233. #UPLOAD AND REMOVE THE TRANSCODED FILE
  234. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  235. then
  236. #scp "$workDIR/$fileNAME" $HostName:"$( echo $filePATH | sed "s/[][!@#$%^&*( ;)]/\\\&/g" )"
  237. scp "$workDIR/$fileNAME" $HostName:"$filePATH"
  238. else
  239. rsync -a --progress "$workDIR/$fileNAME" "$filePATH"
  240. fi
  241. if [ $? != 0 ]
  242. then
  243. echo "UPLOAD OF $filePATH FAILED; EXITING"
  244. if [ $( echo "$HostName"|tr [a-z] [A-Z] ) != "LOCALHOST" ]
  245. then
  246. ssh $HostName <<< "echo $( echo $filePATH | sed "s/[!@#$%^&*( ;)-]/\\\&/g" )>>$hostFile"
  247. else
  248. echo "$filePATH">>$hostFile
  249. fi
  250. exit 1
  251. else
  252. rm "$workDIR"/"$fileNAME"
  253. fi
  254. k=0
  255. fi
  256. #REMOVE THE TEMP FILE (if necessary)
  257. if ls "$workDIR"/"$fileNAME"
  258. then
  259. rm "$workDIR"/"$fileNAME"
  260. else
  261. echo "Workdir already cleaned"
  262. fi
  263. if ls "$tmpDIR"/"$fileNAME"
  264. then
  265. rm "$tmpDIR"/"$fileNAME"
  266. elif ls "$tmpDIR"/"dummy.mkv"
  267. then
  268. rm "$tmpDIR"/"dummy.mkv"
  269. else
  270. echo "Already removed temp. file(s)"
  271. fi
  272. else
  273. echo "OUT OF FILES!? (try number $j/50) ... sleeping 1 min"
  274. let ++j
  275. sleep 60
  276. fi
  277. #Increment if required
  278. if [ $iterLim == "true" ]
  279. then
  280. let --numIter
  281. fi
  282. let ++i
  283. echo "Done LOOP NUMBER $i!"
  284. done
  285. exit 0