conference-video-processing/gen_vids.sh

110 lines
3.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Converts PNG cards to fading videos.
# Assumes NONE of the filenames have spaces in them.
if [ -z "$3" ]; then
echo "Usage: $0 <source.mov> <talk ID> <input start timestamp [[HH:]MM:]SS> <input end timestamp [[HH:]MM:]SS>" >&2
exit 1
fi
set -e
PNG_PATH='cards/png'
VID_OUT_PATH='upload-ready-vids'
VID_GEN_LOG_PATH="$VID_OUT_PATH/0000_gen_vids_log.txt"
mkdir -p "${VID_OUT_PATH}"
TITLE_SHOW_DURATION_SECS=2
FADE_DURATION_SECS=1
AUDIO_FADE_DURATION_SECS=1
TITLE_SHOW_DURATION_MSECS=$((TITLE_SHOW_DURATION_SECS * 1000))
VID_IN_FNAME="$1"
TALK_ID="$2"
INPUT_START_TIMESTAMP="$3"
INPUT_END_TIMESTAMP="$4"
PNG_FNAME=$(ls ${PNG_PATH}/${TALK_ID}-*.png)
if [ ! -e "${PNG_FNAME}" ]; then
echo "No such talk card: ${PNG_FNAME}" >&2
exit 2
fi
BASENAME=$(basename ${PNG_FNAME/.png})
VID_OUT_COMBINED=${VID_OUT_PATH}/${BASENAME}-combined.mkv
if [ ! -e "${VID_IN_FNAME}" ]; then
echo "Source video ${VID_IN_FNAME} does not exist, aborting." >&2
exit 3
fi
if [ -e "${VID_OUT_COMBINED}" ]; then
echo "Destination video ${VID_OUT_COMBINED} already exists."
echo "Press [ENTER] to overwrite, [CTRL]+[C] to abort."
read dummy
fi
FILTER_COMPLEX="
[0:v]format=pix_fmts=yuva420p,fade=t=out:st=${TITLE_SHOW_DURATION_SECS}:d=${FADE_DURATION_SECS}:alpha=1,setpts=PTS-STARTPTS[vid_title];
[1:v]format=pix_fmts=yuva420p,fade=t=in:st=0:d=${FADE_DURATION_SECS}:alpha=1,setpts=PTS-STARTPTS+${TITLE_SHOW_DURATION_SECS}/TB[vid_main];
[vid_title][vid_main] overlay [vid];
[2:a] afade=t=out:st=${TITLE_SHOW_DURATION_SECS}:d=${AUDIO_FADE_DURATION_SECS} [aud_title];
[1:a] afade=t=in:st=0:d=${FADE_DURATION_SECS} [aud_main_faded];
[aud_main_faded] adelay=${TITLE_SHOW_DURATION_MSECS}|${TITLE_SHOW_DURATION_MSECS} [aud_main];
[aud_title][aud_main] amix=duration=longest [audio]
"
DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${VID_IN_FNAME}")
TOTAL_DURATION=$(python3 -c "
import datetime
def parse_timestamp(timestamp_str):
return (datetime.datetime.strptime(timestamp_str, '%S') if timestamp_str.count(':') == 0 else
datetime.datetime.strptime(timestamp_str, '%M:%S') if timestamp_str.count(':') == 1 else
datetime.datetime.strptime(timestamp_str, '%H:%M:%S') if timestamp_str.count(':') == 2 else ...)
input_starttime = parse_timestamp('$INPUT_START_TIMESTAMP')
input_endtime = parse_timestamp('$INPUT_END_TIMESTAMP')
duration = (input_endtime - input_starttime).total_seconds()
print($TITLE_SHOW_DURATION_SECS + (duration if 0.0 < duration < $DURATION else $DURATION))
")
python3 -c "
import datetime
input_dur = datetime.timedelta(seconds=$DURATION)
output_dur = datetime.timedelta(seconds=$TOTAL_DURATION)
print('Input Duration: ', input_dur, '\nOutput Duration:', output_dur)
"
ffmpeg \
-stats \
-v warning \
-hwaccel auto \
-loop 1 \
-i ${PNG_FNAME} \
-ss ${INPUT_START_TIMESTAMP} \
-i "${VID_IN_FNAME}" \
-i silence-24.wav \
-filter_complex "${FILTER_COMPLEX}" \
-map '[vid]' \
-map '[audio]' \
-preset:v fast \
-c:v h264 \
-c:a mp3 \
-b:a 192k \
-crf 23 \
-t ${TOTAL_DURATION} \
-y "${VID_OUT_COMBINED}"
NOW_DATETIME=$(python3 -c "
import datetime
print(datetime.datetime.now())
")
if [ ! -e "${VID_GEN_LOG_PATH}" ]; then
echo "\"Date Time\",\"Source File\",\"Talk ID\",\"Start Time\",\"End Time\"" >> "$VID_GEN_LOG_PATH"
fi
echo "\"$NOW_DATETIME\",\"$1\",\"$2\",\"$3\",\"$4\"" >> "$VID_GEN_LOG_PATH"
echo
echo 'DØNER'