You said:
Can you make me an ffmpeg script that converts a video file to AV1 in the MP4 container (using the NVENC AV1 encoder), passing through all audio tracks, that utilizes VMAF to determine what bitrate to use to convert losslessly
Here's a bash script to achieve this using FFmpeg and VMAF. Since VMAF is used to measure video quality against the original, this script will first perform a quick compression to estimate VMAF quality at different bitrates, then apply the ideal bitrate in the final AV1 encoding pass.
You'll need FFmpeg
built with NVENC support, libvmaf
for VMAF calculations, and Python with scipy
and numpy
to help analyze the results.
Make sure you have the required FFmpeg version that supports NVENC for AV1 and VMAF calculation:
-c:v av1_nvenc
).encode_av1_vmaf.sh
bash#!/bin/bash
# Usage: ./encode_av1_vmaf.sh input_file output_file
input_file="$1"
output_file="$2"
# Temporary folder for VMAF calculation
temp_folder=$(mktemp -d)
bitrate_log="$temp_folder/bitrate_vmaf.log"
# Define bitrate range to test (in Kbps)
bitrate_start=1000
bitrate_end=10000
bitrate_step=500
# Define target VMAF threshold for 'lossless' quality (tweak as needed)
target_vmaf=95
# Function to calculate VMAF for a given bitrate
calculate_vmaf_for_bitrate() {
local bitrate=$1
local temp_output="${temp_folder}/temp_${bitrate}.mp4"
# Encode a sample with the specified bitrate
ffmpeg -y -i "$input_file" -c:v av1_nvenc -b:v "${bitrate}k" -c:a copy -frames:v 500 -an "$temp_output"
# Calculate VMAF score
vmaf_score=$(ffmpeg -i "$input_file" -i "$temp_output" -lavfi libvmaf="model_path=vmaf_v0.6.1.pkl" -f null - 2>&1 | grep "VMAF score" | awk '{print $4}')
# Clean up temp file
rm "$temp_output"
echo "$bitrate $vmaf_score" >> "$bitrate_log"
echo "Tested bitrate: ${bitrate}k, VMAF: $vmaf_score"
# Return VMAF score
echo "$vmaf_score"
}
# Loop to find optimal bitrate
optimal_bitrate=$bitrate_start
for (( bitrate=$bitrate_start; bitrate<=$bitrate_end; bitrate+=$bitrate_step )); do
vmaf_score=$(calculate_vmaf_for_bitrate "$bitrate")
if (( $(echo "$vmaf_score >= $target_vmaf" | bc -l) )); then
optimal_bitrate=$bitrate
break
fi
done
echo "Optimal bitrate found: ${optimal_bitrate}k"
# Final encode with optimal bitrate and all audio tracks
ffmpeg -i "$input_file" -c:v av1_nvenc -b:v "${optimal_bitrate}k" -c:a copy "$output_file"
# Clean up
rm -rf "$temp_folder"
target_vmaf
threshold.Run the script with:
bash./encode_av1_vmaf.sh input_video.mp4 output_video.mp4
This will produce output_video.mp4
encoded with NVENC AV1 at the best bitrate to retain the specified VMAF threshold for high-quality output. Adjust bitrate_start
, bitrate_end
, bitrate_step
, and target_vmaf
as needed for your specific requirements.
Here’s a Windows batch script to convert a video to AV1 with an optimal bitrate for quality preservation based on VMAF scores.
To run this script, you’ll need:
bc
command for basic calculations, or adapt it to PowerShell for more robust math (bc isn’t native to Windows but can be installed with tools like Git Bash or GNU utilities for Windows).encode_av1_vmaf.bat
batch@echo off setlocal REM Usage: encode_av1_vmaf.bat input_file output_file set "input_file=%~1" set "output_file=%~2" REM Temporary folder for VMAF calculation set "temp_folder=%TEMP%\vmaf_calc" mkdir "%temp_folder%" set "bitrate_log=%temp_folder%\bitrate_vmaf.log" REM Define bitrate range to test (in Kbps) set bitrate_start=1000 set bitrate_end=10000 set bitrate_step=500 REM Define target VMAF threshold for 'lossless' quality (adjust as needed) set target_vmaf=95 REM Function to calculate VMAF for a given bitrate set "optimal_bitrate=" for /L %%B in (%bitrate_start%, %bitrate_step%, %bitrate_end%) do ( set "bitrate=%%B" set "temp_output=%temp_folder%\temp_%%B.mp4" echo Testing bitrate: %%B k... REM Encode a short sample with the specified bitrate ffmpeg -y -i "%input_file%" -c:v av1_nvenc -b:v %%B"k" -c:a copy -frames:v 500 -an "%temp_output%" >nul 2>&1 REM Calculate VMAF score for /F "tokens=4 delims= " %%V in ('ffmpeg -i "%input_file%" -i "%temp_output%" -lavfi libvmaf="model_path=vmaf_v0.6.1.pkl" -f null - 2^>^&1 ^| findstr "VMAF score"') do ( set "vmaf_score=%%V" ) REM Clean up temporary file del "%temp_output%" REM Log the VMAF score and bitrate echo %%B %vmaf_score% >> "%bitrate_log%" echo VMAF Score at %%B kbps: %vmaf_score% REM Check if we’ve hit the target VMAF score if not defined optimal_bitrate ( set /A "vmaf_check = %vmaf_score% >= %target_vmaf%" if %vmaf_check% EQU 1 ( set "optimal_bitrate=%%B" goto :encode_final ) ) ) :encode_final if not defined optimal_bitrate ( echo Could not achieve target VMAF with specified bitrate range. Using maximum bitrate: %bitrate_end%k set "optimal_bitrate=%bitrate_end%" ) echo Optimal bitrate found: %optimal_bitrate%k REM Final encode with optimal bitrate and all audio tracks ffmpeg -i "%input_file%" -c:v av1_nvenc -b:v %optimal_bitrate%k -c:a copy "%output_file%" REM Clean up rd /s /q "%temp_folder%" echo Encoding complete. Output file: %output_file% endlocal
for /F
command captures VMAF scores from FFmpeg's output, storing them in the vmaf_score
variable.target_vmaf
), the loop stops, and that bitrate is used for the final encode.Run this in the command prompt as follows:
batchencode_av1_vmaf.bat "input_video.mp4" "output_video.mp4"
This will create output_video.mp4
with NVENC AV1 encoding at the best bitrate for the defined quality threshold. Adjust bitrate_start
, bitrate_end
, bitrate_step
, and target_vmaf
to fine-tune based on your needs.