#11393·remotion

`@remotion/media`: `<Video>` still stalls at t=0.2s on Windows after #11018 — expose decoder `hardwareAcceleration`

Author: udaykirancodesCreated Sep 17, 2026Updated Sep 17, 2026

Bug Report

Client-side rendering (@remotion/web-renderer) with <Video> from @remotion/media still hangs on Windows with the fix from #11018 (shipped in 4.0.521) applied:

A delayRender() "Extracting frame at time 0.2 from blob:https://…" was called but not cleared after 58000ms. See https://remotion.dev/docs/timeout for help. Retries left: 1 - Rendering the frame will be retried.

Environment

  • remotion, @remotion/media, @remotion/web-renderer: 4.0.525 (mediabunny 1.56.1) — verified the deleteFramesBeforeTimestamp change from #11018 is present in the installed dist/esm/index.mjs
  • Windows 10, Chrome 152 and Brave (Chromium 152), Intel integrated GPU, 4–8 GB RAM, 8–10 logical cores
  • Sources: H.264 MP4 from phones, 17–51 s; output 1080×1920 and 2160×2160; source is a blob: URL (IndexedDB)
  • The same projects export fine on macOS and Android; a Windows 11 machine with a different Intel driver also exports fine

This is a production SaaS (browser-only rendering), so we see it across several users' machines rather than one laptop; every failure lands at exactly time 0.2.

Why #11018 does not cover this case

ensureEnoughFramesForTimestamp now calls deleteFramesBeforeTimestamp({ timestampInSeconds: t - getSafeWindowOfMonotonicity(fps) }) before each sampleIterator.next(). getSafeWindowOfMonotonicity(fps) is 0.2 * 30 / fps — i.e. 0.2 s at any fps — so the threshold is ≤ 0 for every request up to t = 0.2 s and nothing is freed until after the point where the stall happens.

At the t = 0.2 request the keyframe bank holds every frame from 0 to 0.2 s (7 frames at 30 fps, 13 at 60 fps), on top of mediabunny's own decoded-sample queue (up to 8, computeMaxQueueSize) and the decoder's in-flight frames. Windows D3D11 hardware decoders have a small, driver-dependent picture-buffer pool; once every buffer is held by an open VideoFrame, the decoder silently stops producing output — no error, so the delayRender is never cleared. This is the same failure mode described in Vanilagy/mediabunny#406 ("the excess decoder accepts configure() and decode() and simply never outputs a frame"). The regression test added in #11018 models only the bank at 30 fps, not the mediabunny queue or a smaller pool, which is why it passes while real machines still stall.

Reproduction

The NewVideo composition from #11020 on a Windows/Intel laptop. If that machine's driver happens to allocate a large enough pool, a 60 fps 4K H.264 source reproduces more reliably (13 frames must be open before the safe window ever frees one).

What fixes it in our app

Decoding in software, which has no fixed picture pool. mediabunny ≥ 1.48 accepts new VideoSampleSink(track, { hardwareAcceleration: 'prefer-software' }), but packages/media/src/get-sink.ts constructs the sink without options and <Video> exposes no prop for it. We are shipping a 3-line pnpm patch that passes a decoder option there, gated by VideoDecoder.isConfigSupported({ ...decoderConfig, hardwareAcceleration: 'prefer-software' }) so that HEVC (no software decoder in Chrome on Windows) keeps the browser default. That removes the stall for AVC/VP8/VP9/AV1 sources.

Possible Solution

Either of:

  1. A <Video> prop, e.g. decoderHardwareAcceleration?: 'no-preference' | 'prefer-hardware' | 'prefer-software', forwarded to VideoSampleSink (and included in the sink cache key); or
  2. An automatic fallback: on Windows, when VideoDecoder.isConfigSupported(...) reports software support for the track, prefer software decoding for client-side renders.

Happy to open a PR following the "Implementing a new option" guide once you indicate which shape you'd prefer.

Related: #10701, #11020, Vanilagy/mediabunny#406.