Skip to content

fix: correct screencast frame timing so playback matches real time (upstream #15112) - #3494

Merged
kblok merged 4 commits into
masterfrom
implement-upstream-change-15112
Jun 27, 2026
Merged

kblok merged 4 commits into
masterfrom
implement-upstream-change-15112

Conversation

@kblok

@kblok kblok commented Jun 23, 2026

Copy link
Copy Markdown
Member

The screencast output was playing in slow motion because of two bugs in the ffmpeg integration.

First, -framerate was being passed as an output option (after -i pipe:0), so ffmpeg ignored it and the image2pipe demuxer defaulted to 25 fps — producing a 30/25 = 1.2× constant stretch regardless of what fps was configured.

Second, per-interval frame counting used Math.Round(fps * interval), which rounds every sub-1/fps interval up to one frame when the page is captured faster than fps. The result: the muxed frame count tracked the capture rate instead of fps, so a 60 fps capture produced double the expected frames and played at half speed. The fix replaces this with CountFrames, which diffs rounded cumulative positions anchored at the first frame — keeping the total at Math.Round(fps × duration) regardless of capture rate.

This PR also wires up the previously-stub ffmpeg process integration: PNG frame piping, output file writing, and tail-frame padding on stop.

Upstream: puppeteer/puppeteer#15112

kblok and others added 4 commits June 23, 2026 18:43
…pstream #15112)

Ports two ffmpeg muxing fixes from upstream Puppeteer PR #15112:

1. Move `-framerate` before `-i pipe:0` (it is an input option; when placed after
   `-i`, ffmpeg ignores it and the image2pipe demuxer falls back to its default
   25 fps, stretching the output timeline by capture_fps/25).

2. Replace per-interval rounding with cumulative frame counting (CountFrames).
   The old Math.Round(fps * interval) approach inflated the frame count when the
   page was captured faster than fps, causing slow-motion playback. The new
   approach diffs rounded cumulative positions so the total always equals
   Math.Round(fps * duration), independent of capture rate.

Also implements the previously-stub ffmpeg process integration in ScreenRecorder:
frame piping, output file writing, and tail-frame padding on stop.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kblok
kblok merged commit f2c340b into master Jun 27, 2026
23 of 26 checks passed
@kblok
kblok deleted the implement-upstream-change-15112 branch June 27, 2026 12:29
sondresjolyst pushed a commit to sondresjolyst/garge-api that referenced this pull request Jul 6, 2026
Updated [PuppeteerSharp](https://github.com/hardkoded/puppeteer-sharp)
from 25.1.2 to 25.2.1.

<details>
<summary>Release notes</summary>

_Sourced from [PuppeteerSharp's
releases](https://github.com/hardkoded/puppeteer-sharp/releases)._

## 25.2.1

## What's New
* feat: add WaitForFunctionAsync to WebWorker (upstream #​15100) by
@​kblok in hardkoded/puppeteer-sharp#3484
* feat: roll to Firefox 152.0 (upstream #​15125) by @​kblok in
hardkoded/puppeteer-sharp#3486
* feat: add page locale emulation (upstream #​15075) by @​kblok in
hardkoded/puppeteer-sharp#3485
* feat: roll to Chrome 150.0.7871.24 (upstream #​15126) by @​kblok in
hardkoded/puppeteer-sharp#3488

## What's Changed
* fix: await Worker script execution before evaluate (upstream #​15099)
by @​kblok in hardkoded/puppeteer-sharp#3489
* fix: apply network allowlist/blocklist to non-auto-attach sessions and
workers (upstream #​15136) by @​kblok in
hardkoded/puppeteer-sharp#3491
* fix: roll to Firefox 152.0.1 (upstream #​15134) by @​kblok in
hardkoded/puppeteer-sharp#3493
* fix(webmcp): invalidate webmcp tools on context destruction (upstream
#​15068) by @​kblok in
hardkoded/puppeteer-sharp#3496
* perf: optimize GetPropertiesAsync property iteration (upstream
#​15094) by @​kblok in
hardkoded/puppeteer-sharp#3497
* perf(cdp): parallelize extension workers fetching (upstream #​15057)
by @​kblok in hardkoded/puppeteer-sharp#3495
* perf: parallelize iframe population in accessibility snapshots
(upstream #​15083) by @​kblok in
hardkoded/puppeteer-sharp#3499
* Fix #​3501: pin Microsoft.Extensions.Logging to the v8 floor by
@​kblok in hardkoded/puppeteer-sharp#3502
* feat: allow extensions to run over websockets (upstream #​15059) by
@​kblok in hardkoded/puppeteer-sharp#3487
* fix: block service worker registrations for blocked URLs (upstream
#​15135) by @​kblok in
hardkoded/puppeteer-sharp#3490
* fix: correct screencast frame timing so playback matches real time
(upstream #​15112) by @​kblok in
hardkoded/puppeteer-sharp#3494
* chore: roll Firefox to 152.0.2 (upstream #​15153) by @​kblok in
hardkoded/puppeteer-sharp#3503
* chore: bump version to 25.2.1 by @​kblok in
hardkoded/puppeteer-sharp#3504
* fix: cache Browser.getVersion for untrusted sessions (upstream
#​15150) by @​kblok in
hardkoded/puppeteer-sharp#3505
* fix: unblock service-worker registration block after worker-buffer
change by @​kblok in
hardkoded/puppeteer-sharp#3506


**Full Changelog**:
hardkoded/puppeteer-sharp@v25.1.2...v25.2.1

Commits viewable in [compare
view](hardkoded/puppeteer-sharp@v25.1.2...v25.2.1).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=PuppeteerSharp&package-manager=nuget&previous-version=25.1.2&new-version=25.2.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.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.

1 participant