Skip to content

Updates for exporting video .mp4 type#438

Open
nguyenducdongdev wants to merge 2 commits intosiddharthvaddem:mainfrom
nguyenducdongdev:dong-nguyen-dev
Open

Updates for exporting video .mp4 type#438
nguyenducdongdev wants to merge 2 commits intosiddharthvaddem:mainfrom
nguyenducdongdev:dong-nguyen-dev

Conversation

@nguyenducdongdev
Copy link
Copy Markdown

@nguyenducdongdev nguyenducdongdev commented Apr 13, 2026

Pull Request Template

Description

Motivation

Type of Change

  • New Feature
  • Bug Fix
  • Refactor / Code Cleanup
  • Documentation Update
  • Other (please specify)

Related Issue(s)

Screenshots / Video

Screenshot (if applicable):

![Screenshot Description](path/to/screenshot.png)

Video (if applicable):

<video src="path/to/video.mp4" controls width="600"></video>

Testing

Checklist

  • I have performed a self-review of my code.
  • I have added any necessary screenshots or videos.
  • I have linked related issue(s) and updated the changelog if applicable.

Thank you for contributing!

Summary by CodeRabbit

  • New Features

    • Audio export now supports AAC and Opus, with automatic selection of the best codec for source audio to improve compatibility and quality.
  • Improvements

    • Clearer handling when a source audio codec isn't supported, surfacing a definitive error instead of silent fallbacks.
  • Documentation

    • Added a Windows build command and example path to the README.
  • Tests

    • Test config updated to exclude browser-specific tests from default runs.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 72c69868-dcfa-4ad0-b002-7621ee31c0a8

📥 Commits

Reviewing files that changed from the base of the PR and between 5a0d3c5 and 4f06cc8.

📒 Files selected for processing (1)
  • README.md
✅ Files skipped from review due to trivial changes (1)
  • README.md

📝 Walkthrough

Walkthrough

Replaces hardcoded Opus audio handling with selectable AAC or Opus paths: new exported codec types, constructors now accept codec choices, muxer and processor use the selected codec, and video exporter probes encoder support to pick AAC or Opus (or fail if none supported).

Changes

Cohort / File(s) Summary
Audio processing
src/lib/exporter/audioEncoder.ts
Exported TargetAudioCodec; AudioProcessor now constructed with a target codec and re-encodes trim-only audio to AAC (mp4a.40.2) when requested, otherwise Opus; simplified muxing flow to call processTrimOnlyAudio.
MP4 muxer
src/lib/exporter/muxer.ts
Added Mp4AudioCodec type; VideoMuxer constructor now takes `audioCodec: Mp4AudioCodec
Exporter & codec probing
src/lib/exporter/videoExporter.ts
Added pickAudioCodec(demuxer) which probes AudioEncoder.isConfigSupported for AAC then Opus; plumbs chosen audioCodec into VideoMuxer and AudioProcessor; throws if source has audio but no supported codec; added AUDIO_BITRATE.
Test config
vitest.config.ts
Added exclude pattern to omit src/**/*.browser.test.{ts,tsx} from default test discovery.
Docs
README.md
Minor top-of-file additions: npm run build:win command and a Windows path entry.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • siddharthvaddem

Poem

late-night builds hum, codecs in debate 🎧
aac or opus — the encoder will rate
muxer wakes up, accepts what it’s told
audio flows tidy, not kinda cursed, just bold
ship it (after a nit or two) 🚀

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is entirely a template with no actual content filled in—all sections are empty placeholders with no concrete information about changes, motivation, or testing. Fill in the template sections with real details: describe the codec selection feature, explain why multi-codec support was needed, clarify testing approach, and link any related issues.
Title check ❓ Inconclusive The title 'Updates for exporting video .mp4 type' is vague and generic—it doesn't clearly convey what was actually changed (audio codec selection logic) or why it matters. Consider a more specific title like 'Add audio codec selection for MP4 exports' or 'Support AAC and Opus codec options for audio encoding' to better reflect the actual changes.
✅ Passed checks (1 passed)
Check name Status Explanation
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.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@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: 5a0d3c530b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

/* reader already closed */
}
}
await this.processTrimOnlyAudio(demuxer, muxer, [], undefined);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid full-frame audio buffering in speed-edited exports

Routing muxRenderedAudioBlob through processTrimOnlyAudio changes this path from chunk streaming to full decode/re-encode buffering, because processTrimOnlyAudio accumulates all decoded AudioData frames before encoding/muxing. For long videos with speed regions, this can drive memory usage to uncompressed PCM scale and cause export stalls/OOMs that did not occur with the previous streamed chunk path.

Useful? React with 👍 / 👎.

Comment on lines +193 to +196
if (hasAudio && !audioCodec) {
throw new Error(
"Source has audio, but no supported audio encoder was found for MP4 export.",
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not fail export when no audio encoder is available

This new hard failure blocks the entire MP4 export whenever the input has an audio stream but neither AAC nor Opus encoding is supported in the runtime. That is a functional regression for environments with limited WebCodecs audio support, where a video-only export is still possible and was previously handled by skipping audio in AudioProcessor.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@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.

Actionable comments posted: 2

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

9-17: Share the codec union with VideoMuxer.

This redefines the same "aac" | "opus" union as Mp4AudioCodec in src/lib/exporter/muxer.ts. importing the existing type keeps the exporter path on one source of truth and avoids drift the next time this list changes.

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

In `@src/lib/exporter/audioEncoder.ts` around lines 9 - 17, Replace the locally
defined TargetAudioCodec union with the shared type from the muxer module:
remove the export type TargetAudioCodec = "aac" | "opus"; and import
Mp4AudioCodec from the muxer file, then use Mp4AudioCodec as the type for the
AudioProcessor.targetCodec and the constructor parameter (i.e. update references
to TargetAudioCodec to Mp4AudioCodec in class AudioProcessor) so both modules
share the same single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/exporter/videoExporter.ts`:
- Around line 71-103: pickAudioCodec currently probes only
AudioEncoder.isConfigSupported for AAC/Opus and returns null if no encoder is
supported; update pickAudioCodec to also call AudioDecoder.isConfigSupported
(using the decoded AudioDecoderConfig from demuxer) before probing encoders so
you gate encoding checks on decoder support, and if neither decoder+encoder
combos work return null; then change the hard throw in the export flow that
handles a null audio codec (the error raised when audio cannot be encoded) to a
console.warn and continue the export as video-only so the operation degrades
gracefully instead of failing completely.

