Repository navigation
fix(studio-server): keep transparency in proxies of VP8/VP9 alpha webm - #6025
Conversation
jrusso1020
left a comment
There was a problem hiding this comment.
Reviewed exact e884fb52d25f6bc8aea9985ad87b7a575d19465c. No blocker found.
packages/parsers/src/mediaAlpha.ts:1–27preserves the engine alpha-format predicate and decoder mapping, and recognizes alpha_mode=1 in any tag-name casing. Studio requests the tag in its existing probe rather than adding a subprocess.packages/studio-server/src/helpers/proxyTranscoder.ts:448–451places the correct VP9/VP8 decoder before input only for the alpha variant. That variant remains VP8/WebM with yuva420p and alpha metadata; opaque media retains the H.264 recipe.- Independent consumer/cache review traced check/publish baking, preview routes, runtime selection and ETags: choosing vp8 bypasses old h264 cache entries; variant validation and cache identity remain consistent.
Executed the current-source metadata → codec-map → resolveProxy chain in an isolated harness with real FFmpeg 8.0.1 and generated half-transparent VP9 and VP8 clips. Both produce WebM proxies with mean alpha exactly 127.5; opaque VP9 chooses H.264/MP4. Cache reuse also passes. Removing the input decoder makes the alpha assertion fail at 255; removing the requested alpha tag makes detection fail. The harness transpiles current TS and isolates unrelated HDR helpers, HTML collection, safe-path integration, binary discovery and cache maintenance; these are not full CLI/Studio or committed Vitest-suite runs. Read the added real VP9 test and shared helper cases; the committed real test explicitly skips without libvpx.
Missing-library behavior: no decoder fallback exists. A build lacking the required libvpx support fails visibly through ProxyTranscodeError (preview error / failed publish proxy), rather than silently generating an opaque replacement. The alpha output encoder already requires libvpx. I did not execute a minimal FFmpeg build with those codecs absent. Engine delegation is behavior-equivalent; parser source/runtime/types/build export entries agree.
Verdict: APPROVE
Reasoning: The shared rule repairs variant selection, and real VP8/VP9 transcodes preserve alpha with the correct input decoder; opaque-media and cache contracts remain intact in the inspected paths.
— hf-review
A webm whose alpha lives in the VP8/VP9 side channel (alpha_mode=1, pix_fmt yuv420p) was proxied to opaque H.264, and the VP8 proxy path decoded it with ffmpeg's native decoder, which drops alpha. The alpha rule and the alpha-reading decoder now live once in @hyperframes/parsers/media-alpha, used by engine and studio-server.
parsers already sat at its packed budget on main; the shared alpha rule adds 676 B of JS and 803 B of declarations (190958 B packed in CI).
d1795b4 to
cf3b539
Compare
jrusso1020
left a comment
There was a problem hiding this comment.
Re-reviewed exact cf3b53993ec50c57d7622795c5910af275c60b5a against previously approved e884fb52d25f6bc8aea9985ad87b7a575d19465c.
All 14 alpha code/test/package-export files are byte-identical to that reviewed revision. The additional own-diff budget change raises the parsers packed allowance from 190591 to 191000 bytes; inherited main changes do not alter the inspected alpha pipeline.
Parent rebuilt the harness from current TypeScript and reran real FFmpeg 8.0.1: VP8 and VP9 alpha inputs both yield WebM proxies with mean alpha 127.5, cache reuse passes, and opaque VP9 still chooses H.264/MP4. A fresh independent rebase audit agreed. Prior scope and missing-libvpx behavior remain: unsupported builds fail visibly, with no alpha-stripping fallback. Harness isolates unrelated HDR/HTML/path/binary/cache-maintenance integrations; no full Vitest, Studio/CLI, Windows-host or codec-absent build run.
Verdict: APPROVE
Reasoning: The rebase preserves the reviewed alpha behavior and current-source real transcodes still retain transparency without changing opaque-media output.
— hf-review

What
A transparent webm, such as the output of
hyperframes remove-background, lost its transparency in the Studio preview proxy.hyperframes check, Studio and publish all made an opaque H.264 copy of it.Why
There were two bugs on the same path.
pix_fmt=yuv420pplus anALPHA_MODE=1stream tag. Studio-server decided "has alpha" frompix_fmtalone, and it never asked ffprobe for the tag.proxyVariantFortherefore pickedh264. The engine already read the tag; the two copies of the rule had drifted (the studio-server regex also missedayuv*).vp8variant, the transcode read the source with ffmpeg's native VP9 decoder, which drops the side channel.format=yuva420pthen filled in a fully opaque alpha plane.Change
@hyperframes/parsers/media-alphais the one owner ofpixelFormatHasAlpha,videoStreamHasAlpha(pix_fmt or a case-insensitivealpha_mode=1tag) andalphaDecoderFor(libvpx-vp9/libvpx).stream_tags=alpha_mode, setsMediaMetadata.hasAlpha, and the codec map uses it. Its own pix_fmt regex is deleted.-c:v libvpx-vp9|libvpxbefore-ionly when it builds thevp8(alpha) variant of a VP8/VP9 source.decoderForCodecdelegates to the shared decoder choice. Engine behavior is unchanged.Opaque media is untouched. Its probe answer, variant, ffmpeg args and cache key are all the same as before. No proxy cache version bump is needed: before this change, no VP8/VP9 source could reach the
vp8variant, so no stale alpha proxies exist.Evidence
The same project and the same half-transparent VP9 clip (
libvpx-vp9,yuva420p,alpha_mode=1, mean alpha 127.5), run throughhyperframes checkwith ffmpeg 8.1.1:.transcode-cacheentryh264 / yuv420p(.mp4)vp8 / yuv420p / alpha_mode=1(.webm)Tests
parsers/src/mediaAlpha.test.ts: the merged pix_fmt lists from both old tests, the tag in both casings, and the decoder choice.studio-server/src/helpers/mediaCodecMap.test.ts: ffprobe output for a real VP9 alpha encode now giveshasAlphaand thevp8variant.studio-server/src/helpers/proxyTranscoder.test.ts: the spawn args put-c:v libvpx-vp9before-iforvp8and leaveh264alone. An end-to-end test with real ffmpeg covers probe, variant and transcode, and checks that the proxy's mean alpha stays at about 127.5. It is skipped when ffmpeg lacks libvpx.Package size
@hyperframes/parserswas already at its packed budget on main (190591 B). The newmedia-alphasubpath adds 676 B of JS and 803 B of declarations, which brings the packed size to 190958 B in CI. The budget moves to 191000 B. Nothing else in the tarball changed.