.PHONY: hevc-nvenc x265 x265-master av1 av1-master

FFMPEG=ffmpeg
IN_FMT=rgba

RESOLUTION=3840x2160
FPS=60
OUT=out.mp4

# 10 s GOP: fractal zooms have no scene cuts, so keyframes only cost bits.
KEYINT=$(shell awk 'BEGIN { print int($(FPS) * 10 + 0.5) }')

FFMPEG_IN=$(FFMPEG) -f rawvideo -pix_fmt $(IN_FMT) -s $(RESOLUTION) -framerate $(FPS) -i -
SCALE=scale=out_color_matrix=bt709:out_range=tv:flags=accurate_rnd+full_chroma_int+bitexact
# setparams tags the frames themselves: encoders read colour info from the
# filter output, so the -color_* options alone left primaries/transfer unset.
TAG=setparams=colorspace=bt709:color_primaries=bt709:color_trc=bt709:range=tv
COLOR_TAGS=-colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv

# Settings and CRFs come from tools/encode/ (see its README for the numbers).
# Tiers: `x265`/`av1` = delivery (VMAF ~95 mean, >= 90 worst frame, smallest
# file); `*-master` = upload master (>= 97 worst frame, size secondary).
# The binding test clip is a faint, low-contrast Julia texture: at a CRF where
# dense filaments already score 99, both encoders smear it, so it sets the CRF.

# preset medium: slow scores better at equal bitrate but runs ~2.4x slower,
#   far outside the speed budget.
# aq-mode=3 (vs 4): 4 loses at matched bitrate on gradients and faint texture.
# no-sao: SAO lowers VMAF at the same bitrate (smooths fine filaments).
# merange=92: 4K zoom motion is large; ~2% smaller at no speed cost.
# rect=1: ~7% smaller at equal or better VMAF (about 20% slower).
# rdoq-level=2 + psy-rdoq=1: keeps the faint texture; the binding clip then
#   needs CRF ~17 instead of ~15, a smaller file overall.
X265_PARAMS=keyint=$(KEYINT):min-keyint=$(FPS):aq-mode=3:no-sao=1:merange=92:rect=1:rdoq-level=2:psy-rdoq=1.0

# preset 6: fits the speed budget (p5 is ~20% slower).
# tune=0 (VQ; ffmpeg defaults to PSNR): much better worst frames on faint texture.
# enable-variance-boost=1: more bits to flat/low-contrast blocks; faint Julia
#   texture goes from p1 ~85 to ~93 at CRF 32.
# enable-qm=1 (default qm-min): 3-11% smaller at equal VMAF; qm-min=0 caps
#   quality on faint texture and hurts filaments.
# film-grain=0: synthetic grain would add noise the renders don't have.
# tf and overlays stay default: disabling tf costs +50% bits and adds banding.
# scd=1: untested on its own; SVT-AV1 4.2 says it won't insert keyframes at
#   scene changes anyway, so it's likely a no-op here.
SVT_PARAMS=film-grain=0:keyint=$(KEYINT):scd=1:tune=0:enable-variance-boost=1:enable-qm=1

hevc-nvenc:
	$(FFMPEG_IN) -vf "$(SCALE),format=p010le" \
		-c:v hevc_nvenc -preset p7 -tune hq -rc vbr -cq 14 -b:v 0 -maxrate 200M -bufsize 400M \
		-profile:v main10 -pix_fmt p010le \
		-spatial-aq 1 -aq-strength 6 -temporal-aq 1 \
		-rc-lookahead 32 -bf 4 -b_ref_mode middle -multipass fullres \
		$(COLOR_TAGS) \
		-tag:v hvc1 -movflags +faststart \
		$(OUT)

# Delivery: CRF 17 (binding clip: VMAF 94.8 mean, 92.8 worst frame).
x265:
	$(FFMPEG_IN) -vf "$(SCALE),format=yuv420p10le,$(TAG)" \
		-c:v libx265 -profile:v main10 -preset medium -crf 17 \
		-x265-params "$(X265_PARAMS)" \
		$(COLOR_TAGS) \
		-tag:v hvc1 -movflags +faststart \
		$(OUT)

# Master: CRF 12 (binding clip: 97.6 worst frame).
x265-master:
	$(FFMPEG_IN) -vf "$(SCALE),format=yuv420p10le,$(TAG)" \
		-c:v libx265 -profile:v main10 -preset medium -crf 12 \
		-x265-params "$(X265_PARAMS)" \
		$(COLOR_TAGS) \
		-tag:v hvc1 -movflags +faststart \
		$(OUT)

# Delivery: CRF 32 (binding clip: VMAF 95.0 mean, 93.4 worst frame).
av1:
	$(FFMPEG_IN) -vf "$(SCALE),format=yuv420p10le,$(TAG)" \
		-c:v libsvtav1 -preset 6 -crf 32 \
		-svtav1-params "$(SVT_PARAMS)" \
		$(COLOR_TAGS) \
		-movflags +faststart \
		$(OUT)

# Master: CRF 17 (binding clip: ~97.1 worst frame, interpolated from CRF 14/20).
av1-master:
	$(FFMPEG_IN) -vf "$(SCALE),format=yuv420p10le,$(TAG)" \
		-c:v libsvtav1 -preset 6 -crf 17 \
		-svtav1-params "$(SVT_PARAMS)" \
		$(COLOR_TAGS) \
		-movflags +faststart \
		$(OUT)
