Skip to content

fix(studio): HEVC with long-term reference pictures keeps its pixel aspect ratio - #7739

Open
miguel-heygen wants to merge 2 commits into
mainfrom
fix/studio-mediabunny-1.66
Open

miguel-heygen wants to merge 2 commits into
mainfrom
fix/studio-mediabunny-1.66

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

Studio moves mediabunny from 1.65.2 to 1.66.0. Its HEVC reader now reads an SPS that lists long-term reference pictures, so such a video keeps its pixel aspect ratio and no longer logs Error parsing HEVC SPS: Invalid exponential-Golomb code.

Why

mediabunny 1.65.2 read lt_ref_pic_poc_lsb_sps as an exponential-Golomb code. It is a fixed-width field, log2_max_pic_order_cnt_lsb bits long. The misread threw inside its HEVC SPS parser, which caught it, logged the error above and fell back to square pixels. Phones often write HEVC with long-term references, so the error shows up in Studio's console for ordinary footage, and an anamorphic one would be drawn at the wrong shape. 1.66.0 reads those fields as fixed bits ("Fixed HEVC SPS with inter-predicted short-term or long-term reference pictures being misparsed, giving wrong aspect ratios and colors").

Related work

Refs mediabunny v1.66.0: https://github.com/Vanilagy/mediabunny/releases/tag/v1.66.0

How

  • packages/studio/package.json: mediabunny ^1.65.2 to ^1.66.0; Studio is the only package that depends on it.
  • bun.lock: only the two mediabunny lines move (relocked with bun 1.4.4, the repo's version; 1.66.0 keeps the same two dependencies).
  • 1.66.0 carries over 400 fixes. The ones near what Studio calls are UrlSource retries and errors (no more endless retries of a failed response read, requests stop after an error) and InputTrack.id becoming the track's 1-based index, which Studio does not read. mediaFetch.test.ts drives real mediabunny reads through Studio's fetch and passes unchanged.

Test plan

mediabunnyHevcSps.test.ts writes a 64x64 HEVC MP4 with mediabunny's own muxer, whose hvcC SPS lists one long-term reference picture and 4:3 pixels, reads it back, and expects 85x64 square pixels with nothing logged.

fails without the fix: on mediabunny 1.65.2 the same test reads 64x64 (expected [ 64, 64 ] to deeply equal [ 85, 64 ]).

  • On 1.66.0: bun install --frozen-lockfile with bun 1.4.4, Studio tsc --noEmit clean, and the full Studio suite: 758 test files, 8641 tests passed (1 file skipped, 16 todo).
  • Unit tests added/updated
  • Manual testing performed
  • Comments follow CONTRIBUTING.md "Comments"

No visible change

Footage whose SPS has no long-term references, or square pixels, looks the same. An anamorphic HEVC with long-term references now draws at its intended shape; I have no decodable file of that kind to capture, so there is no Before and After.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits

CI Format (and Preflight in Windows render / Player perf / preview-regression) is red: oxfmt --check flags mediabunnyHevcSps.test.ts. The fix is the two lines below (bunx oxfmt on the file). Nothing else blocks.

Scope

Read all 3 files. bun.lock moves only the two mediabunny lines, and the integrity matches npm's for 1.66.0. I checked the hand-built SPS field by field against H.265 7.3.2.2: lt_ref_pic_poc_lsb_sps is u(v), 8 bits here, and SAR 4:3 gives 85x64. Locally (bun 1.4.4) the test passes on 1.66.0 and fails on 1.65.2 with expected [ 64, 64 ] to deeply equal [ 85, 64 ], so the fails-without-the-fix line holds. Studio's only mediabunny consumers are pausedVideoDecoder.ts and thumbnailSourcePool.ts, and neither reads InputTrack.id. Other CI jobs were still running at review time.


it("keeps the pixel aspect ratio of HEVC that lists long-term reference pictures", async () => {
const errors = vi.spyOn(console, "error").mockImplementation(() => {});
const input = new Input({ source: new BufferSource(await anamorphicHevcMp4()), formats: [MP4] });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oxfmt --check fails on this line and on line 160, which turns the required Format job red.

Suggested change
const input = new Input({ source: new BufferSource(await anamorphicHevcMp4()), formats: [MP4] });
const input = new Input({
source: new BufferSource(await anamorphicHevcMp4()),
formats: [MP4],
});

const input = new Input({ source: new BufferSource(await anamorphicHevcMp4()), formats: [MP4] });
const track = await input.getPrimaryVideoTrack();

expect([await track!.getSquarePixelWidth(), await track!.getSquarePixelHeight()]).toEqual([85, 64]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same formatter fix:

Suggested change
expect([await track!.getSquarePixelWidth(), await track!.getSquarePixelHeight()]).toEqual([85, 64]);
expect([await track!.getSquarePixelWidth(), await track!.getSquarePixelHeight()]).toEqual([
85, 64,
]);

This branch has not been deployed

No deployments
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.

1 participant