mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
fix(producer): audio drops + blank images on FFmpeg 4.x/CORS-restricted origins (#1140)
* fix(engine): remove amix normalize=0 to fix audio on FFmpeg 4.x/6.x amix's normalize=0 option is absent from many FFmpeg builds (e.g. FFmpeg 4.2 on Ubuntu 20.04). When the option is not recognized, FFmpeg fails the entire filter graph initialization, processCompositionAudio returns success:false, and the assembled video has no audio stream. Replace normalize=0 + weights='1...' with the amix default behavior (normalize=true, divides by track count) and multiply the master output gain by the track count to restore the original per-track volumes. The net volume is identical across all FFmpeg versions. Fixes #1136-adjacent: reported as 'audio doesn't play' in rendered MP4. * fix(producer): strip img crossorigin + fix audioExtractor normalize=0 Two follow-up fixes: 1. htmlCompiler: strip crossorigin attribute from <img> elements during compilation. External images (e.g. S3) with crossorigin='anonymous' force CORS-mode requests against the renderer's localhost file server, which S3 rejects → images render blank. Matches the existing video strip at line 261. 2. audioExtractor: same amix normalize=0 bug as audioMixer.ts. The audioExtractor path is used for <video data-has-audio='true'> mixing in the CLI's local render pipeline; on FFmpeg 4.x it would also drop audio silently. Fix: remove normalize=0, compensate with volume=N. * test(engine,producer): pin amix normalize contract + img crossorigin strip - audioMixer.test.ts: assert filter has no normalize=/weights=; add 3-track test confirming compensatedGain = masterGain × N = 3 - htmlCompiler.test.ts: parallel tests for img and video crossorigin strip (covers both elements, not just video)
This commit is contained in:
@@ -398,9 +398,11 @@ async function mixAudioTracks(
|
||||
});
|
||||
|
||||
const mixInputs = tracks.map((_, i) => `[a${i}]`).join("");
|
||||
const weights = tracks.map(() => "1").join(" ");
|
||||
const mixFilter = `${mixInputs}amix=inputs=${tracks.length}:duration=longest:dropout_transition=0:normalize=0:weights='${weights}'[mixed]`;
|
||||
const postMixGainFilter = `[mixed]volume=${masterOutputGain}[out]`;
|
||||
const mixFilter = `${mixInputs}amix=inputs=${tracks.length}:duration=longest:dropout_transition=0[mixed]`;
|
||||
// amix divides output by inputs count (default normalize=true). Multiply master
|
||||
// gain by track count so per-track volumes authored in data-volume are preserved.
|
||||
const compensatedGain = masterOutputGain * tracks.length;
|
||||
const postMixGainFilter = `[mixed]volume=${formatFilterNumber(compensatedGain)}[out]`;
|
||||
const fullFilter = [...filterParts, mixFilter, postMixGainFilter].join(";");
|
||||
|
||||
return [
|
||||
|
||||
Reference in New Issue
Block a user