4c3b11445c
Phase 0 of design/pyrowave-codec-plan.md — the opt-in wired-LAN ultra-low- latency codec. Vendored at upstream 509e4f88 (API 0.4.0, Granite 44362775, volk + vulkan-headers pins in PUNKTFUNK-VENDOR.txt), pruned to the 6.6 MB the standalone no-renderer build needs; scripts/vendor-pyrowave.sh reproduces the tree (a pin bump is protocol-affecting, plan §4.2). build.rs drives the wrapper CMakeLists (static archives incl. a static C-API lib upstream only ships shared) + bindgen over pyrowave.h; Linux and Windows only, empty stub elsewhere (Apple gets a native Metal port, §4.7). Offline-safe by construction: no network, no system lib, vendored Vulkan headers — same model as the opus dep (flatpak builder has no network). Phase-0 validation on .21 (RTX 5070 Ti, driver 610.43.03): - upstream pyrowave-c-test + interop test (incl. dmabuf/DRM-modifier Vulkan<->Vulkan) pass, from the pristine AND the pruned tree - GPU kernel times at ~1.6 bpp noise: encode/decode 0.090/0.042 ms @800p, 0.146/0.067 @1080p, 0.226/0.103 @1440p, 0.477/0.201 @4K — order of magnitude under NVENC's 1-2 ms retrieve, CBR lands within ~100 B of target - cargo test -p pyrowave-sys green (static link + API-version pin check) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
169 lines
4.7 KiB
Bash
169 lines
4.7 KiB
Bash
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
input_file="$1"
|
|
output_dir="$2"
|
|
|
|
if [ -z $input_file ]; then
|
|
echo "Need to specify input."
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z $output_dir ]; then
|
|
echo "Need to specify output."
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$output_dir"
|
|
rm -f "$output_dir"/*.csv
|
|
|
|
csv_header="bpp,xpsnr,ssim,ssimulacra2,vmaf,vmafneg"
|
|
echo $csv_header > "$output_dir"/h264_nvenc.csv
|
|
echo $csv_header > "$output_dir"/hevc_nvenc.csv
|
|
echo $csv_header > "$output_dir"/av1_nvenc.csv
|
|
#echo $csv_header > "$output_dir"/h264_vaapi.csv
|
|
#echo $csv_header > "$output_dir"/hevc_vaapi.csv
|
|
#echo $csv_header > "$output_dir"/av1_vaapi.csv
|
|
echo $csv_header > "$output_dir"/pyrowave.csv
|
|
|
|
append_stats_to_csv()
|
|
{
|
|
stats=$1
|
|
csv=$2
|
|
|
|
bpp=$(grep "BPP =" $stats | grep -oE '[^ ]+$')
|
|
xpsnr=$(grep "W-XPSNR:" $stats | grep -oE '[^ ]+$')
|
|
ssim=$(grep "SSIM Score:" $stats | grep -oE '[^ ]+$')
|
|
ssimulacra2=$(grep "Average:" $stats | grep -oE '[^ ]+$')
|
|
vmaf=$(grep "VMAF:" $stats | grep -oE '[^ ]+$')
|
|
vmafneg=$(grep "VMAF NEG:" $stats | grep -oE '[^ ]+$')
|
|
|
|
echo "$bpp,$xpsnr,$ssim,$ssimulacra2,$vmaf,$vmafneg" >> $csv
|
|
}
|
|
|
|
encode_nvenc()
|
|
{
|
|
bit_rate=$1k
|
|
# Round up to not give codec an impossible situation
|
|
buf_size=$(($1 / 60 + 1))k
|
|
codec=$2
|
|
encoded_name="$output_dir"/${codec}_nvenc_${bit_rate}.mkv
|
|
stats=""$output_dir"/${codec}_nvenc_stats_${bit_rate}.txt"
|
|
|
|
echo "============="
|
|
echo "Encoding with NVENC, bitrate ${bit_rate}."
|
|
echo ffmpeg -y -i $input_file -b:v $bit_rate -c:v ${codec}_nvenc \
|
|
-preset p1 -tune ull -g 1 -rc cbr -bufsize $buf_size $encoded_name
|
|
ffmpeg -y -i $input_file -b:v $bit_rate -c:v ${codec}_nvenc \
|
|
-preset p1 -tune ull -g 1 -rc cbr -bufsize $buf_size $encoded_name >/dev/null 2>/dev/null
|
|
ffmpeg -y -i $encoded_name $encoded_name.y4m >/dev/null 2>/dev/null
|
|
psy-ex-scores.py $input_file $encoded_name.y4m -t 16 -e 4 | ansi2txt > $stats
|
|
rm $encoded_name.y4m
|
|
echo "Stats in ${stats}, reference output in ${encoded_name}."
|
|
du -b $encoded_name
|
|
echo "============="
|
|
|
|
actual_size=$(stat -c %s $encoded_name)
|
|
input_size=$(stat -c %s $input_file)
|
|
bpp=$(echo "scale=3; 12 * $actual_size / $input_size" | bc)
|
|
echo "BPP = $bpp" >> $stats
|
|
|
|
append_stats_to_csv $stats "$output_dir"/${codec}_nvenc.csv
|
|
|
|
rm $encoded_name
|
|
}
|
|
|
|
encode_vaapi()
|
|
{
|
|
bit_rate=${1}k
|
|
# Round up to not give codec an impossible situation
|
|
buf_size=$(($1 / 60 + 1))k
|
|
codec=$2
|
|
encoded_name="$output_dir"/${codec}_vaapi_${bit_rate}.mkv
|
|
stats=""$output_dir"/${codec}_vaapi_stats_${bit_rate}.txt"
|
|
echo "============="
|
|
echo "Encoding with VAAPI, bitrate ${bit_rate}."
|
|
ffmpeg -y -vaapi_device /dev/dri/renderD128 -i $input_file -c:v ${codec}_vaapi \
|
|
-idr_interval 1 -g 1 -rc_mode CBR -b:v $bit_rate -bufsize $buf_size \
|
|
-vf format=nv12,hwupload $encoded_name >/dev/null 2>/dev/null
|
|
ffmpeg -y -i $encoded_name $encoded_name.y4m >/dev/null 2>/dev/null
|
|
psy-ex-scores.py $input_file $encoded_name.y4m -t 16 -e 4 | ansi2txt > $stats
|
|
rm $encoded_name.y4m
|
|
echo "Stats in ${stats}, reference output in ${encoded_name}."
|
|
du -b $encoded_name
|
|
echo "============="
|
|
|
|
actual_size=$(stat -c %s $encoded_name)
|
|
input_size=$(stat -c %s $input_file)
|
|
bpp=$(echo "scale=3; 12 * $actual_size / $input_size" | bc)
|
|
echo "BPP = $bpp" >> $stats
|
|
|
|
append_stats_to_csv $stats "$output_dir"/${codec}_vaapi.csv
|
|
|
|
rm $encoded_name
|
|
}
|
|
|
|
encode_pyrowave()
|
|
{
|
|
bit_rate=${1}k
|
|
bytes_per_image=$((($1 * 1000) / (60 * 8)))
|
|
encoded_name="$output_dir"/pyrowave_${bit_rate}.y4m
|
|
stats=""$output_dir"/pyrowave_stats_${bit_rate}.txt"
|
|
echo "============="
|
|
echo "Encoding with PyroWave, bitrate ${bit_rate}, $bytes_per_image bytes per image."
|
|
pyrowave-sandbox $input_file $encoded_name $bytes_per_image 2>/dev/null
|
|
psy-ex-scores.py $input_file $encoded_name -t 16 -e 4 | ansi2txt > $stats
|
|
echo "Stats in ${stats}, reference output in ${encoded_name}."
|
|
echo "============="
|
|
|
|
bpp=$(echo "scale=3; 8 * $bytes_per_image / (1920 * 1080)" | bc)
|
|
echo "BPP = $bpp" >> $stats
|
|
append_stats_to_csv $stats "$output_dir"/pyrowave.csv
|
|
|
|
rm $encoded_name
|
|
}
|
|
|
|
encode_nvenc_group()
|
|
{
|
|
encode_nvenc $1 h264
|
|
encode_nvenc $1 hevc
|
|
encode_nvenc $1 av1
|
|
}
|
|
|
|
encode_vaapi_group()
|
|
{
|
|
encode_vaapi $1 h264
|
|
encode_vaapi $1 hevc
|
|
encode_vaapi $1 av1
|
|
}
|
|
|
|
encode_accel_group()
|
|
{
|
|
encode_nvenc_group $1
|
|
# VAAPI seems to not understand what CBR rate control means :') Ignore it.
|
|
#encode_vaapi_group $1
|
|
}
|
|
|
|
encode_pyrowave 50000
|
|
encode_pyrowave 75000
|
|
encode_pyrowave 100000
|
|
encode_pyrowave 150000
|
|
encode_pyrowave 200000
|
|
encode_pyrowave 250000
|
|
encode_pyrowave 300000
|
|
encode_pyrowave 400000
|
|
encode_pyrowave 500000
|
|
encode_accel_group 50000
|
|
encode_accel_group 75000
|
|
encode_accel_group 100000
|
|
encode_accel_group 150000
|
|
encode_accel_group 200000
|
|
encode_accel_group 250000
|
|
encode_accel_group 300000
|
|
encode_accel_group 400000
|
|
encode_accel_group 500000
|
|
|
|
python plot.py $output_dir
|
|
|