Slate With FFmpeg

This is a little buggy with certain input movies but generally works great for anything prores or h264 at standard 1080p resolution.

A screenshot of the slate this creates


#!/bin/bash

# slated_output.bash 
# Add slate to the beginning of a movie 
# by Jamie Hardt
# (c) 2025 Squad 51 Inc. All rights reserved.

# This will add:
# - a slate to the beginning of the input movie
# - Three thumbnails taken from pre-selected times in the input movie will be 
#   on the slate
# - A lower-third text will be printed to the entire length of the outpu 
# - Then entire output will be standardized to 1920x1080
# - Audio output is 48000 pcm_s24le
#
# The INPUT_FILE is expected as argument 1 on the command line, the idea being
# you might make a copy of this script for each project and customise the
# thumbnail positions, client and title, while the movie always changes.
# 
# The output file will be name INPUT_FILE_slated.

# Enter project info here
HEADLINE="SOUND DESIGN REVIEW"
TITLE="\"TITLE\""
CLIENT="CLIENT"
CONTACT="CONTACT"
PIX_REF="PIC_REF"
MESSAGE="MESSAGE"

# Enter the times for each thumbnail here
THUMB1_TIME="00:00:37"
THUMB2_TIME="00:08:39"
THUMB3_TIME="00:11:00"

MESSAGE_COLOR=yellow

# Enter the slate duration in seconds
SLATE_DURATION="1"

# Set a number here to play a test tone at -20 dBFS under the slate. Don't set 
# it and the slate will be silent
# SLATE_TONE=440

# Font for slate titles. Leave it unset for the default
FONT=/System/Library/Fonts/Avenir.ttc

# Set this to "-to 20" while you're testing your script out, once it looks 
# right then set it to ""
OUTPUT_LENGTH_ARG="-to 20" 

# Set this to a positive number to move the middle block, the HEADLINE, TITLE 
# and CLIENT fields down/south, to avoid covering the thumbnails.
MIDDLE_Y_NUDGE="80"

# Set this to a positive number to move the lower-third and "file" field in 
# the slate up/north, to avoid covering burnins
BOTTOM_Y_NUDGE="0"



#################################################################################
#####
#####    DON'T EDIT BELOW THIS LINE


if [ ! -z $FONT ]; then
  FONT=":fontfile="$FONT
fi

INPUT_FILE="$1"
INPUT_BASENAME=$(basename -- "$INPUT_FILE")
OUTPUT_FILE=$(dirname -- "$INPUT_FILE")/"${INPUT_BASENAME%.*}_slated.mov"

# Escape title, client and message fields in case they have quotes or colons
TITLE=$(echo -n $TITLE | ffescape -p "" -s "':" | ffescape -p "")
CLIENT=$(echo -n $CLIENT | ffescape -p "" -s "':" | ffescape -p "")
MESSAGE=$(echo -n $MESSAGE | ffescape -p "" -s "':" | ffescape -p "")

SLATE_AUDIO="-f lavfi -t $SLATE_DURATION -i "
if [ -z $SLATE_TONE ]; then 
  SLATE_AUDIO+=anullsrc=r=48000:cl=stereo,aformat=sample_fmts=s32:\
    channel_layouts=stereo
else 
  SLATE_AUDIO+="sine=$SLATE_TONE:r=48000,aformat=sample_fmts=s32:"
  SLATE_AUDIO+="channel_layouts=stereo,aeval=val(ch):c=same"
fi 

ffmpeg -y -hide_banner \
  -f lavfi -i "color=c=black:s=1920x1080:d=$SLATE_DURATION" \
  -ss $THUMB1_TIME -i "$INPUT_FILE" \
  -ss $THUMB2_TIME -i "$INPUT_FILE" \
  -ss $THUMB3_TIME -i "$INPUT_FILE" \
  -i "$INPUT_FILE" \
  $SLATE_AUDIO \
  -filter_complex "
    [1:v]trim=duration=0.04,setpts=PTS-STARTPTS,scale=560:-1,
      tpad=stop_mode=clone:stop_duration=$SLATE_DURATION[thumb1];
    [2:v]trim=duration=0.04,setpts=PTS-STARTPTS,scale=560:-1,
      tpad=stop_mode=clone:stop_duration=$SLATE_DURATION[thumb2];
    [3:v]trim=duration=0.04,setpts=PTS-STARTPTS,scale=560:-1,
      tpad=stop_mode=clone:stop_duration=$SLATE_DURATION[thumb3];
    [0:v][thumb1]overlay=100:100[tmp1];
    [tmp1][thumb2]overlay=690:100[tmp2];
    [tmp2][thumb3]overlay=1280:100[slate_raw];

    [slate_raw]
    drawtext=text='$HEADLINE':fontcolor=white:box=1:boxcolor=black@.6:
      boxborderw=10:fontsize=72:x=(w-text_w)/2:y=(h/2)-90+$MIDDLE_Y_NUDGE$FONT,
    drawtext=text='$TITLE':fontcolor=white:fontsize=48:
      x=(w-text_w)/2:y=(h/2)+$MIDDLE_Y_NUDGE$FONT,
    drawtext=text='$CLIENT':fontcolor=white:fontsize=48:
      x=(w-text_w)/2:y=(h/2)+60+$MIDDLE_Y_NUDGE$FONT,
    drawtext=text='$CONTACT':fontcolor=gray:fontsize=36:
      x=(w-text_w)/2:y=(h-(230+$BOTTOM_Y_NUDGE))$FONT,
    drawtext=text='Pix Ref\: $PIX_REF':expansion=normal:fontcolor=gray:
      fontsize=36:x=(w-text_w)/2:y=(h-(180+$BOTTOM_Y_NUDGE))$FONT[slate];
  
    [4:v]scale=1920:1080:force_original_aspect_ratio=decrease,
      pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black, setsar=1:1[v1];
    [4:a]aresample=48000,aformat=sample_fmts=s32:channel_layouts=stereo[a1];

    [slate][5:a][v1][a1]concat=n=2:v=1:a=1[vcat][acat];
    [vcat]drawtext=text='$MESSAGE':fontcolor=$MESSAGE_COLOR:box=1:boxcolor=black:
      boxborderw=10:fontsize=42:x=(w-text_w)/2:
      y=h-(100+$BOTTOM_Y_NUDGE):fontfile=$FONT[outv]
  " \
  -map "[outv]" -map "[acat]" \
  -c:v libx264 -pix_fmt yuv420p -c:a pcm_s24le -movflags +faststart $OUTPUT_LENGTH_ARG "$OUTPUT_FILE"