Skip to content

fix(export): fast-path simple edited audio tracks#297

Merged
webadderall merged 5 commits into
webadderallorg:mainfrom
meiiie:fix/export-edited-track-filtergraph
Apr 22, 2026
Merged

fix(export): fast-path simple edited audio tracks#297
webadderall merged 5 commits into
webadderallorg:mainfrom
meiiie:fix/export-edited-track-filtergraph

Conversation

@meiiie
Copy link
Copy Markdown
Collaborator

@meiiie meiiie commented Apr 20, 2026

Description

Add a native FFmpeg fast path for simple edited-track exports so the app does not always fall back to offline Web Audio rendering for embedded-source trim/speed edits.

Motivation

Long exports that land in edited-track still spend a noticeable amount of time in audio finalization even when the edit is only trim/speed on the original embedded audio track. This PR narrows that case to a conservative native filtergraph path while preserving the existing fallback for more complex mixes.

Type of Change

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

Related Issue(s)

Screenshots / Video

N/A. This changes the export path rather than the visible editor UI.

Testing Guide

  • npx vitest --run src/lib/exporter/editedTrackStrategy.test.ts electron/ipc/nativeVideoExport.test.ts
  • node ./node_modules/typescript/bin/tsc --noEmit
  • npx vite build
  • Manual Windows smoke export on a real 4K AAC source using modern + breeze with a 2000:120000:1.5 speed region
    • baseline: 358873 ms
    • patched: 189657 ms
    • finalization: 31722.6 ms -> 25524.2 ms
    • output streams matched in both runs: H.264 + AAC, 214.166667 s, 266231169 bytes

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.

Summary by CodeRabbit

  • New Features

    • Intelligent export strategy for edited audio tracks: fast-path filtergraph or offline-render fallback to speed up exports.
    • Variable-speed audio support and optional audio-source sample-rate handling for more accurate audio edits.
    • Per-segment edit controls (start/end/speed) accepted in export options for precise timing.
  • Tests

    • Added unit tests covering edited-track segment generation and filtergraph behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a filtergraph fast-path for edited-track audio muxing, a classifier and segment builder to choose fast-path vs offline fallback, propagates strategy/segments/sample-rate through exporter and Electron IPC, and includes tests for filterbuilders and strategy logic.

Changes

Cohort / File(s) Summary
IPC types & bridge
electron/electron-env.d.ts, electron/preload.ts
Expose audioSourceSampleRate?, editedTrackStrategy?, and editedTrackSegments? on nativeVideoExportFinish / muxExportedVideoAudio; minor getLocalMediaUrl formatting change.
Electron mux & filter logic
electron/ipc/nativeVideoExport.ts, electron/ipc/export/native-video.ts
Add buildEditedTrackSourceAudioFilter(...); implement filtergraph-fast-path in muxNativeVideoExportAudio that uses -filter_complex and maps [aout]; preserve offline-temp-file fallback; minor signature/formatting tweaks.
Filter builder tests
electron/ipc/nativeVideoExport.test.ts
New Vitest cases validating buildTrimmedSourceAudioFilter and buildEditedTrackSourceAudioFilter outputs and failure modes for invalid segments/sample rates.
Edited-track strategy & segments
src/lib/exporter/editedTrackStrategy.ts, src/lib/exporter/editedTrackStrategy.test.ts
New classifier classifyEditedTrackStrategy and buildEditedTrackSourceSegments producing {startMs,endMs,speed} segments and selecting fast-path only for safe single-source speed-only edits; tests cover acceptance and multiple rejection conditions.
Renderer exporter integration
src/lib/exporter/videoExporter.ts, src/lib/exporter/modernVideoExporter.ts
Extend native audio plan with strategy discriminator; choose between "filtergraph-fast-path" and "offline-render-fallback" via classifier; send editedTrackSegments and audioSourceSampleRate for fast-path; only run offline render when fallback chosen.
Streaming metadata
src/lib/exporter/streamingDecoder.ts
Add optional audioSampleRate?: number parsed from ffprobe sample_rate when available.
FFmpeg args / helpers
electron/ipc/nativeVideoExport.ts
Add exported types for edited-track strategy/segment and refactor H.264 args array formatting (semantic-preserving).

Sequence Diagram

