Skip to content

Instantly share code, notes, and snippets.

@ismith
Last active January 19, 2021 23:43
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ismith/d1b080c18e2de6d19075e6d02cd84291 to your computer and use it in GitHub Desktop.
Save ismith/d1b080c18e2de6d19075e6d02cd84291 to your computer and use it in GitHub Desktop.
Dark's caption embedding script
#!/usr/bin/env bash
set -euo pipefail
if [ $# -eq 0 ]; then
echo "This script takes two mandatory options - \$1 is the input video, \$2 is the
input subtitles."
echo
echo "By default, we burn in hard subs; you may use --soft-subs to embed soft
subs. See: https://en.wikipedia.org/wiki/Subtitle_(captioning)#Types"
# Note: mkv would allow default subs on (`-disposition:s:s:0 forced`), but mkv
# doesn't work out of box in Quicktime
exit 0
fi
###############################
# verify correct getopt version
#
# this assumes you're using gnu's getopt, which is not the same as osx' default
# getopt
###############################
# If we've got brew installed, use its gnu-getopt
if [ -x "$(command -v brew)" ]; then
if ( ! brew list gnu-getopt ); then
echo "You need to install gnu-getopt:"
echo " brew install gnu-getopt"
exit 1
fi
brew_prefix=$(brew --prefix gnu-getopt)
export PATH=${brew_prefix}/bin:$PATH
fi
set +e
opt=$(getopt -T)
set -e
# 4 is the return code from gnu's `getopt -T`, and the -n $opt checks that its
# stdout is empty, not '--' (it will be '--' if using the non-gnu osx getopt
if (( $? != 4 )) && [[ -n $opt ]]; then
echo "Either no getopt is installed, or you're using a non-gnu getopt."
echo "If you're on OS X, you can install gnu-getopt using homebrew to fix
this."
exit 1
fi
##############################
# end verifying correct getopt
##############################
OPTS=$(getopt --options s --longoptions soft-subs "$@")
eval set -- "$OPTS"
SOFTSUBS=0
while true ; do
case "$1" in
--soft-subs|-s)
SOFTSUBS=1
shift
;;
--)
shift
break
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
INVIDEO=$1
INSUBS=$2
CCOVERLAY=$(dirname "$0")/cc.png
if ( ! command -v ffmpeg ); then
echo "This script depends on ffmpeg."
exit 1
fi
if [[ "$INVIDEO" == "" ]]; then
echo "No in video (foo.mp4?) provided."
echo
exit 1
fi
if ! [[ "$INSUBS" =~ .srt$ ]]; then
echo "No subtitles provided."
echo
echo "Debug: options given: INVIDEO: ${INVIDEO}, INSUBS: ${INSUBS}"
exit 1
fi
if (( "$SOFTSUBS" )); then
# if this file needs scaling at some point, use imagemagick:
# convert cc.png -resize 120x120 cc.png
if [[ ! -f $CCOVERLAY ]]; then
echo "No ccoverlay image found."
exit 1
fi
fi
tmpfile=$(mktemp /tmp/postprocess-video.XXXXXX.mp4)
rm "$tmpfile" # so ffmpeg doesn't ask if you want to overwrite it
set -x
if (( "$SOFTSUBS" )); then
# Add CCOVERLAY watermark in bottom right corner
ffmpeg -i "$INVIDEO" \
-vf "movie=${CCOVERLAY} [watermark]; [in][watermark] overlay=(main_w-overlay_w-10):(main_h-overlay_h-10) [out]" \
"$tmpfile"
else
ffmpeg -i "$INVIDEO" -vf subtitles="$INSUBS" "$tmpfile"
fi
ffmpeg -i "$tmpfile" -f srt -i "$INSUBS" \
-c:v copy -c:a copy -c:s mov_text \
-metadata:s:s:0 language=English \
out.mp4
# could put this in a signal handler if you wanted to be really sure it gets
# cleaned up
rm "$tmpfile"
if (( "$SOFTSUBS" )); then
echo "Done, with soft subs! See out.mp4"
else
echo "Done, with hard and soft subs! See out.mp4"
fi
@ellenchisa
Copy link

If you are not a regular bash user, this is the format for the CLI:

./captioning.sh video.mp4 subs.srt

@ellenchisa
Copy link

ellenchisa commented May 26, 2020

If you are receiving the wrong outputs for $1 and $2 (check using echo) chances are it is an issue with getopt.

  1. Install gnu-getopt via homebrew (brew install gnu-getopt).
  2. Run with this prefix: PATH=/usr/local/opt/gnu-getopt/bin:$PATH ./embed-captions.sh video.mp4 subs.srt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment