mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-27 00:05:39 +00:00
Merge pull request #433 from meiiie/codex/fix-export-duration-mismatch
fix(export): preserve duration with short video-stream metadata
This commit is contained in:
@@ -15,6 +15,7 @@ import type {
|
||||
ZoomTransitionEasing,
|
||||
} from "@/components/video-editor/types";
|
||||
import { extensionHost } from "@/lib/extensions";
|
||||
import { getEffectiveVideoStreamDurationSeconds } from "@/lib/mediaTiming";
|
||||
import { AudioProcessor, isAacAudioEncodingSupported } from "./audioEncoder";
|
||||
import { normalizeLightningRuntimePlatform, shouldPreferNativeAutoBackend } from "./backendPolicy";
|
||||
import { buildEditedTrackSourceSegments, classifyEditedTrackStrategy } from "./editedTrackStrategy";
|
||||
@@ -824,7 +825,12 @@ export class ModernVideoExporter {
|
||||
) {
|
||||
const sourceDurationMs = Math.max(
|
||||
0,
|
||||
Math.round((videoInfo.streamDuration ?? videoInfo.duration) * 1000),
|
||||
Math.round(
|
||||
getEffectiveVideoStreamDurationSeconds({
|
||||
duration: videoInfo.duration,
|
||||
streamDuration: videoInfo.streamDuration,
|
||||
}) * 1000,
|
||||
),
|
||||
);
|
||||
const trimRegions = this.config.trimRegions ?? [];
|
||||
const strategy =
|
||||
@@ -883,7 +889,12 @@ export class ModernVideoExporter {
|
||||
if ((this.config.trimRegions ?? []).length > 0) {
|
||||
const sourceDurationMs = Math.max(
|
||||
0,
|
||||
Math.round((videoInfo.streamDuration ?? videoInfo.duration) * 1000),
|
||||
Math.round(
|
||||
getEffectiveVideoStreamDurationSeconds({
|
||||
duration: videoInfo.duration,
|
||||
streamDuration: videoInfo.streamDuration,
|
||||
}) * 1000,
|
||||
),
|
||||
);
|
||||
const trimSegments = this.buildNativeTrimSegments(sourceDurationMs);
|
||||
if (trimSegments.length === 0) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import type {
|
||||
ZoomRegion,
|
||||
ZoomTransitionEasing,
|
||||
} from "@/components/video-editor/types";
|
||||
import { getEffectiveVideoStreamDurationSeconds } from "@/lib/mediaTiming";
|
||||
import { AudioProcessor, isAacAudioEncodingSupported } from "./audioEncoder";
|
||||
import { buildEditedTrackSourceSegments, classifyEditedTrackStrategy } from "./editedTrackStrategy";
|
||||
import {
|
||||
@@ -551,7 +552,12 @@ export class VideoExporter {
|
||||
) {
|
||||
const sourceDurationMs = Math.max(
|
||||
0,
|
||||
Math.round((videoInfo.streamDuration ?? videoInfo.duration) * 1000),
|
||||
Math.round(
|
||||
getEffectiveVideoStreamDurationSeconds({
|
||||
duration: videoInfo.duration,
|
||||
streamDuration: videoInfo.streamDuration,
|
||||
}) * 1000,
|
||||
),
|
||||
);
|
||||
const trimRegions = this.config.trimRegions ?? [];
|
||||
const strategy =
|
||||
@@ -610,7 +616,12 @@ export class VideoExporter {
|
||||
if ((this.config.trimRegions ?? []).length > 0) {
|
||||
const sourceDurationMs = Math.max(
|
||||
0,
|
||||
Math.round((videoInfo.streamDuration ?? videoInfo.duration) * 1000),
|
||||
Math.round(
|
||||
getEffectiveVideoStreamDurationSeconds({
|
||||
duration: videoInfo.duration,
|
||||
streamDuration: videoInfo.streamDuration,
|
||||
}) * 1000,
|
||||
),
|
||||
);
|
||||
const trimSegments = this.buildNativeTrimSegments(sourceDurationMs);
|
||||
if (trimSegments.length === 0) {
|
||||
|
||||
@@ -111,6 +111,15 @@ describe("getEffectiveVideoStreamDurationSeconds", () => {
|
||||
).toBe(11.2);
|
||||
});
|
||||
|
||||
it("uses the container duration when the video stream is much shorter", () => {
|
||||
expect(
|
||||
getEffectiveVideoStreamDurationSeconds({
|
||||
duration: 60,
|
||||
streamDuration: 40,
|
||||
}),
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it("falls back to the container duration when stream duration is missing", () => {
|
||||
expect(
|
||||
getEffectiveVideoStreamDurationSeconds({
|
||||
|
||||
+21
-4
@@ -81,12 +81,29 @@ export function getEffectiveVideoStreamDurationSeconds({
|
||||
duration?: number | null;
|
||||
streamDuration?: number | null;
|
||||
}): number {
|
||||
if (Number.isFinite(streamDuration) && (streamDuration ?? 0) > 0) {
|
||||
return Math.max(0, streamDuration ?? 0);
|
||||
const safeDuration =
|
||||
Number.isFinite(duration) && (duration ?? 0) > 0 ? Math.max(0, duration ?? 0) : 0;
|
||||
const safeStreamDuration =
|
||||
Number.isFinite(streamDuration) && (streamDuration ?? 0) > 0
|
||||
? Math.max(0, streamDuration ?? 0)
|
||||
: 0;
|
||||
|
||||
if (safeDuration > 0 && safeStreamDuration > 0) {
|
||||
const gapSeconds = safeDuration - safeStreamDuration;
|
||||
const largeMismatchThresholdSeconds = Math.max(2, safeDuration * 0.1);
|
||||
if (gapSeconds > largeMismatchThresholdSeconds) {
|
||||
return safeDuration;
|
||||
}
|
||||
|
||||
return safeStreamDuration;
|
||||
}
|
||||
|
||||
if (Number.isFinite(duration) && (duration ?? 0) > 0) {
|
||||
return Math.max(0, duration ?? 0);
|
||||
if (safeStreamDuration > 0) {
|
||||
return safeStreamDuration;
|
||||
}
|
||||
|
||||
if (safeDuration > 0) {
|
||||
return safeDuration;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user