sequenceDiagram
    participant Renderer
    participant Strategy as Strategy<br/>Decision
    participant Exporter as Native<br/>Audio Plan
    participant ElectronMain as Electron<br/>Main
    participant FFmpeg

    rect rgba(200,150,100,0.5)
    Note over Renderer,FFmpeg: Filtergraph Fast-Path
    Renderer->>Strategy: classifyEditedTrackStrategy(input)
    Strategy-->>Renderer: "filtergraph-fast-path" or "offline-render-fallback"
    Renderer->>Exporter: buildNativeAudioPlan()
    Exporter-->>Renderer: Plan (includes editedTrackSegments, audioSourceSampleRate when fast-path)
    Renderer->>ElectronMain: nativeVideoExportFinish({editedTrackStrategy, editedTrackSegments, audioSourceSampleRate})
    ElectronMain->>ElectronMain: buildEditedTrackSourceAudioFilter(segments, sampleRate)
    ElectronMain->>FFmpeg: ffmpeg -i video -i audioSource -filter_complex "[...]" -map 0:v -map [aout]
    FFmpeg-->>ElectronMain: Muxed output
    end

    rect rgba(100,150,200,0.5)
    Note over Renderer,FFmpeg: Offline Render Fallback
    Renderer->>Strategy: classifyEditedTrackStrategy(input)
    Strategy-->>Renderer: "offline-render-fallback"
    Renderer->>Exporter: buildNativeAudioPlan()
    Renderer->>ElectronMain: nativeVideoExportFinish({audioMode: "edited-track"})
    ElectronMain->>ElectronMain: AudioProcessor.renderEditedAudioTrack()
    ElectronMain->>FFmpeg: ffmpeg -i video -i renderedAudio -map 0:v -map 1:a
    FFmpeg-->>ElectronMain: Muxed output
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • webadderall/Recordly#254: Touches the same Electron IPC/native-video export and FFmpeg mux/filtergraph logic; likely overlaps the fast-path/filter changes.
  • webadderall/Recordly#262: Related to offline audio rendering and muxing pipeline that the fallback path uses.
  • webadderall/Recordly#228: Prior IPC and FFmpeg audio-muxing changes that this PR extends with edited-track strategy.

Poem

