diff --git a/flow-state/src/export/Exporter.js b/flow-state/src/export/Exporter.js index fdf739c..ef137cc 100644 --- a/flow-state/src/export/Exporter.js +++ b/flow-state/src/export/Exporter.js @@ -123,18 +123,24 @@ async function pickVideoConfig(width, height, bitrate, fps) { const config = { codec: cand.codec, width, height, bitrate, framerate: fps }; if (cand.avc) config.avc = cand.avc; let supported = false; + let negotiatedConfig = null; let negotiatedHardware = ''; try { const sup = await VideoEncoder.isConfigSupported(config); supported = !!sup.supported; - negotiatedHardware = sup.config ? sup.config.hardwareAcceleration || '' : ''; + negotiatedConfig = sup.config || null; + negotiatedHardware = negotiatedConfig ? negotiatedConfig.hardwareAcceleration || '' : ''; } catch { supported = false; } attempted.push(`${family.muxerCodec}:${cand.codec}=${supported ? 'ok' : 'no'}`); if (!supported) continue; - // Found a supported profile — does it reorder? Baseline AVC never does; - // VP9/AV1 may, so we enforce the same test. - if (await emitsInPresentationOrder(config)) { - return { config, muxerCodec: family.muxerCodec, hardwareAcceleration: negotiatedHardware }; + // Use the browser-negotiated config when available — it is guaranteed + // to satisfy VideoEncoderConfig validation (required fields, avc + // shape, etc). Chrome has started rejecting our minimal config with + // "not of type VideoEncoderConfig" even though isConfigSupported said + // "supported", while the negotiated config it returned configures fine. + const configToTest = negotiatedConfig || config; + if (await emitsInPresentationOrder(configToTest)) { + return { config: configToTest, muxerCodec: family.muxerCodec, hardwareAcceleration: negotiatedHardware }; } reorderFailures.push(`${cand.codec}`); } @@ -160,6 +166,7 @@ export async function probeExportCodec(width, height, bitrate, fps = 60) { const picked = await pickVideoConfig(width, height, bitrate, fps); if (!picked) return null; return { + config: picked.config, codec: picked.config.codec, muxerCodec: picked.muxerCodec, hardwareAcceleration: picked.hardwareAcceleration || '', diff --git a/flow-state/src/main.js b/flow-state/src/main.js index 5b2fab9..535808d 100644 --- a/flow-state/src/main.js +++ b/flow-state/src/main.js @@ -658,7 +658,7 @@ async function runExport(segment) { const exporter = new Exporter(state.show); const blob = segment ? await exportSegment(state.show, state.show.timeline.frame, - { seconds: 20, preset, onProgress: exportProgress, exporter }) + { seconds: 20, preset, onProgress: exportProgress, exporter, videoPick: pick }) : await exporter.export({ preset, onProgress: exportProgress, videoPick: pick }); const suffix = segment ? `-segment-${state.show.timeline.frame}` : '';