Skip to content

Instantly share code, notes, and snippets.

@glektarssza
Created June 13, 2025 21:22
Show Gist options
  • Save glektarssza/556a94716d5f84f621408d3deea54266 to your computer and use it in GitHub Desktop.
Save glektarssza/556a94716d5f84f621408d3deea54266 to your computer and use it in GitHub Desktop.
ffmpeg two pass loudnorm application
#!/usr/bin/env bash
declare FFMPEG_OUTPUT INPUT OUTPUT;
while [[ -n "$1" ]]; do
case "$1" in
--help|-h)
echo "ffmpeg-loudnorm.sh [--help|-h] [--version] <INPUT> [OUTPUT]";
printf "\n";
echo "=== Arguments ===";
printf "\tINPUT\tThe file to process.";
printf "\tOUTPUT\tThe file to write the processed file to.";
printf "\n\n";
echo "=== Options ===";
printf "\t--help|-h\tShow this information and then exit.\n";
printf "\t--version\tShow the version information and then exit.\n";
echo "";
echo "Copyright (c) 2025 G'lek Tarssza, licensed under the MIT License.";
exit 0;
;;
--version)
echo "v0.0.1 (2025-06-13)";
exit 0;
;;
*)
if [[ -z "${INPUT}" ]]; then
INPUT="$1";
elif [[ -z "${OUTPUT}" ]]; then
OUTPUT="$1";
else
printf "[\e[38;5;196mFATAL\e[0m] Too many command line arguments provided!\n";
exit 128;
fi
;;
esac
shift 1;
done
if [[ -z "${OUTPUT}" ]]; then
OUTPUT="${INPUT%.*}_loudnorm.${INPUT##*.}";
printf "[\e[38;5;208mWARN\e[0m] No output file given, defaulting to '%s'\n" "${OUTPUT}";
fi
printf "[\e[38;5;105mINFO\e[0m] Extracting loudness levels from '%s'...\n" "${INPUT}";
mkfifo ffmpeg_loudnorm;
ffmpeg -hide_banner -i "${INPUT}" '-filter:a' 'loudnorm=print_format=json' -f null - &> ffmpeg_loudnorm &
FFMPEG_OUTPUT="$(awk 'begin {inJSON=false;} {if ($0 ~ "}" && inJSON == "true") {print $0; inJSON = "false"} if ($0 ~ "{" || inJSON == "true") {print $0; if (inJSON != "true") {inJSON="true";}}}' < ffmpeg_loudnorm)";
rm ffmpeg_loudnorm;
set -e;
printf "[\e[38;5;105mINFO\e[0m] Extracted the following parameters from 'ffmpeg':\n";
echo "${FFMPEG_OUTPUT}" | jq '.';
printf "[\e[38;5;105mINFO\e[0m] Creating '%s_loudnorm.%s'...\n" "${OUTPUT}" "${OUTPUT}";
ffmpeg -hide_banner -i "${INPUT}" '-c:v' copy -pass 2 '-filter:a' "loudnorm=linear=true:measured_I=$(echo "${FFMPEG_OUTPUT}" | jq --raw-output '.input_i'):measured_LRA=$(echo "${FFMPEG_OUTPUT}" | jq --raw-output '.input_lra'):measured_tp=$(echo "${FFMPEG_OUTPUT}" | jq --raw-output '.input_tp'):measured_thresh=$(echo "${FFMPEG_OUTPUT}" | jq --raw-output '.input_thresh')" -c:a aac -b:a 256k "${OUTPUT}";
unset FFMPEG_OUTPUT INPUT OUTPUT;
printf "[\e[38;5;105mINFO\e[0m] Done!\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment