Skip to content

feat(libvmaf): compile picture_pool unconditionally, drop VMAF_PICTURE_POOL gate#32

Merged
lusoris merged 3 commits intomasterfrom
feat/picture-pool-always-on
Apr 18, 2026
Merged

feat(libvmaf): compile picture_pool unconditionally, drop VMAF_PICTURE_POOL gate#32
lusoris merged 3 commits intomasterfrom
feat/picture-pool-always-on

Conversation

@lusoris
Copy link
Copy Markdown
Owner

@lusoris lusoris commented Apr 17, 2026

Summary

  • vmaf_preallocate_pictures / vmaf_fetch_preallocated_picture were declared unconditionally in libvmaf/libvmaf.h:341,355, but the definitions lived under #ifdef VMAF_PICTURE_POOL — an opt-in C flag nobody passes. Default builds shipped the declarations without the bodies → any consumer got a linker error.
  • Picked issue-recommendation B (always compile). The surface has been public the whole time; flip the switch so the symbols actually exist.

Closes #29.

Changes

Verification

  • nm -D libvmaf.so now shows both symbols on default build:
    T vmaf_fetch_preallocated_picture
    T vmaf_preallocate_pictures
    
  • All 26 meson tests pass (meson test -C build), including test_pic_preallocation.
  • CI required status checks.

🤖 Generated with Claude Code

@lusoris lusoris force-pushed the feat/picture-pool-always-on branch from a95e4d1 to f3156a5 Compare April 18, 2026 00:42
Lusoris and others added 2 commits April 18, 2026 04:02
…E_POOL gate

vmaf_preallocate_pictures and vmaf_fetch_preallocated_picture have
always been declared in the public header libvmaf/libvmaf.h, but the
definitions were guarded by -DVMAF_PICTURE_POOL — a flag the user had
to opt into manually. Default builds shipped the declarations without
the bodies, so any consumer who called either function got a linker
error.

Flip to always-on per issue recommendation B:
- src/meson.build: picture_pool.c is now part of libvmaf_sources.
- src/libvmaf.c: drop 5 #ifdef VMAF_PICTURE_POOL sites (include,
  struct field, prepare_picture_pool block, vmaf_close cleanup,
  check_picture_pool call in the frame path).
- tools/vmaf.c: drop fallback branch — the CLI always uses the pool.
- test/meson.build: test_pic_preallocation always builds and runs.

All 26 meson tests pass. nm -D libvmaf.so now shows:
  T vmaf_fetch_preallocated_picture
  T vmaf_preallocate_pictures

Closes #29.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The always-on picture pool (PR #32 parent commit) used pic_cnt = 2 when
--threads 0 and (thread_cnt+1)*2 otherwise. Both undercount by one:
vmaf->prev_ref holds the previous frame's ref picture across frame
boundaries for motion features, so one pool slot is permanently live.
Frame N+1 then cannot fetch both ref + dist and deadlocks in
vmaf_picture_pool_fetch -> pthread_cond_wait.

Reproduced on the Netflix golden pair (src01_hrc00 vs src01_hrc01): prior
code hangs at frame 2; with pic_cnt = 2*(thread_cnt+1)+1 the CLI
processes all frames and matches expected scores.

Adds ADR-0104 capturing the sizing rationale + rejected alternatives.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@lusoris lusoris force-pushed the feat/picture-pool-always-on branch from f3156a5 to b47ff26 Compare April 18, 2026 02:05
The four early `return err;` sites (gpu collect, gpu submit, cpu extract,
dnn run-frame) skipped the trailing vmaf_picture_unref(ref/dist) at the
function tail. Pre-#32 this was a small malloc-backed leak the OS
reclaimed at exit; with the always-on picture pool from #32 the leak
holds a finite pool slot, and the next vmaf_picture_pool_fetch deadlocks
in pthread_cond_wait once the pool drains.

Reproducible deterministically by running the Netflix-golden pytest
sequence: test_run_vmaf_runner_rdh540 invokes the adm extractor with
adm_ref_display_height=540, the extractor errors on frame 0, and the
single-threaded CLI hangs on frame 1's pool fetch. Standalone vmaf
invocations exit cleanly because they bail out before any second-frame
fetch is attempted.

Restructured the four returns to `goto cleanup` so the existing
ref/dist teardown runs on both success and error paths. CUDA branch
unrefs are unchanged (also reachable via the new label). prev_ref
update remains success-only.

Verified: full quality_runner_test.py + feature_extractor_test.py
sequence completes in 73s; previously hung indefinitely at rdh540.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@lusoris lusoris merged commit 65460e3 into master Apr 18, 2026
22 of 23 checks passed
@lusoris lusoris deleted the feat/picture-pool-always-on branch April 18, 2026 10:38
@github-actions github-actions Bot mentioned this pull request Apr 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

libvmaf: vmaf_preallocate_pictures / vmaf_fetch_preallocated_picture are ghost symbols in default builds

1 participant