🐇 I stitched the segments, trimmed with care,
Fast-path hops where temp files once were there,
Filters hum, labels line the way,
Fallback waits if timings stray,
A rabbit's hop — clean audio for the day.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(export): fast-path simple edited audio tracks' clearly summarizes the main change: adding a native FFmpeg fast path for simple edited-track exports, which directly aligns with the changeset's primary objective.
Description check ✅ Passed The PR description covers all required template sections: Description (purpose clearly stated), Motivation (problem explained), Type of Change (Bug Fix selected), Related Issues (#221, #194 linked), Testing Guide (comprehensive), and Checklist (all items marked complete). All critical sections are present and adequately filled out.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

This was referenced Apr 20, 2026
@meiiie meiiie marked this pull request as ready for review April 20, 2026 17:25
Copy link
Copy Markdown
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
electron/ipc/export/native-video.ts (1)

383-403: ⚠️ Potential issue | 🟠 Major

Validate the fast-path audio source before returning early.

When editedTrackStrategy === "filtergraph-fast-path" but audioSourcePath is missing, Line 401 returns the video unchanged, silently dropping edited-track audio. Fast-path requests should fail before the generic !audioInputPath early return.

Proposed fix
 	let audioInputPath = options.audioSourcePath ?? null;
 	const useEditedTrackFiltergraph =
 		audioMode === "edited-track" && options.editedTrackStrategy === "filtergraph-fast-path";
 
 	if (audioMode === "edited-track" && !useEditedTrackFiltergraph) {
 		if (!options.editedAudioData) {
 			throw new Error("Edited audio data is missing for native export");
 		}
@@
 		await fs.writeFile(audioInputPath, Buffer.from(options.editedAudioData));
 		tempArtifacts.push(audioInputPath);
 	}
 
+	if (useEditedTrackFiltergraph && !audioInputPath) {
+		throw new Error("Edited-track source audio path is missing for native export");
+	}
+
 	if (!audioInputPath) {
 		return videoPath;
 	}

Also applies to: 428-436

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

In `@electron/ipc/export/native-video.ts` around lines 383 - 403, When using the
fast-path (useEditedTrackFiltergraph true) we must fail if there is no audio
source instead of falling through to the generic early return; before the
generic `if (!audioInputPath) { return videoPath; }` add a check that if
`useEditedTrackFiltergraph` (or equivalently `options.editedTrackStrategy ===
"filtergraph-fast-path"` and `audioMode === "edited-track"`) and
`!audioInputPath` then throw a clear Error (e.g., "Fast-path edited-track export
requires an audio source"); apply the same validation in the other similar block
(the later edited-track handling around lines 428-436) so fast-path requests
never silently drop audio.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@electron/ipc/nativeVideoExport.ts`:
- Around line 165-193: buildEditedTrackSourceAudioFilter currently lets
malformed parameters generate invalid FFmpeg filters; update it to reject bad
inputs by returning null: verify sourceSampleRate is finite and after
Math.round(normalized) is >= 1 (reject if normalizedSourceSampleRate < 1); for
each segment ensure segment.startMs and segment.endMs are finite numbers and
that (endMs - startMs) > 0.5; require segment.speed to be Number.isFinite and >
0 (do not silently default to 1) and return null if any segment has invalid
speed; use formatFfmpegSeconds only after these checks. Reference:
buildEditedTrackSourceAudioFilter, segments array items, sourceSampleRate,
formatFfmpegSeconds.

In `@src/lib/exporter/editedTrackStrategy.ts`:
- Around line 23-31: The fast-path check currently only verifies region.speed
via isSafeFiltergraphSpeed and hasSafeFiltergraphSpeedRegions; update these
validations to also require finite, well-formed timeline bounds: ensure
sourceDurationMs is finite, >0, and that each SpeedRegion has finite startMs and
endMs with 0 <= startMs < endMs <= sourceDurationMs; if any of these fail, treat
as unsafe and fall back from the fast path. Modify or add checks around
isSafeFiltergraphSpeed, hasSafeFiltergraphSpeedRegions, and the fast-path opt-in
logic in editedTrackStrategy to incorporate these bounds checks so
open-ended/infinite durations or regions prevent selecting the fast path.

---

Outside diff comments:
In `@electron/ipc/export/native-video.ts`:
- Around line 383-403: When using the fast-path (useEditedTrackFiltergraph true)
we must fail if there is no audio source instead of falling through to the
generic early return; before the generic `if (!audioInputPath) { return
videoPath; }` add a check that if `useEditedTrackFiltergraph` (or equivalently
`options.editedTrackStrategy === "filtergraph-fast-path"` and `audioMode ===
"edited-track"`) and `!audioInputPath` then throw a clear Error (e.g.,
"Fast-path edited-track export requires an audio source"); apply the same
validation in the other similar block (the later edited-track handling around
lines 428-436) so fast-path requests never silently drop audio.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 734600c9-96b4-4f8e-abef-913e7d29bd1a

📥 Commits

Reviewing files that changed from the base of the PR and between 7494c90 and 0989929.

📒 Files selected for processing (10)
  • electron/electron-env.d.ts
  • electron/ipc/export/native-video.ts
  • electron/ipc/nativeVideoExport.test.ts
  • electron/ipc/nativeVideoExport.ts
  • electron/preload.ts
  • src/lib/exporter/editedTrackStrategy.test.ts
  • src/lib/exporter/editedTrackStrategy.ts
  • src/lib/exporter/modernVideoExporter.ts
  • src/lib/exporter/streamingDecoder.ts
  • src/lib/exporter/videoExporter.ts

Comment thread electron/ipc/nativeVideoExport.ts
Comment thread src/lib/exporter/editedTrackStrategy.ts
Copy link
Copy Markdown
Contributor

@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 (2)
src/lib/exporter/editedTrackStrategy.ts (2)

54-81: Consider validating trimRegions bounds alongside speedRegions.

buildKeptRanges trusts trimRegion.startMs/endMs to be finite numbers, but unlike speedRegions they're never checked. A non-finite or negative entry propagates through Math.max/Math.min as NaN, which in turn corrupts cursorMs and the kept-range set. In practice this currently degrades gracefully (segments come out empty, so classifyEditedTrackStrategy falls back to offline render), but it's silent — a malformed trim region takes the fast path off the table without any signal. A cheap finiteness/ordering guard (either reject the whole fast path like hasSafeFiltergraphSpeedRegions does, or skip individual malformed trims) would make the behavior explicit and match the validation rigor already applied to speed regions.

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

In `@src/lib/exporter/editedTrackStrategy.ts` around lines 54 - 81,
buildKeptRanges currently assumes trimRegion.startMs/endMs are finite and
ordered which can produce NaN and corrupt kept ranges; add validation like
hasSafeFiltergraphSpeedRegions: for each trimRegion in buildKeptRanges check
Number.isFinite(startMs) and Number.isFinite(endMs), enforce startMs < endMs,
and clamp to [0, sourceDurationMs]; either skip individual malformed entries (so
they don't pollute cursorMs) or, to be stricter, return an error/empty marker to
force the slow path in classifyEditedTrackStrategy; reference the
buildKeptRanges function and trimRegions array when adding these guards.

125-131: First-match speed lookup silently hides overlapping speedRegions.

speedRegions.find(...) picks the first region containing the midpoint, so if two regions overlap (same midpoint covered), the later one is silently ignored rather than rejected. Since the fast path is opt-in and correctness-critical, consider either (a) rejecting overlapping speed regions in hasSafeFiltergraphSpeedRegions / buildEditedTrackSourceSegments and falling back, or (b) asserting at most one match here and returning [] otherwise. Low likelihood in normal UI flows, but worth hardening given silent incorrect audio would be hard to diagnose.

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

In `@src/lib/exporter/editedTrackStrategy.ts` around lines 125 - 131, The current
first-match lookup for speedRegions in buildEditedTrackSourceSegments (using
speedRegions.find with midpointMs) silently ignores overlapping regions; update
the logic to detect multiple matches for a given midpointMs and harden behavior:
either (a) add an explicit overlap check earlier (e.g., in
hasSafeFiltergraphSpeedRegions or a new validateSpeedRegions helper) that
rejects/returns false when any two speedRegions overlap so
buildEditedTrackSourceSegments never encounters ambiguous matches, or (b) in
buildEditedTrackSourceSegments assert there is at most one matching region for
midpointMs (by using filter to collect matches) and if matches.length !== 1
treat it as a failure (return []), ensuring you still call
isSafeFiltergraphSpeed and handle non-safe speeds the same way; reference
symbols: speedRegions, midpointMs, buildEditedTrackSourceSegments,
hasSafeFiltergraphSpeedRegions, isSafeFiltergraphSpeed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@electron/ipc/nativeVideoExport.ts`:
- Around line 205-215: The multiplication normalizedSourceSampleRate * speed can
produce NaN/Infinity or an integer outside JS safe range before pushing asetrate
into segmentFilter, so validate adjustedSampleRate after computing it in the
block that handles Math.abs(speed - 1) > 0.0001: ensure it's finite,
Number.isSafeInteger(adjustedSampleRate) (or round then check), and >= 1; if the
check fails set hasInvalidSegment = true and return (same behavior as the
current <1 guard) to avoid emitting an invalid asetrate; reference the
adjustedSampleRate, normalizedSourceSampleRate, speed, segmentFilter and
hasInvalidSegment symbols.
- Around line 182-201: Add a validation step inside the segments.forEach loop to
reject negative timestamps before building the atrim filter: check if
segment.startMs < 0 || segment.endMs < 0 and if so set hasInvalidSegment = true
and return (skip that segment), and ensure the surrounding exported function
returns null when hasInvalidSegment is true (so malformed input is rejected).
Place this check before constructing the segmentFilter (near the existing
Number.isFinite and duration checks) and reference the existing symbols
segments, hasInvalidSegment, formatFfmpegSeconds, and the atrim filter builder
so the invalid negatives never reach the atrim invocation.

---

Nitpick comments:
In `@src/lib/exporter/editedTrackStrategy.ts`:
- Around line 54-81: buildKeptRanges currently assumes trimRegion.startMs/endMs
are finite and ordered which can produce NaN and corrupt kept ranges; add
validation like hasSafeFiltergraphSpeedRegions: for each trimRegion in
buildKeptRanges check Number.isFinite(startMs) and Number.isFinite(endMs),
enforce startMs < endMs, and clamp to [0, sourceDurationMs]; either skip
individual malformed entries (so they don't pollute cursorMs) or, to be
stricter, return an error/empty marker to force the slow path in
classifyEditedTrackStrategy; reference the buildKeptRanges function and
trimRegions array when adding these guards.
- Around line 125-131: The current first-match lookup for speedRegions in
buildEditedTrackSourceSegments (using speedRegions.find with midpointMs)
silently ignores overlapping regions; update the logic to detect multiple
matches for a given midpointMs and harden behavior: either (a) add an explicit
overlap check earlier (e.g., in hasSafeFiltergraphSpeedRegions or a new
validateSpeedRegions helper) that rejects/returns false when any two
speedRegions overlap so buildEditedTrackSourceSegments never encounters
ambiguous matches, or (b) in buildEditedTrackSourceSegments assert there is at
most one matching region for midpointMs (by using filter to collect matches) and
if matches.length !== 1 treat it as a failure (return []), ensuring you still
call isSafeFiltergraphSpeed and handle non-safe speeds the same way; reference
symbols: speedRegions, midpointMs, buildEditedTrackSourceSegments,
hasSafeFiltergraphSpeedRegions, isSafeFiltergraphSpeed.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bed4b9e9-c747-458f-bf9c-6604beaa46b6

📥 Commits

Reviewing files that changed from the base of the PR and between 0989929 and 8cb5693.

📒 Files selected for processing (4)
  • electron/ipc/nativeVideoExport.test.ts
  • electron/ipc/nativeVideoExport.ts
  • src/lib/exporter/editedTrackStrategy.test.ts
  • src/lib/exporter/editedTrackStrategy.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/exporter/editedTrackStrategy.test.ts
  • electron/ipc/nativeVideoExport.test.ts

Comment thread electron/ipc/nativeVideoExport.ts
Comment thread electron/ipc/nativeVideoExport.ts
Copy link
Copy Markdown
Contributor

@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 (2)
electron/ipc/nativeVideoExport.test.ts (2)

18-32: Assert the complete edited-track graph to cover segment ordering.

The current checks validate the speed-adjusted segment but not the identity-speed segment or concat input order. An exact assertion would better guard the fast-path contract.

🧪 Proposed test tightening
 		const filter = buildEditedTrackSourceAudioFilter(
 			[
 				{ startMs: 0, endMs: 2_000, speed: 1 },
 				{ startMs: 2_000, endMs: 6_000, speed: 1.5 },
 			],
 			44_100,
 		);
 
-		expect(filter).toContain(
-			"[1:a]atrim=start=2.000:end=6.000,asetpts=PTS-STARTPTS,asetrate=66150,aresample=44100[edited_audio_1]",
-		);
-		expect(filter).toContain("concat=n=2:v=0:a=1[aout]");
+		expect(filter).toBe(
+			"[1:a]atrim=start=0.000:end=2.000,asetpts=PTS-STARTPTS[edited_audio_0];" +
+				"[1:a]atrim=start=2.000:end=6.000,asetpts=PTS-STARTPTS,asetrate=66150,aresample=44100[edited_audio_1];" +
+				"[edited_audio_0][edited_audio_1]concat=n=2:v=0:a=1[aout]",
+		);
 	});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@electron/ipc/nativeVideoExport.test.ts` around lines 18 - 32, Replace the
partial contains assertions in the buildEditedTrackSourceAudioFilter test with a
single exact equality assertion that verifies the full generated filter string
(so it includes the first identity-speed segment
[0:a]atrim=start=0.000:end=2.000,asetpts=PTS-STARTPTS[edited_audio_0], the
second speed-shifted segment
[1:a]atrim=start=2.000:end=6.000,asetpts=PTS-STARTPTS,asetrate=66150,aresample=44100[edited_audio_1],
and the concat tail concat=n=2:v=0:a=1[aout]) in the correct order; use
buildEditedTrackSourceAudioFilter as the source and replace the two
expect(...).toContain calls with expect(filter).toEqual(<expected full filter
string>) to lock segment ordering and exact graph shape.

7-16: Pin the trimmed filtergraph, not just the concat suffix.

This builder returns a deterministic filtergraph, so an exact assertion would catch regressions in the trim ranges, labels, and concat inputs that the current toContain would miss.

🧪 Proposed test tightening
 describe("buildTrimmedSourceAudioFilter", () => {
 	it("concatenates trimmed source segments into a single output label", () => {
 		expect(
 			buildTrimmedSourceAudioFilter([
 				{ startMs: 0, endMs: 2_000 },
 				{ startMs: 4_000, endMs: 6_000 },
 			]),
-		).toContain("concat=n=2:v=0:a=1[aout]");
+		).toBe(
+			"[1:a]atrim=start=0.000:end=2.000,asetpts=PTS-STARTPTS[trimmed_audio_0];" +
+				"[1:a]atrim=start=4.000:end=6.000,asetpts=PTS-STARTPTS[trimmed_audio_1];" +
+				"[trimmed_audio_0][trimmed_audio_1]concat=n=2:v=0:a=1[aout]",
+		);
 	});
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@electron/ipc/nativeVideoExport.test.ts` around lines 7 - 16, The test for
buildTrimmedSourceAudioFilter is too loose — replace the toContain assertion
with an exact equality assertion that compares the full deterministic
filtergraph string returned by buildTrimmedSourceAudioFilter for the given
segments; construct an expected string that includes the full trim filters (with
the correct startMs/endMs ranges), the generated labels for each trimmed
segment, the concat input ordering (n=2:v=0:a=1) and the final output label
([aout]) and assert the produced string equals that exact expected string so
regressions in ranges, labels, or input ordering are caught.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@electron/ipc/nativeVideoExport.test.ts`:
- Around line 18-32: Replace the partial contains assertions in the
buildEditedTrackSourceAudioFilter test with a single exact equality assertion
that verifies the full generated filter string (so it includes the first
identity-speed segment
[0:a]atrim=start=0.000:end=2.000,asetpts=PTS-STARTPTS[edited_audio_0], the
second speed-shifted segment
[1:a]atrim=start=2.000:end=6.000,asetpts=PTS-STARTPTS,asetrate=66150,aresample=44100[edited_audio_1],
and the concat tail concat=n=2:v=0:a=1[aout]) in the correct order; use
buildEditedTrackSourceAudioFilter as the source and replace the two
expect(...).toContain calls with expect(filter).toEqual(<expected full filter
string>) to lock segment ordering and exact graph shape.
- Around line 7-16: The test for buildTrimmedSourceAudioFilter is too loose —
replace the toContain assertion with an exact equality assertion that compares
the full deterministic filtergraph string returned by
buildTrimmedSourceAudioFilter for the given segments; construct an expected
string that includes the full trim filters (with the correct startMs/endMs
ranges), the generated labels for each trimmed segment, the concat input
ordering (n=2:v=0:a=1) and the final output label ([aout]) and assert the
produced string equals that exact expected string so regressions in ranges,
labels, or input ordering are caught.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ac0981de-eb1e-4034-996c-3222a3f3a62a

📥 Commits

Reviewing files that changed from the base of the PR and between 8cb5693 and a6d03c1.

📒 Files selected for processing (2)
  • electron/ipc/nativeVideoExport.test.ts
  • electron/ipc/nativeVideoExport.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • electron/ipc/nativeVideoExport.ts

Copy link
Copy Markdown
Contributor

@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)
electron/ipc/nativeVideoExport.test.ts (1)

49-71: Consider adding coverage for slowdown and boundary speeds.

Malformed-input coverage is solid, but the happy-path only exercises speed=1 and speed=1.5. A speed<1 case (e.g., 0.5) would guard against regressions in the asetrate/aresample formula for slowdowns, and an assertion for negative/NaN speed values would round out the rejection set alongside the existing speed=0 and MAX_SAFE_INTEGER cases.

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

In `@electron/ipc/nativeVideoExport.test.ts` around lines 49 - 71, Add test cases
to cover slowdown and additional malformed speeds for
buildEditedTrackSourceAudioFilter: add a successful (happy-path) assertion using
speed < 1 (e.g., 0.5) to verify slowdown handling (ensure it returns a
non-null/expected filter), and extend the malformed-input assertions with
negative and NaN speed values (e.g., speed: -1 and speed: Number.NaN) alongside
the existing 0 and MAX_SAFE_INTEGER checks to ensure those inputs return null;
target the same test block that currently exercises
buildEditedTrackSourceAudioFilter so the new expectations run with the same
sample rate and segment shapes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@electron/ipc/nativeVideoExport.test.ts`:
- Around line 49-71: Add test cases to cover slowdown and additional malformed
speeds for buildEditedTrackSourceAudioFilter: add a successful (happy-path)
assertion using speed < 1 (e.g., 0.5) to verify slowdown handling (ensure it
returns a non-null/expected filter), and extend the malformed-input assertions
with negative and NaN speed values (e.g., speed: -1 and speed: Number.NaN)
alongside the existing 0 and MAX_SAFE_INTEGER checks to ensure those inputs
return null; target the same test block that currently exercises
buildEditedTrackSourceAudioFilter so the new expectations run with the same
sample rate and segment shapes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0d2ebf6e-1858-4035-a608-ec6408764e98

📥 Commits

Reviewing files that changed from the base of the PR and between a6d03c1 and 4fc0ac1.

📒 Files selected for processing (1)
  • electron/ipc/nativeVideoExport.test.ts

@meiiie meiiie force-pushed the fix/export-edited-track-filtergraph branch from d344a83 to 383bde9 Compare April 21, 2026 11:12
@webadderall webadderall merged commit 69c1c45 into webadderallorg:main Apr 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants