Skip to content

Stabilize video export on Windows#210

Open
linyqh wants to merge 1 commit intosiddharthvaddem:mainfrom
linyqh:codex/exporter-timeout-fallback
Open

Stabilize video export on Windows#210
linyqh wants to merge 1 commit intosiddharthvaddem:mainfrom
linyqh:codex/exporter-timeout-fallback

Conversation

@linyqh
Copy link

@linyqh linyqh commented Mar 14, 2026

What changed

This PR improves export stability, especially on Windows, by adding timeout protection and safer encoder fallback behavior.

Key updates

  • add source-loading timeouts in streamingDecoder

    • protect fetch, blob reading, demuxer load, and metadata parsing
    • surface clearer timeout errors when the source video cannot be loaded or parsed in time
  • harden the video export pipeline in videoExporter

    • split export flow into encoder-preference attempts
    • retry with a safer encoder preference when an export attempt fails
    • track encoder output activity and fail fast when the encoder stalls
    • add timeout protection when flushing the encoder
    • propagate fatal encoder errors immediately instead of letting export hang
  • improve Windows export behavior

    • prefer software encoding first on Windows to reduce instability
    • cap the encode queue more aggressively for software encoding to avoid memory growth
    • keep hardware/software fallback logic explicit and easier to reason about
  • small cleanup/refactor

    • centralize progress reporting
    • reset encoder state more consistently during cleanup

Files changed

  • src/lib/exporter/streamingDecoder.ts
  • src/lib/exporter/videoExporter.ts

Why

This round mainly addresses export hangs, long waits, and encoder stall issues during video export, with extra attention to Windows stability and clearer failure paths.

Validation

  • git diff --check passed
  • npm run lint and npm test could not be completed locally because dependencies were not in a clean usable state
  • npm ci --cache .npm-cache --foreground-scripts hit EBUSY on node_modules/electron, and the current environment also showed Node engine warnings

Merge request

@author This change is ready for review. If it looks good, please help merge it so the Windows export stability fixes can ship soon. Thanks!

Summary by CodeRabbit

  • Bug Fixes

    • Added timeout protection to prevent extended stalls during video metadata loading and frame encoding operations.
    • Implemented stall detection with automatic fallback to safer encoder options if encoding becomes unresponsive.
  • New Features

    • Enhanced video export reliability with automatic fallback between encoder preferences when encoding fails.

@siddharthvaddem
Copy link
Owner

siddharthvaddem commented Mar 17, 2026

@codex
@coderabbitai

@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

@siddharthvaddem Sure! I'll review the changes in this PR right away.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

📝 Walkthrough
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main objective of the PR — stabilizing video export specifically on Windows — which aligns with the primary purpose described in the changeset.
Description check ✅ Passed The PR description covers most required template sections including motivation, type of change, and detailed explanation of changes, though some optional sections like screenshots and formal testing steps are not included.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use oxc to improve the quality of JavaScript and TypeScript code reviews.

Add a configuration file to your project to customize how CodeRabbit runs oxc.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/lib/exporter/videoExporter.ts (1)

413-427: Consider extracting withTimeout to a shared utility.

This implementation is identical to the one in streamingDecoder.ts. Extracting to a shared utility (e.g., src/lib/utils/withTimeout.ts) would reduce duplication and ensure consistent behavior.

♻️ Proposed shared utility

Create a new file src/lib/utils/withTimeout.ts:

export function withTimeout<T>(
  promise: Promise<T>,
  timeoutMs: number,
  message: string,
): Promise<T> {
  return new Promise<T>((resolve, reject) => {
    const timer = window.setTimeout(() => reject(new Error(message)), timeoutMs);
    promise.then(
      (value) => {
        window.clearTimeout(timer);
        resolve(value);
      },
      (error) => {
        window.clearTimeout(timer);
        reject(error);
      },
    );
  });
}

Then import and use in both files.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/exporter/videoExporter.ts` around lines 413 - 427, Extract the
duplicate withTimeout<T> implementation into a single shared utility function
named withTimeout and export it from a new module, then replace the local
implementations in videoExporter.ts (method withTimeout) and streamingDecoder.ts
with imports of that shared withTimeout to remove duplication and ensure
consistent behavior; keep the same signature (promise: Promise<T>, timeoutMs:
number, message: string) and the same timer/clear logic so callers (e.g., the
withTimeout call sites in VideoExporter and StreamingDecoder) continue to work
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/lib/exporter/videoExporter.ts`:
- Around line 413-427: Extract the duplicate withTimeout<T> implementation into
a single shared utility function named withTimeout and export it from a new
module, then replace the local implementations in videoExporter.ts (method
withTimeout) and streamingDecoder.ts with imports of that shared withTimeout to
remove duplication and ensure consistent behavior; keep the same signature
(promise: Promise<T>, timeoutMs: number, message: string) and the same
timer/clear logic so callers (e.g., the withTimeout call sites in VideoExporter
and StreamingDecoder) continue to work unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 851ef0a9-eb04-4211-a61a-f48f3295f45e

📥 Commits

Reviewing files that changed from the base of the PR and between 5e8bb99 and 3726ed7.

📒 Files selected for processing (2)
  • src/lib/exporter/streamingDecoder.ts
  • src/lib/exporter/videoExporter.ts

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3726ed73c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

import type { ExportConfig, ExportProgress, ExportResult } from "./types";

const ENCODER_STALL_TIMEOUT_MS = 15_000;
const ENCODER_FLUSH_TIMEOUT_MS = 20_000;

Choose a reason for hiding this comment

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

P1 Badge Scale encoder flush timeout with pending frame backlog

A fixed ENCODER_FLUSH_TIMEOUT_MS = 20_000 can make healthy exports fail on slower machines because VideoEncoder.flush() must wait for all queued frames to finish encoding, and this pipeline can still have a sizable backlog at finalize time. With up to 32 queued frames in software mode (and 120 in hardware mode), valid exports can legitimately take longer than 20s to drain, so this introduces false "encoder stopped responding" failures and unnecessary fallback/final failure paths.

Useful? React with 👍 / 👎.

@siddharthvaddem
Copy link
Owner

Looks reasonable to me. Have you tested it thoroughly with exporting?

@linyqh
Copy link
Author

linyqh commented Mar 18, 2026

Looks reasonable to me. Have you tested it thoroughly with exporting?

Yes, I have. Initially, I found that it would get stuck on the export screen when running on Windows 11, making it unusable. After fixing the bug, I've verified that the export process now works correctly.

@siddharthvaddem
Copy link
Owner

can we have the conflicts resolved?

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.

2 participants