ambevar-dotfiles/.scripts/tc-video-transcode

201 lines
5.1 KiB
Bash
Executable File

#!/bin/sh
################################################################################
## User options
################################################################################
## To check what fmmpeg supports:
# ffmpeg -codecs
# ffmpeg -formats
## Useful guides
## x264: http://ffmpeg.org/trac/ffmpeg/wiki/x264EncodingGuide
## ID3 details: http://en.wikipedia.org/wiki/ID3
TC_VIDEO_AUDIO_QUAL=192k
## quality*size ~= 1/speed
# ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo
TC_VIDEO_PRESET=slow
## Overall quality. Logarithmic scale.
# 18 is near perfection.
# 22 is really good compression, while a bit more blurry than the original.
# 20 is a good compromise.
TC_VIDEO_QUAL=20
## x264 tuning (presets).
## Possible values: film, animation, grain, ...
## See x264 --fullhelp.
## No tuning by default.
# TC_VIDEO_TUNE="-tune film"
TC_VIDEO_TUNE=""
## x264 options.
## Possible values: hex, umh...
## me=umh is default.
# TC_VIDEO_OPTS="-x264opts me=hex"
TC_VIDEO_OPTS=""
################################################################################
## End of user options
################################################################################
## TODO: option to replace original file.
## TODO: audio quality. Copy if AAC or OGG <320k.
## TODO: crop options.
## TODO: handle srt encoding.
## TODO: separate functions:
## tc_video_batch
## tc_video_transcode
if [ -z "$(command -v ffmpeg)" ]; then
echo "ffmpeg required."
exit
fi
_printhelp()
{
cat <<EOF
Usage: ${1##*/} [OPTIONS] FILES|FOLDERS
Transcode FILES or files found in FOLDERS to .mkv with x264 and ogg. Output
files are the same as the original, with time appended. You can customize
encoding with the TC_* variables.
-f: Overwrite existing file if any.
-h: Display this help.
-o OPT: Additional options.
-s: Sample of 5 minutes.
-S MIN: Sample of MIN minutes.
-t: Remove all "title" metadata.
Examples:
* Exchange stream 1 an 2 by first removing them, then reading them in the
desired order.
${1##*/} -o '-map -0:1 -map -0:2 -map 0:2 -map 0:1' input.mkv
* Change audio stream 1 title and remove audio stream 2 title:
${1##*/} -o '-metadata:s:a:0 title="FR: OGG Stereo" -metadata:s:a:1 title=' input.mkv
EOF
}
## What to do if file exists:
# -y overwrite
# -n do not overwrite.
TC_OVERWRITE="-n"
TC_SAMPLE=""
TC_USER_OPT=""
TC_REMOVE_TITLE=0
while getopts ":fho:sS:t" opt; do
case $opt in
f)
TC_OVERWRITE="-y"
;;
h)
_printhelp "$0"
exit 1
;;
o)
TC_USER_OPT="$OPTARG"
;;
s)
TC_SAMPLE="-ss 60 -t 360"
;;
S)
TC_SAMPLE="-ss 60 -t $((60*$OPTARG))"
;;
t)
TC_REMOVE_TITLE=1
;;
?)
_printhelp "$0"
exit 1
;;
:)
echo "Missing argument."
_printhelp "$0"
exit 1
;;
esac
done
shift $(($OPTIND - 1))
if [ $# -eq 0 ]; then
_printhelp "$0"
exit
fi
## Zsh compatibility. We need it otherwise word splitting of parameter like
## TC_SAMPLE will not work.
STATUS="$(set -o | grep 'shwordsplit' | awk '{print $2}')"
[ "$STATUS" = "off" ] && set -o shwordsplit
## WARNING: we mix down audio to 2 channels with '-ac 2'. This greatly reduce
## file size and avoid any confusion for playback, which is often the case when
## converting DTS to any other format because DTS has embedded channel
## description which is not available in other formats.
_tc_transcode()
{
cat<<EOF
================================================================================
User options: ${TC_USER_OPT:-None}
Sample: ${TC_SAMPLE:-No}
Clear 'Title': $TC_REMOVE_TITLE
================================================================================
EOF
STREAM_TITLE=""
if [ $TC_REMOVE_TITLE -eq 1 ]; then
STREAM_NUM=$(ffmpeg -i "$1" 2>&1 | grep -c 'Stream')
for i in $(seq 0 $STREAM_NUM); do
STREAM_TITLE="${STREAM_TITLE}-metadata:s:$i title= "
done
# echo "$STREAM_NUM[$STREAM_TITLE]"
fi
ffmpeg $TC_OVERWRITE $TC_SAMPLE -i "$1" \
-c:v libx264 -preset $TC_VIDEO_PRESET -crf $TC_VIDEO_QUAL $TC_VIDEO_TUNE $TC_VIDEO_OPTS \
-c:a libvorbis -b:a $TC_VIDEO_AUDIO_QUAL -ac 2 \
-c:s copy \
-map 0 $STREAM_TITLE \
$TC_USER_OPT "${1%.*}-$(date '+%F-%H%M%S').mkv"
}
for i in "$@"; do
## Argument is a folder. We search for all video files in there.
if [ -d "$i" ]; then
## TODO: provide max-depth as option.
while read -r j; do
_tc_transcode $j
done <<EOF
$(find "$i" \( \
-iname '*.mkv' -o \
-iname '*.mp4' -o \
-iname '*.avi' -o \
-iname '*.webm' -o \
-iname '*.flv' -o \
-iname '*.wmv' -o \
-iname '*.mpg' \) )
EOF
else
## Argument is a regular file.
_tc_transcode "$i"
fi
done
## Restore Zsh previous options. This will not turn off shwordsplit if it
## was on before calling the function.
[ "$STATUS" = "off" ] && set +o shwordsplit