From 015d46245c636e24cb1ed8db3f3011a11975be84 Mon Sep 17 00:00:00 2001 From: webadderall <131426131+webadderall@users.noreply.github.com> Date: Sat, 4 Apr 2026 13:07:34 +1100 Subject: [PATCH] add export pipeline core types --- src/lib/exporter/mp4Support.ts | 7 ++++ src/lib/exporter/types.ts | 59 ++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/lib/exporter/mp4Support.ts b/src/lib/exporter/mp4Support.ts index c0975cbc..422f76cc 100644 --- a/src/lib/exporter/mp4Support.ts +++ b/src/lib/exporter/mp4Support.ts @@ -1,4 +1,11 @@ export const DEFAULT_MP4_CODEC = "avc1.640033"; +export const MP4_CODEC_FALLBACK_LIST = [ + DEFAULT_MP4_CODEC, + "avc1.4d4033", + "avc1.420033", + "avc1.4d401f", + "avc1.42001f", +] as const; export type SupportedMp4EncoderPath = { codec: string; diff --git a/src/lib/exporter/types.ts b/src/lib/exporter/types.ts index a92d28db..9063c881 100644 --- a/src/lib/exporter/types.ts +++ b/src/lib/exporter/types.ts @@ -4,21 +4,66 @@ export interface ExportConfig { frameRate: number; bitrate: number; codec?: string; + encodingMode?: ExportEncodingMode; + backendPreference?: ExportBackendPreference; + experimentalNativeExport?: boolean; + maxEncodeQueue?: number; + maxDecodeQueue?: number; + maxPendingFrames?: number; + maxInFlightNativeWrites?: number; } +export type ExportRenderBackend = 'webgpu' | 'webgl'; +export type ExportEncodeBackend = 'ffmpeg' | 'webcodecs'; +export type ExportBackendPreference = 'auto' | 'webcodecs' | 'breeze'; +export type ExportPipelineModel = 'modern' | 'legacy'; + export interface ExportProgress { currentFrame: number; totalFrames: number; percentage: number; estimatedTimeRemaining: number; // in seconds + renderFps?: number; + renderBackend?: ExportRenderBackend; + encodeBackend?: ExportEncodeBackend; + encoderName?: string; phase?: 'extracting' | 'finalizing' | 'saving'; // Phase of export renderProgress?: number; // 0-100, progress of GIF rendering phase } +export interface ExportMetrics { + totalElapsedMs: number; + metadataLoadMs?: number; + rendererInitMs?: number; + nativeSessionStartMs?: number; + decodeLoopMs?: number; + frameCallbackMs?: number; + renderFrameMs?: number; + encodeWaitMs?: number; + encodeWaitEvents?: number; + peakEncodeQueueSize?: number; + peakNativeWriteInFlight?: number; + nativeCaptureMs?: number; + nativeWriteMs?: number; + finalizationMs?: number; + frameCount?: number; + renderBackend?: ExportRenderBackend; + encodeBackend?: ExportEncodeBackend; + encoderName?: string; + backpressureProfile?: string; + averageFrameCallbackMs?: number; + averageRenderFrameMs?: number; + averageEncodeWaitMs?: number; + averageNativeCaptureMs?: number; + averageNativeWriteMs?: number; +} + export interface ExportResult { success: boolean; blob?: Blob; + filePath?: string; error?: string; + metrics?: ExportMetrics; } export interface VideoFrameData { @@ -27,8 +72,12 @@ export interface VideoFrameData { duration: number; // in microseconds } +export type ExportEncodingMode = 'fast' | 'balanced' | 'quality'; + export type ExportQuality = 'medium' | 'good' | 'high' | 'source'; +export type ExportMp4FrameRate = 24 | 30 | 60; + // GIF Export Types export type ExportFormat = 'mp4' | 'gif'; @@ -48,10 +97,20 @@ export interface ExportSettings { format: ExportFormat; // MP4 settings quality?: ExportQuality; + encodingMode?: ExportEncodingMode; + mp4FrameRate?: ExportMp4FrameRate; + backendPreference?: ExportBackendPreference; + pipelineModel?: ExportPipelineModel; // GIF settings gifConfig?: GifExportConfig; } +export const MP4_FRAME_RATES: readonly ExportMp4FrameRate[] = [24, 30, 60] as const; + +export function isValidMp4FrameRate(rate: number): rate is ExportMp4FrameRate { + return MP4_FRAME_RATES.includes(rate as ExportMp4FrameRate); +} + export const GIF_SIZE_PRESETS: Record = { medium: { maxHeight: 720, label: 'Medium (720p)' }, large: { maxHeight: 1080, label: 'Large (1080p)' },