tc-video-generic 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #!/bin/sh
  2. ## TODO: handle srt encoding?
  3. usage () {
  4. cat <<EOF>&2
  5. Usage: ${0##*/} [OPTIONS] FILES|FOLDERS
  6. Transcode FILES or files found in FOLDERS to x264 and ogg vorbis in a MKV container.
  7. Black stripes are *not* cropped by default since it may be sometimes inaccurate.
  8. A time stamp is appended to the output filenames.
  9. CRF encoding is performed by default. It targets a desired quality. CRF 20 is
  10. usually a good factor, 18 is higher quality, 22 is lower. The 18-22 range is
  11. reasonable. The quality loss is usually noticeable above 22 and the size
  12. increase is significant below 18 for a barely noticeable quality change.
  13. 2-pass encoding can achieve best compression, if the given bitrate is
  14. appropriate. A sample in CRF encoding can give a good bitrate estimate for the
  15. desired quality. Bitrates for 1080p movies are found within the 1000k-10000k
  16. range.
  17. You can get a list of supported codecs with
  18. $ ffmpeg -codecs
  19. User options are read from the TC_VIDEO_OPT variable. This can be useful if you
  20. often use the same options.
  21. Options:
  22. -a CODEC: Audio codec supported by ffmpeg. (Default: libvorbis).
  23. -b: Default bitrate for audio stream with unidentifiable bitrate.
  24. If 0, copy stream (default).
  25. -c: Copy streams (no reencoding).
  26. -C: Enable auto-crop (needs video reencoding).
  27. -d BR: Perform a 2-pass video encoding at bitrate BR and set '-tune film'.
  28. -f: Remove source when done.
  29. -h: Display this help.
  30. -o OPT: Additional options.
  31. -p: Preview changes, do not encode.
  32. -P: Generate two sequence of thumbnails, one cropped, the other not.
  33. Enable auto-crop, do not encode.
  34. -q QUAL: x264 CRF quality (default 20).
  35. -s: Sample of 5 minutes.
  36. -S MIN: Sample of MIN minutes.
  37. -t: Remove all "title" metadata.
  38. Examples:
  39. * Get a preview of changes.
  40. ${0##*/} -p input.video
  41. * Proceed with default options over folders and files.
  42. ${0##*/} input-folder input.video
  43. * Preview black stripes cropping.
  44. ${0##*/} -P input.video
  45. * Process with default options and remove black stripes.
  46. ${0##*/} -C input.video
  47. * Exchange streams 1 and 2 by first removing them, then adding them in the
  48. desired order.
  49. ${0##*/} -o '-map -0:1 -map -0:2 -map 0:2 -map 0:1' input.video
  50. * Change audio stream 1 title and remove audio stream 2 title:
  51. ${0##*/} -o '-metadata:s:a:0 title="FR: OGG Stereo" -metadata:s:a:1 title=' input.video
  52. See <https://trac.ffmpeg.org/wiki/Encode/H.264>, 'ffmpeg -h encoder=libx264' and 'x264 --fullhelp'.
  53. EOF
  54. }
  55. EXT="mkv"
  56. AUDIO_CODEC="libvorbis"
  57. VIDEO_PARAM="-c:v libx264 -preset slower -crf 20"
  58. AUDIO_PARAM=""
  59. VIDEO_FILTER=""
  60. AUDIO_DEFAULT_RATE=0
  61. OVERWRITE="-n"
  62. SAMPLE=""
  63. OPT_OVERWRITE=false
  64. OPT_REMOVE_TITLE=false
  65. OPT_CROP=false
  66. OPT_CROPPREVIEW=false
  67. OPT_PREVIEW=false
  68. OPT_COPY=false
  69. OPT_2PASS=false
  70. while getopts ":a:b:cCd:fho:pPq:sS:t" opt; do
  71. case $opt in
  72. a)
  73. AUDIO_CODEC=$OPTARG ;;
  74. b)
  75. AUDIO_DEFAULT_RATE=$OPTARG ;;
  76. c)
  77. VIDEO_PARAM="-c:v copy"
  78. AUDIO_PARAM="-c:a copy"
  79. OPT_COPY=true;;
  80. C)
  81. OPT_CROP=true;;
  82. d)
  83. VIDEO_PARAM="-c:v libx264 -preset slower -b:v ${OPTARG}k"
  84. OPT_2PASS=true;;
  85. f)
  86. OVERWRITE="-y"
  87. OPT_OVERWRITE=true;;
  88. h)
  89. usage
  90. exit 1 ;;
  91. o)
  92. TC_VIDEO_OPT="$OPTARG" ;;
  93. p)
  94. OPT_PREVIEW=true ;;
  95. P)
  96. OPT_CROP=true
  97. OPT_PREVIEW=true
  98. OPT_CROPPREVIEW=true ;;
  99. q)
  100. VIDEO_PARAM="-c:v libx264 -preset slower -crf $OPTARG";;
  101. s)
  102. SAMPLE="-ss 60 -t 300" ;;
  103. S)
  104. SAMPLE="-ss 60 -t $((60*OPTARG))" ;;
  105. t)
  106. OPT_REMOVE_TITLE=true ;;
  107. \?)
  108. usage
  109. exit 1 ;;
  110. esac
  111. done
  112. shift $((OPTIND - 1))
  113. if [ $# -eq 0 ]; then
  114. usage
  115. exit
  116. fi
  117. if ! command -v ffmpeg >/dev/null; then
  118. echo "ffmpeg required."
  119. exit
  120. fi
  121. highfreq () {
  122. awk 'BEGIN{max=0} /crop=/ {t[$NF]++; if (t[$NF]>max) {max=t[$NF]; val=$NF}} END{print val}'
  123. }
  124. ## Usage: cropvalue FILE STEP
  125. ## Return the crop values as ffmpeg output them.
  126. cropvalue () {
  127. local step=$2
  128. for i in $(seq "$step" "$step" $((5*step))); do
  129. ffmpeg -nostdin -ss "$i" -i "$1" -t 10 -vf "cropdetect=24:2:0" -f null - 2>&1
  130. done | highfreq
  131. }
  132. ## Return the audio encoding parameters. For instance
  133. ## -c:2 libvorbis -b:2 384k -c:5 copy
  134. ## If input codec is $AUDIO_CODEC, we copy. If some stream bitrates are missing
  135. ## or 0, we encode it to a default value. If default value is 0, then we copy
  136. ## stream.
  137. audiobitrate () {
  138. local bitrate
  139. for i in $(seq 0 $((format_nb_streams-1))); do
  140. ## Skip non audio tracks.
  141. [ "$(eval echo \$streams_stream_"$i"_codec_type)" != "audio" ] && continue
  142. bitrate=$(eval echo \$streams_stream_"$i"_bit_rate)
  143. if [ -n "$bitrate" ] && [ "$bitrate" -gt 0 ] 2>/dev/null; then
  144. ## If non-empty and a positive number.
  145. bitrate=$((bitrate / 1000))
  146. else
  147. bitrate="$AUDIO_DEFAULT_RATE"
  148. fi
  149. if [ "$bitrate" -le 0 ] || \
  150. [ "$AUDIO_CODEC" = "$(eval echo \$streams_stream_"$i"_codec_name)" ] || \
  151. [ "$AUDIO_CODEC" = "lib$(eval echo \$streams_stream_"$i"_codec_name)" ]; then
  152. printf -- "-c:%s copy " "$i"
  153. else
  154. [ "$bitrate" -gt 500 ] && bitrate=500
  155. printf -- "-c:%s %s -b:%s %sk " "$i" "$AUDIO_CODEC" "$i" "$bitrate"
  156. fi
  157. done
  158. }
  159. transcode () {
  160. echo "==> [$1]"
  161. OUTPUT="${1%.*}.$EXT"
  162. [ -e "$OUTPUT" ] && OUTPUT="${1%.*}-$(date '+%F-%H%M%S').$EXT"
  163. ## Metadata (i.e. tags + technical data).
  164. buffer="$(ffprobe -v quiet -print_format flat=s=_ -show_streams -show_format "$1")"
  165. if [ $? -ne 0 ]; then
  166. echo "File [$1] is unsupported by FFmpeg."
  167. return
  168. fi
  169. ## The following 'eval' defines variables such as format_nb_streams
  170. eval "$buffer"
  171. unset buffer
  172. STREAM_TITLE=""
  173. if $OPT_REMOVE_TITLE; then
  174. for i in $(seq 0 $((format_nb_streams-1)) ); do
  175. STREAM_TITLE="${STREAM_TITLE}-metadata:s:$i title= "
  176. done
  177. fi
  178. if $OPT_CROP; then
  179. echo "Computing crop values... "
  180. ## For 5 different timeslices of 1 second at every 1/6th of the video,
  181. ## we sample the crop values. We keep the values with highest
  182. ## frequency. This is much faster than encoding in one pass with low
  183. ## framerate.
  184. STEP=${format_duration:-$streams_stream_0_duration}
  185. STEP="${STEP%%.*}"
  186. STEP=$((STEP/6))
  187. VIDEO_FILTER="-vf $(cropvalue "$1" "$STEP")"
  188. if $OPT_CROPPREVIEW; then
  189. echo "Generating preview... "
  190. for i in $(seq $STEP $STEP $((5*STEP))); do
  191. ffmpeg -nostdin -v warning -y -ss "$i" -i "$1" \
  192. -f image2 -vframes 1 "$VIDEO_FILTER" "${1%.*}-preview-$i-cropped.png" \
  193. -f image2 -vframes 1 "${1%.*}-preview-$i-uncropped.png"
  194. done
  195. fi
  196. fi
  197. ## WARNING: We mix down audio to 2 channels with '-ac 2'. This greatly reduce
  198. ## file size and avoid any confusion for playback, which is often the case
  199. ## when converting DTS to any other format. (DTS has embedded channel
  200. ## description which is not always available in other formats.)
  201. ! $OPT_COPY && AUDIO_PARAM="$(audiobitrate "$1") -ac 2"
  202. cat <<EOF>&2
  203. User options: ${TC_VIDEO_OPT:-none}
  204. Sample: ${SAMPLE:-no}
  205. Clear tags: $OPT_REMOVE_TITLE
  206. In place: $OPT_OVERWRITE
  207. Crop: $OPT_CROP
  208. Video params: $VIDEO_PARAM
  209. Video filter: $VIDEO_FILTER
  210. Audio params: $AUDIO_PARAM
  211. Output file: $OUTPUT
  212. EOF
  213. $OPT_PREVIEW && return
  214. if $OPT_2PASS; then
  215. echo ":: FIRST PASS"
  216. ffmpeg -nostdin -y "$SAMPLE" -i "$1" \
  217. "$VIDEO_PARAM" -pass 1 -tune film "$VIDEO_FILTER" \
  218. "$AUDIO_PARAM" \
  219. -c:s copy \
  220. -dn \
  221. -map 0 "$STREAM_TITLE" \
  222. "$TC_VIDEO_OPT" -f matroska /dev/null
  223. VIDEO_PARAM="$VIDEO_PARAM -pass 2 -tune film"
  224. echo
  225. echo ":: SECOND PASS"
  226. fi
  227. ffmpeg -nostdin "$OVERWRITE" -i "$1" \
  228. "$VIDEO_PARAM" "$VIDEO_FILTER" \
  229. "$AUDIO_PARAM" \
  230. -c:s copy \
  231. -dn \
  232. -map 0 "$STREAM_TITLE" \
  233. "$SAMPLE" "$TC_VIDEO_OPT" "$OUTPUT"
  234. $OPT_2PASS && rm -v ffmpeg2pass-0.log ffmpeg2pass-0.log.mbtree
  235. if $OPT_OVERWRITE; then
  236. rm "$1"
  237. mv -f "$OUTPUT" "${1%.*}.$EXT"
  238. fi
  239. echo
  240. }
  241. for i; do
  242. transcode "$i"
  243. done