Skip to content

chore(video): emit frames with real timestamps, drop frame number quantization - #42480

Open
Pavel Feldman (pavelfeldman) wants to merge 1 commit into
microsoft:mainfrom
pavelfeldman:chore-video-timestamps
Open

chore(video): emit frames with real timestamps, drop frame number quantization#42480
Pavel Feldman (pavelfeldman) wants to merge 1 commit into
microsoft:mainfrom
pavelfeldman:chore-video-timestamps

Conversation

@pavelfeldman

@pavelfeldman Pavel Feldman (pavelfeldman) commented Aug 31, 2026

Copy link
Copy Markdown
Member

Summary

  • Emit each screencast frame into the Matroska stream immediately with its wall-clock timestamp relative to the recorder creation time; ffmpeg's -r 25 output resampling handles frame timing. Drops the frame number quantization, same-slot coalescing and the one-frame emission delay.
  • Write the recorder creation time into the webm creation_time metadata.
  • Firefox and WebKit screencast timestamps are monotonic, so frameSwapWallTime is now anchored to the wall clock at the first frame.

Fixes: #42361

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…ntization

Cluster timestamps are computed relative to the recorder creation time,
which is also written into the webm creation_time metadata. Firefox and
WebKit screencast timestamps are monotonic, so they are anchored to the
wall clock at the first frame.
Comment thread packages/playwright-core/src/server/firefox/ffPage.ts
Comment thread packages/playwright-core/src/server/webkit/wkPage.ts
const h = this._size.height;
const videoFilterArgs = page.getFFmpegVideoFilterArgs?.({ width: w, height: h }) ?? `pad=${w}:${h}:0:0:gray,crop=${w}:${h}:0:0`;
const args = `-loglevel error -f matroska -fpsprobesize 0 -probesize 32 -analyzeduration 0 -i pipe:0 -y -an -r ${fps} -c:v vp8 -qmin 0 -qmax 50 -crf 8 -deadline realtime -speed 8 -b:v 1M -threads 1 -vf ${videoFilterArgs}`.split(' ');
args.push('-metadata', `creation_time=${new Date(this._creationTimeMs).toISOString()}`);

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.

creation_time is captured before the first frame, and ffmpeg rebases the first input timestamp to zero, so if this is meant to supplant #42478 then this would be earlier than desired

Comment thread packages/playwright-core/src/server/videoRecorder.ts
const timestampMs = Math.max(0, Math.round(frameNumber * 1000 / fps));
this._process!.stdin!.write(writeClusterHeader(timestampMs, frame.length));
private _emitFrame(frame: Buffer, timestampMs: number) {
this._process!.stdin!.write(writeClusterHeader(Math.max(0, Math.round(timestampMs)), frame.length));

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.

this removes the explicit video frame slot selection added in 7070565 and rounds timestamps before ffmpeg resamples to 25fps, so frames near a 40ms boundary may land in a different output video frame slot

everything may end up working just fine, but id suggest adding a test to make sure

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Could you help me understand the problem? Do we not trust ffmpeg to resample?

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.

i dont really know about ffmpeg enough to know whether it'll do the right thing or not

i was just trying to understand why this explicit slot mapping existed and whether these changes would cause a regression

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Test results for "tests 1"

4 flaky ⚠️ [chromium-library] › library/video.spec.ts:495 › screencast › should capture static page in persistent context Radoslav Kirilov (@smoke) `@chromium-ubuntu-22.04-node22`
⚠️ [firefox-library] › library/browsercontext-cookies-third-party.spec.ts:257 › third party 'Partitioned;' cookies `@firefox-ubuntu-22.04-node20`
⚠️ [firefox-library] › library/browsercontext-cookies-third-party.spec.ts:470 › top level 'Partitioned;' cookie and same origin iframe `@firefox-ubuntu-22.04-node20`
⚠️ [firefox-page] › page/page-emulate-media.spec.ts:144 › should keep reduced motion and color emulation after reload `@firefox-ubuntu-22.04-node20`

51278 passed, 1241 skipped


Merge workflow run.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Test results for "MCP"

2 failed
❌ [firefox] › mcp/cli-core.spec.ts:70 › dblclick @mcp-windows-latest-firefox
❌ [webkit] › mcp/dashboard.spec.ts:184 › two concurrent cli show invocations both succeed @mcp-ubuntu-latest-webkit

8303 passed, 1367 skipped


Merge workflow run.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🟢 CI is clear — no failures caused by this PR

Hi, I'm the Playwright bot and I took a look at the failing CI here.

This PR only reworks video frame timestamps (videoRecorder.ts, plus the Firefox/WebKit
screencast frame handlers in ffPage.ts/wkPage.ts). The two hard failures are Firefox and
WebKit MCP CLI tests that never touch video recording, and both are pre-existing cross-run
flakes in the aggregated results. The tests 1 run reported no failures — only flaky tests.

Details

Overall: nothing in the failing set exercises the changed code. The diff is confined to the
screencast → ffmpeg frame path; the failures are MCP CLI-dispatch tests.

Pre-existing flake / infra

  • [firefox] › mcp/cli-core.spec.ts:70 › dblclick (mcp-windows-latest-firefox) — cross-run
    flake. In the test-results DB this bot failed 7 of 703 runs, passed the other 696, across
    unrelated SHAs. Green everywhere else (ubuntu/macos firefox and all chromium/webkit/msedge
    bots: 0 failures over hundreds of runs each). A dblclick CLI test has nothing to do with the
    video timestamp change.
  • [webkit] › mcp/dashboard.spec.ts:184 › two concurrent cli show invocations both succeed
    (mcp-ubuntu-latest-webkit) — cross-run flake, and a broad one: it flips verdict on several
    bots on unrelated SHAs (ubuntu-webkit 1/724, windows-webkit 2/724, windows-chromium 2/721,
    windows-chrome 2/717, windows-msedge 2/716, windows-firefox 2/703). A concurrency race in the
    CLI-show path, unrelated to screencast frames.

Flaky only — nothing to triage (but worth a note, since it's the PR's area)

  • The tests 1 report lists 4 flaky tests, no failures. library/video.spec.ts:495 › screencast › should capture static page in persistent context is right in the area this PR touches, but
    it was rescued by a retry, matching its long-standing flaky baseline — no sign of a regression
    from the timestamp rework. The Firefox cookie / emulate-media flakes are unrelated to video.

Triaged by the Playwright bot - agent run

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.

[Feature]: Allow receiving screencast frame timestamps without JPEG data

3 participants