Skip to content

Instantly share code, notes, and snippets.

@Cygon
Last active May 24, 2023 09:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cygon/420c0fa894f96e2994c27d8b175576d4 to your computer and use it in GitHub Desktop.
Save Cygon/420c0fa894f96e2994c27d8b175576d4 to your computer and use it in GitHub Desktop.
Shell script that encodes a movie to the free AV1 video codec using the highest possible quality
#!/bin/sh
# Helper script to transcode to high-quality AV1 clips via ffmpeg
#
# Uses best possible settings with two-pass encode.
# Encoding a full will take months or years!
#
# File from which the video is taken
inputFile=$1
# File to which the final generated output video will be written
outputFile=${inputfile%.*}.av1transcoded.webm
# Whether to encode the video into 2x2 tiles instead of whole
#
# Allows decoders to decode single frames with up to 4 threads
# Might not be necessary for modern decoders (which simply decode
# 4 frames in parallel, thereby achieving the same without tiles.
# Also lowers quality/efficiency a little bit.
#
: ${useFourTiles:=false}
# Bits per second to use for the video and audio streams
#
# Suggested for stereo movies | Suggested for 5.1 movies
# --------------------------------|--------------------------------
# 768 = 672 video + 96 audio
# 1024 = 928 video + 96 audio
# 1536 = 1408 video + 128 audio 1536 = 1280 video + 256 audio
# 2048 = 1920 video + 128 audio 2048 = 1792 video + 256 audio
# 2560 = 2432 video + 128 audio 2560 = 2152 video + 384 audio
# 3072 = 2944 video + 128 audio 3072 = 2688 video + 384 audio
# 4096 = 3968 video + 128 audio 4096 = 3712 video + 384 audio
# 5120 = 4992 video + 128 audio 5120 = 4736 video + 384 audio
# 6144 = 5670 video + 384 audio
: ${videoBitRate:=2432}
: ${audioBitRate:=128}
# After how many frames to force a keyframe
#
# More keyframes worsen overall compression but allow better seeking.
# Many encoders recommend one keyframe per second, but one every two
# seconds is much more sensible imho.
#
: ${keyFrameInterval:=72}
# Whether to do a 10-bit encode
#
# Ten bit encodes are claimed to avoid banding, but I've yet to see
# any of it in a high-quality 8-bit encode.
#
: ${tenBit:=false}
# Set to crop the video
#
# Should be set to "width:height:offsetX:offsetY" if used
# Leave set to false in order to perform no cropping at all
#
: ${cropBoundaries:=false}
# Whether to sharpen the video
#
: ${sharpenVideo:=false}
# ----------------------------------------------------------------------------------------------- #
# Delete intermediate file if already there
if [[ -f ffmpeg2pass-0.log ]]
then
echo Deleting intermediate files...
rm ffmpeg2pass-0.log
fi
ffmpegParameters=()
# If the user has specified cropping bounds, set up the respective ffmpeg parameter
if [ "$cropBoundaries" = false ]
then
echo Cropping disabled.
else
echo Cropping to $cropBoundaries
ffmpegParameters+=(-filter:v crop=$cropBoundaries)
fi
# ----------------------------------------------------------------------------------------------- #
# Video encoder settings
#
ffmpegParameters+=(-strict experimental)
ffmpegParameters+=(-c:v libaom-av1)
ffmpegParameters+=(-b:v $videoBitRate)
ffmpegParameters+=(-g $keyFrameInterval)
ffmpegParameters+=(-auto-alt-ref 1)
ffmpegParameters+=(-lag-in-frames 25)
ffmpegParameters+=(-crf 0)
#ffmpegParameters+=(-frame-parallel 1)
if [ "$tenBit" = true ]
then
echo 10-bit encode
ffmpegParameters+=(-pix_fmt yuv420p10le)
else
echo 8-bit encode
ffmpegParameters+=(-pix_fmt yuv420p)
fi
if [ "$useFourTiles" = true ]
then
echo Encoding as 2x2 tiles
ffmpegParameters+=(-tile-columns 2)
ffmpegParameters+=(-tile-rows 2)
else
echo Encoding as single tile
fi
# ----------------------------------------------------------------------------------------------- #
# Audio encoder settings
#
ffmpegParameters+=(-c:a libopus)
ffmpegParameters+=(-b:a $audioBitRate)
ffmpegParameters+=(-ar 48000)
# ----------------------------------------------------------------------------------------------- #
# Other settings
#
ffmpegParameters+=(-threads 1)
# ----------------------------------------------------------------------------------------------- #
echo "ffmpeg options: ${ffmpegParameters[@]}"
# ----------------------------------------------------------------------------------------------- #
echo "=============================================================================="
echo ""
echo "Encoding first pass"
echo ""
ffmpeg \
-hide_banner \
-i "$inputFile" \
-shortest \
"${ffmpegParameters[@]}" \
-cpu-used 1 \
-pass 1 \
-f null \
/dev/null
echo "=============================================================================="
echo ""
echo "Encoding second pass"
echo ""
ffmpeg \
-hide_banner \
-i "$inputFile" \
-shortest \
"${ffmpegParameters[@]}" \
-cpu-used 0 \
-pass 2 \
-y \
$outputFile
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment