hyperframes 0.8.180 → 0.8.183
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/bin/hyperframes.mjs +3 -1
- package/dist/{add-HUVEWSVU.js → add-HW3ZGR36.js} +22 -22
- package/dist/{animatedGifPrep-V6GJQOEB.js → animatedGifPrep-EPLN37ZN.js} +13 -13
- package/dist/api.js +28 -28
- package/dist/{asset-ZGQHDMIO.js → asset-TOASKL3Z.js} +3 -3
- package/dist/{assetCataloger-MZWCOV6C.js → assetCataloger-PZN5HYG2.js} +15 -13
- package/dist/{audio-XDWHLNIW.js → audio-F5OIQVJO.js} +29 -29
- package/dist/{auth-VIV3M7S6.js → auth-YVQLRS3T.js} +4 -4
- package/dist/{autoUpdate-R32XDL42.js → autoUpdate-EG4ZFW4D.js} +2 -2
- package/dist/{backgroundChecks-A2N6EVCP.js → backgroundChecks-WINNQVR2.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-3AYDQRBI.js → batchRender-PASZTMEE.js} +7 -7
- package/dist/{beats-2O423Z6Q.js → beats-KGIOEBLW.js} +12 -12
- package/dist/{benchmark-YXP3PTZP.js → benchmark-ZNY2L7HN.js} +24 -24
- package/dist/{browser-M47BNOTJ.js → browser-REAO7RU4.js} +20 -20
- package/dist/{bundleWithLocalizedFonts-GCIHOMIU.js → bundleWithLocalizedFonts-OAYLYC4W.js} +2 -2
- package/dist/{capture-IV3Y2MT4.js → capture-IK6GWQDD.js} +8 -5
- package/dist/{capture-BT2ZXN5P.js → capture-WOSF276U.js} +49 -41
- package/dist/{captureCompositionFrame-BMZEKPOU.js → captureCompositionFrame-DDZNKYRE.js} +21 -20
- package/dist/{captureTimeout-K2JNVVCI.js → captureTimeout-RIMG6IYH.js} +1 -1
- package/dist/{catalog-GI6P22KI.js → catalog-AKTXS7OJ.js} +42 -42
- package/dist/{catch-up-QS6HUHAO.js → catch-up-O3VZMPVE.js} +15 -15
- package/dist/check-6E46NIWI.js +116 -0
- package/dist/checkBrowser-UNZHQFNH.js +117 -0
- package/dist/{chunk-ST2ARHQ5.js → chunk-3BA2GP4H.js} +5 -5
- package/dist/{chunk-7Z6AARJR.js → chunk-3OLIGYWN.js} +3 -3
- package/dist/{chunk-OR5WCFWZ.js → chunk-3Q47QC46.js} +2 -2
- package/dist/{chunk-Q2ASTBSG.js → chunk-4FQKS7BJ.js} +16 -14
- package/dist/{chunk-G2ZMCNRN.js → chunk-4UFJWRHG.js} +527 -283
- package/dist/{chunk-537IYAEE.js → chunk-4UMPIPCQ.js} +9 -1
- package/dist/{chunk-65CLIHK2.js → chunk-5MBLWFLM.js} +1 -1
- package/dist/{chunk-UVEQLDKB.js → chunk-5OGDBU4G.js} +3 -2
- package/dist/{chunk-L3YOGIPG.js → chunk-66LREXGS.js} +1 -1
- package/dist/{chunk-W4SLIGGM.js → chunk-73LTCCZI.js} +249 -161
- package/dist/{chunk-GZVP4TWN.js → chunk-7JAD4MEW.js} +1 -1
- package/dist/{chunk-NAMGMP3R.js → chunk-7KVVNF7B.js} +1 -1
- package/dist/{chunk-GK2FIKIQ.js → chunk-ADDHW2FS.js} +214 -37
- package/dist/{chunk-WUQUR33W.js → chunk-AKFADCMS.js} +1 -1
- package/dist/{chunk-2VJNKE7C.js → chunk-ANR6WOC3.js} +1 -1
- package/dist/{chunk-L527FLMV.js → chunk-ATMDOUNN.js} +2 -2
- package/dist/{chunk-ZJPCQBU7.js → chunk-B2SZZFWW.js} +4 -4
- package/dist/{chunk-TO6JNTML.js → chunk-BP4VNTZL.js} +13 -8
- package/dist/{chunk-3YXTFXT7.js → chunk-CAHTO62O.js} +8 -8
- package/dist/{chunk-MPWLGNM2.js → chunk-CGK4XZ2J.js} +1 -1
- package/dist/{chunk-NOXGG4C7.js → chunk-CJYAJ3QM.js} +37 -33
- package/dist/{chunk-F5VMPELS.js → chunk-COTLNID2.js} +16 -16
- package/dist/{chunk-E24HSMZV.js → chunk-CYBXXSC4.js} +65 -14
- package/dist/{chunk-NZZYJOMJ.js → chunk-CZUAX3BV.js} +6 -5
- package/dist/{chunk-K7RGIADJ.js → chunk-DEORFAWP.js} +12 -12
- package/dist/{chunk-GV5R5B7Q.js → chunk-DGECWPTL.js} +1 -1
- package/dist/{chunk-BRHI7EIA.js → chunk-DKPNNYBZ.js} +4 -0
- package/dist/{chunk-R46P7TGY.js → chunk-DLC2FICN.js} +7 -7
- package/dist/{chunk-D3ZWBHZP.js → chunk-DYAPHNV6.js} +3 -2
- package/dist/{chunk-RGHQID2E.js → chunk-EHSBBBR2.js} +5 -3
- package/dist/{chunk-IWTRHPTP.js → chunk-EVAQPW6O.js} +8 -8
- package/dist/{chunk-S3RYRF3W.js → chunk-F6WHPHLF.js} +1 -1
- package/dist/chunk-FG4BBFZI.js +122 -0
- package/dist/{chunk-V6MQP32U.js → chunk-GAGMLVCV.js} +2 -2
- package/dist/chunk-GMNHAOMJ.js +3805 -0
- package/dist/{chunk-KIO3R4QN.js → chunk-GPE3WWTO.js} +16 -6
- package/dist/{chunk-ULWZYLCV.js → chunk-GTE5WZAM.js} +72 -140
- package/dist/{chunk-2JDLESMS.js → chunk-HLBODNGW.js} +1 -1
- package/dist/{chunk-KMAAOHLO.js → chunk-HRPWRZGF.js} +1 -1
- package/dist/{chunk-UPFUC4DB.js → chunk-HTIUNMTP.js} +1 -1
- package/dist/{chunk-FCUTQM2P.js → chunk-IC2WYONA.js} +5 -5
- package/dist/{chunk-VE3OKVSD.js → chunk-ITSLKUQM.js} +2 -2
- package/dist/{chunk-YJDB4FLT.js → chunk-JQYJXUJW.js} +1 -1
- package/dist/{chunk-PBN6GBJE.js → chunk-JVBRJMOP.js} +14 -1
- package/dist/{chunk-XH262OWN.js → chunk-K2Z5DZBS.js} +1 -1
- package/dist/{chunk-RHWJKSGH.js → chunk-KANNRHY7.js} +1 -1
- package/dist/{chunk-Y5APFFMD.js → chunk-KRFAX5JK.js} +1 -1
- package/dist/{chunk-4J7DHVN2.js → chunk-LBWRQ4XA.js} +1 -1
- package/dist/{chunk-MQOE5RE4.js → chunk-MIZDJVPZ.js} +9 -9
- package/dist/{chunk-32GKETR7.js → chunk-MMQ52NIZ.js} +74 -0
- package/dist/chunk-MOEGCMKI.js +180 -0
- package/dist/{chunk-E6RPWJVC.js → chunk-NAUKCKCJ.js} +5 -1
- package/dist/{chunk-JBCU6NR5.js → chunk-NZ3BE2QE.js} +56 -55
- package/dist/{chunk-VKMP3IVR.js → chunk-O7N3A7PE.js} +2 -2
- package/dist/{chunk-3QENZQSL.js → chunk-OH56PXFH.js} +5 -5
- package/dist/{chunk-H4YZZ2VQ.js → chunk-PFD25NAC.js} +1 -1
- package/dist/{check-HE5E4Q7Q.js → chunk-Q6UYKWBG.js} +198 -142
- package/dist/{chunk-3DKN5WKL.js → chunk-QH3T4WI2.js} +77 -6
- package/dist/{chunk-RGXAN3YU.js → chunk-QX4GGPMY.js} +2 -2
- package/dist/{chunk-A3NFBMYX.js → chunk-R6OV4J4K.js} +6 -6
- package/dist/{chunk-LL5VQ4WS.js → chunk-RZXUQR42.js} +2 -2
- package/dist/{chunk-SEMOZNVE.js → chunk-SAQYJLI6.js} +1 -1
- package/dist/{chunk-55P7GDT6.js → chunk-TJB4GAV6.js} +2 -2
- package/dist/{checkBrowser-BHLYP3YW.js → chunk-TOHA5NAU.js} +187 -114
- package/dist/{chunk-RXQHSGAQ.js → chunk-TXGZZKDF.js} +2 -2
- package/dist/{chunk-KZ3VI5K6.js → chunk-U5YVWG5W.js} +3 -3
- package/dist/{chunk-ICMXC3MI.js → chunk-U6RXZNZE.js} +31 -18
- package/dist/{chunk-XO6CWU7D.js → chunk-UNOSCGBG.js} +2 -2
- package/dist/{chunk-NXYBR4QX.js → chunk-VAK7A2N6.js} +16 -16
- package/dist/{chunk-OFY6JTZC.js → chunk-VDJO4DJ7.js} +2 -2
- package/dist/{chunk-LBQFLUIY.js → chunk-VFBAKPRC.js} +9 -49
- package/dist/{chunk-K3KANDZQ.js → chunk-VH5KESLX.js} +1 -1
- package/dist/{chunk-22QHO26F.js → chunk-W64L7IFS.js} +1 -1
- package/dist/{chunk-4IEH6EAC.js → chunk-WT4PYV2J.js} +4 -6
- package/dist/{chunk-XFCLWWL3.js → chunk-X3IA5RYH.js} +2 -2
- package/dist/{chunk-UZOZ2W2E.js → chunk-XAQDR5Y5.js} +2 -2
- package/dist/{chunk-BI52RNRW.js → chunk-XJHKJXT4.js} +103 -20
- package/dist/{chunk-HFZ4UILX.js → chunk-XOVHO3TT.js} +25 -14
- package/dist/{chunk-VARUKXOZ.js → chunk-XR5BSEUF.js} +7 -15
- package/dist/{chunk-IZM562YJ.js → chunk-Z4R35NJS.js} +4 -4
- package/dist/{chunk-AMX53HVX.js → chunk-ZFO3A3QL.js} +2 -2
- package/dist/{clean-TQOW24OF.js → clean-WNEIVBF3.js} +40 -40
- package/dist/cli.js +68 -64
- package/dist/{cloud-7TOVPUMY.js → cloud-6GSSDCJL.js} +4 -4
- package/dist/{cloudrun-2BKGY53X.js → cloudrun-4NEJRE4T.js} +8 -8
- package/dist/commands/layout-audit.browser.js +15 -4
- package/dist/commands/motion-signature.browser.js +52 -0
- package/dist/{compare-WDV3Q6WC.js → compare-2JWQ5ABA.js} +50 -47
- package/dist/{compiler-U3W6CJW7.js → compiler-27KQD7KW.js} +6 -6
- package/dist/{component-U66GBIUO.js → component-HCRET3MH.js} +4 -4
- package/dist/{compositions-Y63YGLCE.js → compositions-HTSQ6SUJ.js} +28 -29
- package/dist/{contactSheet-27SRU7A4.js → contactSheet-CAGMKI3E.js} +3 -1
- package/dist/{delete-TBAIAD7M.js → delete-GHQ5UYM7.js} +9 -9
- package/dist/{deploy-BIWOSWS3.js → deploy-I3Z3NAVA.js} +11 -11
- package/dist/{destroy-QBLMYDBF.js → destroy-4B5HW5FH.js} +5 -5
- package/dist/{deterministicFonts-L7YEEFGI.js → deterministicFonts-JFLSSKRB.js} +2 -2
- package/dist/{dist-2FMTAVGL.js → dist-SENYPQGW.js} +4 -4
- package/dist/{dist-VO7OXOFK.js → dist-WRDLWRMS.js} +5 -5
- package/dist/{docs-MPOM3PHH.js → docs-UEWLIP6D.js} +1 -1
- package/dist/{doctor-GC4REGB6.js → doctor-UGFVQZHI.js} +27 -27
- package/dist/{events-PUUP24FT.js → events-BLJGWMNP.js} +9 -9
- package/dist/{events-4NMQVUZR.js → events-YS4OVX3I.js} +6 -6
- package/dist/{feedback-BIDXK7TE.js → feedback-AZ3SJ5HF.js} +35 -35
- package/dist/{ffmpeg-2VJDEWQQ.js → ffmpeg-2AECXG7V.js} +15 -15
- package/dist/{figma-THMXYLMU.js → figma-DRYIJQHV.js} +3 -3
- package/dist/fontLocalizeCli.js +23 -23
- package/dist/{get-5T4B7ERH.js → get-DDEAOFPB.js} +9 -9
- package/dist/{gpuPolicy-GLUATV5I.js → gpuPolicy-UDJT2MQK.js} +13 -13
- package/dist/{grade-compare-2A65YEHZ.js → grade-compare-LJKK5NSY.js} +55 -50
- package/dist/{help-JFBDXFRC.js → help-TQBGYOID.js} +1 -1
- package/dist/{history-OJEWFWMS.js → history-5TOOCF2Y.js} +15 -15
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +17 -17
- package/dist/hyperframes-player.global.js +8 -3
- package/dist/{info-KJZBU3SZ.js → info-ENI5MP4W.js} +20 -20
- package/dist/{init-6V4ELU4Z.js → init-JXPXWV3G.js} +68 -68
- package/dist/{inspect-WGBZZUZU.js → inspect-WZNYQ5AB.js} +45 -44
- package/dist/{installer-EPRSH6QI.js → installer-3SGRBLJW.js} +7 -7
- package/dist/{keyframes-57LYKC2M.js → keyframes-HEOC4CT4.js} +16 -16
- package/dist/{lambda-5P5X2X5E.js → lambda-2VHQ4AL2.js} +15 -15
- package/dist/{layout-PM2VAUT2.js → layout-7WEUNO6T.js} +45 -44
- package/dist/{lint-DXS6QRYZ.js → lint-5YMAF3L7.js} +23 -23
- package/dist/{lintProject-ARKJXDQF.js → lintProject-C2ONSH2U.js} +4 -4
- package/dist/{list-6IBSX7FU.js → list-BIE3X7CO.js} +10 -10
- package/dist/{login-RY3PWK44.js → login-YDIGJWCG.js} +7 -7
- package/dist/{logout-DKJANASY.js → logout-DDC4QLVK.js} +3 -3
- package/dist/{manager-N3COY6BJ.js → manager-D2UV6RDQ.js} +16 -16
- package/dist/{manager-V2QCCPOJ.js → manager-UHWEKPXC.js} +8 -3
- package/dist/{media-treatment-3HEZR7ZS.js → media-treatment-FSKHPMWA.js} +33 -33
- package/dist/{media-use-4XXGABIL.js → media-use-JBN57JE3.js} +1 -1
- package/dist/{models-FEULJWSX.js → models-COEK6LXG.js} +24 -24
- package/dist/{motionShot-BZTEIZEO.js → motionShot-HYZ2ZGJQ.js} +28 -26
- package/dist/{normalize-audio-O4X4LPLK.js → normalize-audio-UXR6WQ7Q.js} +12 -12
- package/dist/{open-H3MX4TI2.js → open-OFT2GIDG.js} +24 -24
- package/dist/{parakeetRunner-5ABMPCI6.js → parakeetRunner-4NZ3QXS3.js} +25 -25
- package/dist/{pipeline-RJ4DOVWX.js → pipeline-ZKE54JMG.js} +18 -18
- package/dist/{play-3PBKEZIX.js → play-2VG77FT6.js} +39 -38
- package/dist/{policies-5NTZOHJA.js → policies-XXNGXWHV.js} +1 -1
- package/dist/{preflight-3RABQJT3.js → preflight-QTWDIM5C.js} +18 -18
- package/dist/{present-6SNRG3GI.js → present-OONXQLJG.js} +33 -33
- package/dist/{preview-LSDFCJ3H.js → preview-6RZJFU76.js} +49 -49
- package/dist/{producer-SUZDRXHJ.js → producer-6YM3UH3B.js} +1 -1
- package/dist/{progress-I37JB7R4.js → progress-NHJIHAAG.js} +2 -2
- package/dist/{projectConfig-5QCNTGQT.js → projectConfig-YMW4P2X6.js} +9 -9
- package/dist/{publication-2QT7VVE2.js → publication-SEINUAPZ.js} +5 -5
- package/dist/{publish-53EBL7OO.js → publish-KZBTBWFO.js} +27 -27
- package/dist/{refresh-MGCVWX56.js → refresh-RXTOPRBB.js} +3 -3
- package/dist/{remove-background-4G4MX5WK.js → remove-background-BIQNMIR7.js} +31 -31
- package/dist/{render-RXKUYTYI.js → render-65K3K6SD.js} +31 -31
- package/dist/{render-SKY6FKYB.js → render-FIH37HJA.js} +101 -96
- package/dist/{render-75CRB3BW.js → render-LW76HOMJ.js} +8 -8
- package/dist/{render-batch-CEVWUYBP.js → render-batch-POLEEYD4.js} +8 -8
- package/dist/renderSetupWorker.js +12 -9
- package/dist/{resolver-4ICE2AT6.js → resolver-O2SED3XB.js} +7 -7
- package/dist/{screenshotCapture-HXEZ3TNJ.js → screenshotCapture-UBY6TT75.js} +33 -6
- package/dist/{sherpa-TMX3WBTM.js → sherpa-HTFFFTVQ.js} +24 -24
- package/dist/{sites-3ZBYB5X4.js → sites-MAVH57MO.js} +2 -2
- package/dist/skills/hyperframes/references/review-loop.md +1 -1
- package/dist/{skills-MCWFAGIP.js → skills-J6MBGS5O.js} +17 -17
- package/dist/{skillsUpdateCheck-NXOI35BW.js → skillsUpdateCheck-ZAXNLBF3.js} +3 -3
- package/dist/{snapshot-ESZMKQ6J.js → snapshot-TL7TTFS6.js} +72 -71
- package/dist/{src-XRTZOBO5.js → src-EL6HGIS4.js} +35 -26
- package/dist/{src-GYYWBQXJ.js → src-Z5H5N5T4.js} +19 -19
- package/dist/{state-KAXGHF77.js → state-ORRPOLMQ.js} +2 -2
- package/dist/{staticProjectServer-GYPUQGI7.js → staticProjectServer-EO7X7RAY.js} +20 -20
- package/dist/{status-BV7QAUQD.js → status-CM7IQTU2.js} +6 -6
- package/dist/studio/assets/{hyperframes-player-1wdLVP-x.js → hyperframes-player-hz_VqxBZ.js} +7 -2
- package/dist/studio/assets/{index-CaWPPTQ1.js → index-CV_ojgp5.js} +1 -1
- package/dist/studio/assets/{index-mdtW0Ug-.js → index-S1ceEagc.js} +71 -71
- package/dist/studio/index.html +1 -1
- package/dist/{studio-api-IXGX5ZFI.js → studio-api-CUZDC5B3.js} +17 -17
- package/dist/{studioServer-XVGYU6O3.js → studioServer-EZPRV43Y.js} +90 -84
- package/dist/{telemetry-E355EUDZ.js → telemetry-LFUVHARP.js} +10 -10
- package/dist/{telemetry-CQYHCCPL.js → telemetry-QG5AANZ4.js} +1 -1
- package/dist/{timeline-VWH6WSD7.js → timeline-GSH743JE.js} +41 -41
- package/dist/{tokens-IOAVF4UI.js → tokens-3ZMPSH7B.js} +3 -3
- package/dist/{transcribe-EGUXJGD4.js → transcribe-4SHNDPWW.js} +47 -47
- package/dist/{transcribe-EJA7OOHH.js → transcribe-TV7JBZQS.js} +19 -19
- package/dist/{tts-EDK3QS7M.js → tts-A2WILYGN.js} +6 -6
- package/dist/{updateCheck-U2CVTKPF.js → updateCheck-W7FTFOQF.js} +2 -2
- package/dist/{upgrade-CWEKQ4JO.js → upgrade-7YYYNAPF.js} +3 -3
- package/dist/{urlDownloader-DY5BLAFA.js → urlDownloader-PQSUS2CP.js} +12 -12
- package/dist/{validate-XOMNMKD6.js → validate-GCHAEVXM.js} +39 -38
- package/dist/{video-22NN6OEH.js → video-KGN7NJS5.js} +16 -14
- package/dist/warmCheck.js +227 -0
- package/dist/warmCheckClient.js +139 -0
- package/package.json +4 -2
- package/dist/chunk-BAZ5LCR3.js +0 -3805
- package/dist/hyperframe-runtime.js +0 -1125
- package/dist/{chunk-B4VT6YU2.js → chunk-QGOYNPQT.js} +3 -3
- package/dist/{synthesize-I2C24XJ5.js → synthesize-PKTB5ATG.js} +1 -1
|
@@ -5,12 +5,10 @@ var require = __hf_createRequire(import.meta.url);
|
|
|
5
5
|
var __filename = __hf_fileURLToPath(import.meta.url);
|
|
6
6
|
var __dirname = __hf_dirname(__filename);
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
createStudioPositionSeekReapplyScript
|
|
13
|
-
} from "./chunk-EVMY7IPL.js";
|
|
8
|
+
EncoderInterruptedError,
|
|
9
|
+
encoderFailureError,
|
|
10
|
+
prepareAnimatedGifInputs
|
|
11
|
+
} from "./chunk-ATMDOUNN.js";
|
|
14
12
|
import {
|
|
15
13
|
GENERIC_FAMILIES,
|
|
16
14
|
collectFontFamilyCustomProperties,
|
|
@@ -18,12 +16,14 @@ import {
|
|
|
18
16
|
iterateFontFamilyDeclarations,
|
|
19
17
|
normalizeSystemFontPrimaryFamilies,
|
|
20
18
|
resolveFontFamilyDeclarationFamilies
|
|
21
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-QGOYNPQT.js";
|
|
22
20
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
parseEncoderOptions
|
|
22
|
+
} from "./chunk-KLIKCX6Q.js";
|
|
23
|
+
import {
|
|
24
|
+
RENDER_TEMP_DIR,
|
|
25
|
+
createStudioPositionSeekReapplyScript
|
|
26
|
+
} from "./chunk-EVMY7IPL.js";
|
|
27
27
|
import {
|
|
28
28
|
BROWSER_GPU_NOT_SOFTWARE,
|
|
29
29
|
CaptureFailure,
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
ManagedChildProcess,
|
|
38
38
|
NotMediaPayloadError,
|
|
39
39
|
VIDEO_FRAME_FORMATS,
|
|
40
|
+
aacSegmentCount,
|
|
40
41
|
analyzeCompositionHdr,
|
|
41
42
|
analyzeKeyframeIntervals,
|
|
42
43
|
appendRenderProvenanceArgs,
|
|
@@ -79,6 +80,7 @@ import {
|
|
|
79
80
|
distributeFrames,
|
|
80
81
|
distributeFramesInterleaved,
|
|
81
82
|
downloadToTemp,
|
|
83
|
+
encodeAac,
|
|
82
84
|
encodeFramesChunkedConcat,
|
|
83
85
|
encodeFramesFromDir,
|
|
84
86
|
executeParallelCapture,
|
|
@@ -112,6 +114,7 @@ import {
|
|
|
112
114
|
isVideoFrameFormat,
|
|
113
115
|
isVideoHiddenBeforeStreamStart,
|
|
114
116
|
isVideoPastTimelineEnd,
|
|
117
|
+
measureVideoShownBoxes,
|
|
115
118
|
mergeWorkerFrames,
|
|
116
119
|
muxVideoWithAudio,
|
|
117
120
|
normalizeObjectFit,
|
|
@@ -138,7 +141,6 @@ import {
|
|
|
138
141
|
resolveFinalFrameExtractionWindow,
|
|
139
142
|
resolveHeadlessShellPath,
|
|
140
143
|
resolvePlayableVideoDuration,
|
|
141
|
-
resolveReferencedStart,
|
|
142
144
|
resolveVideoExtractionWindow,
|
|
143
145
|
runFfmpeg,
|
|
144
146
|
runVideoExtractionWithRetry,
|
|
@@ -152,46 +154,35 @@ import {
|
|
|
152
154
|
validateEngineConfigSnapshot,
|
|
153
155
|
verifyDiskDrawElementSamples,
|
|
154
156
|
writeCapturedFrame
|
|
155
|
-
} from "./chunk-
|
|
156
|
-
import {
|
|
157
|
-
assignBundledRuntimeCompositionIds,
|
|
158
|
-
buildVariablesByCompScript,
|
|
159
|
-
emitMountedModuleScripts,
|
|
160
|
-
emitRootCompositionVariableStyles,
|
|
161
|
-
ensureExternalLinkTag,
|
|
162
|
-
ensureExternalScriptTag,
|
|
163
|
-
extractStandaloneEntryFromIndex,
|
|
164
|
-
inlineSubCompositions,
|
|
165
|
-
isTemplateEntry,
|
|
166
|
-
parsesAsScript,
|
|
167
|
-
prepareFlattenedInnerRoot
|
|
168
|
-
} from "./chunk-4IEH6EAC.js";
|
|
169
|
-
import {
|
|
170
|
-
LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
171
|
-
getCgroupMemoryLimitMb,
|
|
172
|
-
getSystemTotalMb
|
|
173
|
-
} from "./chunk-W2LGJSEN.js";
|
|
157
|
+
} from "./chunk-73LTCCZI.js";
|
|
174
158
|
import {
|
|
175
159
|
DISTRIBUTED_FPS,
|
|
176
160
|
HF_VFX_ATTR,
|
|
177
|
-
MEDIA_START_BASIS_ATTR,
|
|
178
161
|
chainCapture,
|
|
179
162
|
clearGifFramesBeforeNext,
|
|
180
|
-
compositionOriginSeconds,
|
|
181
|
-
cutToHostSlots,
|
|
182
163
|
fpsToFfmpegArg,
|
|
183
164
|
fpsToNumber,
|
|
184
165
|
gifClearsAfterLeavingFrameInPlace,
|
|
185
166
|
gsapCdnDist,
|
|
186
|
-
hostInPointSeconds,
|
|
187
167
|
isDistributedFps,
|
|
188
168
|
parseFps,
|
|
189
169
|
parseVfxChain,
|
|
190
|
-
readMediaStartBasis,
|
|
191
|
-
resolveAbsoluteMediaStartSeconds,
|
|
192
170
|
resolveAuthoredTimingWindow,
|
|
193
171
|
toFps
|
|
194
|
-
} from "./chunk-
|
|
172
|
+
} from "./chunk-VFBAKPRC.js";
|
|
173
|
+
import {
|
|
174
|
+
assignBundledRuntimeCompositionIds,
|
|
175
|
+
buildVariablesByCompScript,
|
|
176
|
+
emitMountedModuleScripts,
|
|
177
|
+
emitRootCompositionVariableStyles,
|
|
178
|
+
ensureExternalLinkTag,
|
|
179
|
+
ensureExternalScriptTag,
|
|
180
|
+
extractStandaloneEntryFromIndex,
|
|
181
|
+
inlineSubCompositions,
|
|
182
|
+
isTemplateEntry,
|
|
183
|
+
parsesAsScript,
|
|
184
|
+
prepareFlattenedInnerRoot
|
|
185
|
+
} from "./chunk-WT4PYV2J.js";
|
|
195
186
|
import {
|
|
196
187
|
COMPOSITION_SOURCE_URL,
|
|
197
188
|
HF_COLOR_GRADING_ATTR,
|
|
@@ -219,7 +210,7 @@ import {
|
|
|
219
210
|
shouldClampResolvedMediaDuration,
|
|
220
211
|
sourceTimeAt,
|
|
221
212
|
styleElementsFor
|
|
222
|
-
} from "./chunk-
|
|
213
|
+
} from "./chunk-GMNHAOMJ.js";
|
|
223
214
|
import {
|
|
224
215
|
MAX_AUDIO_GAIN
|
|
225
216
|
} from "./chunk-UJKQWGFF.js";
|
|
@@ -234,24 +225,36 @@ import {
|
|
|
234
225
|
normalizeResolutionFlag,
|
|
235
226
|
suggestMatchingPreset
|
|
236
227
|
} from "./chunk-YMS5FOMC.js";
|
|
228
|
+
import {
|
|
229
|
+
TRANSITIONS,
|
|
230
|
+
convertTransfer,
|
|
231
|
+
crossfade
|
|
232
|
+
} from "./chunk-3GXQPCJC.js";
|
|
237
233
|
import {
|
|
238
234
|
redactKnownPaths,
|
|
239
235
|
redactTelemetryString
|
|
240
236
|
} from "./chunk-634HSJ3J.js";
|
|
241
237
|
import {
|
|
242
238
|
chromeMajorCeiling
|
|
243
|
-
} from "./chunk-
|
|
239
|
+
} from "./chunk-4UMPIPCQ.js";
|
|
244
240
|
import {
|
|
245
|
-
lintHyperframeHtml
|
|
246
|
-
|
|
241
|
+
lintHyperframeHtml,
|
|
242
|
+
resolveReferencedStart
|
|
243
|
+
} from "./chunk-ADDHW2FS.js";
|
|
247
244
|
import {
|
|
248
245
|
isUnresolvedAssetPlaceholder,
|
|
249
246
|
readProjectFile,
|
|
250
247
|
resolveProjectRelativeSrc
|
|
251
248
|
} from "./chunk-6BNTGNGD.js";
|
|
252
249
|
import {
|
|
253
|
-
|
|
254
|
-
|
|
250
|
+
MEDIA_START_BASIS_ATTR,
|
|
251
|
+
checkSubCompositionUsability,
|
|
252
|
+
compositionOriginSeconds,
|
|
253
|
+
cutToHostSlots,
|
|
254
|
+
hostInPointSeconds,
|
|
255
|
+
readMediaStartBasis,
|
|
256
|
+
resolveAbsoluteMediaStartSeconds
|
|
257
|
+
} from "./chunk-MMQ52NIZ.js";
|
|
255
258
|
import {
|
|
256
259
|
CSS_URL_RE,
|
|
257
260
|
decodedUrlPath,
|
|
@@ -264,10 +267,10 @@ import {
|
|
|
264
267
|
parseHTML
|
|
265
268
|
} from "./chunk-SDYDNHEE.js";
|
|
266
269
|
import {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
} from "./chunk-
|
|
270
|
+
LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
271
|
+
getCgroupMemoryLimitMb,
|
|
272
|
+
getSystemTotalMb
|
|
273
|
+
} from "./chunk-W2LGJSEN.js";
|
|
271
274
|
|
|
272
275
|
// ../producer/src/services/renderOrchestrator.ts
|
|
273
276
|
import {
|
|
@@ -1595,7 +1598,7 @@ function pidScope() {
|
|
|
1595
1598
|
return {
|
|
1596
1599
|
host: hostname(),
|
|
1597
1600
|
// Without /proc (macOS, Windows) the boot time, to the minute, stands in for the boot id.
|
|
1598
|
-
boot: attempt(() => readFileSync2("/proc/sys/kernel/random/boot_id", "utf-8").trim()) ?? String(Math.round(Date.now() / 6e4 - uptime() / 60)),
|
|
1601
|
+
boot: attempt(() => readFileSync2("/proc/sys/kernel/random/boot_id", "utf-8").trim()) ?? attempt(() => String(Math.round(Date.now() / 6e4 - uptime() / 60))),
|
|
1599
1602
|
pidns: attempt(() => readlinkSync("/proc/self/ns/pid"))
|
|
1600
1603
|
};
|
|
1601
1604
|
}
|
|
@@ -1613,9 +1616,14 @@ function alive(pid) {
|
|
|
1613
1616
|
return error.code === "EPERM";
|
|
1614
1617
|
}
|
|
1615
1618
|
}
|
|
1616
|
-
function
|
|
1619
|
+
function knownPidScope() {
|
|
1617
1620
|
const scope = pidScope();
|
|
1618
|
-
|
|
1621
|
+
const unknown = scope.boot === void 0 || process.platform === "linux" && scope.pidns === void 0;
|
|
1622
|
+
return unknown ? void 0 : scope;
|
|
1623
|
+
}
|
|
1624
|
+
function inThisPidScope(owner) {
|
|
1625
|
+
const scope = knownPidScope();
|
|
1626
|
+
return scope !== void 0 && owner.host === scope.host && owner.boot === scope.boot && owner.pidns === scope.pidns;
|
|
1619
1627
|
}
|
|
1620
1628
|
function ownerState(dir) {
|
|
1621
1629
|
let owner;
|
|
@@ -1680,7 +1688,9 @@ async function defaultArtifactDurationProbe(path) {
|
|
|
1680
1688
|
const meta = await extractMediaMetadata(path);
|
|
1681
1689
|
return {
|
|
1682
1690
|
durationSeconds: meta.durationSeconds,
|
|
1683
|
-
frames: meta.frames
|
|
1691
|
+
frames: meta.frames,
|
|
1692
|
+
width: meta.width,
|
|
1693
|
+
height: meta.height
|
|
1684
1694
|
};
|
|
1685
1695
|
}
|
|
1686
1696
|
function buildArtifactExpectation(input) {
|
|
@@ -1689,7 +1699,9 @@ function buildArtifactExpectation(input) {
|
|
|
1689
1699
|
const expectation = {
|
|
1690
1700
|
expectedDurationSeconds: input.durationSeconds,
|
|
1691
1701
|
fps: input.fps,
|
|
1692
|
-
expectedFrames: input.expectedFrames
|
|
1702
|
+
expectedFrames: input.expectedFrames,
|
|
1703
|
+
expectedWidth: input.width,
|
|
1704
|
+
expectedHeight: input.height
|
|
1693
1705
|
};
|
|
1694
1706
|
if (input.outputFormat !== "hls") return expectation;
|
|
1695
1707
|
return {
|
|
@@ -1757,6 +1769,16 @@ function assertFrameCountWithinTolerance(expectedFrames, probedFrames, stagingPa
|
|
|
1757
1769
|
`Render artifact is truncated: expected ${expectedFrames} frames, probed ${probedFrames} frames (shortfall ${shortfall} frames). Artifact: ${stagingPath}`
|
|
1758
1770
|
);
|
|
1759
1771
|
}
|
|
1772
|
+
function assertSizeMatches(expected, probed, stagingPath) {
|
|
1773
|
+
const { expectedWidth: width, expectedHeight: height } = expected;
|
|
1774
|
+
if (width === void 0 || height === void 0) return;
|
|
1775
|
+
if (probed.width === void 0 || probed.height === void 0) return;
|
|
1776
|
+
const fits = (want, got) => got === want || got === want + want % 2;
|
|
1777
|
+
if (fits(width, probed.width) && fits(height, probed.height)) return;
|
|
1778
|
+
throw new Error(
|
|
1779
|
+
`Render artifact has the wrong size: expected ${width}x${height}, probed ${probed.width}x${probed.height}. Artifact: ${stagingPath}`
|
|
1780
|
+
);
|
|
1781
|
+
}
|
|
1760
1782
|
var ArtifactTransaction = class {
|
|
1761
1783
|
constructor(destinationPath, kind, fileSystem = defaultFileSystem, durationProbe = defaultArtifactDurationProbe) {
|
|
1762
1784
|
this.kind = kind;
|
|
@@ -1829,6 +1851,7 @@ var ArtifactTransaction = class {
|
|
|
1829
1851
|
if (expected.expectedFrames !== void 0) {
|
|
1830
1852
|
assertFrameCountWithinTolerance(expected.expectedFrames, probed.frames, probePath);
|
|
1831
1853
|
}
|
|
1854
|
+
assertSizeMatches(expected, probed, probePath);
|
|
1832
1855
|
}
|
|
1833
1856
|
async runDurationProbe(probePath) {
|
|
1834
1857
|
try {
|
|
@@ -3307,7 +3330,9 @@ function aggregateDrawElement(perfs, de) {
|
|
|
3307
3330
|
if (perfs.length === 0) return void 0;
|
|
3308
3331
|
const modes = [...new Set(perfs.map((p) => p.captureMode).filter(Boolean))].sort();
|
|
3309
3332
|
const gateReasons = [
|
|
3310
|
-
...new Set(
|
|
3333
|
+
...new Set(
|
|
3334
|
+
[de.probeGateReason, ...perfs.map((p) => p.deGateReason)].filter((r) => !!r)
|
|
3335
|
+
)
|
|
3311
3336
|
].sort();
|
|
3312
3337
|
const gpuRenderers = [
|
|
3313
3338
|
...new Set(perfs.map((p) => p.gpuRenderer).filter((r) => !!r))
|
|
@@ -6579,7 +6604,7 @@ async function readLocalFont(absPath) {
|
|
|
6579
6604
|
return { kind: "inline", buffer: Buffer.concat(chunks, totalBytes) };
|
|
6580
6605
|
}
|
|
6581
6606
|
async function embedLocalFontFaces(html, projectDir) {
|
|
6582
|
-
const { fontToDataUri: toDataUri } = await import("./deterministicFonts-
|
|
6607
|
+
const { fontToDataUri: toDataUri } = await import("./deterministicFonts-JFLSSKRB.js");
|
|
6583
6608
|
const styleBlockRe = /<style\b[^>]*>([\s\S]*?)<\/style>/gi;
|
|
6584
6609
|
const fontFaceRe = /@font-face\s*\{([^}]*)\}/gi;
|
|
6585
6610
|
let result = html;
|
|
@@ -8336,6 +8361,7 @@ async function runAudioStage(input) {
|
|
|
8336
8361
|
audios,
|
|
8337
8362
|
masterFxChain,
|
|
8338
8363
|
urlByAbsentLocalPath,
|
|
8364
|
+
keepEncoderInputAt,
|
|
8339
8365
|
abortSignal,
|
|
8340
8366
|
assertNotAborted,
|
|
8341
8367
|
log
|
|
@@ -8355,7 +8381,13 @@ async function runAudioStage(input) {
|
|
|
8355
8381
|
audioOutputPath,
|
|
8356
8382
|
duration,
|
|
8357
8383
|
abortSignal,
|
|
8358
|
-
{
|
|
8384
|
+
{
|
|
8385
|
+
ffmpegProcessTimeout,
|
|
8386
|
+
audioGain,
|
|
8387
|
+
masterFxChain,
|
|
8388
|
+
urlByAbsentLocalPath,
|
|
8389
|
+
keepEncoderInputAt
|
|
8390
|
+
},
|
|
8359
8391
|
compiledDir
|
|
8360
8392
|
);
|
|
8361
8393
|
} catch (err) {
|
|
@@ -8455,13 +8487,29 @@ function inspectDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, free
|
|
|
8455
8487
|
}
|
|
8456
8488
|
return { available: false, estimatedBytes, freeBytes };
|
|
8457
8489
|
}
|
|
8458
|
-
function
|
|
8490
|
+
function diskCaptureRemedy(cfg, outputFormat, durationSeconds, workerCount) {
|
|
8491
|
+
const oneWorker = explainStreamingEncodeGate(cfg, outputFormat, 1, durationSeconds);
|
|
8492
|
+
if (workerCount > 1 && oneWorker.enabled) {
|
|
8493
|
+
return `This render stores frames because it captures with ${workerCount} workers. Free up disk space, or re-run this render with --workers 1 to stream frames into the encoder instead. One worker is slower, so keep the default worker count for renders that fit on disk.`;
|
|
8494
|
+
}
|
|
8495
|
+
switch (oneWorker.reason) {
|
|
8496
|
+
case "format_excluded":
|
|
8497
|
+
return `${outputFormat} output stores every frame at any worker count. Free up disk space or render to mp4.`;
|
|
8498
|
+
case "disabled_by_config":
|
|
8499
|
+
return "PRODUCER_ENABLE_STREAMING_ENCODE=false sends every render to disk. Free up disk space or unset it.";
|
|
8500
|
+
case "duration_cap":
|
|
8501
|
+
return "The streaming duration cap (PRODUCER_STREAMING_ENCODE_DURATION_CAP_ENABLED=true) sends renders longer than PRODUCER_STREAMING_ENCODE_MAX_DURATION_SECONDS to disk at any worker count. Free up disk space, unset the cap, or use --low-memory-mode, which streams past it on one worker.";
|
|
8502
|
+
default:
|
|
8503
|
+
return "Free up disk space.";
|
|
8504
|
+
}
|
|
8505
|
+
}
|
|
8506
|
+
function diskCaptureShortfallError(needBytes, freeBytes, framesDir, basis, remedy) {
|
|
8459
8507
|
const basisNote = basis === "measured" ? ` (measured from the first ${DISK_PROJECTION_SAMPLE_FRAMES} frames)` : "";
|
|
8460
8508
|
return new Error(
|
|
8461
|
-
`Disk capture may need ~${(needBytes / 1e6).toFixed(1)} MB of temporary frame storage${basisNote}, but only ${(freeBytes / 1e6).toFixed(1)} MB is free at ${framesDir}. Disk capture stores every frame as an image file (JPEG, or PNG for alpha).
|
|
8509
|
+
`Disk capture may need ~${(needBytes / 1e6).toFixed(1)} MB of temporary frame storage${basisNote}, but only ${(freeBytes / 1e6).toFixed(1)} MB is free at ${framesDir}. Disk capture stores every frame as an image file (JPEG, or PNG for alpha). ${remedy}`
|
|
8462
8510
|
);
|
|
8463
8511
|
}
|
|
8464
|
-
function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeDiskBytes) {
|
|
8512
|
+
function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, remedy, freeDiskBytes) {
|
|
8465
8513
|
const headroom = inspectDiskCaptureHeadroom(
|
|
8466
8514
|
framesDir,
|
|
8467
8515
|
totalFrames,
|
|
@@ -8473,7 +8521,8 @@ function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeD
|
|
|
8473
8521
|
headroom.estimatedBytes,
|
|
8474
8522
|
headroom.freeBytes,
|
|
8475
8523
|
framesDir,
|
|
8476
|
-
"estimate"
|
|
8524
|
+
"estimate",
|
|
8525
|
+
remedy
|
|
8477
8526
|
);
|
|
8478
8527
|
}
|
|
8479
8528
|
function measureCaptureFrameBytes(workDir, framesDir) {
|
|
@@ -8493,7 +8542,7 @@ function measureCaptureFrameBytes(workDir, framesDir) {
|
|
|
8493
8542
|
return total;
|
|
8494
8543
|
}
|
|
8495
8544
|
function createDiskCaptureProjection(input) {
|
|
8496
|
-
const { framesDir, totalFrames, measureBytes, freeDiskBytes = freeDiskBytesAt } = input;
|
|
8545
|
+
const { framesDir, totalFrames, measureBytes, remedy, freeDiskBytes = freeDiskBytesAt } = input;
|
|
8497
8546
|
let checked = false;
|
|
8498
8547
|
return (capturedFrames) => {
|
|
8499
8548
|
if (checked || capturedFrames < DISK_PROJECTION_SAMPLE_FRAMES) return;
|
|
@@ -8505,7 +8554,7 @@ function createDiskCaptureProjection(input) {
|
|
|
8505
8554
|
if (remaining <= 0 || freeBytes === null) return;
|
|
8506
8555
|
const needBytes = Math.ceil(measured / capturedFrames * remaining);
|
|
8507
8556
|
if (needBytes > freeBytes * 0.9) {
|
|
8508
|
-
throw diskCaptureShortfallError(needBytes, freeBytes, framesDir, "measured");
|
|
8557
|
+
throw diskCaptureShortfallError(needBytes, freeBytes, framesDir, "measured", remedy);
|
|
8509
8558
|
}
|
|
8510
8559
|
};
|
|
8511
8560
|
}
|
|
@@ -8547,11 +8596,13 @@ async function runCaptureStage(input) {
|
|
|
8547
8596
|
}
|
|
8548
8597
|
}
|
|
8549
8598
|
const captureOptions = buildCaptureOptions();
|
|
8550
|
-
|
|
8599
|
+
const remedy = diskCaptureRemedy(cfg, job.config.format ?? "mp4", job.duration ?? 0, workerCount);
|
|
8600
|
+
assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, remedy);
|
|
8551
8601
|
const checkDiskProjection = createDiskCaptureProjection({
|
|
8552
8602
|
framesDir,
|
|
8553
8603
|
totalFrames,
|
|
8554
|
-
measureBytes: () => measureCaptureFrameBytes(workDir, framesDir)
|
|
8604
|
+
measureBytes: () => measureCaptureFrameBytes(workDir, framesDir),
|
|
8605
|
+
remedy
|
|
8555
8606
|
});
|
|
8556
8607
|
if (workerCount > 1) {
|
|
8557
8608
|
const attempts = await executeDiskCaptureWithAdaptiveRetry({
|
|
@@ -9727,8 +9778,10 @@ function fpsToFfmpegArg2(fps) {
|
|
|
9727
9778
|
}
|
|
9728
9779
|
var KEEP_FILTER_GRAPH_WHEN_FRAMES_DROP_ALPHA = ["-reinit_filter", "0"];
|
|
9729
9780
|
var WRITE_EVERY_FRAME_WHOLE = ["-gifflags", "0"];
|
|
9781
|
+
var FAIL_ON_UNREADABLE_FRAME_INSTEAD_OF_ENDING_THERE = ["-xerror"];
|
|
9730
9782
|
function framesInput(input, fpsArg) {
|
|
9731
9783
|
return [
|
|
9784
|
+
...FAIL_ON_UNREADABLE_FRAME_INSTEAD_OF_ENDING_THERE,
|
|
9732
9785
|
"-framerate",
|
|
9733
9786
|
fpsArg,
|
|
9734
9787
|
...KEEP_FILTER_GRAPH_WHEN_FRAMES_DROP_ALPHA,
|
|
@@ -9974,28 +10027,82 @@ import { extname as extname3 } from "path";
|
|
|
9974
10027
|
import { spawn } from "child_process";
|
|
9975
10028
|
import { mkdtempSync as mkdtempSync3, renameSync as renameSync3, rmSync as rmSync7 } from "fs";
|
|
9976
10029
|
import { dirname as dirname8, join as join24 } from "path";
|
|
10030
|
+
|
|
10031
|
+
// ../producer/src/services/render/audioTruePeak.ts
|
|
10032
|
+
var toDbfs = (token) => token.toLowerCase() === "-inf" ? Number.NEGATIVE_INFINITY : Number(token);
|
|
10033
|
+
function checkedDbfs(value) {
|
|
10034
|
+
if (Number.isNaN(value) || value === Number.POSITIVE_INFINITY) {
|
|
10035
|
+
throw new Error("[audioTruePeak] FFmpeg did not report AAC true peak");
|
|
10036
|
+
}
|
|
10037
|
+
return value;
|
|
10038
|
+
}
|
|
10039
|
+
async function scanTruePeak(audioPath, trim, timeoutMs, signal) {
|
|
10040
|
+
let firstBlock;
|
|
10041
|
+
let laterBlocks = Number.NEGATIVE_INFINITY;
|
|
10042
|
+
let partialLine = "";
|
|
10043
|
+
const readLines = (chunk) => {
|
|
10044
|
+
const lines = (partialLine + chunk).split(/\r|\n/);
|
|
10045
|
+
partialLine = lines.pop() ?? "";
|
|
10046
|
+
for (const line of lines) {
|
|
10047
|
+
const ftpk = /FTPK:([^d]*)dBFS/.exec(line)?.[1];
|
|
10048
|
+
if (!ftpk) continue;
|
|
10049
|
+
const block = Math.max(...ftpk.trim().split(/\s+/).map(toDbfs));
|
|
10050
|
+
if (firstBlock === void 0) firstBlock = block;
|
|
10051
|
+
else laterBlocks = Math.max(laterBlocks, block);
|
|
10052
|
+
}
|
|
10053
|
+
};
|
|
10054
|
+
const result = await runFfmpeg(
|
|
10055
|
+
["-i", audioPath, "-map", "0:a:0", "-vn", "-af", `${trim}ebur128=peak=true`, "-f", "null", "-"],
|
|
10056
|
+
{ signal, timeout: timeoutMs, onStderr: readLines }
|
|
10057
|
+
);
|
|
10058
|
+
if (!result.success) {
|
|
10059
|
+
throw new Error(`[audioTruePeak] ${describeFfmpegFailure(result, timeoutMs)}`);
|
|
10060
|
+
}
|
|
10061
|
+
const summary = [...result.stderr.matchAll(/^\s*Peak:\s*([+-]?(?:[\d.]+|inf)) dBFS$/gim)];
|
|
10062
|
+
return {
|
|
10063
|
+
peak: checkedDbfs(toDbfs(summary.at(-1)?.[1] ?? "nan")),
|
|
10064
|
+
firstBlock: checkedDbfs(firstBlock ?? Number.NEGATIVE_INFINITY),
|
|
10065
|
+
laterBlocks: checkedDbfs(laterBlocks)
|
|
10066
|
+
};
|
|
10067
|
+
}
|
|
10068
|
+
async function measureTruePeakDbfs(audioPath, options) {
|
|
10069
|
+
const { timeoutMs, signal } = options;
|
|
10070
|
+
const wholeFile = async () => (await scanTruePeak(audioPath, "", timeoutMs, signal)).peak;
|
|
10071
|
+
const { durationSeconds, sampleRate } = await extractAudioMetadata(audioPath, { signal });
|
|
10072
|
+
const block = 4800;
|
|
10073
|
+
const count = sampleRate === 48e3 && Number.isFinite(durationSeconds) ? aacSegmentCount(durationSeconds) : 1;
|
|
10074
|
+
if (count === 1) return wholeFile();
|
|
10075
|
+
const cut = (k) => k * Math.floor(durationSeconds * 10 / count) * block;
|
|
10076
|
+
const peers = new AbortController();
|
|
10077
|
+
const segmentSignal = signal ? AbortSignal.any([signal, peers.signal]) : peers.signal;
|
|
10078
|
+
const scans = await Promise.all(
|
|
10079
|
+
Array.from({ length: count }, (_, k) => {
|
|
10080
|
+
const start = k === 0 ? 0 : cut(k) - block;
|
|
10081
|
+
const end = k === count - 1 ? "" : `:end_sample=${cut(k + 1)}`;
|
|
10082
|
+
return scanTruePeak(
|
|
10083
|
+
audioPath,
|
|
10084
|
+
`atrim=start_sample=${start}${end},`,
|
|
10085
|
+
timeoutMs,
|
|
10086
|
+
segmentSignal
|
|
10087
|
+
);
|
|
10088
|
+
})
|
|
10089
|
+
).catch((error) => {
|
|
10090
|
+
peers.abort();
|
|
10091
|
+
throw error;
|
|
10092
|
+
});
|
|
10093
|
+
const last = scans[count - 1];
|
|
10094
|
+
const counted = Math.max(scans[0].peak, ...scans.slice(1).map((scan) => scan.laterBlocks));
|
|
10095
|
+
if (last.peak > last.firstBlock || last.peak <= counted) return Math.max(counted, last.peak);
|
|
10096
|
+
return wholeFile();
|
|
10097
|
+
}
|
|
10098
|
+
|
|
10099
|
+
// ../producer/src/services/render/audioPadTrim.ts
|
|
9977
10100
|
var AUDIO_DURATION_TOLERANCE_SECONDS = 1e-3;
|
|
9978
10101
|
var AAC_DELIVERY_TRUE_PEAK_DBFS = -1;
|
|
9979
10102
|
var AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB = 0.5;
|
|
9980
10103
|
var MAX_TRUE_PEAK_CORRECTION_PASSES = 3;
|
|
9981
|
-
function
|
|
9982
|
-
return
|
|
9983
|
-
"-i",
|
|
9984
|
-
inputPath,
|
|
9985
|
-
"-map",
|
|
9986
|
-
"0:a:0",
|
|
9987
|
-
"-vn",
|
|
9988
|
-
"-af",
|
|
9989
|
-
`volume=${attenuationDb.toFixed(3)}dB`,
|
|
9990
|
-
"-t",
|
|
9991
|
-
formatSeconds(targetDurationSeconds),
|
|
9992
|
-
"-c:a",
|
|
9993
|
-
"aac",
|
|
9994
|
-
"-b:a",
|
|
9995
|
-
"192k",
|
|
9996
|
-
"-y",
|
|
9997
|
-
outputPath
|
|
9998
|
-
];
|
|
10104
|
+
function aacTruePeakCorrectionFilter(targetDurationSeconds, attenuationDb) {
|
|
10105
|
+
return `volume=${attenuationDb.toFixed(3)}dB,apad,atrim=0:${formatSeconds(targetDurationSeconds)}`;
|
|
9999
10106
|
}
|
|
10000
10107
|
function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, targetDurationSeconds) {
|
|
10001
10108
|
const delta = targetDurationSeconds - sourceDurationSeconds;
|
|
@@ -10010,53 +10117,13 @@ function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, tar
|
|
|
10010
10117
|
if (delta > 0) {
|
|
10011
10118
|
return {
|
|
10012
10119
|
operation: "pad",
|
|
10013
|
-
steps: [
|
|
10014
|
-
{
|
|
10015
|
-
kind: "normalize",
|
|
10016
|
-
args: [
|
|
10017
|
-
"-i",
|
|
10018
|
-
audioPath,
|
|
10019
|
-
"-af",
|
|
10020
|
-
`apad,atrim=0:${targetSec}`,
|
|
10021
|
-
"-t",
|
|
10022
|
-
targetSec,
|
|
10023
|
-
"-c:a",
|
|
10024
|
-
"aac",
|
|
10025
|
-
"-b:a",
|
|
10026
|
-
"192k",
|
|
10027
|
-
"-y",
|
|
10028
|
-
outputPath
|
|
10029
|
-
]
|
|
10030
|
-
}
|
|
10031
|
-
],
|
|
10120
|
+
steps: [{ kind: "normalize", filter: `apad,atrim=0:${targetSec}` }],
|
|
10032
10121
|
cleanupPaths: []
|
|
10033
10122
|
};
|
|
10034
10123
|
}
|
|
10035
10124
|
return {
|
|
10036
10125
|
operation: "trim",
|
|
10037
|
-
steps: [
|
|
10038
|
-
{
|
|
10039
|
-
kind: "trim",
|
|
10040
|
-
args: [
|
|
10041
|
-
"-i",
|
|
10042
|
-
audioPath,
|
|
10043
|
-
"-af",
|
|
10044
|
-
`atrim=duration=${targetSec},asetpts=PTS-STARTPTS`,
|
|
10045
|
-
// `atrim` limits decoded samples but does not cap muxer timestamps
|
|
10046
|
-
// introduced by encoder delay/flush. The output duration contract
|
|
10047
|
-
// is enforced at the container boundary as well; without `-t`, a
|
|
10048
|
-
// long primed source can retain its original tail after re-encode.
|
|
10049
|
-
"-t",
|
|
10050
|
-
targetSec,
|
|
10051
|
-
"-c:a",
|
|
10052
|
-
"aac",
|
|
10053
|
-
"-b:a",
|
|
10054
|
-
"192k",
|
|
10055
|
-
"-y",
|
|
10056
|
-
outputPath
|
|
10057
|
-
]
|
|
10058
|
-
}
|
|
10059
|
-
],
|
|
10126
|
+
steps: [{ kind: "trim", filter: `atrim=duration=${targetSec},asetpts=PTS-STARTPTS` }],
|
|
10060
10127
|
cleanupPaths: []
|
|
10061
10128
|
};
|
|
10062
10129
|
}
|
|
@@ -10073,7 +10140,8 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
10073
10140
|
const probeAudio = input.probeAudioInfo ?? defaultProbeAudioInfo;
|
|
10074
10141
|
const timeoutMs = input.timeoutMs ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
|
|
10075
10142
|
const runner = input.runFfmpeg ?? ((args) => defaultRunFfmpeg(args, timeoutMs, input.signal));
|
|
10076
|
-
const
|
|
10143
|
+
const encode = input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal);
|
|
10144
|
+
const probeTruePeak = input.probeAudioTruePeakDbfs ?? (input.runFfmpeg || input.encodeAac ? void 0 : (audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal }));
|
|
10077
10145
|
const [videoResult, audioResult] = await Promise.allSettled([
|
|
10078
10146
|
probeVideo(input.videoPath),
|
|
10079
10147
|
probeAudio(input.audioPath, input.signal)
|
|
@@ -10120,7 +10188,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
10120
10188
|
);
|
|
10121
10189
|
try {
|
|
10122
10190
|
for (const step of plan2.steps) {
|
|
10123
|
-
const ffmpegResult = await runner(step.args);
|
|
10191
|
+
const ffmpegResult = step.kind === "copy" ? await runner(step.args) : await encode(input.audioPath, input.outputPath, targetDurationSeconds, step.filter);
|
|
10124
10192
|
if (!ffmpegResult.success) {
|
|
10125
10193
|
return {
|
|
10126
10194
|
success: false,
|
|
@@ -10152,7 +10220,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
10152
10220
|
targetDurationSeconds,
|
|
10153
10221
|
signal: input.signal,
|
|
10154
10222
|
probeTruePeak,
|
|
10155
|
-
|
|
10223
|
+
encode
|
|
10156
10224
|
});
|
|
10157
10225
|
if (!correction.success) {
|
|
10158
10226
|
return {
|
|
@@ -10182,8 +10250,8 @@ async function constrainAacTruePeak(input) {
|
|
|
10182
10250
|
audioPath: input.audioPath,
|
|
10183
10251
|
targetDurationSeconds: input.targetDurationSeconds,
|
|
10184
10252
|
signal: input.signal,
|
|
10185
|
-
probeTruePeak: (audioPath, signal) =>
|
|
10186
|
-
|
|
10253
|
+
probeTruePeak: (audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal }),
|
|
10254
|
+
encode: defaultAacEncoder(timeoutMs, input.signal, input.sourcePath)
|
|
10187
10255
|
});
|
|
10188
10256
|
}
|
|
10189
10257
|
async function enforceAacTruePeak(input) {
|
|
@@ -10210,13 +10278,11 @@ async function enforceAacTruePeak(input) {
|
|
|
10210
10278
|
}
|
|
10211
10279
|
if (pass === MAX_TRUE_PEAK_CORRECTION_PASSES) break;
|
|
10212
10280
|
attenuationDb += correctionTargetDbfs - truePeakDbfs;
|
|
10213
|
-
const result = await input.
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
attenuationDb
|
|
10219
|
-
)
|
|
10281
|
+
const result = await input.encode(
|
|
10282
|
+
input.audioPath,
|
|
10283
|
+
correctedPath,
|
|
10284
|
+
input.targetDurationSeconds,
|
|
10285
|
+
aacTruePeakCorrectionFilter(input.targetDurationSeconds, attenuationDb)
|
|
10220
10286
|
);
|
|
10221
10287
|
if (!result.success) {
|
|
10222
10288
|
return {
|
|
@@ -10319,24 +10385,19 @@ async function defaultProbeAudioInfo(audioPath, signal) {
|
|
|
10319
10385
|
audioCodec: metadata.audioCodec
|
|
10320
10386
|
};
|
|
10321
10387
|
}
|
|
10322
|
-
async function defaultProbeAudioTruePeakDbfs(audioPath, timeoutMs, signal) {
|
|
10323
|
-
const result = await runFfmpeg(
|
|
10324
|
-
["-i", audioPath, "-map", "0:a:0", "-vn", "-af", "ebur128=peak=true", "-f", "null", "-"],
|
|
10325
|
-
{ signal, timeout: timeoutMs }
|
|
10326
|
-
);
|
|
10327
|
-
if (!result.success) {
|
|
10328
|
-
throw new Error(`[audioPadTrim] ${describeFfmpegFailure(result, timeoutMs)}`);
|
|
10329
|
-
}
|
|
10330
|
-
const matches = [...result.stderr.matchAll(/^\s*Peak:\s*([+-]?(?:[\d.]+|inf)) dBFS$/gim)];
|
|
10331
|
-
const token = matches.at(-1)?.[1]?.toLowerCase();
|
|
10332
|
-
const value = token === "-inf" ? Number.NEGATIVE_INFINITY : Number(token);
|
|
10333
|
-
if (Number.isNaN(value) || value === Number.POSITIVE_INFINITY) {
|
|
10334
|
-
throw new Error("[audioPadTrim] FFmpeg did not report AAC true peak");
|
|
10335
|
-
}
|
|
10336
|
-
return value;
|
|
10337
|
-
}
|
|
10338
10388
|
async function defaultRunFfmpeg(args, timeoutMs, signal) {
|
|
10339
|
-
|
|
10389
|
+
return toStepResult(await runFfmpeg(args, { signal, timeout: timeoutMs }), timeoutMs);
|
|
10390
|
+
}
|
|
10391
|
+
function defaultAacEncoder(timeoutMs, signal, pcmSourcePath) {
|
|
10392
|
+
return async (inputPath, outputPath, durationSeconds, filter) => {
|
|
10393
|
+
const options = pcmSourcePath ? { signal, timeout: timeoutMs, filter } : { signal, timeout: timeoutMs, filter, segments: 1 };
|
|
10394
|
+
return toStepResult(
|
|
10395
|
+
await encodeAac(pcmSourcePath ?? inputPath, outputPath, durationSeconds, options),
|
|
10396
|
+
timeoutMs
|
|
10397
|
+
);
|
|
10398
|
+
};
|
|
10399
|
+
}
|
|
10400
|
+
function toStepResult(result, timeoutMs) {
|
|
10340
10401
|
if (result.success) return { success: true };
|
|
10341
10402
|
return {
|
|
10342
10403
|
success: false,
|
|
@@ -10524,7 +10585,7 @@ function assertOutputScaleSupported(deviceScaleFactor, route) {
|
|
|
10524
10585
|
const reason = UNSUPPORTED_REASON2[route];
|
|
10525
10586
|
if (reason === null) return;
|
|
10526
10587
|
throw new Error(
|
|
10527
|
-
`[Render] --resolution other than the composition's size is not supported on the "${route}" capture route: ${reason}. Render at the composition's size, or
|
|
10588
|
+
`[Render] --resolution other than the composition's size is not supported on the "${route}" capture route: ${reason}. Render at the composition's size; or, for HDR footage, add --sdr to render this size in standard colour; or, for shader transitions, render as mp4.`
|
|
10528
10589
|
);
|
|
10529
10590
|
}
|
|
10530
10591
|
|
|
@@ -10742,7 +10803,7 @@ function getNextRetryWorkerCount(currentWorkers) {
|
|
|
10742
10803
|
return Math.max(1, Math.floor(currentWorkers / 2));
|
|
10743
10804
|
}
|
|
10744
10805
|
function resolveRenderWorkDirPrefix(outputPath, jobId, platform2 = process.platform, systemTempDir = tmpdir2()) {
|
|
10745
|
-
if (platform2 === "win32") return join25(systemTempDir, "hf-render-");
|
|
10806
|
+
if (platform2 === "win32" || platform2 === "darwin") return join25(systemTempDir, "hf-render-");
|
|
10746
10807
|
return join25(dirname9(outputPath), `work-${jobId}-`);
|
|
10747
10808
|
}
|
|
10748
10809
|
var MAX_TRANSIENT_CAPTURE_RETRIES = 1;
|
|
@@ -11236,6 +11297,9 @@ function resolveDeShortBand(args) {
|
|
|
11236
11297
|
function shouldPreferSingleWorkerDrawElement(args) {
|
|
11237
11298
|
return args.workerCount > 1 && typeof args.requestedWorkers !== "number" && args.useDrawElement && !args.deCompileGate && !args.forceScreenshot && outputUsesH264Pipeline(args.outputFormat) && args.minFrames > 0 && args.totalFrames >= args.minFrames && args.singleWorkerStreamingOk && !args.layeredOrEffectRoute && !args.supersampling && !args.probeDeGated && !args.experimentalParallelDeOptIn;
|
|
11238
11299
|
}
|
|
11300
|
+
function isProbeDeGated(session) {
|
|
11301
|
+
return session !== null && session.captureMode !== "drawelement" && !session.deInitDeferred;
|
|
11302
|
+
}
|
|
11239
11303
|
function resolveInversionRetryPlan(args) {
|
|
11240
11304
|
if (args.deWorkerInversion !== "inverted") return null;
|
|
11241
11305
|
const workerCount = args.isMemoryExhaustion ? 1 : args.preInversionWorkerCount;
|
|
@@ -11317,7 +11381,8 @@ async function closeOrphanedProbeForRetry(probe, closer, log, retryContext) {
|
|
|
11317
11381
|
}
|
|
11318
11382
|
function resolveParallelCaptureMode(args) {
|
|
11319
11383
|
const supersampling = (args.deviceScaleFactor ?? 1) !== 1;
|
|
11320
|
-
|
|
11384
|
+
const headlessShell = args.headlessShellPath !== void 0;
|
|
11385
|
+
return headlessShell && args.platform === "linux" && !args.forceScreenshot && !supersampling ? "beginframe" : "screenshot";
|
|
11321
11386
|
}
|
|
11322
11387
|
function isCaptureParallelStreamRouterEnabled(env, resolvedMode) {
|
|
11323
11388
|
const raw = env.HF_CAPTURE_PARALLEL_STREAM?.trim().toLowerCase();
|
|
@@ -11925,6 +11990,7 @@ async function executeRenderPipeline(input) {
|
|
|
11925
11990
|
);
|
|
11926
11991
|
const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
|
|
11927
11992
|
const hasHdrContent = Boolean(effectiveHdr && nativeHdrIds.size > 0);
|
|
11993
|
+
if (hasHdrContent) assertOutputScaleSupported(deviceScaleFactor, "hdr_layered");
|
|
11928
11994
|
const deSingleMinFramesRaw = process.env.HF_DE_SINGLE_MIN_FRAMES;
|
|
11929
11995
|
const deSingleMinFramesNum = deSingleMinFramesRaw === void 0 || deSingleMinFramesRaw.trim() === "" ? 900 : Number(deSingleMinFramesRaw);
|
|
11930
11996
|
const deSingleMinFrames = Number.isFinite(deSingleMinFramesNum) ? deSingleMinFramesNum : 900;
|
|
@@ -11965,7 +12031,7 @@ async function executeRenderPipeline(input) {
|
|
|
11965
12031
|
singleWorkerStreamingOk: shouldUseStreamingEncode(cfg, outputFormat, 1, job.duration),
|
|
11966
12032
|
layeredOrEffectRoute: hasHdrContent || compiled.hasShaderTransitions,
|
|
11967
12033
|
supersampling: deviceScaleFactor !== 1,
|
|
11968
|
-
probeDeGated: probeSession
|
|
12034
|
+
probeDeGated: isProbeDeGated(probeSession),
|
|
11969
12035
|
experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || // Verified parallel DE streaming (opt-in) wants its parallelism kept.
|
|
11970
12036
|
process.env.HF_DE_PARALLEL_STREAM === "true"
|
|
11971
12037
|
};
|
|
@@ -11974,14 +12040,14 @@ async function executeRenderPipeline(input) {
|
|
|
11974
12040
|
...deInversionArgs,
|
|
11975
12041
|
minFrames: Math.min(deSingleMinFrames, deShortBandMinFrames)
|
|
11976
12042
|
});
|
|
11977
|
-
|
|
12043
|
+
let deShortBand = resolveDeShortBand({
|
|
11978
12044
|
invertAtBaseFloor,
|
|
11979
12045
|
invertAtBandFloor,
|
|
11980
12046
|
bandEnabled: deShortBandEnabled,
|
|
11981
12047
|
bandOpen: deShortBandOpen,
|
|
11982
12048
|
elementCountSource: compositionElementCountSource
|
|
11983
12049
|
});
|
|
11984
|
-
|
|
12050
|
+
let deInversionEligible = deShortBandRoute && deShortBand === "applied" ? invertAtBandFloor : invertAtBaseFloor;
|
|
11985
12051
|
const deInversionEffectiveMinFrames = deShortBandRoute && deShortBand === "applied" ? Math.min(deSingleMinFrames, deShortBandMinFrames) : deSingleMinFrames;
|
|
11986
12052
|
const deParallelRouterEnabled = isDeParallelRouterEnabled(process.env);
|
|
11987
12053
|
const deParallelMinFramesRaw = process.env.HF_DE_PARALLEL_MIN_FRAMES;
|
|
@@ -11990,7 +12056,7 @@ async function executeRenderPipeline(input) {
|
|
|
11990
12056
|
const deParallelMinMemRaw = process.env.HF_DE_PARALLEL_MIN_MEM_MB;
|
|
11991
12057
|
const deParallelMinMemNum = deParallelMinMemRaw === void 0 || deParallelMinMemRaw.trim() === "" ? 24576 : Number(deParallelMinMemRaw);
|
|
11992
12058
|
const deParallelMinMemoryMb = Number.isFinite(deParallelMinMemNum) ? deParallelMinMemNum : 24576;
|
|
11993
|
-
|
|
12059
|
+
let deParallelRouterEligible = shouldPreferParallelDrawElement({
|
|
11994
12060
|
workerCount: WOULD_RESOLVE_MULTI_WORKER,
|
|
11995
12061
|
requestedWorkers: job.config.workers,
|
|
11996
12062
|
useDrawElement: cfg.useDrawElement,
|
|
@@ -12001,7 +12067,7 @@ async function executeRenderPipeline(input) {
|
|
|
12001
12067
|
minFrames: deParallelMinFrames,
|
|
12002
12068
|
layeredOrEffectRoute: hasHdrContent || compiled.hasShaderTransitions,
|
|
12003
12069
|
supersampling: deviceScaleFactor !== 1,
|
|
12004
|
-
probeDeGated: probeSession
|
|
12070
|
+
probeDeGated: isProbeDeGated(probeSession),
|
|
12005
12071
|
experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || process.env.HF_DE_PARALLEL_STREAM === "true",
|
|
12006
12072
|
routerEnabled: deParallelRouterEnabled,
|
|
12007
12073
|
// Router pins 3 workers for the streaming path; don't pin when a
|
|
@@ -12017,6 +12083,35 @@ async function executeRenderPipeline(input) {
|
|
|
12017
12083
|
totalMemoryMb: Math.round(totalmem2() / (1024 * 1024)),
|
|
12018
12084
|
minMemoryMb: deParallelMinMemoryMb
|
|
12019
12085
|
});
|
|
12086
|
+
if (probeSession === null && (deInversionEligible || deParallelRouterEligible)) {
|
|
12087
|
+
try {
|
|
12088
|
+
probeSession = await createCaptureSession(
|
|
12089
|
+
activeFileServer.url,
|
|
12090
|
+
framesDir,
|
|
12091
|
+
buildCaptureOptions(),
|
|
12092
|
+
null,
|
|
12093
|
+
{ ...cfg, forceScreenshot: captureForceScreenshot }
|
|
12094
|
+
);
|
|
12095
|
+
await initializeSession(probeSession);
|
|
12096
|
+
} catch (error) {
|
|
12097
|
+
assertNotAborted();
|
|
12098
|
+
if (probeSession) {
|
|
12099
|
+
lastBrowserConsole = probeSession.browserConsoleBuffer;
|
|
12100
|
+
await closeCaptureSession(probeSession).catch(() => {
|
|
12101
|
+
});
|
|
12102
|
+
probeSession = null;
|
|
12103
|
+
}
|
|
12104
|
+
log.warn("[Render] Fast capture gate check failed; routing without it.", {
|
|
12105
|
+
error: error instanceof Error ? error.message : String(error)
|
|
12106
|
+
});
|
|
12107
|
+
}
|
|
12108
|
+
if (isProbeDeGated(probeSession)) {
|
|
12109
|
+
deInversionEligible = false;
|
|
12110
|
+
deParallelRouterEligible = false;
|
|
12111
|
+
deShortBand = void 0;
|
|
12112
|
+
}
|
|
12113
|
+
}
|
|
12114
|
+
const deProbeGateReason = isProbeDeGated(probeSession) ? probeSession.deGateReason : void 0;
|
|
12020
12115
|
let workerCount;
|
|
12021
12116
|
const captureStageObservationData = (extra = {}) => ({
|
|
12022
12117
|
stagePhase: "capturing",
|
|
@@ -12204,7 +12299,7 @@ async function executeRenderPipeline(input) {
|
|
|
12204
12299
|
}
|
|
12205
12300
|
const parallelCaptureMode = resolveParallelCaptureMode({
|
|
12206
12301
|
platform: process.platform,
|
|
12207
|
-
|
|
12302
|
+
headlessShellPath: resolveHeadlessShellPath(cfg),
|
|
12208
12303
|
forceScreenshot: captureForceScreenshot,
|
|
12209
12304
|
deviceScaleFactor: captureOptions.deviceScaleFactor
|
|
12210
12305
|
});
|
|
@@ -12976,7 +13071,9 @@ async function executeRenderPipeline(input) {
|
|
|
12976
13071
|
outputFormat,
|
|
12977
13072
|
durationSeconds: job.duration,
|
|
12978
13073
|
fps: fpsToNumber(job.config.fps),
|
|
12979
|
-
expectedFrames: captureTotalFrames
|
|
13074
|
+
expectedFrames: captureTotalFrames,
|
|
13075
|
+
width: outputWidth,
|
|
13076
|
+
height: outputHeight
|
|
12980
13077
|
})
|
|
12981
13078
|
);
|
|
12982
13079
|
const totalElapsed = Date.now() - pipelineStart;
|
|
@@ -13012,6 +13109,7 @@ async function executeRenderPipeline(input) {
|
|
|
13012
13109
|
drawElement: {
|
|
13013
13110
|
compileGate: deCompileGate,
|
|
13014
13111
|
clampReason: deClampReason,
|
|
13112
|
+
probeGateReason: deProbeGateReason,
|
|
13015
13113
|
workerInversion: deWorkerInversion,
|
|
13016
13114
|
preInversionWorkers: deWorkerInversion ? preRoutingWorkerCount : void 0,
|
|
13017
13115
|
compositionElementCount,
|
|
@@ -13564,6 +13662,29 @@ function buildChunkCaptureOptions(input) {
|
|
|
13564
13662
|
requiresWebGpu: compositionRequiresWebGpu(input.html)
|
|
13565
13663
|
};
|
|
13566
13664
|
}
|
|
13665
|
+
function shownDeferredFrameIndexes(planVideos, frames, fps) {
|
|
13666
|
+
const shown = /* @__PURE__ */ new Map();
|
|
13667
|
+
const deferred = planVideos.extracted.filter((video) => video.deferredRange);
|
|
13668
|
+
if (deferred.length === 0) return shown;
|
|
13669
|
+
const table = createFrameLookupTable(
|
|
13670
|
+
planVideos.videos,
|
|
13671
|
+
deferred.map((video) => ({
|
|
13672
|
+
...video,
|
|
13673
|
+
outputDir: "",
|
|
13674
|
+
framePaths: new Map(Array.from({ length: video.totalFrames }, (_, i) => [i, String(i)]))
|
|
13675
|
+
})),
|
|
13676
|
+
resolveRenderFpsConfig(fps).value
|
|
13677
|
+
);
|
|
13678
|
+
for (const frame of frames) {
|
|
13679
|
+
const globalTime = frame * fps.den / fps.num;
|
|
13680
|
+
for (const [videoId, payload] of table.getActiveFramePayloads(globalTime)) {
|
|
13681
|
+
const indexes = shown.get(videoId) ?? /* @__PURE__ */ new Set();
|
|
13682
|
+
indexes.add(payload.frameIndex);
|
|
13683
|
+
shown.set(videoId, indexes);
|
|
13684
|
+
}
|
|
13685
|
+
}
|
|
13686
|
+
return shown;
|
|
13687
|
+
}
|
|
13567
13688
|
async function extractDeferredVideoFramesForChunk(input) {
|
|
13568
13689
|
const deferred = input.planVideos.extracted.filter((video) => video.deferredRange);
|
|
13569
13690
|
const remoteSources = input.remoteSources ?? {};
|
|
@@ -13580,24 +13701,7 @@ async function extractDeferredVideoFramesForChunk(input) {
|
|
|
13580
13701
|
});
|
|
13581
13702
|
}
|
|
13582
13703
|
if (deferred.length === 0) return [];
|
|
13583
|
-
const
|
|
13584
|
-
input.planVideos.videos,
|
|
13585
|
-
deferred.map((video) => ({
|
|
13586
|
-
...video,
|
|
13587
|
-
outputDir: input.outputRoot,
|
|
13588
|
-
framePaths: new Map(Array.from({ length: video.totalFrames }, (_, i) => [i, String(i)]))
|
|
13589
|
-
})),
|
|
13590
|
-
resolveRenderFpsConfig(input.fps).value
|
|
13591
|
-
);
|
|
13592
|
-
const shown = /* @__PURE__ */ new Map();
|
|
13593
|
-
for (const frame of input.frames) {
|
|
13594
|
-
const globalTime = frame * input.fps.den / input.fps.num;
|
|
13595
|
-
for (const [videoId, payload] of table.getActiveFramePayloads(globalTime)) {
|
|
13596
|
-
const indexes = shown.get(videoId) ?? /* @__PURE__ */ new Set();
|
|
13597
|
-
indexes.add(payload.frameIndex);
|
|
13598
|
-
shown.set(videoId, indexes);
|
|
13599
|
-
}
|
|
13600
|
-
}
|
|
13704
|
+
const shown = shownDeferredFrameIndexes(input.planVideos, input.frames, input.fps);
|
|
13601
13705
|
return Promise.all(
|
|
13602
13706
|
deferred.map(async (video) => {
|
|
13603
13707
|
const outputDir = join27(input.outputRoot, video.videoId);
|
|
@@ -13623,7 +13727,8 @@ async function extractDeferredVideoFramesForChunk(input) {
|
|
|
13623
13727
|
fps: input.fps,
|
|
13624
13728
|
outputDir: input.outputRoot,
|
|
13625
13729
|
format: range.format,
|
|
13626
|
-
frameRanges: contiguousRuns(indexes)
|
|
13730
|
+
frameRanges: contiguousRuns(indexes),
|
|
13731
|
+
shownBox: input.shownBoxes?.get(video.videoId)
|
|
13627
13732
|
},
|
|
13628
13733
|
void 0,
|
|
13629
13734
|
input.cfg
|
|
@@ -14275,6 +14380,20 @@ function withDuration(buf, target, duration) {
|
|
|
14275
14380
|
function timescaleOf(buf, header) {
|
|
14276
14381
|
return buf.readUInt32BE(header.bodyStart + (buf[header.bodyStart] === 1 ? 20 : 12));
|
|
14277
14382
|
}
|
|
14383
|
+
var TRACK_ID_AT = { tkhd: [12, 20], mvhd: [96, 108] };
|
|
14384
|
+
function idOf(buf, target) {
|
|
14385
|
+
return buf.readUInt32BE(
|
|
14386
|
+
target.bodyStart + TRACK_ID_AT[target.type][buf[target.bodyStart] === 1 ? 1 : 0]
|
|
14387
|
+
);
|
|
14388
|
+
}
|
|
14389
|
+
function withId(boxBytes, type, id) {
|
|
14390
|
+
const header = boxAt(boxBytes, 0, 0, boxBytes.length);
|
|
14391
|
+
boxBytes.writeUInt32BE(
|
|
14392
|
+
id,
|
|
14393
|
+
header.bodyStart + TRACK_ID_AT[type][boxBytes[header.bodyStart] === 1 ? 1 : 0]
|
|
14394
|
+
);
|
|
14395
|
+
return boxBytes;
|
|
14396
|
+
}
|
|
14278
14397
|
function buildStbl(stsd, track) {
|
|
14279
14398
|
const stts = runs(track.durations);
|
|
14280
14399
|
const stsc = [];
|
|
@@ -14316,24 +14435,48 @@ function planTracksOf(tracks, plan2, index) {
|
|
|
14316
14435
|
}
|
|
14317
14436
|
return matched;
|
|
14318
14437
|
}
|
|
14319
|
-
function
|
|
14320
|
-
const
|
|
14321
|
-
const
|
|
14438
|
+
function sourceTracks(layouts, audio) {
|
|
14439
|
+
const chunkPlan = readTracks(layouts[0].moov);
|
|
14440
|
+
const audioTracks = audio ? readTracks(audio.moov) : [];
|
|
14441
|
+
if (audio && (audioTracks.length !== 1 || audioTracks[0].handler !== "soun")) {
|
|
14442
|
+
throw new Error("[mp4Stitch] the separate audio file must hold one audio track");
|
|
14443
|
+
}
|
|
14444
|
+
const plan2 = [...chunkPlan, ...audioTracks];
|
|
14445
|
+
const chunks = layouts.map((layout, i) => {
|
|
14446
|
+
const tracks = readTracks(layout.moov);
|
|
14447
|
+
if (audio && tracks.some((track) => track.handler === "soun")) {
|
|
14448
|
+
throw new Error(`[mp4Stitch] chunk ${i} carries its own audio`);
|
|
14449
|
+
}
|
|
14450
|
+
return planTracksOf(tracks, plan2, i);
|
|
14451
|
+
});
|
|
14452
|
+
return {
|
|
14453
|
+
plan: plan2,
|
|
14454
|
+
chunkTrackCount: chunkPlan.length,
|
|
14455
|
+
sources: audio ? [[...chunkPlan.map(() => null), audioTracks[0]], ...chunks] : chunks
|
|
14456
|
+
};
|
|
14457
|
+
}
|
|
14458
|
+
function buildStitchedHeader(layouts, audio) {
|
|
14459
|
+
const { plan: plan2, chunkTrackCount, sources } = sourceTracks(layouts, audio);
|
|
14460
|
+
const sourceLayouts = audio ? [audio, ...layouts] : layouts;
|
|
14322
14461
|
const payloadBases = [];
|
|
14323
14462
|
let payloadBytes = 0;
|
|
14324
|
-
for (const layout of
|
|
14463
|
+
for (const layout of sourceLayouts) {
|
|
14325
14464
|
payloadBases.push(payloadBytes);
|
|
14326
14465
|
payloadBytes += layout.payloadEnd - layout.payloadStart;
|
|
14327
14466
|
}
|
|
14328
14467
|
const template = layouts[0].moov;
|
|
14329
14468
|
const root = boxAt(template, 0, 0, template.length);
|
|
14330
|
-
const
|
|
14469
|
+
const mvhd = child(template, root, "mvhd");
|
|
14470
|
+
const movieTimescale = timescaleOf(template, mvhd);
|
|
14471
|
+
const chunkTrackIds = plan2.slice(0, chunkTrackCount).map((track) => idOf(template, child(template, track.trak, "tkhd")));
|
|
14472
|
+
const audioTrackId = Math.max(...chunkTrackIds) + 1;
|
|
14331
14473
|
const buildMoov = (dataStart2) => {
|
|
14332
14474
|
const traks = plan2.map((track, t) => {
|
|
14333
|
-
const parts =
|
|
14475
|
+
const parts = sources.flatMap((tracks, chunk) => {
|
|
14334
14476
|
const part = tracks[t];
|
|
14335
14477
|
return part ? [{ ...part, chunk }] : [];
|
|
14336
14478
|
});
|
|
14479
|
+
const moov = t < chunkTrackCount ? template : audio.moov;
|
|
14337
14480
|
const merged = {
|
|
14338
14481
|
durations: parts.flatMap((part) => part.durations),
|
|
14339
14482
|
sizes: parts.flatMap((part) => part.sizes),
|
|
@@ -14342,9 +14485,9 @@ function buildStitchedHeader(layouts) {
|
|
|
14342
14485
|
chunkOffsets: parts.flatMap(
|
|
14343
14486
|
(part) => part.chunkOffsets.map((offset) => {
|
|
14344
14487
|
const i = part.chunk;
|
|
14345
|
-
const { payloadStart, payloadEnd } =
|
|
14488
|
+
const { payloadStart, payloadEnd } = sourceLayouts[i];
|
|
14346
14489
|
if (offset < payloadStart || offset >= payloadEnd) {
|
|
14347
|
-
throw new Error(`[mp4Stitch]
|
|
14490
|
+
throw new Error(`[mp4Stitch] source ${i} has samples outside its mdat`);
|
|
14348
14491
|
}
|
|
14349
14492
|
return offset - payloadStart + payloadBases[i] + dataStart2;
|
|
14350
14493
|
})
|
|
@@ -14360,20 +14503,25 @@ function buildStitchedHeader(layouts) {
|
|
|
14360
14503
|
elst.writeBigInt64BE(BigInt(track.mediaTime), 12);
|
|
14361
14504
|
elst.writeUInt32BE(65536, 20);
|
|
14362
14505
|
const edts = track.mediaTime ? box("edts", fullBox("elst", 1, elst)) : Buffer.alloc(0);
|
|
14363
|
-
const
|
|
14364
|
-
|
|
14506
|
+
const tkhdOf = (tkhd) => {
|
|
14507
|
+
const timed = withDuration(moov, tkhd, shown);
|
|
14508
|
+
return t < chunkTrackCount ? timed : withId(timed, "tkhd", audioTrackId);
|
|
14509
|
+
};
|
|
14510
|
+
const trak = rebuild(moov, track.trak, {
|
|
14511
|
+
tkhd: (tkhd) => Buffer.concat([tkhdOf(tkhd), edts]),
|
|
14365
14512
|
edts: () => Buffer.alloc(0),
|
|
14366
|
-
mdia: (mdia) => rebuild(
|
|
14367
|
-
mdhd: (mdhd) => withDuration(
|
|
14368
|
-
minf: (minf) => rebuild(
|
|
14513
|
+
mdia: (mdia) => rebuild(moov, mdia, {
|
|
14514
|
+
mdhd: (mdhd) => withDuration(moov, mdhd, mediaDuration),
|
|
14515
|
+
minf: (minf) => rebuild(moov, minf, { stbl: () => buildStbl(track.stsd, merged) })
|
|
14369
14516
|
})
|
|
14370
14517
|
});
|
|
14371
14518
|
return { trak, shown };
|
|
14372
14519
|
});
|
|
14373
14520
|
let next = 0;
|
|
14521
|
+
const movieHeader = withDuration(template, mvhd, Math.max(...traks.map((t) => t.shown)));
|
|
14374
14522
|
return rebuild(template, root, {
|
|
14375
|
-
mvhd: (
|
|
14376
|
-
trak: () => traks[next
|
|
14523
|
+
mvhd: () => audio ? withId(movieHeader, "mvhd", audioTrackId + 1) : movieHeader,
|
|
14524
|
+
trak: () => ++next < chunkTrackCount ? traks[next - 1].trak : Buffer.concat(traks.slice(next - 1).map((t) => t.trak))
|
|
14377
14525
|
});
|
|
14378
14526
|
};
|
|
14379
14527
|
const ftyp = layouts[0].ftyp;
|
|
@@ -14406,15 +14554,16 @@ async function copyPayload(path, layout, index, out) {
|
|
|
14406
14554
|
);
|
|
14407
14555
|
}
|
|
14408
14556
|
}
|
|
14409
|
-
async function writeStitchedMp4(chunkPaths, outputPath) {
|
|
14410
|
-
const
|
|
14411
|
-
const
|
|
14557
|
+
async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
|
|
14558
|
+
const sourcePaths = audioPath ? [audioPath, ...chunkPaths] : chunkPaths;
|
|
14559
|
+
const layouts = await Promise.all(sourcePaths.map((path) => readMp4Layout(fileRange(path))));
|
|
14560
|
+
const header = audioPath ? buildStitchedHeader(layouts.slice(1), layouts[0]) : buildStitchedHeader(layouts);
|
|
14412
14561
|
mkdirSync10(dirname11(outputPath), { recursive: true });
|
|
14413
14562
|
const workDir = mkdtempSync4(`${outputPath}.stitch-`);
|
|
14414
14563
|
const out = createWriteStream(join30(workDir, "out.mp4"));
|
|
14415
14564
|
try {
|
|
14416
14565
|
out.write(header);
|
|
14417
|
-
for (const [i, path] of
|
|
14566
|
+
for (const [i, path] of sourcePaths.entries()) await copyPayload(path, layouts[i], i, out);
|
|
14418
14567
|
out.end();
|
|
14419
14568
|
await finished(out);
|
|
14420
14569
|
renameSync4(join30(workDir, "out.mp4"), outputPath);
|
|
@@ -14985,7 +15134,8 @@ function buildLockedRenderConfig(input) {
|
|
|
14985
15134
|
chunkCount: input.chunkCount,
|
|
14986
15135
|
runtimeEnv: input.runtimeEnv,
|
|
14987
15136
|
variables: config.variables,
|
|
14988
|
-
...input.chunksCarryAudio ? { chunksCarryAudio: true } : {}
|
|
15137
|
+
...input.chunksCarryAudio ? { chunksCarryAudio: true } : {},
|
|
15138
|
+
...input.separateAudio ? { separateAudio: true } : {}
|
|
14989
15139
|
};
|
|
14990
15140
|
}
|
|
14991
15141
|
function carriesChunkAudio(config, options) {
|
|
@@ -15080,8 +15230,10 @@ function createVideoSourceShipper(input) {
|
|
|
15080
15230
|
return result;
|
|
15081
15231
|
};
|
|
15082
15232
|
}
|
|
15083
|
-
|
|
15084
|
-
|
|
15233
|
+
function plansSeparateAudio(config, options) {
|
|
15234
|
+
return options.deferAudio === true && config.format === "mp4" && config.cfr !== true;
|
|
15235
|
+
}
|
|
15236
|
+
async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
15085
15237
|
rejectUnsupportedDistributedFormat(config);
|
|
15086
15238
|
validateNoGpuEncode({
|
|
15087
15239
|
useGpu: false,
|
|
@@ -15209,7 +15361,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15209
15361
|
if (probeResult.fileServer) closeFileServerSafely(probeResult.fileServer, "plan", log);
|
|
15210
15362
|
if (probeResult.probeSession) {
|
|
15211
15363
|
try {
|
|
15212
|
-
const { closeCaptureSession: closeCaptureSession2 } = await import("./src-
|
|
15364
|
+
const { closeCaptureSession: closeCaptureSession2 } = await import("./src-EL6HGIS4.js");
|
|
15213
15365
|
await closeCaptureSession2(probeResult.probeSession);
|
|
15214
15366
|
} catch (err) {
|
|
15215
15367
|
log.warn("[plan] probe session close failed", {
|
|
@@ -15217,6 +15369,100 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15217
15369
|
});
|
|
15218
15370
|
}
|
|
15219
15371
|
}
|
|
15372
|
+
return {
|
|
15373
|
+
projectDir,
|
|
15374
|
+
log,
|
|
15375
|
+
sizeLimitBytes,
|
|
15376
|
+
abortSignal,
|
|
15377
|
+
assertNotAborted,
|
|
15378
|
+
cfg,
|
|
15379
|
+
job,
|
|
15380
|
+
workDir,
|
|
15381
|
+
compiledDir,
|
|
15382
|
+
finalCompiledDir,
|
|
15383
|
+
remoteFiles,
|
|
15384
|
+
urlByAbsentLocalPath,
|
|
15385
|
+
localPathByUrl,
|
|
15386
|
+
compileResult,
|
|
15387
|
+
compiled,
|
|
15388
|
+
composition,
|
|
15389
|
+
deviceScaleFactor,
|
|
15390
|
+
forceScreenshot,
|
|
15391
|
+
width,
|
|
15392
|
+
height,
|
|
15393
|
+
probeResult,
|
|
15394
|
+
totalFrames
|
|
15395
|
+
};
|
|
15396
|
+
}
|
|
15397
|
+
function mixPlanAudio(c, compiledDir, seconds, pcmPath) {
|
|
15398
|
+
return runAudioStage({
|
|
15399
|
+
projectDir: c.projectDir,
|
|
15400
|
+
workDir: c.workDir,
|
|
15401
|
+
compiledDir,
|
|
15402
|
+
urlByAbsentLocalPath: c.urlByAbsentLocalPath,
|
|
15403
|
+
duration: seconds,
|
|
15404
|
+
ffmpegProcessTimeout: c.cfg.ffmpegProcessTimeout,
|
|
15405
|
+
audioGain: c.cfg.audioGain,
|
|
15406
|
+
audios: c.composition.audios,
|
|
15407
|
+
masterFxChain: c.composition.masterFxChain,
|
|
15408
|
+
...pcmPath ? { keepEncoderInputAt: pcmPath } : {},
|
|
15409
|
+
abortSignal: c.abortSignal,
|
|
15410
|
+
assertNotAborted: c.assertNotAborted
|
|
15411
|
+
});
|
|
15412
|
+
}
|
|
15413
|
+
async function extractPlanVideos(c, deferRangeExtraction) {
|
|
15414
|
+
const extractResult = await runExtractVideosStage({
|
|
15415
|
+
projectDir: c.projectDir,
|
|
15416
|
+
compiledDir: c.compiledDir,
|
|
15417
|
+
job: c.job,
|
|
15418
|
+
cfg: c.cfg,
|
|
15419
|
+
composition: c.composition,
|
|
15420
|
+
abortSignal: c.abortSignal,
|
|
15421
|
+
assertNotAborted: c.assertNotAborted,
|
|
15422
|
+
materializeSymlinks: true,
|
|
15423
|
+
deferRangeExtraction,
|
|
15424
|
+
urlByAbsentLocalPath: c.urlByAbsentLocalPath
|
|
15425
|
+
});
|
|
15426
|
+
if (extractResult.failureToEnforce) throw extractResult.failureToEnforce;
|
|
15427
|
+
if (extractResult.extractionResult) {
|
|
15428
|
+
assertVideoExtractionSucceeded(extractResult.extractionResult);
|
|
15429
|
+
}
|
|
15430
|
+
return extractResult;
|
|
15431
|
+
}
|
|
15432
|
+
async function holdPlanAudioPeak(c, audioPath, pcmPath, seconds) {
|
|
15433
|
+
const peak = await constrainAacTruePeak({
|
|
15434
|
+
audioPath,
|
|
15435
|
+
...existsSync20(pcmPath) ? { sourcePath: pcmPath } : {},
|
|
15436
|
+
targetDurationSeconds: seconds,
|
|
15437
|
+
signal: c.abortSignal,
|
|
15438
|
+
timeoutMs: c.cfg.ffmpegProcessTimeout
|
|
15439
|
+
}).finally(() => rmSync10(pcmPath, { force: true }));
|
|
15440
|
+
if (!peak.success) throw encoderFailureError("[plan] audio true-peak check failed", peak);
|
|
15441
|
+
}
|
|
15442
|
+
async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, options = {}) {
|
|
15443
|
+
const planDir = executionPlanDir;
|
|
15444
|
+
const c = await compilePlanComposition(projectDir, config, planDir, options);
|
|
15445
|
+
const {
|
|
15446
|
+
log,
|
|
15447
|
+
sizeLimitBytes,
|
|
15448
|
+
cfg,
|
|
15449
|
+
job,
|
|
15450
|
+
workDir,
|
|
15451
|
+
compiledDir,
|
|
15452
|
+
finalCompiledDir,
|
|
15453
|
+
remoteFiles,
|
|
15454
|
+
urlByAbsentLocalPath,
|
|
15455
|
+
localPathByUrl,
|
|
15456
|
+
compileResult,
|
|
15457
|
+
compiled,
|
|
15458
|
+
composition,
|
|
15459
|
+
deviceScaleFactor,
|
|
15460
|
+
forceScreenshot,
|
|
15461
|
+
width,
|
|
15462
|
+
height,
|
|
15463
|
+
probeResult,
|
|
15464
|
+
totalFrames
|
|
15465
|
+
} = c;
|
|
15220
15466
|
const megapixels = compileResult.outputWidth * compileResult.outputHeight / 1e6;
|
|
15221
15467
|
let maxParallel = resolveMaxParallelChunks(config, totalFrames, megapixels, log);
|
|
15222
15468
|
const measureFrameCost = chunkSizingUsesFrameCost(config) && planNeedsFrameCostMeasurement(compiled.html);
|
|
@@ -15227,24 +15473,9 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15227
15473
|
observedAt: "pre-extract",
|
|
15228
15474
|
log
|
|
15229
15475
|
});
|
|
15230
|
-
stageStarted = Date.now();
|
|
15231
|
-
const extractResult = await
|
|
15232
|
-
projectDir,
|
|
15233
|
-
compiledDir,
|
|
15234
|
-
job,
|
|
15235
|
-
cfg,
|
|
15236
|
-
composition,
|
|
15237
|
-
abortSignal,
|
|
15238
|
-
assertNotAborted,
|
|
15239
|
-
materializeSymlinks: true,
|
|
15240
|
-
deferRangeExtraction: options.deferVideoExtraction,
|
|
15241
|
-
urlByAbsentLocalPath
|
|
15242
|
-
});
|
|
15476
|
+
let stageStarted = Date.now();
|
|
15477
|
+
const extractResult = await extractPlanVideos(c, options.deferVideoExtraction);
|
|
15243
15478
|
logPlanStage(log, "extract", stageStarted);
|
|
15244
|
-
if (extractResult.failureToEnforce) throw extractResult.failureToEnforce;
|
|
15245
|
-
if (extractResult.extractionResult) {
|
|
15246
|
-
assertVideoExtractionSucceeded(extractResult.extractionResult);
|
|
15247
|
-
}
|
|
15248
15479
|
const stagedVideoFrames = join33(compiledDir, "__hyperframes_video_frames");
|
|
15249
15480
|
const videoFramesDst = join33(planDir, "video-frames");
|
|
15250
15481
|
if (existsSync20(videoFramesDst)) rmSync10(videoFramesDst, { recursive: true, force: true });
|
|
@@ -15300,23 +15531,18 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15300
15531
|
"utf-8"
|
|
15301
15532
|
);
|
|
15302
15533
|
const digests = options.digests ?? /* @__PURE__ */ new Map();
|
|
15303
|
-
const
|
|
15304
|
-
const
|
|
15534
|
+
const separateAudio = plansSeparateAudio(config, options);
|
|
15535
|
+
const chunksCarryAudio = !separateAudio && carriesChunkAudio(config, options);
|
|
15536
|
+
const audioSeconds = chunksCarryAudio ? totalFrames / config.fps : probeResult.duration;
|
|
15537
|
+
const planMixPcmPath = join33(workDir, "plan-mix.wav");
|
|
15305
15538
|
stageStarted = Date.now();
|
|
15306
15539
|
const [audioOutcome, overlapOutcome, frameCostOutcome] = await Promise.allSettled([
|
|
15307
|
-
|
|
15308
|
-
|
|
15309
|
-
|
|
15310
|
-
|
|
15311
|
-
|
|
15312
|
-
|
|
15313
|
-
ffmpegProcessTimeout: cfg.ffmpegProcessTimeout,
|
|
15314
|
-
audioGain: cfg.audioGain,
|
|
15315
|
-
audios: composition.audios,
|
|
15316
|
-
masterFxChain: composition.masterFxChain,
|
|
15317
|
-
abortSignal,
|
|
15318
|
-
assertNotAborted
|
|
15319
|
-
}).finally(() => logPlanStage(log, "audio", stageStarted)),
|
|
15540
|
+
separateAudio ? null : mixPlanAudio(
|
|
15541
|
+
c,
|
|
15542
|
+
finalCompiledDir,
|
|
15543
|
+
audioSeconds,
|
|
15544
|
+
chunksCarryAudio ? planMixPcmPath : void 0
|
|
15545
|
+
).finally(() => logPlanStage(log, "audio", stageStarted)),
|
|
15320
15546
|
(async () => {
|
|
15321
15547
|
for (const dir of [finalCompiledDir, videoFramesDst, videoSourcesDir]) {
|
|
15322
15548
|
await prehashPlanFiles(dir, digests);
|
|
@@ -15366,22 +15592,16 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15366
15592
|
);
|
|
15367
15593
|
const chunks = buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize);
|
|
15368
15594
|
const audioResult = audioOutcome.value;
|
|
15369
|
-
if (audioResult
|
|
15595
|
+
if (audioResult?.audioError) {
|
|
15370
15596
|
applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
|
|
15371
15597
|
}
|
|
15372
15598
|
const planAudioPath = join33(planDir, PLAN_AUDIO_RELATIVE_PATH);
|
|
15373
|
-
if (audioResult
|
|
15599
|
+
if (audioResult?.hasAudio && existsSync20(audioResult.audioOutputPath)) {
|
|
15374
15600
|
renameSync5(audioResult.audioOutputPath, planAudioPath);
|
|
15375
15601
|
}
|
|
15376
|
-
if (
|
|
15602
|
+
if (chunksCarryAudio && existsSync20(planAudioPath)) {
|
|
15377
15603
|
stageStarted = Date.now();
|
|
15378
|
-
|
|
15379
|
-
audioPath: planAudioPath,
|
|
15380
|
-
targetDurationSeconds: audioSeconds,
|
|
15381
|
-
signal: abortSignal,
|
|
15382
|
-
timeoutMs: cfg.ffmpegProcessTimeout
|
|
15383
|
-
});
|
|
15384
|
-
if (!peak.success) throw encoderFailureError("[plan] audio true-peak check failed", peak);
|
|
15604
|
+
await holdPlanAudioPeak(c, planAudioPath, planMixPcmPath, audioSeconds);
|
|
15385
15605
|
logPlanStage(log, "audio-peak", stageStarted);
|
|
15386
15606
|
if (options.sliceChunkAudio) {
|
|
15387
15607
|
stageStarted = Date.now();
|
|
@@ -15407,7 +15627,8 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15407
15627
|
effectiveChunkSize,
|
|
15408
15628
|
chunkCount,
|
|
15409
15629
|
runtimeEnv,
|
|
15410
|
-
chunksCarryAudio
|
|
15630
|
+
chunksCarryAudio,
|
|
15631
|
+
separateAudio
|
|
15411
15632
|
});
|
|
15412
15633
|
const compositionJson = {
|
|
15413
15634
|
durationSeconds: job.duration ?? 0,
|
|
@@ -15452,7 +15673,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15452
15673
|
fontSnapshotSha,
|
|
15453
15674
|
durationSeconds: job.duration ?? 0,
|
|
15454
15675
|
totalFrames,
|
|
15455
|
-
hasAudio: audioResult
|
|
15676
|
+
hasAudio: audioResult?.hasAudio ?? false,
|
|
15456
15677
|
digests
|
|
15457
15678
|
});
|
|
15458
15679
|
logPlanStage(log, "freeze", stageStarted);
|
|
@@ -16803,7 +17024,7 @@ function startServer(options = {}) {
|
|
|
16803
17024
|
});
|
|
16804
17025
|
async function shutdown(signal) {
|
|
16805
17026
|
log.info(`Received ${signal}, shutting down`);
|
|
16806
|
-
const { drainBrowserPool } = await import("./src-
|
|
17027
|
+
const { drainBrowserPool } = await import("./src-EL6HGIS4.js");
|
|
16807
17028
|
await drainBrowserPool().catch(() => {
|
|
16808
17029
|
});
|
|
16809
17030
|
const handle = await Promise.race([
|
|
@@ -17427,7 +17648,8 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
|
|
|
17427
17648
|
)
|
|
17428
17649
|
),
|
|
17429
17650
|
chunksCarryAudio: options.chunksCarryAudio,
|
|
17430
|
-
sliceChunkAudio: true
|
|
17651
|
+
sliceChunkAudio: true,
|
|
17652
|
+
deferAudio: options.deferAudio
|
|
17431
17653
|
});
|
|
17432
17654
|
return await publishExecutionPlan(stagingRoot, publisher, { digests, log: config.logger });
|
|
17433
17655
|
} catch (error) {
|
|
@@ -17753,7 +17975,8 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
17753
17975
|
return mergePngFrameDirs(chunkPaths, outputPath, plan2.totalFrames, audioPath, start);
|
|
17754
17976
|
}
|
|
17755
17977
|
if (chunksAreStitchedMp4(planDir, cfr)) {
|
|
17756
|
-
|
|
17978
|
+
const separateAudio = stitchesSeparateAudio(planDir) && audioPath !== null;
|
|
17979
|
+
await writeStitchedMp4(chunkPaths, outputPath, separateAudio ? audioPath : void 0);
|
|
17757
17980
|
return {
|
|
17758
17981
|
outputPath,
|
|
17759
17982
|
durationMs: Date.now() - start,
|
|
@@ -17951,16 +18174,20 @@ async function runAssembleFfmpeg(args, step, signal, timeout) {
|
|
|
17951
18174
|
}
|
|
17952
18175
|
}
|
|
17953
18176
|
function chunksAreStitchedMp4(planDir, cfr) {
|
|
17954
|
-
|
|
18177
|
+
const { chunksCarryAudio, separateAudio } = lockedAudio(planDir);
|
|
18178
|
+
if (!chunksCarryAudio && !separateAudio) return false;
|
|
17955
18179
|
if (cfr) {
|
|
17956
|
-
throw new Error("[assemble] cfr=true cannot re-encode a plan whose mp4 chunks
|
|
18180
|
+
throw new Error("[assemble] cfr=true cannot re-encode a plan whose mp4 chunks are stitched");
|
|
17957
18181
|
}
|
|
17958
18182
|
return true;
|
|
17959
18183
|
}
|
|
17960
|
-
function
|
|
18184
|
+
function stitchesSeparateAudio(planDir) {
|
|
18185
|
+
return lockedAudio(planDir).separateAudio === true;
|
|
18186
|
+
}
|
|
18187
|
+
function lockedAudio(planDir) {
|
|
17961
18188
|
const encoderJsonPath = join40(planDir, "meta", "encoder.json");
|
|
17962
|
-
if (!existsSync26(encoderJsonPath)) return
|
|
17963
|
-
return JSON.parse(readFileSync13(encoderJsonPath, "utf-8"))
|
|
18189
|
+
if (!existsSync26(encoderJsonPath)) return {};
|
|
18190
|
+
return JSON.parse(readFileSync13(encoderJsonPath, "utf-8"));
|
|
17964
18191
|
}
|
|
17965
18192
|
function readCfrEncoder(planDir, format) {
|
|
17966
18193
|
if (format !== "mp4") {
|
|
@@ -18244,34 +18471,15 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18244
18471
|
const framesDir = join41(workDir, "captured-frames");
|
|
18245
18472
|
mkdirSync17(framesDir, { recursive: true });
|
|
18246
18473
|
const videoFramesDir = `${workDir}.video-frames`;
|
|
18247
|
-
const
|
|
18248
|
-
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
|
|
18252
|
-
outputRoot: videoFramesDir,
|
|
18253
|
-
cfg,
|
|
18254
|
-
remoteSources
|
|
18255
|
-
}) : [];
|
|
18474
|
+
const chunkFrameNumbers = Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i);
|
|
18475
|
+
const chunkFps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
|
|
18476
|
+
const deferredVideos = planVideos?.extracted.filter((video) => video.deferredRange) ?? [];
|
|
18477
|
+
const shownFrames = planVideos ? shownDeferredFrameIndexes(planVideos, chunkFrameNumbers, chunkFps) : /* @__PURE__ */ new Map();
|
|
18256
18478
|
const remoteVideoIds = new Set(
|
|
18257
18479
|
planVideos?.extracted.filter(
|
|
18258
18480
|
(video) => video.deferredRange && Object.hasOwn(remoteSources, video.deferredRange.sourcePath)
|
|
18259
18481
|
).map((video) => video.videoId)
|
|
18260
18482
|
);
|
|
18261
|
-
const remoteVideos = deferredVideoFrames.filter((video) => remoteVideoIds.has(video.videoId));
|
|
18262
|
-
const videoFrameLookup = planVideos && planVideos.extracted.length > 0 ? createFrameLookupTable(
|
|
18263
|
-
planVideos.videos,
|
|
18264
|
-
[
|
|
18265
|
-
...rebuildExtractedFramesFromPlanDir(
|
|
18266
|
-
planDir,
|
|
18267
|
-
planVideos.extracted.filter((video) => !video.deferredRange),
|
|
18268
|
-
v2Manifest === null ? "dense-v1" : "sparse-v2"
|
|
18269
|
-
),
|
|
18270
|
-
...deferredVideoFrames
|
|
18271
|
-
],
|
|
18272
|
-
resolveRenderFpsConfig(job.config.fps).value
|
|
18273
|
-
) : null;
|
|
18274
|
-
const createChunkVideoFrameInjector = createChunkVideoFrameInjectorFactory(videoFrameLookup);
|
|
18275
18483
|
const fileServer = await createFileServer({
|
|
18276
18484
|
projectDir: compiledDir,
|
|
18277
18485
|
compiledDir,
|
|
@@ -18287,8 +18495,12 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18287
18495
|
videoCount: planVideos?.videos.length ?? 0,
|
|
18288
18496
|
html: readFileSync14(join41(compiledDir, "index.html"), "utf-8"),
|
|
18289
18497
|
// The plan ships a deferred source only to chunks that show it; don't wait on the rest.
|
|
18290
|
-
skipReadinessVideoIds:
|
|
18291
|
-
|
|
18498
|
+
skipReadinessVideoIds: deferredVideos.filter(
|
|
18499
|
+
(video) => !shownFrames.get(video.videoId)?.size || remoteVideoIds.has(video.videoId)
|
|
18500
|
+
).map((video) => video.videoId),
|
|
18501
|
+
videoMetadataHints: collectVideoMetadataHints(
|
|
18502
|
+
deferredVideos.filter((video) => remoteVideoIds.has(video.videoId))
|
|
18503
|
+
)
|
|
18292
18504
|
});
|
|
18293
18505
|
const chunkWorkerCount = calculateOptimalWorkers(framesInChunk, void 0, cfg);
|
|
18294
18506
|
let session = null;
|
|
@@ -18301,6 +18513,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18301
18513
|
const capturePerfs = [];
|
|
18302
18514
|
const captureAttempts = [];
|
|
18303
18515
|
let forceScreenshotForChunk = encoder.forceScreenshot;
|
|
18516
|
+
let shownBoxes;
|
|
18304
18517
|
try {
|
|
18305
18518
|
if (chunkWorkerCount === 1 || !forceScreenshotForChunk) {
|
|
18306
18519
|
const bootStarted = Date.now();
|
|
@@ -18311,6 +18524,11 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18311
18524
|
cfg
|
|
18312
18525
|
);
|
|
18313
18526
|
sessionBootMs = Date.now() - bootStarted;
|
|
18527
|
+
shownBoxes = await measureVideoShownBoxes(
|
|
18528
|
+
session.page,
|
|
18529
|
+
[...shownFrames.keys()],
|
|
18530
|
+
chunkFrameNumbers.map((frame) => frame * chunkFps.den / chunkFps.num)
|
|
18531
|
+
);
|
|
18314
18532
|
const browserSelectedScreenshot = session.launchCaptureMode === "screenshot";
|
|
18315
18533
|
const beginFrameStalled = !browserSelectedScreenshot && await beginFrameSessionNeedsScreenshotFallback(session);
|
|
18316
18534
|
if (browserSelectedScreenshot) {
|
|
@@ -18352,6 +18570,29 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18352
18570
|
session = null;
|
|
18353
18571
|
}
|
|
18354
18572
|
}
|
|
18573
|
+
const deferredVideoFrames = planVideos ? await extractDeferredVideoFramesForChunk({
|
|
18574
|
+
planDir,
|
|
18575
|
+
planVideos,
|
|
18576
|
+
frames: chunkFrameNumbers,
|
|
18577
|
+
fps: chunkFps,
|
|
18578
|
+
outputRoot: videoFramesDir,
|
|
18579
|
+
cfg,
|
|
18580
|
+
remoteSources,
|
|
18581
|
+
shownBoxes
|
|
18582
|
+
}) : [];
|
|
18583
|
+
const videoFrameLookup = planVideos && planVideos.extracted.length > 0 ? createFrameLookupTable(
|
|
18584
|
+
planVideos.videos,
|
|
18585
|
+
[
|
|
18586
|
+
...rebuildExtractedFramesFromPlanDir(
|
|
18587
|
+
planDir,
|
|
18588
|
+
planVideos.extracted.filter((video) => !video.deferredRange),
|
|
18589
|
+
v2Manifest === null ? "dense-v1" : "sparse-v2"
|
|
18590
|
+
),
|
|
18591
|
+
...deferredVideoFrames
|
|
18592
|
+
],
|
|
18593
|
+
resolveRenderFpsConfig(job.config.fps).value
|
|
18594
|
+
) : null;
|
|
18595
|
+
const createChunkVideoFrameInjector = createChunkVideoFrameInjectorFactory(videoFrameLookup);
|
|
18355
18596
|
const captureStarted = Date.now();
|
|
18356
18597
|
captureMode = await runCaptureWithScreenshotFallback({
|
|
18357
18598
|
forceScreenshot: forceScreenshotForChunk,
|
|
@@ -18542,6 +18783,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18542
18783
|
encodeStageMs,
|
|
18543
18784
|
workers: chunkWorkerCount,
|
|
18544
18785
|
captureMode,
|
|
18786
|
+
// Device-pixel box each video's frames were extracted to cover; a video not listed kept full size.
|
|
18787
|
+
videoShownBoxes: Object.fromEntries(shownBoxes ?? []),
|
|
18545
18788
|
sha256,
|
|
18546
18789
|
outputKind,
|
|
18547
18790
|
producerVersion: plan2.producerVersion,
|
|
@@ -18611,9 +18854,10 @@ async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
|
|
|
18611
18854
|
}
|
|
18612
18855
|
|
|
18613
18856
|
// ../producer/src/services/distributed/projectHash.ts
|
|
18614
|
-
import { readdirSync as readdirSync12,
|
|
18857
|
+
import { closeSync as closeSync8, openSync as openSync7, readdirSync as readdirSync12, readSync as readSync5, realpathSync as realpathSync2, statSync as statSync11 } from "fs";
|
|
18615
18858
|
import { createHash as createHash7 } from "crypto";
|
|
18616
18859
|
import { join as join43 } from "path";
|
|
18860
|
+
var READ_CHUNK_BYTES = 256 * 1024;
|
|
18617
18861
|
|
|
18618
18862
|
export {
|
|
18619
18863
|
createConsoleLogger,
|