---

Nitpick comments:
In `@src/lib/exporter/audioEncoder.ts`:
- Around line 9-17: Replace the locally defined TargetAudioCodec union with the
shared type from the muxer module: remove the export type TargetAudioCodec =
"aac" | "opus"; and import Mp4AudioCodec from the muxer file, then use
Mp4AudioCodec as the type for the AudioProcessor.targetCodec and the constructor
parameter (i.e. update references to TargetAudioCodec to Mp4AudioCodec in class
AudioProcessor) so both modules share the same single source of truth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1f90a6ee-e170-43c7-860a-2fbbcf40521b

📥 Commits

Reviewing files that changed from the base of the PR and between a6ae0e6 and 5a0d3c5.

📒 Files selected for processing (4)
  • src/lib/exporter/audioEncoder.ts
  • src/lib/exporter/muxer.ts
  • src/lib/exporter/videoExporter.ts
  • vitest.config.ts

/* reader already closed */
}
}
await this.processTrimOnlyAudio(demuxer, muxer, [], undefined);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

This makes speed-region exports much heavier in memory.

Line 332 now sends the rendered blob through processTrimOnlyAudio(), and that path buffers the whole track twice: once in decodedFrames and again in encodedChunks before muxing. for longer recordings that's a pretty easy way to balloon memory on top of the already-recorded blob. If re-encode is required here, it'd be safer to stream decode → encode → mux instead of materializing both arrays.

Comment on lines +71 to +103
private async pickAudioCodec(demuxer: WebDemuxer | null): Promise<Mp4AudioCodec | null> {
if (!demuxer) return null;

let audioConfig: AudioDecoderConfig;
try {
audioConfig = (await demuxer.getDecoderConfig("audio")) as AudioDecoderConfig;
} catch {
return null;
}

const sampleRate = audioConfig.sampleRate || 48000;
const channels = audioConfig.numberOfChannels || 2;

const aacConfig: AudioEncoderConfig = {
codec: "mp4a.40.2",
sampleRate,
numberOfChannels: channels,
bitrate: AUDIO_BITRATE,
};
const aacSupport = await AudioEncoder.isConfigSupported(aacConfig);
if (aacSupport.supported) return "aac";

const opusConfig: AudioEncoderConfig = {
codec: "opus",
sampleRate,
numberOfChannels: channels,
bitrate: AUDIO_BITRATE,
};
const opusSupport = await AudioEncoder.isConfigSupported(opusConfig);
if (opusSupport.supported) return "opus";

return null;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "video exporter codec probing:"
rg -n -C3 'pickAudioCodec|AudioEncoder\.isConfigSupported|return "aac"|return "opus"|return null' src/lib/exporter/videoExporter.ts

echo '---'
echo "audio processor decode/encode gates:"
rg -n -C3 'AudioDecoder\.isConfigSupported|Audio codec not supported|Audio encoding not supported' src/lib/exporter/audioEncoder.ts

echo '---'
echo "hard failure on missing audio codec:"
rg -n -C2 'Source has audio, but no supported audio encoder was found for MP4 export' src/lib/exporter/videoExporter.ts

Repository: siddharthvaddem/openscreen

Length of output: 2198


Add decoder gate to pickAudioCodec() and gracefully degrade on audio encode failures.

The codec picker at lines 71–103 only probes AudioEncoder.isConfigSupported() for AAC and Opus, but audioEncoder.ts separately checks AudioDecoder.isConfigSupported() at line 71. If source audio can be decoded (demuxer config parses fine) but can't be encoded to any supported format, pickAudioCodec() returns null at line 102. Then lines 193–196 throw a hard error instead of falling back to video-only export, which tanks the whole operation for files with oddball audio tracks.

Suggested fix:

  • Add AudioDecoder.isConfigSupported() check inside pickAudioCodec() before probing encoders
  • Change the throw at lines 193–196 to console.warn() so export continues without audio
🤖 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 71 - 103, pickAudioCodec
currently probes only AudioEncoder.isConfigSupported for AAC/Opus and returns
null if no encoder is supported; update pickAudioCodec to also call
AudioDecoder.isConfigSupported (using the decoded AudioDecoderConfig from
demuxer) before probing encoders so you gate encoding checks on decoder support,
and if neither decoder+encoder combos work return null; then change the hard
throw in the export flow that handles a null audio codec (the error raised when
audio cannot be encoded) to a console.warn and continue the export as video-only
so the operation degrades gracefully instead of failing completely.

@siddharthvaddem
Copy link
Copy Markdown
Owner

@nguyenducdongdev can you provide a better pr desc

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