Skip to content

Conform an ISO frame to the size its writer opened at (T3.8 / #482) - #503

Merged
iamfatness merged 1 commit into
mainfrom
fix/iso-frame-size-change
Sep 12, 2026
Merged

iamfatness merged 1 commit into
mainfrom
fix/iso-frame-size-change

Conversation

@iamfatness

@iamfatness iamfatness commented Sep 12, 2026 •

Copy link
Copy Markdown
Owner

Closes #482.

An ISO writer opens lazily at its source's first frame and keeps that size for the life of the recording. When a guest's frame size changed later, the current frame's dimensions were handed to a writer opened at the original size.

#478 turned this from rare into routine: under stable resolution tiers a guest moves 720P ↔ 1080P every time they're cued onto or off a bus, so an ordinary show changes a source's frame size several times.

An MP4 video track has one size, so conforming isn't a choice — the only question is whether it's deliberate. modules/IsoFrameConform.h makes it deliberate: aspect-preserving, centred, letterboxed with BT.601 studio-swing black, the same shape the FFmpeg media path already uses. An unchanged size takes a straight copy/interleave, so the ordinary path pays nothing.

Details worth keeping

  • Every edge is even-aligned. I420 and NV12 carry chroma at half resolution, so an odd origin or extent splits a chroma sample across the letterbox edge and fringes it.
  • The scale is box-filtered, not point-sampled. A 4K guest downscaled to 1080p would otherwise alias into shimmer, and a still frame that crawls is worse than a soft one.
  • Aspects compare as integer cross-products — no float, no rounding drift.
  • BGRA (capture, ISO-3) is refused loudly rather than conformed. No BGRA scaler exists, capture sources don't retier the way Zoom guests do, and inventing an unexercised one would be worse than a named refusal.

Verification — and its limits, stated plainly

IsoFrameConformTest asserts geometry and pixels exactly: scaled values survive, the bars are legal black (luma 16, chroma 128/128 — not 0, which is blacker than legal), output is always the opened size, and an unchanged size is bit-exact. 8 tests.

The end-to-end Media Foundation test is a guard, not a red-green proof — and I checked rather than assumed. It passes with and without the fix. MF accepts a mismatched sample silently, so the frame count, the warning, and even ffprobe's view of the container (640x360, 9 frames) are identical either way.

That is CLAUDE.md's "verify pixels, not stream presence" trap met again: every observable at that level survives the bug. My first same-aspect test case (320x180 into 640x360, both 16:9) could not have distinguished it either. The test's comment now says this outright rather than implying cover it does not give. What it does earn: two size changes leave the writer accepting frames with no warning, so a conform that dropped or failed frames would fail there.

922 native tests pass.

How to check it live: record ISOs with a guest who gets cued onto and off a bus during the take, then open their ISO in post. Their picture should stay correctly framed across the whole file instead of jumping scale or losing edges.

🤖 Generated with Claude Code

https://claude.ai/code/session_014yuH7EMvWCWdkhvevrtMyJ

…3.8 / #482)

An ISO writer opens LAZILY at its source's first frame and keeps that size for
the life of the recording (ISO-1: "sized to that frame's native dims (no
scaling)"). When a guest's frame size changed later, the CURRENT frame's
dimensions were handed to a writer opened at the ORIGINAL size.

#478 turned that from rare into routine: under stable resolution tiers a guest
moves 720P <-> 1080P every time they are cued onto or off a bus, so an ordinary
show changes a source's frame size several times.

An MP4 video track has ONE size, so conforming is not a choice -- the only
question is whether it is deliberate. modules/IsoFrameConform.h makes it
deliberate: aspect-preserving, centred, letterboxed with BT.601 studio-swing
black, the same shape the FFmpeg media path already uses. An unchanged size
takes a straight copy/interleave, so the ordinary path pays nothing.

Details worth keeping:

- Every edge is EVEN-aligned. I420 and NV12 carry chroma at half resolution, so
  an odd origin or extent splits a chroma sample across the letterbox edge.
- The scale is box-filtered, not point-sampled: a 4K guest downscaled to 1080p
  would otherwise alias into shimmer, and a still frame that crawls is worse
  than a soft one.
- Aspects are compared as integer cross-products -- no float, no rounding drift.
- BGRA (capture, ISO-3) is REFUSED loudly rather than conformed. No BGRA scaler
  exists, capture sources do not retier the way Zoom guests do, and inventing an
  unexercised one would be worse than a named refusal.

VERIFICATION, and its limits, stated plainly.

IsoFrameConformTest asserts the geometry and the PIXELS exactly: scaled values
survive, the bars are legal black (16 / 128 128, not 0), output is always the
opened size, and an unchanged size is bit-exact.

The end-to-end MF test is a GUARD, not a red-green proof, and I checked rather
than assumed: it passes with and without the fix. Media Foundation accepts a
mismatched sample silently, so the frame count, the warning and ffprobe's view
of the container (640x360, 9 frames) are identical either way. That is the
"verify pixels, not stream presence" trap met again -- every observable at that
level survives the bug. The test's comment says so rather than implying cover it
does not give. What it does earn is that two size changes leave the writer
accepting frames with no warning, so a conform that dropped or failed frames
would fail there.

922 native tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014yuH7EMvWCWdkhvevrtMyJ
@iamfatness
iamfatness merged commit 3007a9e into main Sep 12, 2026
19 checks passed
@iamfatness
iamfatness deleted the fix/iso-frame-size-change branch September 12, 2026 16:23
iamfatness added a commit that referenced this pull request Sep 12, 2026
Nine items closed and two partial, all shipped in beta-2026-09-12-e1223d3 and
none of them live-checked:

  T1.12 #475  join-time prompts answered            #493
  T1.13 #473  media decoder failures are loud       #494  (observability ONLY)
  T2.6  #438  packaging spec reconciled             #504
  T2.7  #474  one shortcut, uninstall cleans up     #497
  T2.8  #469  recordings resolve absolute           #496
  T2.9  #466  recording lifecycle survives a stream #499
  T2.10 #468  sender health stops lying             #499
  T3.2  #440  WebView2 message                      #504
  T3.7  #470  ISOs armed with capture off warn      #502
  T3.8  #482  ISO frames conform to the writer      #503
  T2.1  #433  PARTIAL — WER dumps are HKLM-only
  T3.5  #476  PARTIAL — the rest is a product call

Each row keeps the thing that is expensive to rediscover rather than just a tick:
T2.8 records that the issue's premise was wrong (the default was already
absolute; a persisted relative preference bypassed it), T3.8 records that its
end-to-end test is a guard which passes either way, T2.6 records that dropping
MSIX cost auto-update, and T2.1 records the measurement proving a per-user
installer cannot enable crash dumps.

Tier 1 now has ONE open item, and it is waiting on a decision rather than
effort: T1.11 step 1 needs a change to the Take path itself, because a plain cut
never captures the outgoing scene. That is written into the row so the next
session does not rediscover it and ship it blind.

Two entries came out of the work rather than the list: #505 (the per-layer
border controls are vestigial — the core forces borderStyle="none" on every
route layer, so they cannot do anything) and the T1.11 ruling.

The honest header: the binding constraint is now T0.1 and a live check, not
engineering capacity.


Claude-Session: https://claude.ai/code/session_014yuH7EMvWCWdkhvevrtMyJ

Co-authored-by: Claude <noreply@anthropic.com>
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.

ISO recordings crop or pad a guest's picture when their frame size changes mid-recording

2 participants