@hyperframes/producer 0.9.4 → 0.9.6
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.
- package/dist/distributed.js +230 -120
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +64 -64
- package/dist/index.d.ts +1 -0
- package/dist/index.js +297 -141
- package/dist/public-server.js +58 -9
- package/dist/services/distributed/assemble.d.ts +2 -21
- package/dist/services/distributed/plan.d.ts +3 -2
- package/dist/services/distributed/planV2.d.ts +2 -13
- package/dist/services/distributed/renderSpan.d.ts +2 -1
- package/dist/services/render/planReferenceBackground.d.ts +12 -0
- package/dist/services/render/stages/freezePlan.d.ts +2 -2
- package/dist/services/render/stages/probeStage.d.ts +3 -3
- package/dist/services/renderOrchestrator.d.ts +5 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD7,
|
|
4
|
+
referenceBackgroundResult as referenceBackgroundResult9,
|
|
5
|
+
createReferenceBackgroundRecorder as createReferenceBackgroundRecorder3,
|
|
6
|
+
readReferenceBackground as readReferenceBackground2
|
|
7
|
+
} from "@hyperframes/engine";
|
|
8
|
+
|
|
1
9
|
// src/services/renderOrchestrator.ts
|
|
2
10
|
import { audioFailureDiagnostics as audioFailureDiagnostics2 } from "@hyperframes/engine";
|
|
3
11
|
import {
|
|
@@ -56,6 +64,10 @@ import {
|
|
|
56
64
|
augmentProtocolTimeoutError,
|
|
57
65
|
augmentPageNavigationTimeoutError
|
|
58
66
|
} from "@hyperframes/engine";
|
|
67
|
+
import {
|
|
68
|
+
referenceBackgroundResult,
|
|
69
|
+
createReferenceBackgroundRecorder
|
|
70
|
+
} from "@hyperframes/engine";
|
|
59
71
|
import { join as join28, dirname as dirname12, resolve as resolve8 } from "path";
|
|
60
72
|
import { totalmem as totalmem2 } from "node:os";
|
|
61
73
|
import { randomUUID } from "crypto";
|
|
@@ -8801,6 +8813,7 @@ async function runProbeStage(input) {
|
|
|
8801
8813
|
const motionBlur = job.config.motionBlur;
|
|
8802
8814
|
const captureFormat = resolveCaptureImageFormat({ needsAlpha, motionBlur });
|
|
8803
8815
|
const captureOpts = {
|
|
8816
|
+
recordReferenceBackground: input.recordReferenceBackground,
|
|
8804
8817
|
width,
|
|
8805
8818
|
height,
|
|
8806
8819
|
fps: job.config.fps,
|
|
@@ -12479,6 +12492,17 @@ function applyRenderWarningPolicy(job, captureWarnings, log = defaultLogger) {
|
|
|
12479
12492
|
throw new RenderQualityError(job.warnings);
|
|
12480
12493
|
}
|
|
12481
12494
|
}
|
|
12495
|
+
var stopPrepSessionOnScriptFailure = (options) => ({
|
|
12496
|
+
...options,
|
|
12497
|
+
onSubTimelineScriptFailure: () => {
|
|
12498
|
+
throw new Error("a composition script failed, so this preparation session stops");
|
|
12499
|
+
}
|
|
12500
|
+
});
|
|
12501
|
+
var surfaceScriptFailure = (error, job) => error instanceof RenderQualityError || error instanceof RenderCancelledError || !job.warnings?.some((warning) => warning.code === "sub_timeline_script_failure") ? error : new RenderQualityError(job.warnings);
|
|
12502
|
+
var withScriptFailureStop = (options, job, log) => ({
|
|
12503
|
+
...options,
|
|
12504
|
+
onSubTimelineScriptFailure: (warnings) => applyRenderWarningPolicy(job, warnings, log)
|
|
12505
|
+
});
|
|
12482
12506
|
var RenderCancelledError = class extends Error {
|
|
12483
12507
|
reason;
|
|
12484
12508
|
constructor(message = "render_cancelled", reason = "aborted") {
|
|
@@ -12846,6 +12870,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
|
|
|
12846
12870
|
}
|
|
12847
12871
|
function createRenderJob(config) {
|
|
12848
12872
|
return {
|
|
12873
|
+
...referenceBackgroundResult(void 0),
|
|
12849
12874
|
id: randomUUID(),
|
|
12850
12875
|
config: {
|
|
12851
12876
|
...config,
|
|
@@ -13611,6 +13636,9 @@ async function executeRenderPipeline(input) {
|
|
|
13611
13636
|
cfg.protocolTimeout = scaledProtocolTimeout;
|
|
13612
13637
|
updateCaptureObservability({ protocolTimeoutMs: scaledProtocolTimeout });
|
|
13613
13638
|
}
|
|
13639
|
+
const recordReferenceBackground = createReferenceBackgroundRecorder(
|
|
13640
|
+
(result) => Object.assign(job, result)
|
|
13641
|
+
);
|
|
13614
13642
|
const subTimelineWaitMemo = {};
|
|
13615
13643
|
const probeResult = await observeRenderStage(
|
|
13616
13644
|
observability,
|
|
@@ -13631,7 +13659,8 @@ async function executeRenderPipeline(input) {
|
|
|
13631
13659
|
height,
|
|
13632
13660
|
needsAlpha,
|
|
13633
13661
|
deviceScaleFactor,
|
|
13634
|
-
subTimelineWaitMemo
|
|
13662
|
+
subTimelineWaitMemo,
|
|
13663
|
+
recordReferenceBackground
|
|
13635
13664
|
}),
|
|
13636
13665
|
// Browser probe is pre-capture; report `browser calibrating` so a
|
|
13637
13666
|
// slow probe (~64s SwiftShader warm-up on Windows was the reported
|
|
@@ -13887,6 +13916,7 @@ async function executeRenderPipeline(input) {
|
|
|
13887
13916
|
let routePageMotionBlur;
|
|
13888
13917
|
const buildCaptureOptions = () => ({
|
|
13889
13918
|
...captureOptions,
|
|
13919
|
+
recordReferenceBackground,
|
|
13890
13920
|
...routePageMotionBlur ? { pageMotionBlur: routePageMotionBlur } : {},
|
|
13891
13921
|
videoMetadataHints,
|
|
13892
13922
|
skipReadinessVideoIds: videoReadinessSkipIds,
|
|
@@ -13919,6 +13949,8 @@ async function executeRenderPipeline(input) {
|
|
|
13919
13949
|
});
|
|
13920
13950
|
}
|
|
13921
13951
|
});
|
|
13952
|
+
const buildPrepCaptureOptions = () => stopPrepSessionOnScriptFailure(buildCaptureOptions());
|
|
13953
|
+
const buildWorkerCaptureOptions = () => withScriptFailureStop(buildCaptureOptions(), job, log);
|
|
13922
13954
|
const createRenderVideoFrameInjector = () => createVideoFrameInjector(frameLookup, frameCacheOptions(cfg, workerCount));
|
|
13923
13955
|
let captureCalibration;
|
|
13924
13956
|
const htmlInCanvasDetected = compiled.renderModeHints.reasons.some(
|
|
@@ -14022,7 +14054,7 @@ async function executeRenderPipeline(input) {
|
|
|
14022
14054
|
probeSession = await createCaptureSession8(
|
|
14023
14055
|
activeFileServer.url,
|
|
14024
14056
|
framesDir,
|
|
14025
|
-
|
|
14057
|
+
buildPrepCaptureOptions(),
|
|
14026
14058
|
null,
|
|
14027
14059
|
{ ...cfg, forceScreenshot: captureForceScreenshot }
|
|
14028
14060
|
);
|
|
@@ -14105,7 +14137,7 @@ async function executeRenderPipeline(input) {
|
|
|
14105
14137
|
totalFrames,
|
|
14106
14138
|
forceScreenshot: captureForceScreenshot,
|
|
14107
14139
|
probeSession,
|
|
14108
|
-
buildCaptureOptions,
|
|
14140
|
+
buildCaptureOptions: buildPrepCaptureOptions,
|
|
14109
14141
|
createRenderVideoFrameInjector,
|
|
14110
14142
|
assertNotAborted
|
|
14111
14143
|
}),
|
|
@@ -14577,7 +14609,7 @@ async function executeRenderPipeline(input) {
|
|
|
14577
14609
|
effectiveBitrate,
|
|
14578
14610
|
deliveryEncoder,
|
|
14579
14611
|
fileServer: activeFileServer,
|
|
14580
|
-
buildCaptureOptions,
|
|
14612
|
+
buildCaptureOptions: buildWorkerCaptureOptions,
|
|
14581
14613
|
createRenderVideoFrameInjector,
|
|
14582
14614
|
hdrDiagnostics,
|
|
14583
14615
|
abortSignal: attempt,
|
|
@@ -14695,7 +14727,7 @@ async function executeRenderPipeline(input) {
|
|
|
14695
14727
|
// Each segment sets its own GOP (at most the interval); hls never reaches this route.
|
|
14696
14728
|
...deliveryEncoder
|
|
14697
14729
|
},
|
|
14698
|
-
buildCaptureOptions,
|
|
14730
|
+
buildCaptureOptions: buildWorkerCaptureOptions,
|
|
14699
14731
|
createRenderVideoFrameInjector,
|
|
14700
14732
|
abortSignal: executionSignal,
|
|
14701
14733
|
assertNotAborted,
|
|
@@ -14843,7 +14875,7 @@ async function executeRenderPipeline(input) {
|
|
|
14843
14875
|
// encoder's open-GOP output untouched.
|
|
14844
14876
|
...deliveryEncoder
|
|
14845
14877
|
},
|
|
14846
|
-
buildCaptureOptions,
|
|
14878
|
+
buildCaptureOptions: buildWorkerCaptureOptions,
|
|
14847
14879
|
createRenderVideoFrameInjector,
|
|
14848
14880
|
abortSignal: executionSignal,
|
|
14849
14881
|
assertNotAborted,
|
|
@@ -15028,7 +15060,7 @@ async function executeRenderPipeline(input) {
|
|
|
15028
15060
|
probeSession,
|
|
15029
15061
|
captureAttempts,
|
|
15030
15062
|
dedupPerfs,
|
|
15031
|
-
buildCaptureOptions,
|
|
15063
|
+
buildCaptureOptions: buildWorkerCaptureOptions,
|
|
15032
15064
|
createRenderVideoFrameInjector,
|
|
15033
15065
|
abortSignal: executionSignal,
|
|
15034
15066
|
assertNotAborted,
|
|
@@ -15261,7 +15293,7 @@ async function executeRenderPipeline(input) {
|
|
|
15261
15293
|
await eventPublisher.flush();
|
|
15262
15294
|
} catch (caught) {
|
|
15263
15295
|
await pendingAudio;
|
|
15264
|
-
const error = tooSlowError ?? caught;
|
|
15296
|
+
const error = surfaceScriptFailure(tooSlowError ?? caught, job);
|
|
15265
15297
|
if (!tooSlowError && (error instanceof RenderCancelledError || executionSignal?.aborted)) {
|
|
15266
15298
|
job.error = error instanceof Error ? error.message : "render_cancelled";
|
|
15267
15299
|
updateJobStatus(job, "cancelled", "Render cancelled", job.progress, onProgress);
|
|
@@ -15353,8 +15385,12 @@ async function executeRenderPipeline(input) {
|
|
|
15353
15385
|
}
|
|
15354
15386
|
|
|
15355
15387
|
// src/services/distributed/renderSpan.ts
|
|
15388
|
+
import {
|
|
15389
|
+
REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD4,
|
|
15390
|
+
referenceBackgroundResult as referenceBackgroundResult6
|
|
15391
|
+
} from "@hyperframes/engine";
|
|
15356
15392
|
import { mkdirSync as mkdirSync18, mkdtempSync as mkdtempSync7, readFileSync as readFileSync13, rmSync as rmSync16 } from "node:fs";
|
|
15357
|
-
import { join as
|
|
15393
|
+
import { join as join42 } from "node:path";
|
|
15358
15394
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
15359
15395
|
|
|
15360
15396
|
// src/services/distributed/mp4Stitch.ts
|
|
@@ -15741,6 +15777,11 @@ async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
|
|
|
15741
15777
|
}
|
|
15742
15778
|
|
|
15743
15779
|
// src/services/distributed/plan.ts
|
|
15780
|
+
import {
|
|
15781
|
+
REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD2,
|
|
15782
|
+
referenceBackgroundResult as referenceBackgroundResult4,
|
|
15783
|
+
createReferenceBackgroundRecorder as createReferenceBackgroundRecorder2
|
|
15784
|
+
} from "@hyperframes/engine";
|
|
15744
15785
|
import { audioFailureDiagnostics as audioFailureDiagnostics3 } from "@hyperframes/engine";
|
|
15745
15786
|
import {
|
|
15746
15787
|
copyFileSync as copyFileSync6,
|
|
@@ -15751,7 +15792,7 @@ import {
|
|
|
15751
15792
|
rmSync as rmSync12,
|
|
15752
15793
|
writeFileSync as writeFileSync9
|
|
15753
15794
|
} from "node:fs";
|
|
15754
|
-
import { extname as extname6, isAbsolute as isAbsolute3, join as
|
|
15795
|
+
import { extname as extname6, isAbsolute as isAbsolute3, join as join37, relative as relative5, sep as sep2 } from "node:path";
|
|
15755
15796
|
import {
|
|
15756
15797
|
fpsToNumber as fpsToNumber9,
|
|
15757
15798
|
HF_COLOR_GRADING_ATTR as HF_COLOR_GRADING_ATTR2
|
|
@@ -16396,9 +16437,69 @@ function buildWeightedChunkSlices(weights, chunkCount, minFrames, maxFrames) {
|
|
|
16396
16437
|
return slices;
|
|
16397
16438
|
}
|
|
16398
16439
|
|
|
16440
|
+
// src/services/render/planReferenceBackground.ts
|
|
16441
|
+
import { join as join33 } from "node:path";
|
|
16442
|
+
import {
|
|
16443
|
+
closeCaptureSession as closeCaptureSession10,
|
|
16444
|
+
createCaptureSession as createCaptureSession10,
|
|
16445
|
+
readReferenceBackground,
|
|
16446
|
+
referenceBackgroundResult as referenceBackgroundResult2
|
|
16447
|
+
} from "@hyperframes/engine";
|
|
16448
|
+
async function readPlanReferenceBackground(input) {
|
|
16449
|
+
let server;
|
|
16450
|
+
let session;
|
|
16451
|
+
try {
|
|
16452
|
+
server = await createFileServer({
|
|
16453
|
+
projectDir: input.projectDir,
|
|
16454
|
+
compiledDir: join33(input.workDir, "compiled"),
|
|
16455
|
+
port: 0,
|
|
16456
|
+
preHeadScripts: [VIRTUAL_TIME_SHIM],
|
|
16457
|
+
fps: input.options.fps
|
|
16458
|
+
});
|
|
16459
|
+
session = await createCaptureSession10(
|
|
16460
|
+
server.url,
|
|
16461
|
+
join33(input.workDir, "reference"),
|
|
16462
|
+
{
|
|
16463
|
+
...input.options,
|
|
16464
|
+
requiresWebGpu: false
|
|
16465
|
+
},
|
|
16466
|
+
null,
|
|
16467
|
+
{
|
|
16468
|
+
...input.cfg,
|
|
16469
|
+
forceScreenshot: true,
|
|
16470
|
+
useDrawElement: false,
|
|
16471
|
+
enablePageSideCompositing: false
|
|
16472
|
+
}
|
|
16473
|
+
);
|
|
16474
|
+
const page = session.page;
|
|
16475
|
+
await page.goto(`${server.url}/index.html`, {
|
|
16476
|
+
waitUntil: "domcontentloaded",
|
|
16477
|
+
timeout: input.cfg.pageNavigationTimeout
|
|
16478
|
+
});
|
|
16479
|
+
await page.evaluate("window.__hfFlushSync?.()");
|
|
16480
|
+
await page.waitForFunction(
|
|
16481
|
+
'!!(window.__hf && typeof window.__hf.seek === "function" && window.__hf.duration > 0)',
|
|
16482
|
+
{ timeout: input.cfg.playerReadyTimeout, polling: 100 }
|
|
16483
|
+
);
|
|
16484
|
+
return referenceBackgroundResult2(await readReferenceBackground(page));
|
|
16485
|
+
} catch (error) {
|
|
16486
|
+
input.log.debug("Reference background unavailable", {
|
|
16487
|
+
error: error instanceof Error ? error.message : String(error)
|
|
16488
|
+
});
|
|
16489
|
+
return referenceBackgroundResult2(void 0);
|
|
16490
|
+
} finally {
|
|
16491
|
+
if (session) await closeCaptureSession10(session).catch(() => void 0);
|
|
16492
|
+
if (server) closeFileServerSafely(server, "reference background", input.log);
|
|
16493
|
+
}
|
|
16494
|
+
}
|
|
16495
|
+
|
|
16399
16496
|
// src/services/render/stages/freezePlan.ts
|
|
16400
16497
|
import { existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync9, readdirSync as readdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
16401
|
-
import { join as
|
|
16498
|
+
import { join as join34, relative as relative3, resolve as resolve9 } from "node:path";
|
|
16499
|
+
import {
|
|
16500
|
+
REFERENCE_BACKGROUND_FIELD,
|
|
16501
|
+
referenceBackgroundResult as referenceBackgroundResult3
|
|
16502
|
+
} from "@hyperframes/engine";
|
|
16402
16503
|
|
|
16403
16504
|
// src/services/distributed/planProtocol.ts
|
|
16404
16505
|
var PLAN_SCHEMA_VERSION = 1;
|
|
@@ -16612,7 +16713,7 @@ function listPlanFiles(planDir) {
|
|
|
16612
16713
|
function walk(dir) {
|
|
16613
16714
|
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
16614
16715
|
for (const entry of entries) {
|
|
16615
|
-
const full =
|
|
16716
|
+
const full = join34(dir, entry.name);
|
|
16616
16717
|
if (entry.isDirectory()) {
|
|
16617
16718
|
walk(full);
|
|
16618
16719
|
} else if (entry.isFile()) {
|
|
@@ -16653,15 +16754,15 @@ var PLAN_REMOTE_FILES_RELATIVE_PATH = "meta/remote-files.json";
|
|
|
16653
16754
|
function writePlanRemoteFiles(planDir, files) {
|
|
16654
16755
|
if (files.length === 0) return;
|
|
16655
16756
|
const sorted = [...files].sort((a, b) => a.path < b.path ? -1 : 1);
|
|
16656
|
-
writeFileSync7(
|
|
16757
|
+
writeFileSync7(join34(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH), JSON.stringify(sorted), "utf-8");
|
|
16657
16758
|
}
|
|
16658
16759
|
function readPlanRemoteFiles(planDir) {
|
|
16659
|
-
const path =
|
|
16760
|
+
const path = join34(planDir, PLAN_REMOTE_FILES_RELATIVE_PATH);
|
|
16660
16761
|
return existsSync21(path) ? JSON.parse(readFileSync9(path, "utf-8")) : [];
|
|
16661
16762
|
}
|
|
16662
16763
|
function recomputePlanHashFromPlanDir(planDir, digests) {
|
|
16663
|
-
const planJsonPath =
|
|
16664
|
-
const encoderJsonPath =
|
|
16764
|
+
const planJsonPath = join34(planDir, "plan.json");
|
|
16765
|
+
const encoderJsonPath = join34(planDir, "meta", "encoder.json");
|
|
16665
16766
|
if (!existsSync21(planJsonPath)) {
|
|
16666
16767
|
throw new Error(`[freezePlan] plan.json missing: ${planJsonPath}`);
|
|
16667
16768
|
}
|
|
@@ -16698,18 +16799,18 @@ async function freezePlan(input) {
|
|
|
16698
16799
|
if (!existsSync21(planDir)) {
|
|
16699
16800
|
throw new Error(`[freezePlan] planDir does not exist: ${planDir}`);
|
|
16700
16801
|
}
|
|
16701
|
-
const metaDir =
|
|
16802
|
+
const metaDir = join34(planDir, "meta");
|
|
16702
16803
|
if (!existsSync21(metaDir)) mkdirSync12(metaDir, { recursive: true });
|
|
16703
16804
|
writeFileSync7(
|
|
16704
|
-
|
|
16805
|
+
join34(metaDir, "composition.json"),
|
|
16705
16806
|
`${JSON.stringify(composition, null, 2)}
|
|
16706
16807
|
`,
|
|
16707
16808
|
"utf-8"
|
|
16708
16809
|
);
|
|
16709
16810
|
const encoderForCanonical = stripUndefined(encoder);
|
|
16710
16811
|
const encoderConfigCanonicalJson = canonicalJsonStringify(encoderForCanonical);
|
|
16711
|
-
writeFileSync7(
|
|
16712
|
-
writeFileSync7(
|
|
16812
|
+
writeFileSync7(join34(metaDir, "encoder.json"), encoderConfigCanonicalJson, "utf-8");
|
|
16813
|
+
writeFileSync7(join34(metaDir, "chunks.json"), `${JSON.stringify(chunks, null, 2)}
|
|
16713
16814
|
`, "utf-8");
|
|
16714
16815
|
const { compositionHtml, assets } = collectPlanAssetShas(planDir, digests);
|
|
16715
16816
|
const planHash = computePlanHash({
|
|
@@ -16722,6 +16823,7 @@ async function freezePlan(input) {
|
|
|
16722
16823
|
dimensions
|
|
16723
16824
|
});
|
|
16724
16825
|
const planJson = {
|
|
16826
|
+
...referenceBackgroundResult3(composition[REFERENCE_BACKGROUND_FIELD]),
|
|
16725
16827
|
protocol: PLAN_PROTOCOL_V1,
|
|
16726
16828
|
planHash,
|
|
16727
16829
|
producerVersion,
|
|
@@ -16733,7 +16835,7 @@ async function freezePlan(input) {
|
|
|
16733
16835
|
duration: durationSeconds,
|
|
16734
16836
|
hasAudio
|
|
16735
16837
|
};
|
|
16736
|
-
const planJsonPath =
|
|
16838
|
+
const planJsonPath = join34(planDir, "plan.json");
|
|
16737
16839
|
writeFileSync7(planJsonPath, `${JSON.stringify(planJson, null, 2)}
|
|
16738
16840
|
`, "utf-8");
|
|
16739
16841
|
return { planJsonPath, planHash };
|
|
@@ -16777,7 +16879,7 @@ function applyRuntimeEnvSnapshot(snapshot, env = process.env) {
|
|
|
16777
16879
|
// src/services/distributed/chunkAudio.ts
|
|
16778
16880
|
import { closeSync as closeSync6, existsSync as existsSync22, ftruncateSync, mkdirSync as mkdirSync13, openSync as openSync6, readFileSync as readFileSync10 } from "node:fs";
|
|
16779
16881
|
import { writeFileSync as writeFileSync8, writeSync } from "node:fs";
|
|
16780
|
-
import { join as
|
|
16882
|
+
import { join as join35 } from "node:path";
|
|
16781
16883
|
import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure4, runFfmpeg as runFfmpeg7 } from "@hyperframes/engine";
|
|
16782
16884
|
function audioCutForChunk(grid, chunks, index, fps) {
|
|
16783
16885
|
const firstPacketAt = (frame) => Math.min(
|
|
@@ -16865,7 +16967,7 @@ async function writeChunkAudioSlices(input) {
|
|
|
16865
16967
|
});
|
|
16866
16968
|
const bytes = readFileSync10(input.audioPath);
|
|
16867
16969
|
const layout = { sizeBytes: bytes.length, payloadStart, payloadEnd, partStarts: {} };
|
|
16868
|
-
mkdirSync13(
|
|
16970
|
+
mkdirSync13(join35(input.planDir, SLICE_DIR), { recursive: true });
|
|
16869
16971
|
input.chunks.forEach((_, index) => {
|
|
16870
16972
|
const cut = audioCutForChunk(grid, input.chunks, index, input.fps);
|
|
16871
16973
|
if (!cut) return;
|
|
@@ -16873,17 +16975,17 @@ async function writeChunkAudioSlices(input) {
|
|
|
16873
16975
|
const start = offsets[cut.firstPacket];
|
|
16874
16976
|
layout.partStarts[index] = start;
|
|
16875
16977
|
const end = offsets[last] + track.sizes[last];
|
|
16876
|
-
writeFileSync8(
|
|
16978
|
+
writeFileSync8(join35(input.planDir, chunkAudioSlicePath(index)), bytes.subarray(start, end));
|
|
16877
16979
|
});
|
|
16878
16980
|
const frame = [bytes.subarray(0, payloadStart), bytes.subarray(payloadEnd)];
|
|
16879
|
-
writeFileSync8(
|
|
16880
|
-
writeFileSync8(
|
|
16981
|
+
writeFileSync8(join35(input.planDir, SLICE_FRAME), Buffer.concat(frame));
|
|
16982
|
+
writeFileSync8(join35(input.planDir, SLICE_LAYOUT), JSON.stringify(layout));
|
|
16881
16983
|
}
|
|
16882
16984
|
function chunkAudioSource(planDir, chunkIndex, scratchPath) {
|
|
16883
|
-
const layoutPath =
|
|
16985
|
+
const layoutPath = join35(planDir, SLICE_LAYOUT);
|
|
16884
16986
|
if (!existsSync22(layoutPath)) return resolvePlanAudioPath(planDir);
|
|
16885
16987
|
const layout = JSON.parse(readFileSync10(layoutPath, "utf-8"));
|
|
16886
|
-
const frame = readFileSync10(
|
|
16988
|
+
const frame = readFileSync10(join35(planDir, SLICE_FRAME));
|
|
16887
16989
|
const fd = openSync6(scratchPath, "w");
|
|
16888
16990
|
try {
|
|
16889
16991
|
writeSync(fd, frame, 0, layout.payloadStart, 0);
|
|
@@ -16896,7 +16998,7 @@ function chunkAudioSource(planDir, chunkIndex, scratchPath) {
|
|
|
16896
16998
|
);
|
|
16897
16999
|
const start = layout.partStarts[chunkIndex];
|
|
16898
17000
|
if (start !== void 0) {
|
|
16899
|
-
const part = readFileSync10(
|
|
17001
|
+
const part = readFileSync10(join35(planDir, chunkAudioSlicePath(chunkIndex)));
|
|
16900
17002
|
writeSync(fd, part, 0, part.length, start);
|
|
16901
17003
|
}
|
|
16902
17004
|
ftruncateSync(fd, layout.sizeBytes);
|
|
@@ -16952,7 +17054,7 @@ async function muxChunkWithAudio(input) {
|
|
|
16952
17054
|
// src/services/distributed/planSize.ts
|
|
16953
17055
|
import { createHash as createHash9 } from "node:crypto";
|
|
16954
17056
|
import { lstatSync as lstatSync2, readdirSync as readdirSync8 } from "node:fs";
|
|
16955
|
-
import { extname as extname5, join as
|
|
17057
|
+
import { extname as extname5, join as join36, relative as relative4 } from "node:path";
|
|
16956
17058
|
var MAX_TOP_COMPONENTS = 10;
|
|
16957
17059
|
var SOURCE_MEDIA_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
16958
17060
|
".aac",
|
|
@@ -17064,7 +17166,7 @@ function walkRegularFiles(dir, visit) {
|
|
|
17064
17166
|
return;
|
|
17065
17167
|
}
|
|
17066
17168
|
for (const entry of entries) {
|
|
17067
|
-
const full =
|
|
17169
|
+
const full = join36(dir, entry.name);
|
|
17068
17170
|
if (entry.isDirectory()) {
|
|
17069
17171
|
walkRegularFiles(full, visit);
|
|
17070
17172
|
} else if (entry.isFile()) {
|
|
@@ -17276,13 +17378,13 @@ function assertPositiveInteger2(name, value) {
|
|
|
17276
17378
|
}
|
|
17277
17379
|
var FREEZE_OWNED_PLAN_FILES = [
|
|
17278
17380
|
"plan.json",
|
|
17279
|
-
|
|
17280
|
-
|
|
17281
|
-
|
|
17381
|
+
join37("meta", "composition.json"),
|
|
17382
|
+
join37("meta", "encoder.json"),
|
|
17383
|
+
join37("meta", "chunks.json")
|
|
17282
17384
|
];
|
|
17283
17385
|
function removeFreezeOwnedPlanFiles(planDir) {
|
|
17284
17386
|
for (const relativePath of FREEZE_OWNED_PLAN_FILES) {
|
|
17285
|
-
rmSync12(
|
|
17387
|
+
rmSync12(join37(planDir, relativePath), { force: true });
|
|
17286
17388
|
}
|
|
17287
17389
|
}
|
|
17288
17390
|
function buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize) {
|
|
@@ -17437,19 +17539,19 @@ function createVideoSourceShipper(input) {
|
|
|
17437
17539
|
const known = shipped.get(srcPath);
|
|
17438
17540
|
if (known) return known;
|
|
17439
17541
|
const stagedRel = pathInside(input.workVideoFramesDir, srcPath);
|
|
17440
|
-
const current = stagedRel === null ? srcPath :
|
|
17542
|
+
const current = stagedRel === null ? srcPath : join37(input.planDir, "video-frames", stagedRel);
|
|
17441
17543
|
let result = null;
|
|
17442
17544
|
for (const root of stagedRel === null ? [input.workCompiledDir, input.projectDir] : []) {
|
|
17443
17545
|
const rel = pathInside(root, srcPath);
|
|
17444
|
-
if (rel !== null && (existsSync23(
|
|
17546
|
+
if (rel !== null && (existsSync23(join37(input.planDir, "compiled", rel)) || input.isRemote(srcPath))) {
|
|
17445
17547
|
result = ["compiled", ...rel.split(sep2)].join("/");
|
|
17446
17548
|
break;
|
|
17447
17549
|
}
|
|
17448
17550
|
}
|
|
17449
17551
|
if (result === null) {
|
|
17450
17552
|
result = `video-sources/${shipped.size}${extname6(current)}`;
|
|
17451
|
-
const destination =
|
|
17452
|
-
mkdirSync14(
|
|
17553
|
+
const destination = join37(input.planDir, ...result.split("/"));
|
|
17554
|
+
mkdirSync14(join37(input.planDir, "video-sources"), { recursive: true });
|
|
17453
17555
|
try {
|
|
17454
17556
|
linkSync(current, destination);
|
|
17455
17557
|
} catch {
|
|
@@ -17498,14 +17600,14 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
17498
17600
|
variables: config.variables
|
|
17499
17601
|
});
|
|
17500
17602
|
const entryFile = config.entryFile ?? "index.html";
|
|
17501
|
-
const htmlPath =
|
|
17603
|
+
const htmlPath = join37(projectDir, entryFile);
|
|
17502
17604
|
if (!existsSync23(htmlPath)) {
|
|
17503
17605
|
throw new Error(`[plan] entry file not found: ${htmlPath}`);
|
|
17504
17606
|
}
|
|
17505
|
-
const workDir =
|
|
17607
|
+
const workDir = join37(planDir, ".plan-work");
|
|
17506
17608
|
rmSync12(workDir, { recursive: true, force: true });
|
|
17507
17609
|
mkdirSync14(workDir, { recursive: true });
|
|
17508
|
-
const compiledDir =
|
|
17610
|
+
const compiledDir = join37(workDir, "compiled");
|
|
17509
17611
|
mkdirSync14(compiledDir, { recursive: true });
|
|
17510
17612
|
let stageStarted = Date.now();
|
|
17511
17613
|
cpSync2(projectDir, compiledDir, {
|
|
@@ -17519,10 +17621,10 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
17519
17621
|
}
|
|
17520
17622
|
});
|
|
17521
17623
|
logPlanStage(log, "copy", stageStarted);
|
|
17522
|
-
const finalCompiledDir =
|
|
17624
|
+
const finalCompiledDir = join37(planDir, "compiled");
|
|
17523
17625
|
const needsAlpha = outputNeedsAlpha(config.format);
|
|
17524
17626
|
const remoteFiles = Object.entries(options.remoteFiles ?? {});
|
|
17525
|
-
const remoteLocalPath = (rel) =>
|
|
17627
|
+
const remoteLocalPath = (rel) => join37(projectDir, ...rel.split("/"));
|
|
17526
17628
|
for (const [, file] of remoteFiles) {
|
|
17527
17629
|
declareContentAddressedUrl(file.url, file.sha256);
|
|
17528
17630
|
if (file.probeFactsUrl) declareProbeFactsUrl(file.url, file.probeFactsUrl);
|
|
@@ -17572,6 +17674,9 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
17572
17674
|
}
|
|
17573
17675
|
stageStarted = Date.now();
|
|
17574
17676
|
const probeResult = await runProbeStage({
|
|
17677
|
+
recordReferenceBackground: createReferenceBackgroundRecorder2(
|
|
17678
|
+
(result) => Object.assign(job, result)
|
|
17679
|
+
),
|
|
17575
17680
|
projectDir,
|
|
17576
17681
|
workDir,
|
|
17577
17682
|
job,
|
|
@@ -17589,6 +17694,21 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
17589
17694
|
subTimelineWaitMemo: {}
|
|
17590
17695
|
});
|
|
17591
17696
|
logPlanStage(log, "probe", stageStarted);
|
|
17697
|
+
if (!probeResult.probeSession) {
|
|
17698
|
+
stageStarted = Date.now();
|
|
17699
|
+
Object.assign(
|
|
17700
|
+
job,
|
|
17701
|
+
await readPlanReferenceBackground({
|
|
17702
|
+
projectDir,
|
|
17703
|
+
workDir,
|
|
17704
|
+
cfg,
|
|
17705
|
+
log,
|
|
17706
|
+
options: { width, height, fps: job.config.fps, variables: job.config.variables }
|
|
17707
|
+
})
|
|
17708
|
+
);
|
|
17709
|
+
assertNotAborted();
|
|
17710
|
+
logPlanStage(log, "reference_background", stageStarted);
|
|
17711
|
+
}
|
|
17592
17712
|
compiled = probeResult.compiled;
|
|
17593
17713
|
job.duration = probeResult.duration;
|
|
17594
17714
|
job.totalFrames = probeResult.totalFrames;
|
|
@@ -17601,8 +17721,8 @@ async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
|
17601
17721
|
if (probeResult.fileServer) closeFileServerSafely(probeResult.fileServer, "plan", log);
|
|
17602
17722
|
if (probeResult.probeSession) {
|
|
17603
17723
|
try {
|
|
17604
|
-
const { closeCaptureSession:
|
|
17605
|
-
await
|
|
17724
|
+
const { closeCaptureSession: closeCaptureSession13 } = await import("@hyperframes/engine");
|
|
17725
|
+
await closeCaptureSession13(probeResult.probeSession);
|
|
17606
17726
|
} catch (err) {
|
|
17607
17727
|
log.warn("[plan] probe session close failed", {
|
|
17608
17728
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -17708,10 +17828,10 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
17708
17828
|
let stageStarted = Date.now();
|
|
17709
17829
|
const extractResult = await extractPlanVideos(c, options.deferVideoExtraction);
|
|
17710
17830
|
logPlanStage(log, "extract", stageStarted);
|
|
17711
|
-
const stagedVideoFrames =
|
|
17712
|
-
const videoFramesDst =
|
|
17831
|
+
const stagedVideoFrames = join37(compiledDir, "__hyperframes_video_frames");
|
|
17832
|
+
const videoFramesDst = join37(planDir, "video-frames");
|
|
17713
17833
|
if (existsSync23(videoFramesDst)) rmSync12(videoFramesDst, { recursive: true, force: true });
|
|
17714
|
-
const videoSourcesDir =
|
|
17834
|
+
const videoSourcesDir = join37(planDir, "video-sources");
|
|
17715
17835
|
rmSync12(videoSourcesDir, { recursive: true, force: true });
|
|
17716
17836
|
if (existsSync23(stagedVideoFrames)) {
|
|
17717
17837
|
renameWithRetry8(stagedVideoFrames, videoFramesDst);
|
|
@@ -17748,7 +17868,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
17748
17868
|
};
|
|
17749
17869
|
})
|
|
17750
17870
|
});
|
|
17751
|
-
mkdirSync14(
|
|
17871
|
+
mkdirSync14(join37(planDir, "meta"), { recursive: true });
|
|
17752
17872
|
writePlanRemoteFiles(
|
|
17753
17873
|
planDir,
|
|
17754
17874
|
remoteFiles.map(([rel, { sha256, sizeBytes }]) => ({
|
|
@@ -17758,7 +17878,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
17758
17878
|
}))
|
|
17759
17879
|
);
|
|
17760
17880
|
writeFileSync9(
|
|
17761
|
-
|
|
17881
|
+
join37(planDir, PLAN_VIDEOS_META_RELATIVE_PATH),
|
|
17762
17882
|
JSON.stringify(planVideosJson, null, 2),
|
|
17763
17883
|
"utf-8"
|
|
17764
17884
|
);
|
|
@@ -17837,7 +17957,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
17837
17957
|
if (audioResult?.audioError) {
|
|
17838
17958
|
applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
|
|
17839
17959
|
}
|
|
17840
|
-
const planAudioPath =
|
|
17960
|
+
const planAudioPath = join37(planDir, PLAN_AUDIO_RELATIVE_PATH);
|
|
17841
17961
|
if (audioResult?.hasAudio && existsSync23(audioResult.audioOutputPath)) {
|
|
17842
17962
|
renameWithRetry8(audioResult.audioOutputPath, planAudioPath);
|
|
17843
17963
|
}
|
|
@@ -17870,6 +17990,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
17870
17990
|
separateAudio
|
|
17871
17991
|
});
|
|
17872
17992
|
const compositionJson = {
|
|
17993
|
+
...referenceBackgroundResult4(job[REFERENCE_BACKGROUND_FIELD2]),
|
|
17873
17994
|
durationSeconds: job.duration ?? 0,
|
|
17874
17995
|
width,
|
|
17875
17996
|
height,
|
|
@@ -17925,6 +18046,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
17925
18046
|
log
|
|
17926
18047
|
});
|
|
17927
18048
|
return {
|
|
18049
|
+
...referenceBackgroundResult4(job[REFERENCE_BACKGROUND_FIELD2]),
|
|
17928
18050
|
executionPlanDir: planDir,
|
|
17929
18051
|
executionPlanHash: planHash,
|
|
17930
18052
|
chunkCount,
|
|
@@ -17940,6 +18062,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
17940
18062
|
async function plan(projectDir, config, planDir, options = {}) {
|
|
17941
18063
|
const executionPlan = await buildLocalExecutionPlan(projectDir, config, planDir, options);
|
|
17942
18064
|
return {
|
|
18065
|
+
...referenceBackgroundResult4(executionPlan[REFERENCE_BACKGROUND_FIELD2]),
|
|
17943
18066
|
planDir: executionPlan.executionPlanDir,
|
|
17944
18067
|
planProtocol: PLAN_PROTOCOL_V1,
|
|
17945
18068
|
planHash: executionPlan.executionPlanHash,
|
|
@@ -17958,14 +18081,14 @@ async function plan(projectDir, config, planDir, options = {}) {
|
|
|
17958
18081
|
import { randomBytes } from "node:crypto";
|
|
17959
18082
|
import { existsSync as existsSync26, mkdirSync as mkdirSync17, readFileSync as readFileSync12, readdirSync as readdirSync10, rmSync as rmSync15, writeFileSync as writeFileSync12 } from "node:fs";
|
|
17960
18083
|
import { cpus as cpus3 } from "node:os";
|
|
17961
|
-
import { join as
|
|
18084
|
+
import { join as join41 } from "node:path";
|
|
17962
18085
|
import {
|
|
17963
18086
|
assertSwiftShader,
|
|
17964
18087
|
BROWSER_GPU_NOT_SOFTWARE as BROWSER_GPU_NOT_SOFTWARE4,
|
|
17965
18088
|
calculateOptimalWorkers as calculateOptimalWorkers2,
|
|
17966
18089
|
classifyCaptureFailure as classifyCaptureFailure4,
|
|
17967
|
-
closeCaptureSession as
|
|
17968
|
-
createCaptureSession as
|
|
18090
|
+
closeCaptureSession as closeCaptureSession11,
|
|
18091
|
+
createCaptureSession as createCaptureSession11,
|
|
17969
18092
|
createFrameLookupTable as createFrameLookupTable5,
|
|
17970
18093
|
deriveBeginFrameProbeTimeTicks as deriveBeginFrameProbeTimeTicks2,
|
|
17971
18094
|
getEncoderPreset as getEncoderPreset5,
|
|
@@ -17977,6 +18100,10 @@ import {
|
|
|
17977
18100
|
} from "@hyperframes/engine";
|
|
17978
18101
|
|
|
17979
18102
|
// src/services/distributed/planV2.ts
|
|
18103
|
+
import {
|
|
18104
|
+
REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD3,
|
|
18105
|
+
referenceBackgroundResult as referenceBackgroundResult5
|
|
18106
|
+
} from "@hyperframes/engine";
|
|
17980
18107
|
import {
|
|
17981
18108
|
copyFileSync as copyFileSync8,
|
|
17982
18109
|
existsSync as existsSync25,
|
|
@@ -17990,7 +18117,7 @@ import {
|
|
|
17990
18117
|
writeFileSync as writeFileSync11
|
|
17991
18118
|
} from "node:fs";
|
|
17992
18119
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
17993
|
-
import { dirname as dirname16, isAbsolute as isAbsolute4, join as
|
|
18120
|
+
import { dirname as dirname16, isAbsolute as isAbsolute4, join as join40, relative as relative6, resolve as resolve10, sep as sep3 } from "node:path";
|
|
17994
18121
|
import { DISTRIBUTED_FPS, isDistributedFps } from "@hyperframes/core";
|
|
17995
18122
|
import { createFrameLookupTable as createFrameLookupTable4, renameWithRetry as renameWithRetry10 } from "@hyperframes/engine";
|
|
17996
18123
|
|
|
@@ -18006,7 +18133,7 @@ import {
|
|
|
18006
18133
|
writeFileSync as writeFileSync10
|
|
18007
18134
|
} from "node:fs";
|
|
18008
18135
|
import { renameWithRetry as renameWithRetry9 } from "@hyperframes/engine";
|
|
18009
|
-
import { dirname as dirname15, join as
|
|
18136
|
+
import { dirname as dirname15, join as join39 } from "node:path";
|
|
18010
18137
|
|
|
18011
18138
|
// src/services/distributed/planV2Errors.ts
|
|
18012
18139
|
var PLAN_V2_INTEGRITY_UNRECOVERABLE = "PLAN_V2_INTEGRITY_UNRECOVERABLE";
|
|
@@ -18021,7 +18148,7 @@ var PlanV2IntegrityError = class extends Error {
|
|
|
18021
18148
|
};
|
|
18022
18149
|
|
|
18023
18150
|
// src/services/distributed/planV2Layout.ts
|
|
18024
|
-
import { join as
|
|
18151
|
+
import { join as join38 } from "node:path";
|
|
18025
18152
|
var SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
18026
18153
|
function assertPlanV2Sha256(value, field) {
|
|
18027
18154
|
if (typeof value !== "string" || !SHA256_PATTERN.test(value)) {
|
|
@@ -18031,7 +18158,7 @@ function assertPlanV2Sha256(value, field) {
|
|
|
18031
18158
|
}
|
|
18032
18159
|
function planV2BlobPath(root, sha256) {
|
|
18033
18160
|
const digest = assertPlanV2Sha256(sha256, "artifact sha256");
|
|
18034
|
-
return
|
|
18161
|
+
return join38(root, "artifacts", "sha256", digest.slice(0, 2), digest);
|
|
18035
18162
|
}
|
|
18036
18163
|
|
|
18037
18164
|
// src/services/distributed/planV2Publisher.ts
|
|
@@ -18072,7 +18199,7 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
18072
18199
|
this.destinationDir = destinationDir;
|
|
18073
18200
|
this.#linkFile = options.linkFile ?? linkSync2;
|
|
18074
18201
|
mkdirSync15(dirname15(destinationDir), { recursive: true });
|
|
18075
|
-
this.temporaryDir = mkdtempSync5(
|
|
18202
|
+
this.temporaryDir = mkdtempSync5(join39(dirname15(destinationDir), ".plan-v2-publish-"));
|
|
18076
18203
|
}
|
|
18077
18204
|
async putBlob(blob) {
|
|
18078
18205
|
const digest = assertPlanV2Sha256(blob.sha256, "published blob sha256");
|
|
@@ -18085,8 +18212,8 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
18085
18212
|
const destinationPath = planV2BlobPath(this.temporaryDir, digest);
|
|
18086
18213
|
if (existsSync24(destinationPath)) return;
|
|
18087
18214
|
mkdirSync15(dirname15(destinationPath), { recursive: true });
|
|
18088
|
-
const stagingDir = mkdtempSync5(
|
|
18089
|
-
const temporaryPath =
|
|
18215
|
+
const stagingDir = mkdtempSync5(join39(dirname15(destinationPath), ".plan-v2-blob-"));
|
|
18216
|
+
const temporaryPath = join39(stagingDir, "blob");
|
|
18090
18217
|
try {
|
|
18091
18218
|
try {
|
|
18092
18219
|
this.#linkFile(blob.sourcePath, temporaryPath);
|
|
@@ -18107,7 +18234,7 @@ var LocalPlanV2ArtifactPublisher = class {
|
|
|
18107
18234
|
);
|
|
18108
18235
|
}
|
|
18109
18236
|
}
|
|
18110
|
-
writeFileSync10(
|
|
18237
|
+
writeFileSync10(join39(this.temporaryDir, "plan.json"), manifestBytes, "utf-8");
|
|
18111
18238
|
renameWithRetry9(this.temporaryDir, this.destinationDir);
|
|
18112
18239
|
this.#committed = true;
|
|
18113
18240
|
}
|
|
@@ -18152,7 +18279,7 @@ function listFiles(root) {
|
|
|
18152
18279
|
const rootResolved = resolve10(root);
|
|
18153
18280
|
function walk(dir) {
|
|
18154
18281
|
for (const entry of readdirSync9(dir, { withFileTypes: true })) {
|
|
18155
|
-
const absolutePath =
|
|
18282
|
+
const absolutePath = join40(dir, entry.name);
|
|
18156
18283
|
if (entry.isDirectory()) {
|
|
18157
18284
|
walk(absolutePath);
|
|
18158
18285
|
} else if (entry.isFile()) {
|
|
@@ -18179,13 +18306,13 @@ function assertValidExtractionCacheCompleteSentinel(path) {
|
|
|
18179
18306
|
}
|
|
18180
18307
|
}
|
|
18181
18308
|
function validateExtractionCacheCompleteSentinels(executionPlanDir) {
|
|
18182
|
-
const videoRoot =
|
|
18309
|
+
const videoRoot = join40(executionPlanDir, "video-frames");
|
|
18183
18310
|
if (!existsSync25(videoRoot)) return;
|
|
18184
18311
|
for (const videoEntry of readdirSync9(videoRoot, { withFileTypes: true })) {
|
|
18185
18312
|
if (!videoEntry.isDirectory()) continue;
|
|
18186
|
-
const videoDir =
|
|
18313
|
+
const videoDir = join40(videoRoot, videoEntry.name);
|
|
18187
18314
|
if (readdirSync9(videoDir).includes(EXTRACTION_CACHE_COMPLETE_SENTINEL)) {
|
|
18188
|
-
const sentinelPath =
|
|
18315
|
+
const sentinelPath = join40(videoDir, EXTRACTION_CACHE_COMPLETE_SENTINEL);
|
|
18189
18316
|
assertValidExtractionCacheCompleteSentinel(sentinelPath);
|
|
18190
18317
|
}
|
|
18191
18318
|
}
|
|
@@ -18232,7 +18359,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
|
|
|
18232
18359
|
if (video.deferredRange) {
|
|
18233
18360
|
const framePaths2 = /* @__PURE__ */ new Map();
|
|
18234
18361
|
for (let index = 0; index < video.totalFrames; index++) {
|
|
18235
|
-
framePaths2.set(index,
|
|
18362
|
+
framePaths2.set(index, join40(outputDir, String(index)));
|
|
18236
18363
|
}
|
|
18237
18364
|
return { ...video, outputDir, framePaths: framePaths2, ownedByLookup: false };
|
|
18238
18365
|
}
|
|
@@ -18240,7 +18367,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
|
|
|
18240
18367
|
const framePaths = /* @__PURE__ */ new Map();
|
|
18241
18368
|
for (const frameName of frameNames) {
|
|
18242
18369
|
if (frameName === EXTRACTION_CACHE_COMPLETE_SENTINEL) {
|
|
18243
|
-
assertValidExtractionCacheCompleteSentinel(
|
|
18370
|
+
assertValidExtractionCacheCompleteSentinel(join40(outputDir, frameName));
|
|
18244
18371
|
continue;
|
|
18245
18372
|
}
|
|
18246
18373
|
const match = /(\d+)(?=\.[^.]+$)/.exec(frameName);
|
|
@@ -18259,7 +18386,7 @@ function listVideoFramePaths(executionPlanDir, videos) {
|
|
|
18259
18386
|
`duplicate extracted frame index ${frameIndex} in ${outputDir}`
|
|
18260
18387
|
);
|
|
18261
18388
|
}
|
|
18262
|
-
framePaths.set(frameIndex,
|
|
18389
|
+
framePaths.set(frameIndex, join40(outputDir, frameName));
|
|
18263
18390
|
}
|
|
18264
18391
|
return {
|
|
18265
18392
|
...video,
|
|
@@ -18280,7 +18407,7 @@ function parsePlanVideosJson2(value) {
|
|
|
18280
18407
|
}
|
|
18281
18408
|
}
|
|
18282
18409
|
function materializeExtractedVideoDirectories(planDir) {
|
|
18283
|
-
const videosPath =
|
|
18410
|
+
const videosPath = join40(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
|
|
18284
18411
|
if (!existsSync25(videosPath)) return;
|
|
18285
18412
|
const videos = parsePlanVideosJson2(readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH));
|
|
18286
18413
|
for (const video of videos.extracted) {
|
|
@@ -18314,13 +18441,13 @@ function parseChunkSlices(value) {
|
|
|
18314
18441
|
});
|
|
18315
18442
|
}
|
|
18316
18443
|
function buildVideoChunkDependencies(executionPlanDir, dimensions) {
|
|
18317
|
-
const videoRoot =
|
|
18444
|
+
const videoRoot = join40(executionPlanDir, "video-frames");
|
|
18318
18445
|
const hasExtractedFrames = existsSync25(videoRoot) && listFiles(videoRoot).length > 0;
|
|
18319
|
-
const videosPath =
|
|
18446
|
+
const videosPath = join40(executionPlanDir, PLAN_VIDEOS_META_RELATIVE_PATH);
|
|
18320
18447
|
if (!existsSync25(videosPath)) {
|
|
18321
18448
|
return hasExtractedFrames ? { mode: "full-source-pack", dependencies: null } : { mode: "exact-rendered-frames", dependencies: /* @__PURE__ */ new Map() };
|
|
18322
18449
|
}
|
|
18323
|
-
const chunksPath =
|
|
18450
|
+
const chunksPath = join40(executionPlanDir, "meta", "chunks.json");
|
|
18324
18451
|
const videos = readJsonFile(videosPath, PLAN_VIDEOS_META_RELATIVE_PATH);
|
|
18325
18452
|
const chunks = readJsonFile(chunksPath, "meta/chunks.json");
|
|
18326
18453
|
const parsedVideos = parsePlanVideosJson2(videos);
|
|
@@ -18376,8 +18503,8 @@ function computeManifestHash(manifest) {
|
|
|
18376
18503
|
function writeBlob(sourcePath, destinationPath) {
|
|
18377
18504
|
if (existsSync25(destinationPath)) return;
|
|
18378
18505
|
mkdirSync16(dirname16(destinationPath), { recursive: true });
|
|
18379
|
-
const temporaryDir = mkdtempSync6(
|
|
18380
|
-
const temporaryPath =
|
|
18506
|
+
const temporaryDir = mkdtempSync6(join40(dirname16(destinationPath), ".plan-v2-blob-"));
|
|
18507
|
+
const temporaryPath = join40(temporaryDir, "blob");
|
|
18381
18508
|
try {
|
|
18382
18509
|
copyFileSync8(sourcePath, temporaryPath);
|
|
18383
18510
|
renameWithRetry10(temporaryPath, destinationPath);
|
|
@@ -18413,7 +18540,7 @@ async function putTasks(tasks) {
|
|
|
18413
18540
|
if (failure) throw failure.reason;
|
|
18414
18541
|
}
|
|
18415
18542
|
function buildPlanV2Publication(executionPlanDir, digests) {
|
|
18416
|
-
const executionPlanPath =
|
|
18543
|
+
const executionPlanPath = join40(executionPlanDir, "plan.json");
|
|
18417
18544
|
if (!existsSync25(executionPlanPath)) {
|
|
18418
18545
|
throw new PlanV2IntegrityError(`execution plan is missing plan.json: ${executionPlanPath}`);
|
|
18419
18546
|
}
|
|
@@ -18441,7 +18568,7 @@ function buildPlanV2Publication(executionPlanDir, digests) {
|
|
|
18441
18568
|
}
|
|
18442
18569
|
validateExtractionCacheCompleteSentinels(executionPlanDir);
|
|
18443
18570
|
const videoDependencyPlan = buildVideoChunkDependencies(executionPlanDir, dimensions);
|
|
18444
|
-
const encoder = readJsonFile(
|
|
18571
|
+
const encoder = readJsonFile(join40(executionPlanDir, "meta", "encoder.json"), "meta/encoder.json");
|
|
18445
18572
|
const files = listFiles(executionPlanDir);
|
|
18446
18573
|
const chunkAudio = !isRecord3(encoder) || encoder.chunksCarryAudio !== true ? "none" : files.some((file) => chunkAudioSliceTarget(file.path) !== null) ? "sliced" : "whole";
|
|
18447
18574
|
for (const file of files) {
|
|
@@ -18502,13 +18629,13 @@ function createPlanV2FromExecutionPlan(executionPlanDir, planV2Dir) {
|
|
|
18502
18629
|
throw new PlanV2IntegrityError("a local plan v2 directory cannot reference remote files");
|
|
18503
18630
|
}
|
|
18504
18631
|
mkdirSync16(dirname16(planV2Dir), { recursive: true });
|
|
18505
|
-
const tempDir = mkdtempSync6(
|
|
18632
|
+
const tempDir = mkdtempSync6(join40(dirname16(planV2Dir), ".plan-v2-build-"));
|
|
18506
18633
|
try {
|
|
18507
18634
|
for (const blob of publication.blobs) {
|
|
18508
18635
|
writeBlob(blob.sourcePath, planV2BlobPath(tempDir, blob.sha256));
|
|
18509
18636
|
}
|
|
18510
18637
|
writeFileSync11(
|
|
18511
|
-
|
|
18638
|
+
join40(tempDir, "plan.json"),
|
|
18512
18639
|
canonicalJsonStringify(publication.manifest),
|
|
18513
18640
|
"utf-8"
|
|
18514
18641
|
);
|
|
@@ -18549,7 +18676,7 @@ async function publishExecutionPlan(executionPlanDir, publisher, { digests, log
|
|
|
18549
18676
|
}
|
|
18550
18677
|
}
|
|
18551
18678
|
async function planV2WithPublisher(projectDir, config, publisher, options = {}) {
|
|
18552
|
-
const stagingRoot = mkdtempSync6(
|
|
18679
|
+
const stagingRoot = mkdtempSync6(join40(options.stagingParentDir ?? tmpdir3(), ".execution-plan-"));
|
|
18553
18680
|
const digests = /* @__PURE__ */ new Map();
|
|
18554
18681
|
try {
|
|
18555
18682
|
await buildLocalExecutionPlan(projectDir, config, stagingRoot, {
|
|
@@ -18560,7 +18687,7 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
|
|
|
18560
18687
|
// artifactTargets ships every compiled/ file to all chunks, so each is in the manifest.
|
|
18561
18688
|
whileAudioMixes: () => putBlobs(
|
|
18562
18689
|
publisher,
|
|
18563
|
-
listFiles(
|
|
18690
|
+
listFiles(join40(stagingRoot, "compiled")).map(
|
|
18564
18691
|
(file) => publishBlobFor(file.absolutePath, digests)
|
|
18565
18692
|
)
|
|
18566
18693
|
),
|
|
@@ -18590,9 +18717,14 @@ async function planV2(projectDir, config, planV2Dir) {
|
|
|
18590
18717
|
return resultFromManifest(planV2Dir, manifest);
|
|
18591
18718
|
}
|
|
18592
18719
|
function resultFromManifest(planV2Dir, manifest) {
|
|
18720
|
+
const artifact = manifest.artifacts.find((entry) => entry.path === "plan.json");
|
|
18721
|
+
const executionPlan = artifact ? readJsonFile(verifyBlob(planV2Dir, artifact), "execution plan.json") : null;
|
|
18593
18722
|
return {
|
|
18723
|
+
...referenceBackgroundResult5(
|
|
18724
|
+
isRecord3(executionPlan) ? executionPlan[REFERENCE_BACKGROUND_FIELD3] : void 0
|
|
18725
|
+
),
|
|
18594
18726
|
planDir: planV2Dir,
|
|
18595
|
-
manifestPath:
|
|
18727
|
+
manifestPath: join40(planV2Dir, "plan.json"),
|
|
18596
18728
|
planProtocol: PLAN_PROTOCOL_V2,
|
|
18597
18729
|
planHash: manifest.planHash,
|
|
18598
18730
|
sourcePlanV1Hash: getPlanV2ExecutionPlanHash(manifest),
|
|
@@ -18728,7 +18860,7 @@ function parsePlanV2Manifest(value) {
|
|
|
18728
18860
|
return parsed;
|
|
18729
18861
|
}
|
|
18730
18862
|
function readPlanV2Manifest(planV2Dir) {
|
|
18731
|
-
const manifestPath =
|
|
18863
|
+
const manifestPath = join40(planV2Dir, "plan.json");
|
|
18732
18864
|
if (!existsSync25(manifestPath)) {
|
|
18733
18865
|
throw new PlanV2IntegrityError(`missing v2 manifest: ${manifestPath}`);
|
|
18734
18866
|
}
|
|
@@ -18774,16 +18906,16 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
|
|
|
18774
18906
|
sourcePath: verifyBlob(planV2Dir, artifact)
|
|
18775
18907
|
}));
|
|
18776
18908
|
mkdirSync16(dirname16(destinationDir), { recursive: true });
|
|
18777
|
-
const tempDir = mkdtempSync6(
|
|
18909
|
+
const tempDir = mkdtempSync6(join40(dirname16(destinationDir), ".plan-v2-materialize-"));
|
|
18778
18910
|
try {
|
|
18779
18911
|
for (const { artifact, sourcePath } of verified) {
|
|
18780
|
-
const destinationPath =
|
|
18912
|
+
const destinationPath = join40(tempDir, ...artifact.path.split("/"));
|
|
18781
18913
|
mkdirSync16(dirname16(destinationPath), { recursive: true });
|
|
18782
18914
|
copyFileSync8(sourcePath, destinationPath);
|
|
18783
18915
|
}
|
|
18784
18916
|
if (target.role === "chunk") materializeExtractedVideoDirectories(tempDir);
|
|
18785
18917
|
writeFileSync11(
|
|
18786
|
-
|
|
18918
|
+
join40(tempDir, PLAN_V2_MATERIALIZATION_MARKER),
|
|
18787
18919
|
canonicalJsonStringify({
|
|
18788
18920
|
manifest,
|
|
18789
18921
|
target,
|
|
@@ -18806,7 +18938,7 @@ function materializePlanV2Target(planV2Dir, target, destinationDir, options = {}
|
|
|
18806
18938
|
// Join the artifact's OWN name, not the current constant: a plan written
|
|
18807
18939
|
// before the container change carries the legacy name, and materializing it
|
|
18808
18940
|
// under the new one would point at a file that was never written.
|
|
18809
|
-
audioPath: target.role === "assembler" ? audioArtifact ?
|
|
18941
|
+
audioPath: target.role === "assembler" ? audioArtifact ? join40(destinationDir, audioArtifact.path) : null : null
|
|
18810
18942
|
};
|
|
18811
18943
|
}
|
|
18812
18944
|
function assertRemoteSources(remoteSources, artifacts) {
|
|
@@ -18825,7 +18957,7 @@ function validatePlanV2MaterializedTarget(planDir, expectedTarget) {
|
|
|
18825
18957
|
return readValidatedPlanV2Materialization(planDir, expectedTarget)?.manifest ?? null;
|
|
18826
18958
|
}
|
|
18827
18959
|
function readValidatedPlanV2Materialization(planDir, expectedTarget) {
|
|
18828
|
-
const markerPath =
|
|
18960
|
+
const markerPath = join40(planDir, PLAN_V2_MATERIALIZATION_MARKER);
|
|
18829
18961
|
if (!existsSync25(markerPath)) return null;
|
|
18830
18962
|
const marker = readJsonFile(markerPath, "materialization marker");
|
|
18831
18963
|
if (!isRecord3(marker) || !isRecord3(marker.manifest) || !isRecord3(marker.target)) {
|
|
@@ -18843,7 +18975,7 @@ function readValidatedPlanV2Materialization(planDir, expectedTarget) {
|
|
|
18843
18975
|
assertRemoteSources(remoteSources, required);
|
|
18844
18976
|
for (const artifact of required) {
|
|
18845
18977
|
if (Object.hasOwn(remoteSources, artifact.path)) continue;
|
|
18846
|
-
const path =
|
|
18978
|
+
const path = join40(planDir, ...artifact.path.split("/"));
|
|
18847
18979
|
if (!existsSync25(path) || statSync10(path).size !== artifact.sizeBytes) {
|
|
18848
18980
|
throw new PlanV2IntegrityError(
|
|
18849
18981
|
`materialized artifact missing or truncated: ${artifact.path}`
|
|
@@ -18890,10 +19022,10 @@ function resolveChunkFrameRange(slice, chunkIndex, frameRange) {
|
|
|
18890
19022
|
return { startFrame, endFrame };
|
|
18891
19023
|
}
|
|
18892
19024
|
var distributedCaptureSessionDependencies = {
|
|
18893
|
-
createCaptureSession:
|
|
19025
|
+
createCaptureSession: createCaptureSession11,
|
|
18894
19026
|
assertSwiftShader,
|
|
18895
19027
|
initializeSession: initializeSession10,
|
|
18896
|
-
closeCaptureSession:
|
|
19028
|
+
closeCaptureSession: closeCaptureSession11,
|
|
18897
19029
|
readWebGlVendorInfo: readWebGlVendorInfoFromCanvas
|
|
18898
19030
|
};
|
|
18899
19031
|
async function createVerifiedDistributedCaptureSession(serverUrl, framesDir, captureOptions, cfg, dependencies = distributedCaptureSessionDependencies) {
|
|
@@ -18964,7 +19096,7 @@ function hashChunkOutput(outputPath, kind) {
|
|
|
18964
19096
|
if (kind === "file") return sha256Hex(readFileSync12(outputPath));
|
|
18965
19097
|
const entries = readdirSync10(outputPath).filter((name) => /\.(png|jpg|jpeg)$/i.test(name)).sort();
|
|
18966
19098
|
const lines = entries.map(
|
|
18967
|
-
(name) => `${name}\0${sha256Hex(readFileSync12(
|
|
19099
|
+
(name) => `${name}\0${sha256Hex(readFileSync12(join41(outputPath, name)))}`
|
|
18968
19100
|
);
|
|
18969
19101
|
return sha256Hex(lines.join("\0"));
|
|
18970
19102
|
}
|
|
@@ -18981,9 +19113,9 @@ function resolveLockedVp9CpuUsed(lockedEncoder) {
|
|
|
18981
19113
|
async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
18982
19114
|
const start = Date.now();
|
|
18983
19115
|
const log = defaultLogger;
|
|
18984
|
-
const planJsonPath =
|
|
18985
|
-
const encoderJsonPath =
|
|
18986
|
-
const chunksJsonPath =
|
|
19116
|
+
const planJsonPath = join41(planDir, "plan.json");
|
|
19117
|
+
const encoderJsonPath = join41(planDir, "meta", "encoder.json");
|
|
19118
|
+
const chunksJsonPath = join41(planDir, "meta", "chunks.json");
|
|
18987
19119
|
if (!existsSync26(planJsonPath)) {
|
|
18988
19120
|
throw new RenderChunkValidationError(
|
|
18989
19121
|
MISSING_PLAN_ARTIFACT,
|
|
@@ -19009,7 +19141,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
19009
19141
|
}
|
|
19010
19142
|
const encoder = JSON.parse(readFileSync12(encoderJsonPath, "utf-8"));
|
|
19011
19143
|
const chunks = JSON.parse(readFileSync12(chunksJsonPath, "utf-8"));
|
|
19012
|
-
const videosJsonPath =
|
|
19144
|
+
const videosJsonPath = join41(planDir, PLAN_VIDEOS_META_RELATIVE_PATH);
|
|
19013
19145
|
let planVideos = null;
|
|
19014
19146
|
if (existsSync26(videosJsonPath)) {
|
|
19015
19147
|
try {
|
|
@@ -19041,7 +19173,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
19041
19173
|
}
|
|
19042
19174
|
const range = resolveChunkFrameRange(slice, chunkIndex, options?.frameRange);
|
|
19043
19175
|
const framesInChunk = range.endFrame - range.startFrame;
|
|
19044
|
-
const compiledDir =
|
|
19176
|
+
const compiledDir = join41(planDir, "compiled");
|
|
19045
19177
|
if (!existsSync26(compiledDir)) {
|
|
19046
19178
|
throw new RenderChunkValidationError(
|
|
19047
19179
|
MISSING_PLAN_ARTIFACT,
|
|
@@ -19099,7 +19231,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
19099
19231
|
};
|
|
19100
19232
|
const workDir = `${outputChunkPath}.work.${process.pid}.${randomBytes(4).toString("hex")}`;
|
|
19101
19233
|
mkdirSync17(workDir, { recursive: true });
|
|
19102
|
-
const framesDir =
|
|
19234
|
+
const framesDir = join41(workDir, "captured-frames");
|
|
19103
19235
|
mkdirSync17(framesDir, { recursive: true });
|
|
19104
19236
|
const videoFramesDir = `${workDir}.video-frames`;
|
|
19105
19237
|
const chunkFrameNumbers = Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i);
|
|
@@ -19124,7 +19256,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
19124
19256
|
dimensions: plan2.dimensions,
|
|
19125
19257
|
encoder,
|
|
19126
19258
|
videoCount: planVideos?.videos.length ?? 0,
|
|
19127
|
-
html: readFileSync12(
|
|
19259
|
+
html: readFileSync12(join41(compiledDir, "index.html"), "utf-8"),
|
|
19128
19260
|
// The plan ships a deferred source only to chunks that show it; don't wait on the rest.
|
|
19129
19261
|
skipReadinessVideoIds: deferredVideos.filter(
|
|
19130
19262
|
(video) => !shownFrames.get(video.videoId)?.size || remoteVideoIds.has(video.videoId)
|
|
@@ -19195,7 +19327,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
19195
19327
|
"[renderChunk] BeginFrame liveness probe failed; using screenshot capture for the entire chunk",
|
|
19196
19328
|
{ chunkIndex }
|
|
19197
19329
|
);
|
|
19198
|
-
await
|
|
19330
|
+
await closeCaptureSession11(session).catch(() => {
|
|
19199
19331
|
});
|
|
19200
19332
|
session = null;
|
|
19201
19333
|
const screenshotBootStarted = Date.now();
|
|
@@ -19294,7 +19426,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
19294
19426
|
if (isPngSequence) {
|
|
19295
19427
|
if (!existsSync26(outputChunkPath)) mkdirSync17(outputChunkPath, { recursive: true });
|
|
19296
19428
|
} else {
|
|
19297
|
-
const outDir =
|
|
19429
|
+
const outDir = join41(outputChunkPath, "..");
|
|
19298
19430
|
if (!existsSync26(outDir)) mkdirSync17(outDir, { recursive: true });
|
|
19299
19431
|
}
|
|
19300
19432
|
const encodeInput = {
|
|
@@ -19468,7 +19600,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
19468
19600
|
});
|
|
19469
19601
|
if (session) {
|
|
19470
19602
|
try {
|
|
19471
|
-
await
|
|
19603
|
+
await closeCaptureSession11(session);
|
|
19472
19604
|
} catch (err) {
|
|
19473
19605
|
log.warn("[renderChunk] error closing capture session in finally", {
|
|
19474
19606
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -19568,10 +19700,10 @@ async function renderSpan(projectDir, config, span, outputPath) {
|
|
|
19568
19700
|
if (config.cfr === true) {
|
|
19569
19701
|
throw new RenderSpanUnsupportedError("--start/--end cannot be combined with a cfr re-encode.");
|
|
19570
19702
|
}
|
|
19571
|
-
const workDir = mkdtempSync7(
|
|
19703
|
+
const workDir = mkdtempSync7(join42(tmpdir4(), "hf-render-span-"));
|
|
19572
19704
|
try {
|
|
19573
|
-
const planDir =
|
|
19574
|
-
const partsDir =
|
|
19705
|
+
const planDir = join42(workDir, "plan");
|
|
19706
|
+
const partsDir = join42(workDir, "parts");
|
|
19575
19707
|
mkdirSync18(partsDir, { recursive: true });
|
|
19576
19708
|
const planned = await plan(
|
|
19577
19709
|
projectDir,
|
|
@@ -19586,7 +19718,7 @@ async function renderSpan(projectDir, config, span, outputPath) {
|
|
|
19586
19718
|
planned.totalFrames
|
|
19587
19719
|
);
|
|
19588
19720
|
const slices = JSON.parse(
|
|
19589
|
-
readFileSync13(
|
|
19721
|
+
readFileSync13(join42(planDir, "meta", "chunks.json"), "utf-8")
|
|
19590
19722
|
);
|
|
19591
19723
|
const parts = [];
|
|
19592
19724
|
for (const slice of slices) {
|
|
@@ -19596,13 +19728,18 @@ async function renderSpan(projectDir, config, span, outputPath) {
|
|
|
19596
19728
|
};
|
|
19597
19729
|
if (range.endFrame <= range.startFrame) continue;
|
|
19598
19730
|
throwIfAborted(config.abortSignal);
|
|
19599
|
-
const part =
|
|
19731
|
+
const part = join42(partsDir, `part-${String(parts.length).padStart(4, "0")}.mp4`);
|
|
19600
19732
|
await renderChunk(planDir, slice.index, part, { frameRange: range });
|
|
19601
19733
|
parts.push(part);
|
|
19602
19734
|
}
|
|
19603
19735
|
throwIfAborted(config.abortSignal);
|
|
19604
19736
|
await writeStitchedMp4(parts, outputPath);
|
|
19605
|
-
return {
|
|
19737
|
+
return {
|
|
19738
|
+
...referenceBackgroundResult6(planned[REFERENCE_BACKGROUND_FIELD4]),
|
|
19739
|
+
startFrame,
|
|
19740
|
+
endFrame,
|
|
19741
|
+
framesEncoded: endFrame - startFrame
|
|
19742
|
+
};
|
|
19606
19743
|
} finally {
|
|
19607
19744
|
rmSync16(workDir, { recursive: true, force: true });
|
|
19608
19745
|
}
|
|
@@ -20167,9 +20304,9 @@ function renderRequestFromDistributedConfig(input) {
|
|
|
20167
20304
|
|
|
20168
20305
|
// src/services/frameCapture.ts
|
|
20169
20306
|
import {
|
|
20170
|
-
createCaptureSession as
|
|
20307
|
+
createCaptureSession as createCaptureSession12,
|
|
20171
20308
|
initializeSession as initializeSession11,
|
|
20172
|
-
closeCaptureSession as
|
|
20309
|
+
closeCaptureSession as closeCaptureSession12,
|
|
20173
20310
|
captureFrame as captureFrame2,
|
|
20174
20311
|
captureFrameToBuffer as captureFrameToBuffer4,
|
|
20175
20312
|
getCompositionDuration as getCompositionDuration2,
|
|
@@ -20197,14 +20334,18 @@ import {
|
|
|
20197
20334
|
rmSync as rmSync17,
|
|
20198
20335
|
createReadStream as createReadStream5
|
|
20199
20336
|
} from "node:fs";
|
|
20200
|
-
import { resolve as resolve12, dirname as dirname18, join as
|
|
20337
|
+
import { resolve as resolve12, dirname as dirname18, join as join45 } from "node:path";
|
|
20201
20338
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
20202
20339
|
import { parseArgs } from "node:util";
|
|
20203
20340
|
import crypto from "node:crypto";
|
|
20204
20341
|
import { Hono as Hono2 } from "hono";
|
|
20205
20342
|
import { streamSSE } from "hono/streaming";
|
|
20206
20343
|
import { serve as serve2 } from "@hono/node-server";
|
|
20207
|
-
import {
|
|
20344
|
+
import {
|
|
20345
|
+
fetchPublicHttpsText as fetchPublicHttpsText2,
|
|
20346
|
+
REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD5,
|
|
20347
|
+
referenceBackgroundResult as referenceBackgroundResult7
|
|
20348
|
+
} from "@hyperframes/engine";
|
|
20208
20349
|
|
|
20209
20350
|
// src/services/hyperframeLint.ts
|
|
20210
20351
|
import {
|
|
@@ -20216,7 +20357,7 @@ import {
|
|
|
20216
20357
|
closeSync as closeSync7,
|
|
20217
20358
|
constants as constants3
|
|
20218
20359
|
} from "node:fs";
|
|
20219
|
-
import { resolve as resolve11, join as
|
|
20360
|
+
import { resolve as resolve11, join as join43, relative as relative7, isAbsolute as isAbsolute5, sep as sep4 } from "node:path";
|
|
20220
20361
|
import { lintHyperframeHtml } from "@hyperframes/lint";
|
|
20221
20362
|
function isStringRecord(value) {
|
|
20222
20363
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -20284,7 +20425,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
|
|
|
20284
20425
|
}
|
|
20285
20426
|
}
|
|
20286
20427
|
return {
|
|
20287
|
-
error: `No HTML entry file found in project directory: ${
|
|
20428
|
+
error: `No HTML entry file found in project directory: ${join43(absProjectDir, preferredEntryFile || "index.html")}`
|
|
20288
20429
|
};
|
|
20289
20430
|
}
|
|
20290
20431
|
function prepareHyperframeLintBody(body) {
|
|
@@ -20330,7 +20471,7 @@ async function runHyperframeLint(prepared) {
|
|
|
20330
20471
|
// src/services/healthWorker.ts
|
|
20331
20472
|
import { Worker as Worker2 } from "node:worker_threads";
|
|
20332
20473
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
20333
|
-
import { dirname as dirname17, join as
|
|
20474
|
+
import { dirname as dirname17, join as join44 } from "node:path";
|
|
20334
20475
|
import { existsSync as existsSync28 } from "node:fs";
|
|
20335
20476
|
var DEFAULT_HEALTH_PORT = 9848;
|
|
20336
20477
|
async function startHealthWorker(options = {}) {
|
|
@@ -20406,7 +20547,7 @@ function defaultLogger2() {
|
|
|
20406
20547
|
}
|
|
20407
20548
|
function resolveWorkerEntry2() {
|
|
20408
20549
|
const here = dirname17(fileURLToPath6(import.meta.url));
|
|
20409
|
-
const candidates = [
|
|
20550
|
+
const candidates = [join44(here, "healthWorkerThread.js"), join44(here, "healthWorkerThread.ts")];
|
|
20410
20551
|
for (const candidate of candidates) {
|
|
20411
20552
|
if (existsSync28(candidate)) return candidate;
|
|
20412
20553
|
}
|
|
@@ -20617,8 +20758,8 @@ async function resolveInlineRenderHtml(body) {
|
|
|
20617
20758
|
}
|
|
20618
20759
|
function materializeInlineProject(html, options) {
|
|
20619
20760
|
const tempRoot = process.env.PRODUCER_TMP_PROJECT_DIR || tmpdir5();
|
|
20620
|
-
const tempProjectDir = mkdtempSync8(
|
|
20621
|
-
writeFileSync13(
|
|
20761
|
+
const tempProjectDir = mkdtempSync8(join45(tempRoot, "producer-project-"));
|
|
20762
|
+
writeFileSync13(join45(tempProjectDir, "index.html"), html, "utf-8");
|
|
20622
20763
|
return {
|
|
20623
20764
|
prepared: {
|
|
20624
20765
|
input: { projectDir: tempProjectDir, ...options },
|
|
@@ -20875,6 +21016,7 @@ function createRenderHandlers(options = {}) {
|
|
|
20875
21016
|
outputUrl,
|
|
20876
21017
|
fileSize,
|
|
20877
21018
|
durationMs,
|
|
21019
|
+
...referenceBackgroundResult7(job[REFERENCE_BACKGROUND_FIELD5]),
|
|
20878
21020
|
videoDurationSeconds: job.duration ?? null,
|
|
20879
21021
|
outcome: job.outcome ?? "completed",
|
|
20880
21022
|
warnings: job.warnings,
|
|
@@ -20962,6 +21104,7 @@ function createRenderHandlers(options = {}) {
|
|
|
20962
21104
|
outputToken,
|
|
20963
21105
|
outputUrl,
|
|
20964
21106
|
fileSize,
|
|
21107
|
+
...referenceBackgroundResult7(job[REFERENCE_BACKGROUND_FIELD5]),
|
|
20965
21108
|
videoDurationSeconds: job.duration ?? null,
|
|
20966
21109
|
outcome: job.outcome ?? "completed",
|
|
20967
21110
|
warnings: job.warnings,
|
|
@@ -21087,9 +21230,13 @@ import { quantizeTimeToFrame, MEDIA_VISUAL_STYLE_PROPERTIES } from "@hyperframes
|
|
|
21087
21230
|
// src/services/distributed/planV2Execution.ts
|
|
21088
21231
|
import { mkdtempSync as mkdtempSync10, rmSync as rmSync19 } from "node:fs";
|
|
21089
21232
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
21090
|
-
import { join as
|
|
21233
|
+
import { join as join47 } from "node:path";
|
|
21091
21234
|
|
|
21092
21235
|
// src/services/distributed/assemble.ts
|
|
21236
|
+
import {
|
|
21237
|
+
REFERENCE_BACKGROUND_FIELD as REFERENCE_BACKGROUND_FIELD6,
|
|
21238
|
+
referenceBackgroundResult as referenceBackgroundResult8
|
|
21239
|
+
} from "@hyperframes/engine";
|
|
21093
21240
|
import {
|
|
21094
21241
|
cpSync as cpSync3,
|
|
21095
21242
|
existsSync as existsSync30,
|
|
@@ -21101,7 +21248,7 @@ import {
|
|
|
21101
21248
|
statSync as statSync13,
|
|
21102
21249
|
writeFileSync as writeFileSync14
|
|
21103
21250
|
} from "node:fs";
|
|
21104
|
-
import { dirname as dirname19, join as
|
|
21251
|
+
import { dirname as dirname19, join as join46 } from "node:path";
|
|
21105
21252
|
import {
|
|
21106
21253
|
appendRateCapArgs as appendRateCapArgs2,
|
|
21107
21254
|
appendRenderProvenanceArgs as appendRenderProvenanceArgs2,
|
|
@@ -21129,12 +21276,16 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
21129
21276
|
const plan2 = readAssemblePlan(planDir, chunkOutputs);
|
|
21130
21277
|
const chunkPaths = chunkOutputs.flat();
|
|
21131
21278
|
if (plan2.dimensions.format === "png-sequence") {
|
|
21132
|
-
return
|
|
21279
|
+
return {
|
|
21280
|
+
...mergePngFrameDirs(chunkPaths, outputPath, plan2.totalFrames, audioPath, start),
|
|
21281
|
+
...referenceBackgroundResult8(plan2[REFERENCE_BACKGROUND_FIELD6])
|
|
21282
|
+
};
|
|
21133
21283
|
}
|
|
21134
21284
|
if (chunksAreStitchedMp4(planDir, cfr)) {
|
|
21135
21285
|
const separateAudio = stitchesSeparateAudio(planDir) && audioPath !== null;
|
|
21136
21286
|
await writeStitchedMp4(chunkPaths, outputPath, separateAudio ? audioPath : void 0);
|
|
21137
21287
|
return {
|
|
21288
|
+
...referenceBackgroundResult8(plan2[REFERENCE_BACKGROUND_FIELD6]),
|
|
21138
21289
|
outputPath,
|
|
21139
21290
|
durationMs: Date.now() - start,
|
|
21140
21291
|
framesEncoded: plan2.totalFrames,
|
|
@@ -21166,7 +21317,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
21166
21317
|
};
|
|
21167
21318
|
try {
|
|
21168
21319
|
const videoSources = cfrEncoder ? [await reencodeCfr(ctx, chunkPaths, cfrEncoder)] : chunkPaths;
|
|
21169
|
-
const finalPath =
|
|
21320
|
+
const finalPath = join46(workDir, `output.${format}`);
|
|
21170
21321
|
const audio = audioPath !== null && existsSync30(audioPath) ? audioPath : null;
|
|
21171
21322
|
await writeJoined(ctx, videoSources, audio, finalPath);
|
|
21172
21323
|
renameWithRetry11(finalPath, outputPath);
|
|
@@ -21187,6 +21338,7 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
21187
21338
|
}
|
|
21188
21339
|
const fileSize = existsSync30(outputPath) ? statSync13(outputPath).size : 0;
|
|
21189
21340
|
return {
|
|
21341
|
+
...referenceBackgroundResult8(plan2[REFERENCE_BACKGROUND_FIELD6]),
|
|
21190
21342
|
outputPath,
|
|
21191
21343
|
durationMs: Date.now() - start,
|
|
21192
21344
|
framesEncoded: plan2.totalFrames,
|
|
@@ -21194,8 +21346,8 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
21194
21346
|
};
|
|
21195
21347
|
}
|
|
21196
21348
|
function readAssemblePlan(planDir, chunkPaths) {
|
|
21197
|
-
const planJsonPath =
|
|
21198
|
-
const chunksJsonPath =
|
|
21349
|
+
const planJsonPath = join46(planDir, "plan.json");
|
|
21350
|
+
const chunksJsonPath = join46(planDir, "meta", "chunks.json");
|
|
21199
21351
|
if (!existsSync30(planJsonPath)) {
|
|
21200
21352
|
throw new Error(`[assemble] planDir missing plan.json: ${planJsonPath}`);
|
|
21201
21353
|
}
|
|
@@ -21246,7 +21398,7 @@ function cfrEncodeArgs(inputArgs, encoder, fpsArg) {
|
|
|
21246
21398
|
return args;
|
|
21247
21399
|
}
|
|
21248
21400
|
async function reencodeCfr(ctx, chunkPaths, encoder) {
|
|
21249
|
-
const cfrOutputPath =
|
|
21401
|
+
const cfrOutputPath = join46(ctx.workDir, `cfr.${ctx.format}`);
|
|
21250
21402
|
const cfrArgs = cfrEncodeArgs(videoInputArgs(ctx, chunkPaths), encoder, ctx.fpsArg);
|
|
21251
21403
|
appendRenderProvenanceArgs2(cfrArgs, cfrOutputPath);
|
|
21252
21404
|
cfrArgs.push("-y", cfrOutputPath);
|
|
@@ -21273,7 +21425,7 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
|
|
|
21273
21425
|
);
|
|
21274
21426
|
return;
|
|
21275
21427
|
}
|
|
21276
|
-
const paddedAudioPath =
|
|
21428
|
+
const paddedAudioPath = join46(ctx.workDir, "audio-padded.m4a");
|
|
21277
21429
|
const padTrimResult = await ctx.timed(
|
|
21278
21430
|
"audioMs",
|
|
21279
21431
|
() => padOrTrimAudioToVideoFrameCount({
|
|
@@ -21313,7 +21465,7 @@ async function writeJoined(ctx, videoSources, audioPath, finalPath) {
|
|
|
21313
21465
|
}
|
|
21314
21466
|
}
|
|
21315
21467
|
function concatDemuxerInput(chunkPaths, workDir, fpsArg) {
|
|
21316
|
-
const listPath =
|
|
21468
|
+
const listPath = join46(workDir, "concat-list.txt");
|
|
21317
21469
|
const body = chunkPaths.map((path) => `file '${path.replace(/'/g, "'\\''")}'`).join("\n");
|
|
21318
21470
|
writeFileSync14(listPath, `${body}
|
|
21319
21471
|
`, "utf-8");
|
|
@@ -21351,11 +21503,11 @@ function stitchesSeparateAudio(planDir) {
|
|
|
21351
21503
|
return lockedAudio(planDir).separateAudio === true;
|
|
21352
21504
|
}
|
|
21353
21505
|
function planFormat(planDir) {
|
|
21354
|
-
const plan2 = JSON.parse(readFileSync15(
|
|
21506
|
+
const plan2 = JSON.parse(readFileSync15(join46(planDir, "plan.json"), "utf-8"));
|
|
21355
21507
|
return plan2.dimensions.format;
|
|
21356
21508
|
}
|
|
21357
21509
|
function lockedAudio(planDir) {
|
|
21358
|
-
const encoderJsonPath =
|
|
21510
|
+
const encoderJsonPath = join46(planDir, "meta", "encoder.json");
|
|
21359
21511
|
if (!existsSync30(encoderJsonPath)) return {};
|
|
21360
21512
|
return JSON.parse(readFileSync15(encoderJsonPath, "utf-8"));
|
|
21361
21513
|
}
|
|
@@ -21365,7 +21517,7 @@ function readCfrEncoder(planDir, format) {
|
|
|
21365
21517
|
`[assemble] cfr=true is only supported for format="mp4" (got "${format}"). Stream-copy paths for webm and mov already produce exact avg_frame_rate; cfr re-encode is not needed.`
|
|
21366
21518
|
);
|
|
21367
21519
|
}
|
|
21368
|
-
const encoderJsonPath =
|
|
21520
|
+
const encoderJsonPath = join46(planDir, "meta", "encoder.json");
|
|
21369
21521
|
if (!existsSync30(encoderJsonPath)) {
|
|
21370
21522
|
throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
|
|
21371
21523
|
}
|
|
@@ -21392,8 +21544,8 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
|
|
|
21392
21544
|
throw new Error(`[assemble] png-sequence chunk has no frames: ${chunkDir}`);
|
|
21393
21545
|
}
|
|
21394
21546
|
for (const frame of frames) {
|
|
21395
|
-
const dst =
|
|
21396
|
-
cpSync3(
|
|
21547
|
+
const dst = join46(outputPath, formatExportFrameName(globalIdx, "png"));
|
|
21548
|
+
cpSync3(join46(chunkDir, frame), dst);
|
|
21397
21549
|
globalIdx += 1;
|
|
21398
21550
|
}
|
|
21399
21551
|
}
|
|
@@ -21403,13 +21555,13 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
|
|
|
21403
21555
|
);
|
|
21404
21556
|
}
|
|
21405
21557
|
if (audioPath !== null && existsSync30(audioPath)) {
|
|
21406
|
-
const sidecar =
|
|
21558
|
+
const sidecar = join46(outputPath, MIXED_AUDIO_FILENAME4);
|
|
21407
21559
|
cpSync3(audioPath, sidecar);
|
|
21408
21560
|
}
|
|
21409
21561
|
let fileSize = 0;
|
|
21410
21562
|
for (const name of readdirSync11(outputPath)) {
|
|
21411
21563
|
try {
|
|
21412
|
-
fileSize += statSync13(
|
|
21564
|
+
fileSize += statSync13(join46(outputPath, name)).size;
|
|
21413
21565
|
} catch {
|
|
21414
21566
|
}
|
|
21415
21567
|
}
|
|
@@ -21423,8 +21575,8 @@ function mergePngFrameDirs(chunkPaths, outputPath, totalFrames, audioPath, start
|
|
|
21423
21575
|
|
|
21424
21576
|
// src/services/distributed/planV2Execution.ts
|
|
21425
21577
|
async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
|
|
21426
|
-
const workRoot = mkdtempSync10(
|
|
21427
|
-
const materializedPlanDir =
|
|
21578
|
+
const workRoot = mkdtempSync10(join47(tmpdir6(), "hf-plan-v2-chunk-"));
|
|
21579
|
+
const materializedPlanDir = join47(workRoot, "plan");
|
|
21428
21580
|
try {
|
|
21429
21581
|
materializePlanV2Target(planV2Dir, { role: "chunk", chunkIndex }, materializedPlanDir);
|
|
21430
21582
|
return await renderChunk(materializedPlanDir, chunkIndex, outputChunkPath, options);
|
|
@@ -21433,8 +21585,8 @@ async function renderChunkV2(planV2Dir, chunkIndex, outputChunkPath, options) {
|
|
|
21433
21585
|
}
|
|
21434
21586
|
}
|
|
21435
21587
|
async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
|
|
21436
|
-
const workRoot = mkdtempSync10(
|
|
21437
|
-
const materializedPlanDir =
|
|
21588
|
+
const workRoot = mkdtempSync10(join47(tmpdir6(), "hf-plan-v2-assembler-"));
|
|
21589
|
+
const materializedPlanDir = join47(workRoot, "plan");
|
|
21438
21590
|
try {
|
|
21439
21591
|
const materialized = materializePlanV2Target(
|
|
21440
21592
|
planV2Dir,
|
|
@@ -21477,6 +21629,7 @@ export {
|
|
|
21477
21629
|
PLAN_V2_SCHEMA_VERSION,
|
|
21478
21630
|
PlanProtocolUnsupportedError,
|
|
21479
21631
|
PlanV2IntegrityError,
|
|
21632
|
+
REFERENCE_BACKGROUND_FIELD7 as REFERENCE_BACKGROUND_FIELD,
|
|
21480
21633
|
RENDER_JOB_DIR,
|
|
21481
21634
|
RENDER_REQUEST_VERSION,
|
|
21482
21635
|
RenderCancelledError,
|
|
@@ -21487,14 +21640,15 @@ export {
|
|
|
21487
21640
|
assembleV2,
|
|
21488
21641
|
captureFrame2 as captureFrame,
|
|
21489
21642
|
captureFrameToBuffer4 as captureFrameToBuffer,
|
|
21490
|
-
|
|
21643
|
+
closeCaptureSession12 as closeCaptureSession,
|
|
21491
21644
|
collectRenderMedia,
|
|
21492
|
-
|
|
21645
|
+
createCaptureSession12 as createCaptureSession,
|
|
21493
21646
|
createConsoleLogger,
|
|
21494
21647
|
createFileServer,
|
|
21495
21648
|
createOwnedRenderDir,
|
|
21496
21649
|
createPlanV2FromExecutionPlan,
|
|
21497
21650
|
createProducerApp,
|
|
21651
|
+
createReferenceBackgroundRecorder3 as createReferenceBackgroundRecorder,
|
|
21498
21652
|
createRenderHandlers,
|
|
21499
21653
|
createRenderJob,
|
|
21500
21654
|
createRenderRequest,
|
|
@@ -21527,6 +21681,8 @@ export {
|
|
|
21527
21681
|
publishPlanV2FromExecutionPlan,
|
|
21528
21682
|
quantizeTimeToFrame,
|
|
21529
21683
|
readPlanV2Manifest,
|
|
21684
|
+
readReferenceBackground2 as readReferenceBackground,
|
|
21685
|
+
referenceBackgroundResult9 as referenceBackgroundResult,
|
|
21530
21686
|
renderChunk,
|
|
21531
21687
|
renderChunkV2,
|
|
21532
21688
|
renderConfigFromRequest,
|