@hyperframes/engine 0.8.162 → 0.8.163
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -892,6 +892,7 @@ async function mixThroughMasterBus(tracks, masterChain, outputPath, workDir, tot
|
|
|
892
892
|
export async function processCompositionAudio(elements, baseDir, workDir, outputPath, totalDuration, signal, config, compiledDir) {
|
|
893
893
|
const startMs = Date.now();
|
|
894
894
|
const tracks = [];
|
|
895
|
+
const preparedTracks = new Array(elements.length);
|
|
895
896
|
const failures = [];
|
|
896
897
|
// Grouped members are diverted here instead of `tracks` during element
|
|
897
898
|
// processing, then summed into one processed track per group before the
|
|
@@ -922,7 +923,7 @@ export async function processCompositionAudio(elements, baseDir, workDir, output
|
|
|
922
923
|
else
|
|
923
924
|
signal.addEventListener("abort", () => internalController.abort(), { once: true });
|
|
924
925
|
}
|
|
925
|
-
await Promise.all(elements.map(async (element) => {
|
|
926
|
+
await Promise.all(elements.map(async (element, index) => {
|
|
926
927
|
if (effectiveSignal.aborted) {
|
|
927
928
|
failures.push({
|
|
928
929
|
stage: "cancelled",
|
|
@@ -1097,27 +1098,7 @@ export async function processCompositionAudio(elements, baseDir, workDir, output
|
|
|
1097
1098
|
...(element.fadeOut ? { fadeOut: element.fadeOut } : {}),
|
|
1098
1099
|
...(tailSeconds > 0 ? { tailSeconds } : {}),
|
|
1099
1100
|
};
|
|
1100
|
-
|
|
1101
|
-
// (FX, envelope) exactly like an ungrouped track — it just lands in
|
|
1102
|
-
// the group's bucket instead of the flat list, to be summed into one
|
|
1103
|
-
// processed bus below rather than mixed directly.
|
|
1104
|
-
if (element.groupId) {
|
|
1105
|
-
const bucket = groupTracks.get(element.groupId);
|
|
1106
|
-
if (bucket)
|
|
1107
|
-
bucket.push(track);
|
|
1108
|
-
else
|
|
1109
|
-
groupTracks.set(element.groupId, [track]);
|
|
1110
|
-
if (!groupMeta.has(element.groupId)) {
|
|
1111
|
-
groupMeta.set(element.groupId, {
|
|
1112
|
-
...(element.groupFxChain ? { fxChain: element.groupFxChain } : {}),
|
|
1113
|
-
...(element.groupAutomation ? { automation: element.groupAutomation } : {}),
|
|
1114
|
-
volume: element.groupVolume ?? 1,
|
|
1115
|
-
});
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
else {
|
|
1119
|
-
tracks.push(track);
|
|
1120
|
-
}
|
|
1101
|
+
preparedTracks[index] = track;
|
|
1121
1102
|
}
|
|
1122
1103
|
catch (err) {
|
|
1123
1104
|
// An FX failure is fatal for the whole mix. Every other failure mode
|
|
@@ -1147,6 +1128,30 @@ export async function processCompositionAudio(elements, baseDir, workDir, output
|
|
|
1147
1128
|
}
|
|
1148
1129
|
throw err;
|
|
1149
1130
|
});
|
|
1131
|
+
// FFmpeg's floating-point sum depends on input order. Keep parallel prep,
|
|
1132
|
+
// but assemble flat tracks, group members and groups in authored order.
|
|
1133
|
+
elements.forEach((element, index) => {
|
|
1134
|
+
const track = preparedTracks[index];
|
|
1135
|
+
if (!track)
|
|
1136
|
+
return;
|
|
1137
|
+
if (element.groupId) {
|
|
1138
|
+
const bucket = groupTracks.get(element.groupId);
|
|
1139
|
+
if (bucket)
|
|
1140
|
+
bucket.push(track);
|
|
1141
|
+
else
|
|
1142
|
+
groupTracks.set(element.groupId, [track]);
|
|
1143
|
+
if (!groupMeta.has(element.groupId)) {
|
|
1144
|
+
groupMeta.set(element.groupId, {
|
|
1145
|
+
...(element.groupFxChain ? { fxChain: element.groupFxChain } : {}),
|
|
1146
|
+
...(element.groupAutomation ? { automation: element.groupAutomation } : {}),
|
|
1147
|
+
volume: element.groupVolume ?? 1,
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
else {
|
|
1152
|
+
tracks.push(track);
|
|
1153
|
+
}
|
|
1154
|
+
});
|
|
1150
1155
|
// Never turn a per-track preparation failure into a successful partial mix.
|
|
1151
1156
|
// The producer only surfaces audio failures when `success` is false; mixing
|
|
1152
1157
|
// the remaining tracks made the omitted cue indistinguishable from a valid
|
|
@@ -48,5 +48,5 @@ export declare function ffmpegStatsReader(onStats: (stats: FfmpegStats) => void)
|
|
|
48
48
|
*/
|
|
49
49
|
export declare function formatFfmpegError(exitCode: number | null, stderr: string, tailLines?: number): string;
|
|
50
50
|
/** formatFfmpegError, led by the timeout when this process was killed at its deadline. */
|
|
51
|
-
export declare function describeFfmpegFailure(result: Pick<RunFfmpegResult, "exitCode" | "stderr" | "terminationReason">, timeoutMs: number): string;
|
|
51
|
+
export declare function describeFfmpegFailure(result: Pick<RunFfmpegResult, "exitCode" | "signal" | "stderr" | "terminationReason">, timeoutMs: number): string;
|
|
52
52
|
export declare function runFfmpeg(args: string[], opts?: RunFfmpegOptions): Promise<RunFfmpegResult>;
|
package/dist/utils/runFfmpeg.js
CHANGED
|
@@ -97,10 +97,16 @@ export function formatFfmpegError(exitCode, stderr, tailLines = DEFAULT_STDERR_T
|
|
|
97
97
|
/** formatFfmpegError, led by the timeout when this process was killed at its deadline. */
|
|
98
98
|
export function describeFfmpegFailure(result, timeoutMs) {
|
|
99
99
|
const error = formatFfmpegError(result.exitCode, result.stderr);
|
|
100
|
-
if (result.terminationReason
|
|
100
|
+
if (result.terminationReason === "deadline") {
|
|
101
|
+
return (`FFmpeg timed out after ${timeoutMs} ms (ffmpegProcessTimeout; long renders can raise ` +
|
|
102
|
+
`FFMPEG_PROCESS_TIMEOUT_MS). ${error}`);
|
|
103
|
+
}
|
|
104
|
+
if (result.exitCode !== null)
|
|
101
105
|
return error;
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
const signalOrRequestedStop = result.terminationReason === "exit" ? result.signal : result.terminationReason;
|
|
107
|
+
return signalOrRequestedStop
|
|
108
|
+
? `FFmpeg ended without an exit code (${signalOrRequestedStop}). ${error}`
|
|
109
|
+
: error;
|
|
104
110
|
}
|
|
105
111
|
function spawnFfmpeg(args) {
|
|
106
112
|
// windowsHide: ffmpeg/ffprobe are console-subsystem binaries, so without
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/engine",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.163",
|
|
4
4
|
"description": "Seekable web page to video rendering engine (Puppeteer + FFmpeg)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"linkedom": "^0.18.12",
|
|
51
51
|
"puppeteer": "^25.8.0",
|
|
52
52
|
"puppeteer-core": "^25.8.0",
|
|
53
|
-
"@hyperframes/core": "^0.8.
|
|
54
|
-
"@hyperframes/parsers": "^0.8.
|
|
53
|
+
"@hyperframes/core": "^0.8.163",
|
|
54
|
+
"@hyperframes/parsers": "^0.8.163"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/node": "^25.0.10",
|