Last active
May 5, 2023 12:30
-
-
Save Cygon/c19e0bff6d5fe3d2eea1f0535e491ebf to your computer and use it in GitHub Desktop.
Shell script that encodes a VP9 `.webm` movie with the highest possible quality
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# Helper script to transcode movies using the free VP9 codec | |
# in very high quality (a full movie will take several days!) | |
# | |
# File from which the video is taken | |
inputFile=$1 | |
# File to which the final generated output video will be written | |
outputFile=${inputfile%.*}.vp9transcoded.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:=60} | |
# 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} | |
# ----------------------------------------------------------------------------------------------- # | |
echo ========================================================================== | |
# Delete intermediate file if already there | |
if [[ -f ffmpeg2pass-0.log ]] | |
then | |
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 | |
# If the user has specified cropping bounds, set up the respective ffmpeg parameter | |
if [ "$sharpenVideo" = false ] | |
then | |
echo Sharpening disabled. | |
else | |
echo Sharpening via smartblur filter. | |
ffmpegParameters+=(-filter:v smartblur=1.5:-0.35:-3.5:0.65:0.25:2.0) | |
fi | |
#ffmpegParameters+=(-filter_complex "drawbox=enable='between(n,0,180)':x=180:y=96:w=288:h=56:color=black:t=fill") | |
# ----------------------------------------------------------------------------------------------- # | |
# Video encoder settings | |
# | |
ffmpegParameters+=(-c:v libvpx-vp9) | |
ffmpegParameters+=(-b:v $videoBitRate) | |
ffmpegParameters+=(-g $keyFrameInterval) | |
ffmpegParameters+=(-auto-alt-ref 1) | |
ffmpegParameters+=(-lag-in-frames 25) | |
ffmpegParameters+=(-crf 0) | |
ffmpegParameters+=(-quality best) | |
ffmpegParameters+=(-deadline best) | |
ffmpegParameters+=(-threads 1) | |
#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 2x2 Tiles | |
ffmpegParameters+=(-tile-columns 2) | |
ffmpegParameters+=(-tile-rows 2) | |
else | |
echo Single Tile | |
fi | |
# ----------------------------------------------------------------------------------------------- # | |
# Audio encoder settings | |
# | |
ffmpegParameters+=(-c:a libopus) | |
ffmpegParameters+=(-b:a $audioBitRate) | |
ffmpegParameters+=(-ar 48000) | |
# ----------------------------------------------------------------------------------------------- # | |
echo "ffmpeg options: ${ffmpegParameters[@]}" | |
# First pass | |
ffmpeg \ | |
-hide_banner \ | |
-i "$inputFile" \ | |
-shortest \ | |
"${ffmpegParameters[@]}" \ | |
-cpu-used 1 \ | |
-speed 1 \ | |
-pass 1 \ | |
-f null \ | |
/dev/null | |
# Second pass | |
ffmpeg \ | |
-hide_banner \ | |
-i "$inputFile" \ | |
-shortest \ | |
"${ffmpegParameters[@]}" \ | |
-cpu-used 0 \ | |
-speed 0 \ | |
-pass 2 \ | |
-y \ | |
transcoded-vp9.webm |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment