hyperframes 0.8.181 → 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-AWQ2EGBU.js → add-HW3ZGR36.js} +22 -22
- package/dist/{animatedGifPrep-SENXJ7TN.js → animatedGifPrep-EPLN37ZN.js} +13 -13
- package/dist/api.js +28 -28
- package/dist/{asset-XBH3MN3Y.js → asset-TOASKL3Z.js} +3 -3
- package/dist/{assetCataloger-KH4X2CRO.js → assetCataloger-PZN5HYG2.js} +15 -13
- package/dist/{audio-Q7I473UN.js → audio-F5OIQVJO.js} +29 -29
- package/dist/{auth-I7CBTEUS.js → auth-YVQLRS3T.js} +4 -4
- package/dist/{autoUpdate-KY5TLSN7.js → autoUpdate-EG4ZFW4D.js} +2 -2
- package/dist/{backgroundChecks-4Q3VVK5W.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-P4LENNVT.js → beats-KGIOEBLW.js} +12 -12
- package/dist/{benchmark-AXOAECN3.js → benchmark-ZNY2L7HN.js} +24 -24
- package/dist/{browser-XZKB5HGJ.js → browser-REAO7RU4.js} +20 -20
- package/dist/{bundleWithLocalizedFonts-2WCR57IN.js → bundleWithLocalizedFonts-OAYLYC4W.js} +2 -2
- package/dist/{capture-NWARHRHR.js → capture-IK6GWQDD.js} +8 -5
- package/dist/{capture-4RN4APDF.js → capture-WOSF276U.js} +49 -41
- package/dist/{captureCompositionFrame-QOF5BRF4.js → captureCompositionFrame-DDZNKYRE.js} +21 -20
- package/dist/{captureTimeout-K2JNVVCI.js → captureTimeout-RIMG6IYH.js} +1 -1
- package/dist/{catalog-CRPOPVD5.js → catalog-AKTXS7OJ.js} +42 -42
- package/dist/{catch-up-MHWGUQ42.js → catch-up-O3VZMPVE.js} +15 -15
- package/dist/check-6E46NIWI.js +116 -0
- package/dist/checkBrowser-UNZHQFNH.js +117 -0
- package/dist/{chunk-Y2RXRPL2.js → chunk-3BA2GP4H.js} +5 -5
- package/dist/{chunk-N5SXQCJL.js → chunk-3OLIGYWN.js} +3 -3
- package/dist/{chunk-OR5WCFWZ.js → chunk-3Q47QC46.js} +2 -2
- package/dist/{chunk-EOADENKV.js → chunk-4FQKS7BJ.js} +16 -14
- package/dist/{chunk-HODBPO4A.js → chunk-4UFJWRHG.js} +461 -275
- package/dist/{chunk-537IYAEE.js → chunk-4UMPIPCQ.js} +9 -1
- package/dist/{chunk-OJTDUF4W.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-YPBIAONI.js → chunk-73LTCCZI.js} +218 -150
- 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-VAJIPSN6.js → chunk-ANR6WOC3.js} +1 -1
- package/dist/{chunk-4USWWI2Y.js → chunk-ATMDOUNN.js} +2 -2
- package/dist/{chunk-XSRUVMXK.js → chunk-B2SZZFWW.js} +4 -4
- package/dist/{chunk-TO6JNTML.js → chunk-BP4VNTZL.js} +13 -8
- package/dist/{chunk-DJJ7SK4F.js → chunk-CAHTO62O.js} +8 -8
- package/dist/{chunk-GNE57O7U.js → chunk-CGK4XZ2J.js} +1 -1
- package/dist/{chunk-O5AE7HOP.js → chunk-CJYAJ3QM.js} +37 -33
- package/dist/{chunk-5JMZLQT6.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-K26FR4SM.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-5E5EYPZO.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-WITHUCCB.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-IL3GTCQY.js → chunk-GTE5WZAM.js} +72 -140
- package/dist/{chunk-55IG255C.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-WUUCEFL5.js → chunk-IC2WYONA.js} +5 -5
- package/dist/{chunk-DUN63LHY.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-AOWDVB2T.js → chunk-KRFAX5JK.js} +1 -1
- package/dist/{chunk-UIDZRCBG.js → chunk-LBWRQ4XA.js} +1 -1
- package/dist/{chunk-T7UHTUUE.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-JMFJI26U.js → chunk-O7N3A7PE.js} +2 -2
- package/dist/{chunk-3PULCIY5.js → chunk-OH56PXFH.js} +5 -5
- package/dist/{chunk-H4YZZ2VQ.js → chunk-PFD25NAC.js} +1 -1
- package/dist/{check-DJCUOUDI.js → chunk-Q6UYKWBG.js} +198 -142
- package/dist/{chunk-3DKN5WKL.js → chunk-QH3T4WI2.js} +77 -6
- package/dist/{chunk-Y5GY6Y7A.js → chunk-QX4GGPMY.js} +2 -2
- package/dist/{chunk-B6JLCPT3.js → chunk-R6OV4J4K.js} +6 -6
- package/dist/{chunk-XEWHUPFS.js → chunk-RZXUQR42.js} +2 -2
- package/dist/{chunk-YMS6CJCD.js → chunk-SAQYJLI6.js} +1 -1
- package/dist/{chunk-OJDXABUF.js → chunk-TJB4GAV6.js} +2 -2
- package/dist/{checkBrowser-VES2NF3K.js → chunk-TOHA5NAU.js} +187 -114
- package/dist/{chunk-RXQHSGAQ.js → chunk-TXGZZKDF.js} +2 -2
- package/dist/{chunk-3XDOGSRD.js → chunk-U5YVWG5W.js} +3 -3
- package/dist/{chunk-ICMXC3MI.js → chunk-U6RXZNZE.js} +31 -18
- package/dist/{chunk-PF7OWVTL.js → chunk-UNOSCGBG.js} +2 -2
- package/dist/{chunk-X7CCSMRR.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-ZUOSILUE.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-6I7V6Q7F.js → chunk-XJHKJXT4.js} +103 -20
- package/dist/{chunk-V2UNZ7QP.js → chunk-XOVHO3TT.js} +25 -14
- package/dist/{chunk-65WIUIHL.js → chunk-XR5BSEUF.js} +7 -15
- package/dist/{chunk-IZM562YJ.js → chunk-Z4R35NJS.js} +4 -4
- package/dist/{chunk-4OT3FWVV.js → chunk-ZFO3A3QL.js} +2 -2
- package/dist/{clean-GJNDVVDI.js → clean-WNEIVBF3.js} +40 -40
- package/dist/cli.js +68 -64
- package/dist/{cloud-JCWNMKXC.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-XWM7FAYM.js → compare-2JWQ5ABA.js} +50 -47
- package/dist/{compiler-U3W6CJW7.js → compiler-27KQD7KW.js} +6 -6
- package/dist/{component-CBRAE325.js → component-HCRET3MH.js} +4 -4
- package/dist/{compositions-EZYJEHQ3.js → compositions-HTSQ6SUJ.js} +28 -29
- package/dist/{contactSheet-27SRU7A4.js → contactSheet-CAGMKI3E.js} +3 -1
- package/dist/{delete-JWWMOITI.js → delete-GHQ5UYM7.js} +9 -9
- package/dist/{deploy-UGOV76OH.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-XSKSZRR7.js → doctor-UGFVQZHI.js} +27 -27
- package/dist/{events-AIZODZMP.js → events-BLJGWMNP.js} +9 -9
- package/dist/{events-RGS4MAH4.js → events-YS4OVX3I.js} +6 -6
- package/dist/{feedback-GE3VDZOH.js → feedback-AZ3SJ5HF.js} +35 -35
- package/dist/{ffmpeg-SCXZTR6X.js → ffmpeg-2AECXG7V.js} +15 -15
- package/dist/{figma-3R4XST4Y.js → figma-DRYIJQHV.js} +3 -3
- package/dist/fontLocalizeCli.js +23 -23
- package/dist/{get-4FKJP6IM.js → get-DDEAOFPB.js} +9 -9
- package/dist/{gpuPolicy-4NNXESM7.js → gpuPolicy-UDJT2MQK.js} +13 -13
- package/dist/{grade-compare-FAYVPXUR.js → grade-compare-LJKK5NSY.js} +55 -50
- package/dist/{help-C3UQMYXK.js → help-TQBGYOID.js} +1 -1
- package/dist/{history-LDGQ2IZJ.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-KMXFLD3Q.js → info-ENI5MP4W.js} +20 -20
- package/dist/{init-D7GYHSX5.js → init-JXPXWV3G.js} +68 -68
- package/dist/{inspect-CUKWHCGS.js → inspect-WZNYQ5AB.js} +45 -44
- package/dist/{installer-EPRSH6QI.js → installer-3SGRBLJW.js} +7 -7
- package/dist/{keyframes-XCUPHBW3.js → keyframes-HEOC4CT4.js} +16 -16
- package/dist/{lambda-IMORFJHN.js → lambda-2VHQ4AL2.js} +15 -15
- package/dist/{layout-JD2IOBMS.js → layout-7WEUNO6T.js} +45 -44
- package/dist/{lint-FHLER36Y.js → lint-5YMAF3L7.js} +23 -23
- package/dist/{lintProject-ARKJXDQF.js → lintProject-C2ONSH2U.js} +4 -4
- package/dist/{list-MGCFG5MA.js → list-BIE3X7CO.js} +10 -10
- package/dist/{login-QX6M4UTR.js → login-YDIGJWCG.js} +7 -7
- package/dist/{logout-DKJANASY.js → logout-DDC4QLVK.js} +3 -3
- package/dist/{manager-IETAVBZS.js → manager-D2UV6RDQ.js} +16 -16
- package/dist/{manager-V2QCCPOJ.js → manager-UHWEKPXC.js} +8 -3
- package/dist/{media-treatment-MDAQRITV.js → media-treatment-FSKHPMWA.js} +33 -33
- package/dist/{media-use-4XXGABIL.js → media-use-JBN57JE3.js} +1 -1
- package/dist/{models-NZAOSI5A.js → models-COEK6LXG.js} +24 -24
- package/dist/{motionShot-6ZDUM2K4.js → motionShot-HYZ2ZGJQ.js} +28 -26
- package/dist/{normalize-audio-7PRYX6QM.js → normalize-audio-UXR6WQ7Q.js} +12 -12
- package/dist/{open-I254NY5J.js → open-OFT2GIDG.js} +24 -24
- package/dist/{parakeetRunner-TL3TOGUS.js → parakeetRunner-4NZ3QXS3.js} +25 -25
- package/dist/{pipeline-YPERVOQM.js → pipeline-ZKE54JMG.js} +18 -18
- package/dist/{play-MYI7BYKS.js → play-2VG77FT6.js} +39 -38
- package/dist/{policies-5NTZOHJA.js → policies-XXNGXWHV.js} +1 -1
- package/dist/{preflight-HRCSZ52D.js → preflight-QTWDIM5C.js} +18 -18
- package/dist/{present-WYXQDV4Q.js → present-OONXQLJG.js} +33 -33
- package/dist/{preview-535HTWQO.js → preview-6RZJFU76.js} +49 -49
- package/dist/{producer-C76CRJ5O.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-OBYHMPD4.js → remove-background-BIQNMIR7.js} +31 -31
- package/dist/{render-5BXTEEG7.js → render-65K3K6SD.js} +31 -31
- package/dist/{render-3MELF6Y3.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-L4UACXT3.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-DXTQPCAO.js → skills-J6MBGS5O.js} +17 -17
- package/dist/{skillsUpdateCheck-ULXRGLDU.js → skillsUpdateCheck-ZAXNLBF3.js} +3 -3
- package/dist/{snapshot-PWFHQU5E.js → snapshot-TL7TTFS6.js} +72 -71
- package/dist/{src-RDSWHMJS.js → src-EL6HGIS4.js} +33 -26
- package/dist/{src-S7NVL5VF.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-DcD3NXpX.js → hyperframes-player-hz_VqxBZ.js} +7 -2
- package/dist/studio/assets/{index-BIDKYk0h.js → index-CV_ojgp5.js} +1 -1
- package/dist/studio/assets/{index-CFrZAwKo.js → index-S1ceEagc.js} +4 -4
- package/dist/studio/index.html +1 -1
- package/dist/{studio-api-IXGX5ZFI.js → studio-api-CUZDC5B3.js} +17 -17
- package/dist/{studioServer-LA5Z7RSS.js → studioServer-EZPRV43Y.js} +90 -84
- package/dist/{telemetry-STEMAMAX.js → telemetry-LFUVHARP.js} +10 -10
- package/dist/{telemetry-CQYHCCPL.js → telemetry-QG5AANZ4.js} +1 -1
- package/dist/{timeline-KLD24EN6.js → timeline-GSH743JE.js} +41 -41
- package/dist/{tokens-ICLORAA4.js → tokens-3ZMPSH7B.js} +3 -3
- package/dist/{transcribe-A6IKK7VS.js → transcribe-4SHNDPWW.js} +47 -47
- package/dist/{transcribe-CTHZLRXF.js → transcribe-TV7JBZQS.js} +19 -19
- package/dist/{tts-EDK3QS7M.js → tts-A2WILYGN.js} +6 -6
- package/dist/{updateCheck-FHCAAAXA.js → updateCheck-W7FTFOQF.js} +2 -2
- package/dist/{upgrade-7EV4F2R7.js → upgrade-7YYYNAPF.js} +3 -3
- package/dist/{urlDownloader-MIMGVASJ.js → urlDownloader-PQSUS2CP.js} +12 -12
- package/dist/{validate-LZF46W3V.js → validate-GCHAEVXM.js} +39 -38
- package/dist/{video-ZC47NFOL.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,
|
|
@@ -80,6 +80,7 @@ import {
|
|
|
80
80
|
distributeFrames,
|
|
81
81
|
distributeFramesInterleaved,
|
|
82
82
|
downloadToTemp,
|
|
83
|
+
encodeAac,
|
|
83
84
|
encodeFramesChunkedConcat,
|
|
84
85
|
encodeFramesFromDir,
|
|
85
86
|
executeParallelCapture,
|
|
@@ -113,6 +114,7 @@ import {
|
|
|
113
114
|
isVideoFrameFormat,
|
|
114
115
|
isVideoHiddenBeforeStreamStart,
|
|
115
116
|
isVideoPastTimelineEnd,
|
|
117
|
+
measureVideoShownBoxes,
|
|
116
118
|
mergeWorkerFrames,
|
|
117
119
|
muxVideoWithAudio,
|
|
118
120
|
normalizeObjectFit,
|
|
@@ -139,7 +141,6 @@ import {
|
|
|
139
141
|
resolveFinalFrameExtractionWindow,
|
|
140
142
|
resolveHeadlessShellPath,
|
|
141
143
|
resolvePlayableVideoDuration,
|
|
142
|
-
resolveReferencedStart,
|
|
143
144
|
resolveVideoExtractionWindow,
|
|
144
145
|
runFfmpeg,
|
|
145
146
|
runVideoExtractionWithRetry,
|
|
@@ -153,46 +154,35 @@ import {
|
|
|
153
154
|
validateEngineConfigSnapshot,
|
|
154
155
|
verifyDiskDrawElementSamples,
|
|
155
156
|
writeCapturedFrame
|
|
156
|
-
} from "./chunk-
|
|
157
|
-
import {
|
|
158
|
-
assignBundledRuntimeCompositionIds,
|
|
159
|
-
buildVariablesByCompScript,
|
|
160
|
-
emitMountedModuleScripts,
|
|
161
|
-
emitRootCompositionVariableStyles,
|
|
162
|
-
ensureExternalLinkTag,
|
|
163
|
-
ensureExternalScriptTag,
|
|
164
|
-
extractStandaloneEntryFromIndex,
|
|
165
|
-
inlineSubCompositions,
|
|
166
|
-
isTemplateEntry,
|
|
167
|
-
parsesAsScript,
|
|
168
|
-
prepareFlattenedInnerRoot
|
|
169
|
-
} from "./chunk-4IEH6EAC.js";
|
|
170
|
-
import {
|
|
171
|
-
LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
172
|
-
getCgroupMemoryLimitMb,
|
|
173
|
-
getSystemTotalMb
|
|
174
|
-
} from "./chunk-W2LGJSEN.js";
|
|
157
|
+
} from "./chunk-73LTCCZI.js";
|
|
175
158
|
import {
|
|
176
159
|
DISTRIBUTED_FPS,
|
|
177
160
|
HF_VFX_ATTR,
|
|
178
|
-
MEDIA_START_BASIS_ATTR,
|
|
179
161
|
chainCapture,
|
|
180
162
|
clearGifFramesBeforeNext,
|
|
181
|
-
compositionOriginSeconds,
|
|
182
|
-
cutToHostSlots,
|
|
183
163
|
fpsToFfmpegArg,
|
|
184
164
|
fpsToNumber,
|
|
185
165
|
gifClearsAfterLeavingFrameInPlace,
|
|
186
166
|
gsapCdnDist,
|
|
187
|
-
hostInPointSeconds,
|
|
188
167
|
isDistributedFps,
|
|
189
168
|
parseFps,
|
|
190
169
|
parseVfxChain,
|
|
191
|
-
readMediaStartBasis,
|
|
192
|
-
resolveAbsoluteMediaStartSeconds,
|
|
193
170
|
resolveAuthoredTimingWindow,
|
|
194
171
|
toFps
|
|
195
|
-
} 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";
|
|
196
186
|
import {
|
|
197
187
|
COMPOSITION_SOURCE_URL,
|
|
198
188
|
HF_COLOR_GRADING_ATTR,
|
|
@@ -220,7 +210,7 @@ import {
|
|
|
220
210
|
shouldClampResolvedMediaDuration,
|
|
221
211
|
sourceTimeAt,
|
|
222
212
|
styleElementsFor
|
|
223
|
-
} from "./chunk-
|
|
213
|
+
} from "./chunk-GMNHAOMJ.js";
|
|
224
214
|
import {
|
|
225
215
|
MAX_AUDIO_GAIN
|
|
226
216
|
} from "./chunk-UJKQWGFF.js";
|
|
@@ -235,24 +225,36 @@ import {
|
|
|
235
225
|
normalizeResolutionFlag,
|
|
236
226
|
suggestMatchingPreset
|
|
237
227
|
} from "./chunk-YMS5FOMC.js";
|
|
228
|
+
import {
|
|
229
|
+
TRANSITIONS,
|
|
230
|
+
convertTransfer,
|
|
231
|
+
crossfade
|
|
232
|
+
} from "./chunk-3GXQPCJC.js";
|
|
238
233
|
import {
|
|
239
234
|
redactKnownPaths,
|
|
240
235
|
redactTelemetryString
|
|
241
236
|
} from "./chunk-634HSJ3J.js";
|
|
242
237
|
import {
|
|
243
238
|
chromeMajorCeiling
|
|
244
|
-
} from "./chunk-
|
|
239
|
+
} from "./chunk-4UMPIPCQ.js";
|
|
245
240
|
import {
|
|
246
|
-
lintHyperframeHtml
|
|
247
|
-
|
|
241
|
+
lintHyperframeHtml,
|
|
242
|
+
resolveReferencedStart
|
|
243
|
+
} from "./chunk-ADDHW2FS.js";
|
|
248
244
|
import {
|
|
249
245
|
isUnresolvedAssetPlaceholder,
|
|
250
246
|
readProjectFile,
|
|
251
247
|
resolveProjectRelativeSrc
|
|
252
248
|
} from "./chunk-6BNTGNGD.js";
|
|
253
249
|
import {
|
|
254
|
-
|
|
255
|
-
|
|
250
|
+
MEDIA_START_BASIS_ATTR,
|
|
251
|
+
checkSubCompositionUsability,
|
|
252
|
+
compositionOriginSeconds,
|
|
253
|
+
cutToHostSlots,
|
|
254
|
+
hostInPointSeconds,
|
|
255
|
+
readMediaStartBasis,
|
|
256
|
+
resolveAbsoluteMediaStartSeconds
|
|
257
|
+
} from "./chunk-MMQ52NIZ.js";
|
|
256
258
|
import {
|
|
257
259
|
CSS_URL_RE,
|
|
258
260
|
decodedUrlPath,
|
|
@@ -265,10 +267,10 @@ import {
|
|
|
265
267
|
parseHTML
|
|
266
268
|
} from "./chunk-SDYDNHEE.js";
|
|
267
269
|
import {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
} from "./chunk-
|
|
270
|
+
LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
271
|
+
getCgroupMemoryLimitMb,
|
|
272
|
+
getSystemTotalMb
|
|
273
|
+
} from "./chunk-W2LGJSEN.js";
|
|
272
274
|
|
|
273
275
|
// ../producer/src/services/renderOrchestrator.ts
|
|
274
276
|
import {
|
|
@@ -1596,7 +1598,7 @@ function pidScope() {
|
|
|
1596
1598
|
return {
|
|
1597
1599
|
host: hostname(),
|
|
1598
1600
|
// Without /proc (macOS, Windows) the boot time, to the minute, stands in for the boot id.
|
|
1599
|
-
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))),
|
|
1600
1602
|
pidns: attempt(() => readlinkSync("/proc/self/ns/pid"))
|
|
1601
1603
|
};
|
|
1602
1604
|
}
|
|
@@ -1614,9 +1616,14 @@ function alive(pid) {
|
|
|
1614
1616
|
return error.code === "EPERM";
|
|
1615
1617
|
}
|
|
1616
1618
|
}
|
|
1617
|
-
function
|
|
1619
|
+
function knownPidScope() {
|
|
1618
1620
|
const scope = pidScope();
|
|
1619
|
-
|
|
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;
|
|
1620
1627
|
}
|
|
1621
1628
|
function ownerState(dir) {
|
|
1622
1629
|
let owner;
|
|
@@ -1681,7 +1688,9 @@ async function defaultArtifactDurationProbe(path) {
|
|
|
1681
1688
|
const meta = await extractMediaMetadata(path);
|
|
1682
1689
|
return {
|
|
1683
1690
|
durationSeconds: meta.durationSeconds,
|
|
1684
|
-
frames: meta.frames
|
|
1691
|
+
frames: meta.frames,
|
|
1692
|
+
width: meta.width,
|
|
1693
|
+
height: meta.height
|
|
1685
1694
|
};
|
|
1686
1695
|
}
|
|
1687
1696
|
function buildArtifactExpectation(input) {
|
|
@@ -1690,7 +1699,9 @@ function buildArtifactExpectation(input) {
|
|
|
1690
1699
|
const expectation = {
|
|
1691
1700
|
expectedDurationSeconds: input.durationSeconds,
|
|
1692
1701
|
fps: input.fps,
|
|
1693
|
-
expectedFrames: input.expectedFrames
|
|
1702
|
+
expectedFrames: input.expectedFrames,
|
|
1703
|
+
expectedWidth: input.width,
|
|
1704
|
+
expectedHeight: input.height
|
|
1694
1705
|
};
|
|
1695
1706
|
if (input.outputFormat !== "hls") return expectation;
|
|
1696
1707
|
return {
|
|
@@ -1758,6 +1769,16 @@ function assertFrameCountWithinTolerance(expectedFrames, probedFrames, stagingPa
|
|
|
1758
1769
|
`Render artifact is truncated: expected ${expectedFrames} frames, probed ${probedFrames} frames (shortfall ${shortfall} frames). Artifact: ${stagingPath}`
|
|
1759
1770
|
);
|
|
1760
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
|
+
}
|
|
1761
1782
|
var ArtifactTransaction = class {
|
|
1762
1783
|
constructor(destinationPath, kind, fileSystem = defaultFileSystem, durationProbe = defaultArtifactDurationProbe) {
|
|
1763
1784
|
this.kind = kind;
|
|
@@ -1830,6 +1851,7 @@ var ArtifactTransaction = class {
|
|
|
1830
1851
|
if (expected.expectedFrames !== void 0) {
|
|
1831
1852
|
assertFrameCountWithinTolerance(expected.expectedFrames, probed.frames, probePath);
|
|
1832
1853
|
}
|
|
1854
|
+
assertSizeMatches(expected, probed, probePath);
|
|
1833
1855
|
}
|
|
1834
1856
|
async runDurationProbe(probePath) {
|
|
1835
1857
|
try {
|
|
@@ -3308,7 +3330,9 @@ function aggregateDrawElement(perfs, de) {
|
|
|
3308
3330
|
if (perfs.length === 0) return void 0;
|
|
3309
3331
|
const modes = [...new Set(perfs.map((p) => p.captureMode).filter(Boolean))].sort();
|
|
3310
3332
|
const gateReasons = [
|
|
3311
|
-
...new Set(
|
|
3333
|
+
...new Set(
|
|
3334
|
+
[de.probeGateReason, ...perfs.map((p) => p.deGateReason)].filter((r) => !!r)
|
|
3335
|
+
)
|
|
3312
3336
|
].sort();
|
|
3313
3337
|
const gpuRenderers = [
|
|
3314
3338
|
...new Set(perfs.map((p) => p.gpuRenderer).filter((r) => !!r))
|
|
@@ -6580,7 +6604,7 @@ async function readLocalFont(absPath) {
|
|
|
6580
6604
|
return { kind: "inline", buffer: Buffer.concat(chunks, totalBytes) };
|
|
6581
6605
|
}
|
|
6582
6606
|
async function embedLocalFontFaces(html, projectDir) {
|
|
6583
|
-
const { fontToDataUri: toDataUri } = await import("./deterministicFonts-
|
|
6607
|
+
const { fontToDataUri: toDataUri } = await import("./deterministicFonts-JFLSSKRB.js");
|
|
6584
6608
|
const styleBlockRe = /<style\b[^>]*>([\s\S]*?)<\/style>/gi;
|
|
6585
6609
|
const fontFaceRe = /@font-face\s*\{([^}]*)\}/gi;
|
|
6586
6610
|
let result = html;
|
|
@@ -8337,6 +8361,7 @@ async function runAudioStage(input) {
|
|
|
8337
8361
|
audios,
|
|
8338
8362
|
masterFxChain,
|
|
8339
8363
|
urlByAbsentLocalPath,
|
|
8364
|
+
keepEncoderInputAt,
|
|
8340
8365
|
abortSignal,
|
|
8341
8366
|
assertNotAborted,
|
|
8342
8367
|
log
|
|
@@ -8356,7 +8381,13 @@ async function runAudioStage(input) {
|
|
|
8356
8381
|
audioOutputPath,
|
|
8357
8382
|
duration,
|
|
8358
8383
|
abortSignal,
|
|
8359
|
-
{
|
|
8384
|
+
{
|
|
8385
|
+
ffmpegProcessTimeout,
|
|
8386
|
+
audioGain,
|
|
8387
|
+
masterFxChain,
|
|
8388
|
+
urlByAbsentLocalPath,
|
|
8389
|
+
keepEncoderInputAt
|
|
8390
|
+
},
|
|
8360
8391
|
compiledDir
|
|
8361
8392
|
);
|
|
8362
8393
|
} catch (err) {
|
|
@@ -8456,13 +8487,29 @@ function inspectDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, free
|
|
|
8456
8487
|
}
|
|
8457
8488
|
return { available: false, estimatedBytes, freeBytes };
|
|
8458
8489
|
}
|
|
8459
|
-
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) {
|
|
8460
8507
|
const basisNote = basis === "measured" ? ` (measured from the first ${DISK_PROJECTION_SAMPLE_FRAMES} frames)` : "";
|
|
8461
8508
|
return new Error(
|
|
8462
|
-
`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}`
|
|
8463
8510
|
);
|
|
8464
8511
|
}
|
|
8465
|
-
function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeDiskBytes) {
|
|
8512
|
+
function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, remedy, freeDiskBytes) {
|
|
8466
8513
|
const headroom = inspectDiskCaptureHeadroom(
|
|
8467
8514
|
framesDir,
|
|
8468
8515
|
totalFrames,
|
|
@@ -8474,7 +8521,8 @@ function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeD
|
|
|
8474
8521
|
headroom.estimatedBytes,
|
|
8475
8522
|
headroom.freeBytes,
|
|
8476
8523
|
framesDir,
|
|
8477
|
-
"estimate"
|
|
8524
|
+
"estimate",
|
|
8525
|
+
remedy
|
|
8478
8526
|
);
|
|
8479
8527
|
}
|
|
8480
8528
|
function measureCaptureFrameBytes(workDir, framesDir) {
|
|
@@ -8494,7 +8542,7 @@ function measureCaptureFrameBytes(workDir, framesDir) {
|
|
|
8494
8542
|
return total;
|
|
8495
8543
|
}
|
|
8496
8544
|
function createDiskCaptureProjection(input) {
|
|
8497
|
-
const { framesDir, totalFrames, measureBytes, freeDiskBytes = freeDiskBytesAt } = input;
|
|
8545
|
+
const { framesDir, totalFrames, measureBytes, remedy, freeDiskBytes = freeDiskBytesAt } = input;
|
|
8498
8546
|
let checked = false;
|
|
8499
8547
|
return (capturedFrames) => {
|
|
8500
8548
|
if (checked || capturedFrames < DISK_PROJECTION_SAMPLE_FRAMES) return;
|
|
@@ -8506,7 +8554,7 @@ function createDiskCaptureProjection(input) {
|
|
|
8506
8554
|
if (remaining <= 0 || freeBytes === null) return;
|
|
8507
8555
|
const needBytes = Math.ceil(measured / capturedFrames * remaining);
|
|
8508
8556
|
if (needBytes > freeBytes * 0.9) {
|
|
8509
|
-
throw diskCaptureShortfallError(needBytes, freeBytes, framesDir, "measured");
|
|
8557
|
+
throw diskCaptureShortfallError(needBytes, freeBytes, framesDir, "measured", remedy);
|
|
8510
8558
|
}
|
|
8511
8559
|
};
|
|
8512
8560
|
}
|
|
@@ -8548,11 +8596,13 @@ async function runCaptureStage(input) {
|
|
|
8548
8596
|
}
|
|
8549
8597
|
}
|
|
8550
8598
|
const captureOptions = buildCaptureOptions();
|
|
8551
|
-
|
|
8599
|
+
const remedy = diskCaptureRemedy(cfg, job.config.format ?? "mp4", job.duration ?? 0, workerCount);
|
|
8600
|
+
assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, remedy);
|
|
8552
8601
|
const checkDiskProjection = createDiskCaptureProjection({
|
|
8553
8602
|
framesDir,
|
|
8554
8603
|
totalFrames,
|
|
8555
|
-
measureBytes: () => measureCaptureFrameBytes(workDir, framesDir)
|
|
8604
|
+
measureBytes: () => measureCaptureFrameBytes(workDir, framesDir),
|
|
8605
|
+
remedy
|
|
8556
8606
|
});
|
|
8557
8607
|
if (workerCount > 1) {
|
|
8558
8608
|
const attempts = await executeDiskCaptureWithAdaptiveRetry({
|
|
@@ -9728,8 +9778,10 @@ function fpsToFfmpegArg2(fps) {
|
|
|
9728
9778
|
}
|
|
9729
9779
|
var KEEP_FILTER_GRAPH_WHEN_FRAMES_DROP_ALPHA = ["-reinit_filter", "0"];
|
|
9730
9780
|
var WRITE_EVERY_FRAME_WHOLE = ["-gifflags", "0"];
|
|
9781
|
+
var FAIL_ON_UNREADABLE_FRAME_INSTEAD_OF_ENDING_THERE = ["-xerror"];
|
|
9731
9782
|
function framesInput(input, fpsArg) {
|
|
9732
9783
|
return [
|
|
9784
|
+
...FAIL_ON_UNREADABLE_FRAME_INSTEAD_OF_ENDING_THERE,
|
|
9733
9785
|
"-framerate",
|
|
9734
9786
|
fpsArg,
|
|
9735
9787
|
...KEEP_FILTER_GRAPH_WHEN_FRAMES_DROP_ALPHA,
|
|
@@ -10014,12 +10066,13 @@ async function scanTruePeak(audioPath, trim, timeoutMs, signal) {
|
|
|
10014
10066
|
};
|
|
10015
10067
|
}
|
|
10016
10068
|
async function measureTruePeakDbfs(audioPath, options) {
|
|
10017
|
-
const { timeoutMs, signal
|
|
10069
|
+
const { timeoutMs, signal } = options;
|
|
10018
10070
|
const wholeFile = async () => (await scanTruePeak(audioPath, "", timeoutMs, signal)).peak;
|
|
10071
|
+
const { durationSeconds, sampleRate } = await extractAudioMetadata(audioPath, { signal });
|
|
10019
10072
|
const block = 4800;
|
|
10020
|
-
const count =
|
|
10021
|
-
if (
|
|
10022
|
-
const cut = (k) => k * Math.floor(
|
|
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;
|
|
10023
10076
|
const peers = new AbortController();
|
|
10024
10077
|
const segmentSignal = signal ? AbortSignal.any([signal, peers.signal]) : peers.signal;
|
|
10025
10078
|
const scans = await Promise.all(
|
|
@@ -10048,24 +10101,8 @@ var AUDIO_DURATION_TOLERANCE_SECONDS = 1e-3;
|
|
|
10048
10101
|
var AAC_DELIVERY_TRUE_PEAK_DBFS = -1;
|
|
10049
10102
|
var AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB = 0.5;
|
|
10050
10103
|
var MAX_TRUE_PEAK_CORRECTION_PASSES = 3;
|
|
10051
|
-
function
|
|
10052
|
-
return
|
|
10053
|
-
"-i",
|
|
10054
|
-
inputPath,
|
|
10055
|
-
"-map",
|
|
10056
|
-
"0:a:0",
|
|
10057
|
-
"-vn",
|
|
10058
|
-
"-af",
|
|
10059
|
-
`volume=${attenuationDb.toFixed(3)}dB`,
|
|
10060
|
-
"-t",
|
|
10061
|
-
formatSeconds(targetDurationSeconds),
|
|
10062
|
-
"-c:a",
|
|
10063
|
-
"aac",
|
|
10064
|
-
"-b:a",
|
|
10065
|
-
"192k",
|
|
10066
|
-
"-y",
|
|
10067
|
-
outputPath
|
|
10068
|
-
];
|
|
10104
|
+
function aacTruePeakCorrectionFilter(targetDurationSeconds, attenuationDb) {
|
|
10105
|
+
return `volume=${attenuationDb.toFixed(3)}dB,apad,atrim=0:${formatSeconds(targetDurationSeconds)}`;
|
|
10069
10106
|
}
|
|
10070
10107
|
function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, targetDurationSeconds) {
|
|
10071
10108
|
const delta = targetDurationSeconds - sourceDurationSeconds;
|
|
@@ -10080,53 +10117,13 @@ function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, tar
|
|
|
10080
10117
|
if (delta > 0) {
|
|
10081
10118
|
return {
|
|
10082
10119
|
operation: "pad",
|
|
10083
|
-
steps: [
|
|
10084
|
-
{
|
|
10085
|
-
kind: "normalize",
|
|
10086
|
-
args: [
|
|
10087
|
-
"-i",
|
|
10088
|
-
audioPath,
|
|
10089
|
-
"-af",
|
|
10090
|
-
`apad,atrim=0:${targetSec}`,
|
|
10091
|
-
"-t",
|
|
10092
|
-
targetSec,
|
|
10093
|
-
"-c:a",
|
|
10094
|
-
"aac",
|
|
10095
|
-
"-b:a",
|
|
10096
|
-
"192k",
|
|
10097
|
-
"-y",
|
|
10098
|
-
outputPath
|
|
10099
|
-
]
|
|
10100
|
-
}
|
|
10101
|
-
],
|
|
10120
|
+
steps: [{ kind: "normalize", filter: `apad,atrim=0:${targetSec}` }],
|
|
10102
10121
|
cleanupPaths: []
|
|
10103
10122
|
};
|
|
10104
10123
|
}
|
|
10105
10124
|
return {
|
|
10106
10125
|
operation: "trim",
|
|
10107
|
-
steps: [
|
|
10108
|
-
{
|
|
10109
|
-
kind: "trim",
|
|
10110
|
-
args: [
|
|
10111
|
-
"-i",
|
|
10112
|
-
audioPath,
|
|
10113
|
-
"-af",
|
|
10114
|
-
`atrim=duration=${targetSec},asetpts=PTS-STARTPTS`,
|
|
10115
|
-
// `atrim` limits decoded samples but does not cap muxer timestamps
|
|
10116
|
-
// introduced by encoder delay/flush. The output duration contract
|
|
10117
|
-
// is enforced at the container boundary as well; without `-t`, a
|
|
10118
|
-
// long primed source can retain its original tail after re-encode.
|
|
10119
|
-
"-t",
|
|
10120
|
-
targetSec,
|
|
10121
|
-
"-c:a",
|
|
10122
|
-
"aac",
|
|
10123
|
-
"-b:a",
|
|
10124
|
-
"192k",
|
|
10125
|
-
"-y",
|
|
10126
|
-
outputPath
|
|
10127
|
-
]
|
|
10128
|
-
}
|
|
10129
|
-
],
|
|
10126
|
+
steps: [{ kind: "trim", filter: `atrim=duration=${targetSec},asetpts=PTS-STARTPTS` }],
|
|
10130
10127
|
cleanupPaths: []
|
|
10131
10128
|
};
|
|
10132
10129
|
}
|
|
@@ -10143,7 +10140,8 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
10143
10140
|
const probeAudio = input.probeAudioInfo ?? defaultProbeAudioInfo;
|
|
10144
10141
|
const timeoutMs = input.timeoutMs ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
|
|
10145
10142
|
const runner = input.runFfmpeg ?? ((args) => defaultRunFfmpeg(args, timeoutMs, input.signal));
|
|
10146
|
-
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 }));
|
|
10147
10145
|
const [videoResult, audioResult] = await Promise.allSettled([
|
|
10148
10146
|
probeVideo(input.videoPath),
|
|
10149
10147
|
probeAudio(input.audioPath, input.signal)
|
|
@@ -10190,7 +10188,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
10190
10188
|
);
|
|
10191
10189
|
try {
|
|
10192
10190
|
for (const step of plan2.steps) {
|
|
10193
|
-
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);
|
|
10194
10192
|
if (!ffmpegResult.success) {
|
|
10195
10193
|
return {
|
|
10196
10194
|
success: false,
|
|
@@ -10222,7 +10220,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
10222
10220
|
targetDurationSeconds,
|
|
10223
10221
|
signal: input.signal,
|
|
10224
10222
|
probeTruePeak,
|
|
10225
|
-
|
|
10223
|
+
encode
|
|
10226
10224
|
});
|
|
10227
10225
|
if (!correction.success) {
|
|
10228
10226
|
return {
|
|
@@ -10252,12 +10250,8 @@ async function constrainAacTruePeak(input) {
|
|
|
10252
10250
|
audioPath: input.audioPath,
|
|
10253
10251
|
targetDurationSeconds: input.targetDurationSeconds,
|
|
10254
10252
|
signal: input.signal,
|
|
10255
|
-
probeTruePeak:
|
|
10256
|
-
|
|
10257
|
-
const segments = { durationSeconds: input.targetDurationSeconds, sampleRate };
|
|
10258
|
-
return measureTruePeakDbfs(audioPath, { timeoutMs, signal, segments });
|
|
10259
|
-
},
|
|
10260
|
-
runner: (args) => defaultRunFfmpeg(args, timeoutMs, input.signal)
|
|
10253
|
+
probeTruePeak: (audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal }),
|
|
10254
|
+
encode: defaultAacEncoder(timeoutMs, input.signal, input.sourcePath)
|
|
10261
10255
|
});
|
|
10262
10256
|
}
|
|
10263
10257
|
async function enforceAacTruePeak(input) {
|
|
@@ -10284,13 +10278,11 @@ async function enforceAacTruePeak(input) {
|
|
|
10284
10278
|
}
|
|
10285
10279
|
if (pass === MAX_TRUE_PEAK_CORRECTION_PASSES) break;
|
|
10286
10280
|
attenuationDb += correctionTargetDbfs - truePeakDbfs;
|
|
10287
|
-
const result = await input.
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
attenuationDb
|
|
10293
|
-
)
|
|
10281
|
+
const result = await input.encode(
|
|
10282
|
+
input.audioPath,
|
|
10283
|
+
correctedPath,
|
|
10284
|
+
input.targetDurationSeconds,
|
|
10285
|
+
aacTruePeakCorrectionFilter(input.targetDurationSeconds, attenuationDb)
|
|
10294
10286
|
);
|
|
10295
10287
|
if (!result.success) {
|
|
10296
10288
|
return {
|
|
@@ -10394,7 +10386,18 @@ async function defaultProbeAudioInfo(audioPath, signal) {
|
|
|
10394
10386
|
};
|
|
10395
10387
|
}
|
|
10396
10388
|
async function defaultRunFfmpeg(args, timeoutMs, signal) {
|
|
10397
|
-
|
|
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) {
|
|
10398
10401
|
if (result.success) return { success: true };
|
|
10399
10402
|
return {
|
|
10400
10403
|
success: false,
|
|
@@ -10582,7 +10585,7 @@ function assertOutputScaleSupported(deviceScaleFactor, route) {
|
|
|
10582
10585
|
const reason = UNSUPPORTED_REASON2[route];
|
|
10583
10586
|
if (reason === null) return;
|
|
10584
10587
|
throw new Error(
|
|
10585
|
-
`[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.`
|
|
10586
10589
|
);
|
|
10587
10590
|
}
|
|
10588
10591
|
|
|
@@ -10800,7 +10803,7 @@ function getNextRetryWorkerCount(currentWorkers) {
|
|
|
10800
10803
|
return Math.max(1, Math.floor(currentWorkers / 2));
|
|
10801
10804
|
}
|
|
10802
10805
|
function resolveRenderWorkDirPrefix(outputPath, jobId, platform2 = process.platform, systemTempDir = tmpdir2()) {
|
|
10803
|
-
if (platform2 === "win32") return join25(systemTempDir, "hf-render-");
|
|
10806
|
+
if (platform2 === "win32" || platform2 === "darwin") return join25(systemTempDir, "hf-render-");
|
|
10804
10807
|
return join25(dirname9(outputPath), `work-${jobId}-`);
|
|
10805
10808
|
}
|
|
10806
10809
|
var MAX_TRANSIENT_CAPTURE_RETRIES = 1;
|
|
@@ -11294,6 +11297,9 @@ function resolveDeShortBand(args) {
|
|
|
11294
11297
|
function shouldPreferSingleWorkerDrawElement(args) {
|
|
11295
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;
|
|
11296
11299
|
}
|
|
11300
|
+
function isProbeDeGated(session) {
|
|
11301
|
+
return session !== null && session.captureMode !== "drawelement" && !session.deInitDeferred;
|
|
11302
|
+
}
|
|
11297
11303
|
function resolveInversionRetryPlan(args) {
|
|
11298
11304
|
if (args.deWorkerInversion !== "inverted") return null;
|
|
11299
11305
|
const workerCount = args.isMemoryExhaustion ? 1 : args.preInversionWorkerCount;
|
|
@@ -11375,7 +11381,8 @@ async function closeOrphanedProbeForRetry(probe, closer, log, retryContext) {
|
|
|
11375
11381
|
}
|
|
11376
11382
|
function resolveParallelCaptureMode(args) {
|
|
11377
11383
|
const supersampling = (args.deviceScaleFactor ?? 1) !== 1;
|
|
11378
|
-
|
|
11384
|
+
const headlessShell = args.headlessShellPath !== void 0;
|
|
11385
|
+
return headlessShell && args.platform === "linux" && !args.forceScreenshot && !supersampling ? "beginframe" : "screenshot";
|
|
11379
11386
|
}
|
|
11380
11387
|
function isCaptureParallelStreamRouterEnabled(env, resolvedMode) {
|
|
11381
11388
|
const raw = env.HF_CAPTURE_PARALLEL_STREAM?.trim().toLowerCase();
|
|
@@ -11983,6 +11990,7 @@ async function executeRenderPipeline(input) {
|
|
|
11983
11990
|
);
|
|
11984
11991
|
const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
|
|
11985
11992
|
const hasHdrContent = Boolean(effectiveHdr && nativeHdrIds.size > 0);
|
|
11993
|
+
if (hasHdrContent) assertOutputScaleSupported(deviceScaleFactor, "hdr_layered");
|
|
11986
11994
|
const deSingleMinFramesRaw = process.env.HF_DE_SINGLE_MIN_FRAMES;
|
|
11987
11995
|
const deSingleMinFramesNum = deSingleMinFramesRaw === void 0 || deSingleMinFramesRaw.trim() === "" ? 900 : Number(deSingleMinFramesRaw);
|
|
11988
11996
|
const deSingleMinFrames = Number.isFinite(deSingleMinFramesNum) ? deSingleMinFramesNum : 900;
|
|
@@ -12023,7 +12031,7 @@ async function executeRenderPipeline(input) {
|
|
|
12023
12031
|
singleWorkerStreamingOk: shouldUseStreamingEncode(cfg, outputFormat, 1, job.duration),
|
|
12024
12032
|
layeredOrEffectRoute: hasHdrContent || compiled.hasShaderTransitions,
|
|
12025
12033
|
supersampling: deviceScaleFactor !== 1,
|
|
12026
|
-
probeDeGated: probeSession
|
|
12034
|
+
probeDeGated: isProbeDeGated(probeSession),
|
|
12027
12035
|
experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || // Verified parallel DE streaming (opt-in) wants its parallelism kept.
|
|
12028
12036
|
process.env.HF_DE_PARALLEL_STREAM === "true"
|
|
12029
12037
|
};
|
|
@@ -12032,14 +12040,14 @@ async function executeRenderPipeline(input) {
|
|
|
12032
12040
|
...deInversionArgs,
|
|
12033
12041
|
minFrames: Math.min(deSingleMinFrames, deShortBandMinFrames)
|
|
12034
12042
|
});
|
|
12035
|
-
|
|
12043
|
+
let deShortBand = resolveDeShortBand({
|
|
12036
12044
|
invertAtBaseFloor,
|
|
12037
12045
|
invertAtBandFloor,
|
|
12038
12046
|
bandEnabled: deShortBandEnabled,
|
|
12039
12047
|
bandOpen: deShortBandOpen,
|
|
12040
12048
|
elementCountSource: compositionElementCountSource
|
|
12041
12049
|
});
|
|
12042
|
-
|
|
12050
|
+
let deInversionEligible = deShortBandRoute && deShortBand === "applied" ? invertAtBandFloor : invertAtBaseFloor;
|
|
12043
12051
|
const deInversionEffectiveMinFrames = deShortBandRoute && deShortBand === "applied" ? Math.min(deSingleMinFrames, deShortBandMinFrames) : deSingleMinFrames;
|
|
12044
12052
|
const deParallelRouterEnabled = isDeParallelRouterEnabled(process.env);
|
|
12045
12053
|
const deParallelMinFramesRaw = process.env.HF_DE_PARALLEL_MIN_FRAMES;
|
|
@@ -12048,7 +12056,7 @@ async function executeRenderPipeline(input) {
|
|
|
12048
12056
|
const deParallelMinMemRaw = process.env.HF_DE_PARALLEL_MIN_MEM_MB;
|
|
12049
12057
|
const deParallelMinMemNum = deParallelMinMemRaw === void 0 || deParallelMinMemRaw.trim() === "" ? 24576 : Number(deParallelMinMemRaw);
|
|
12050
12058
|
const deParallelMinMemoryMb = Number.isFinite(deParallelMinMemNum) ? deParallelMinMemNum : 24576;
|
|
12051
|
-
|
|
12059
|
+
let deParallelRouterEligible = shouldPreferParallelDrawElement({
|
|
12052
12060
|
workerCount: WOULD_RESOLVE_MULTI_WORKER,
|
|
12053
12061
|
requestedWorkers: job.config.workers,
|
|
12054
12062
|
useDrawElement: cfg.useDrawElement,
|
|
@@ -12059,7 +12067,7 @@ async function executeRenderPipeline(input) {
|
|
|
12059
12067
|
minFrames: deParallelMinFrames,
|
|
12060
12068
|
layeredOrEffectRoute: hasHdrContent || compiled.hasShaderTransitions,
|
|
12061
12069
|
supersampling: deviceScaleFactor !== 1,
|
|
12062
|
-
probeDeGated: probeSession
|
|
12070
|
+
probeDeGated: isProbeDeGated(probeSession),
|
|
12063
12071
|
experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || process.env.HF_DE_PARALLEL_STREAM === "true",
|
|
12064
12072
|
routerEnabled: deParallelRouterEnabled,
|
|
12065
12073
|
// Router pins 3 workers for the streaming path; don't pin when a
|
|
@@ -12075,6 +12083,35 @@ async function executeRenderPipeline(input) {
|
|
|
12075
12083
|
totalMemoryMb: Math.round(totalmem2() / (1024 * 1024)),
|
|
12076
12084
|
minMemoryMb: deParallelMinMemoryMb
|
|
12077
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;
|
|
12078
12115
|
let workerCount;
|
|
12079
12116
|
const captureStageObservationData = (extra = {}) => ({
|
|
12080
12117
|
stagePhase: "capturing",
|
|
@@ -12262,7 +12299,7 @@ async function executeRenderPipeline(input) {
|
|
|
12262
12299
|
}
|
|
12263
12300
|
const parallelCaptureMode = resolveParallelCaptureMode({
|
|
12264
12301
|
platform: process.platform,
|
|
12265
|
-
|
|
12302
|
+
headlessShellPath: resolveHeadlessShellPath(cfg),
|
|
12266
12303
|
forceScreenshot: captureForceScreenshot,
|
|
12267
12304
|
deviceScaleFactor: captureOptions.deviceScaleFactor
|
|
12268
12305
|
});
|
|
@@ -13034,7 +13071,9 @@ async function executeRenderPipeline(input) {
|
|
|
13034
13071
|
outputFormat,
|
|
13035
13072
|
durationSeconds: job.duration,
|
|
13036
13073
|
fps: fpsToNumber(job.config.fps),
|
|
13037
|
-
expectedFrames: captureTotalFrames
|
|
13074
|
+
expectedFrames: captureTotalFrames,
|
|
13075
|
+
width: outputWidth,
|
|
13076
|
+
height: outputHeight
|
|
13038
13077
|
})
|
|
13039
13078
|
);
|
|
13040
13079
|
const totalElapsed = Date.now() - pipelineStart;
|
|
@@ -13070,6 +13109,7 @@ async function executeRenderPipeline(input) {
|
|
|
13070
13109
|
drawElement: {
|
|
13071
13110
|
compileGate: deCompileGate,
|
|
13072
13111
|
clampReason: deClampReason,
|
|
13112
|
+
probeGateReason: deProbeGateReason,
|
|
13073
13113
|
workerInversion: deWorkerInversion,
|
|
13074
13114
|
preInversionWorkers: deWorkerInversion ? preRoutingWorkerCount : void 0,
|
|
13075
13115
|
compositionElementCount,
|
|
@@ -13622,6 +13662,29 @@ function buildChunkCaptureOptions(input) {
|
|
|
13622
13662
|
requiresWebGpu: compositionRequiresWebGpu(input.html)
|
|
13623
13663
|
};
|
|
13624
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
|
+
}
|
|
13625
13688
|
async function extractDeferredVideoFramesForChunk(input) {
|
|
13626
13689
|
const deferred = input.planVideos.extracted.filter((video) => video.deferredRange);
|
|
13627
13690
|
const remoteSources = input.remoteSources ?? {};
|
|
@@ -13638,24 +13701,7 @@ async function extractDeferredVideoFramesForChunk(input) {
|
|
|
13638
13701
|
});
|
|
13639
13702
|
}
|
|
13640
13703
|
if (deferred.length === 0) return [];
|
|
13641
|
-
const
|
|
13642
|
-
input.planVideos.videos,
|
|
13643
|
-
deferred.map((video) => ({
|
|
13644
|
-
...video,
|
|
13645
|
-
outputDir: input.outputRoot,
|
|
13646
|
-
framePaths: new Map(Array.from({ length: video.totalFrames }, (_, i) => [i, String(i)]))
|
|
13647
|
-
})),
|
|
13648
|
-
resolveRenderFpsConfig(input.fps).value
|
|
13649
|
-
);
|
|
13650
|
-
const shown = /* @__PURE__ */ new Map();
|
|
13651
|
-
for (const frame of input.frames) {
|
|
13652
|
-
const globalTime = frame * input.fps.den / input.fps.num;
|
|
13653
|
-
for (const [videoId, payload] of table.getActiveFramePayloads(globalTime)) {
|
|
13654
|
-
const indexes = shown.get(videoId) ?? /* @__PURE__ */ new Set();
|
|
13655
|
-
indexes.add(payload.frameIndex);
|
|
13656
|
-
shown.set(videoId, indexes);
|
|
13657
|
-
}
|
|
13658
|
-
}
|
|
13704
|
+
const shown = shownDeferredFrameIndexes(input.planVideos, input.frames, input.fps);
|
|
13659
13705
|
return Promise.all(
|
|
13660
13706
|
deferred.map(async (video) => {
|
|
13661
13707
|
const outputDir = join27(input.outputRoot, video.videoId);
|
|
@@ -13681,7 +13727,8 @@ async function extractDeferredVideoFramesForChunk(input) {
|
|
|
13681
13727
|
fps: input.fps,
|
|
13682
13728
|
outputDir: input.outputRoot,
|
|
13683
13729
|
format: range.format,
|
|
13684
|
-
frameRanges: contiguousRuns(indexes)
|
|
13730
|
+
frameRanges: contiguousRuns(indexes),
|
|
13731
|
+
shownBox: input.shownBoxes?.get(video.videoId)
|
|
13685
13732
|
},
|
|
13686
13733
|
void 0,
|
|
13687
13734
|
input.cfg
|
|
@@ -14333,6 +14380,20 @@ function withDuration(buf, target, duration) {
|
|
|
14333
14380
|
function timescaleOf(buf, header) {
|
|
14334
14381
|
return buf.readUInt32BE(header.bodyStart + (buf[header.bodyStart] === 1 ? 20 : 12));
|
|
14335
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
|
+
}
|
|
14336
14397
|
function buildStbl(stsd, track) {
|
|
14337
14398
|
const stts = runs(track.durations);
|
|
14338
14399
|
const stsc = [];
|
|
@@ -14374,24 +14435,48 @@ function planTracksOf(tracks, plan2, index) {
|
|
|
14374
14435
|
}
|
|
14375
14436
|
return matched;
|
|
14376
14437
|
}
|
|
14377
|
-
function
|
|
14378
|
-
const
|
|
14379
|
-
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;
|
|
14380
14461
|
const payloadBases = [];
|
|
14381
14462
|
let payloadBytes = 0;
|
|
14382
|
-
for (const layout of
|
|
14463
|
+
for (const layout of sourceLayouts) {
|
|
14383
14464
|
payloadBases.push(payloadBytes);
|
|
14384
14465
|
payloadBytes += layout.payloadEnd - layout.payloadStart;
|
|
14385
14466
|
}
|
|
14386
14467
|
const template = layouts[0].moov;
|
|
14387
14468
|
const root = boxAt(template, 0, 0, template.length);
|
|
14388
|
-
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;
|
|
14389
14473
|
const buildMoov = (dataStart2) => {
|
|
14390
14474
|
const traks = plan2.map((track, t) => {
|
|
14391
|
-
const parts =
|
|
14475
|
+
const parts = sources.flatMap((tracks, chunk) => {
|
|
14392
14476
|
const part = tracks[t];
|
|
14393
14477
|
return part ? [{ ...part, chunk }] : [];
|
|
14394
14478
|
});
|
|
14479
|
+
const moov = t < chunkTrackCount ? template : audio.moov;
|
|
14395
14480
|
const merged = {
|
|
14396
14481
|
durations: parts.flatMap((part) => part.durations),
|
|
14397
14482
|
sizes: parts.flatMap((part) => part.sizes),
|
|
@@ -14400,9 +14485,9 @@ function buildStitchedHeader(layouts) {
|
|
|
14400
14485
|
chunkOffsets: parts.flatMap(
|
|
14401
14486
|
(part) => part.chunkOffsets.map((offset) => {
|
|
14402
14487
|
const i = part.chunk;
|
|
14403
|
-
const { payloadStart, payloadEnd } =
|
|
14488
|
+
const { payloadStart, payloadEnd } = sourceLayouts[i];
|
|
14404
14489
|
if (offset < payloadStart || offset >= payloadEnd) {
|
|
14405
|
-
throw new Error(`[mp4Stitch]
|
|
14490
|
+
throw new Error(`[mp4Stitch] source ${i} has samples outside its mdat`);
|
|
14406
14491
|
}
|
|
14407
14492
|
return offset - payloadStart + payloadBases[i] + dataStart2;
|
|
14408
14493
|
})
|
|
@@ -14418,20 +14503,25 @@ function buildStitchedHeader(layouts) {
|
|
|
14418
14503
|
elst.writeBigInt64BE(BigInt(track.mediaTime), 12);
|
|
14419
14504
|
elst.writeUInt32BE(65536, 20);
|
|
14420
14505
|
const edts = track.mediaTime ? box("edts", fullBox("elst", 1, elst)) : Buffer.alloc(0);
|
|
14421
|
-
const
|
|
14422
|
-
|
|
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]),
|
|
14423
14512
|
edts: () => Buffer.alloc(0),
|
|
14424
|
-
mdia: (mdia) => rebuild(
|
|
14425
|
-
mdhd: (mdhd) => withDuration(
|
|
14426
|
-
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) })
|
|
14427
14516
|
})
|
|
14428
14517
|
});
|
|
14429
14518
|
return { trak, shown };
|
|
14430
14519
|
});
|
|
14431
14520
|
let next = 0;
|
|
14521
|
+
const movieHeader = withDuration(template, mvhd, Math.max(...traks.map((t) => t.shown)));
|
|
14432
14522
|
return rebuild(template, root, {
|
|
14433
|
-
mvhd: (
|
|
14434
|
-
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))
|
|
14435
14525
|
});
|
|
14436
14526
|
};
|
|
14437
14527
|
const ftyp = layouts[0].ftyp;
|
|
@@ -14464,15 +14554,16 @@ async function copyPayload(path, layout, index, out) {
|
|
|
14464
14554
|
);
|
|
14465
14555
|
}
|
|
14466
14556
|
}
|
|
14467
|
-
async function writeStitchedMp4(chunkPaths, outputPath) {
|
|
14468
|
-
const
|
|
14469
|
-
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);
|
|
14470
14561
|
mkdirSync10(dirname11(outputPath), { recursive: true });
|
|
14471
14562
|
const workDir = mkdtempSync4(`${outputPath}.stitch-`);
|
|
14472
14563
|
const out = createWriteStream(join30(workDir, "out.mp4"));
|
|
14473
14564
|
try {
|
|
14474
14565
|
out.write(header);
|
|
14475
|
-
for (const [i, path] of
|
|
14566
|
+
for (const [i, path] of sourcePaths.entries()) await copyPayload(path, layouts[i], i, out);
|
|
14476
14567
|
out.end();
|
|
14477
14568
|
await finished(out);
|
|
14478
14569
|
renameSync4(join30(workDir, "out.mp4"), outputPath);
|
|
@@ -15043,7 +15134,8 @@ function buildLockedRenderConfig(input) {
|
|
|
15043
15134
|
chunkCount: input.chunkCount,
|
|
15044
15135
|
runtimeEnv: input.runtimeEnv,
|
|
15045
15136
|
variables: config.variables,
|
|
15046
|
-
...input.chunksCarryAudio ? { chunksCarryAudio: true } : {}
|
|
15137
|
+
...input.chunksCarryAudio ? { chunksCarryAudio: true } : {},
|
|
15138
|
+
...input.separateAudio ? { separateAudio: true } : {}
|
|
15047
15139
|
};
|
|
15048
15140
|
}
|
|
15049
15141
|
function carriesChunkAudio(config, options) {
|
|
@@ -15138,8 +15230,10 @@ function createVideoSourceShipper(input) {
|
|
|
15138
15230
|
return result;
|
|
15139
15231
|
};
|
|
15140
15232
|
}
|
|
15141
|
-
|
|
15142
|
-
|
|
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) {
|
|
15143
15237
|
rejectUnsupportedDistributedFormat(config);
|
|
15144
15238
|
validateNoGpuEncode({
|
|
15145
15239
|
useGpu: false,
|
|
@@ -15267,7 +15361,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15267
15361
|
if (probeResult.fileServer) closeFileServerSafely(probeResult.fileServer, "plan", log);
|
|
15268
15362
|
if (probeResult.probeSession) {
|
|
15269
15363
|
try {
|
|
15270
|
-
const { closeCaptureSession: closeCaptureSession2 } = await import("./src-
|
|
15364
|
+
const { closeCaptureSession: closeCaptureSession2 } = await import("./src-EL6HGIS4.js");
|
|
15271
15365
|
await closeCaptureSession2(probeResult.probeSession);
|
|
15272
15366
|
} catch (err) {
|
|
15273
15367
|
log.warn("[plan] probe session close failed", {
|
|
@@ -15275,6 +15369,100 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15275
15369
|
});
|
|
15276
15370
|
}
|
|
15277
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;
|
|
15278
15466
|
const megapixels = compileResult.outputWidth * compileResult.outputHeight / 1e6;
|
|
15279
15467
|
let maxParallel = resolveMaxParallelChunks(config, totalFrames, megapixels, log);
|
|
15280
15468
|
const measureFrameCost = chunkSizingUsesFrameCost(config) && planNeedsFrameCostMeasurement(compiled.html);
|
|
@@ -15285,24 +15473,9 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15285
15473
|
observedAt: "pre-extract",
|
|
15286
15474
|
log
|
|
15287
15475
|
});
|
|
15288
|
-
stageStarted = Date.now();
|
|
15289
|
-
const extractResult = await
|
|
15290
|
-
projectDir,
|
|
15291
|
-
compiledDir,
|
|
15292
|
-
job,
|
|
15293
|
-
cfg,
|
|
15294
|
-
composition,
|
|
15295
|
-
abortSignal,
|
|
15296
|
-
assertNotAborted,
|
|
15297
|
-
materializeSymlinks: true,
|
|
15298
|
-
deferRangeExtraction: options.deferVideoExtraction,
|
|
15299
|
-
urlByAbsentLocalPath
|
|
15300
|
-
});
|
|
15476
|
+
let stageStarted = Date.now();
|
|
15477
|
+
const extractResult = await extractPlanVideos(c, options.deferVideoExtraction);
|
|
15301
15478
|
logPlanStage(log, "extract", stageStarted);
|
|
15302
|
-
if (extractResult.failureToEnforce) throw extractResult.failureToEnforce;
|
|
15303
|
-
if (extractResult.extractionResult) {
|
|
15304
|
-
assertVideoExtractionSucceeded(extractResult.extractionResult);
|
|
15305
|
-
}
|
|
15306
15479
|
const stagedVideoFrames = join33(compiledDir, "__hyperframes_video_frames");
|
|
15307
15480
|
const videoFramesDst = join33(planDir, "video-frames");
|
|
15308
15481
|
if (existsSync20(videoFramesDst)) rmSync10(videoFramesDst, { recursive: true, force: true });
|
|
@@ -15358,23 +15531,18 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15358
15531
|
"utf-8"
|
|
15359
15532
|
);
|
|
15360
15533
|
const digests = options.digests ?? /* @__PURE__ */ new Map();
|
|
15361
|
-
const
|
|
15362
|
-
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");
|
|
15363
15538
|
stageStarted = Date.now();
|
|
15364
15539
|
const [audioOutcome, overlapOutcome, frameCostOutcome] = await Promise.allSettled([
|
|
15365
|
-
|
|
15366
|
-
|
|
15367
|
-
|
|
15368
|
-
|
|
15369
|
-
|
|
15370
|
-
|
|
15371
|
-
ffmpegProcessTimeout: cfg.ffmpegProcessTimeout,
|
|
15372
|
-
audioGain: cfg.audioGain,
|
|
15373
|
-
audios: composition.audios,
|
|
15374
|
-
masterFxChain: composition.masterFxChain,
|
|
15375
|
-
abortSignal,
|
|
15376
|
-
assertNotAborted
|
|
15377
|
-
}).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)),
|
|
15378
15546
|
(async () => {
|
|
15379
15547
|
for (const dir of [finalCompiledDir, videoFramesDst, videoSourcesDir]) {
|
|
15380
15548
|
await prehashPlanFiles(dir, digests);
|
|
@@ -15424,22 +15592,16 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15424
15592
|
);
|
|
15425
15593
|
const chunks = buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize);
|
|
15426
15594
|
const audioResult = audioOutcome.value;
|
|
15427
|
-
if (audioResult
|
|
15595
|
+
if (audioResult?.audioError) {
|
|
15428
15596
|
applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
|
|
15429
15597
|
}
|
|
15430
15598
|
const planAudioPath = join33(planDir, PLAN_AUDIO_RELATIVE_PATH);
|
|
15431
|
-
if (audioResult
|
|
15599
|
+
if (audioResult?.hasAudio && existsSync20(audioResult.audioOutputPath)) {
|
|
15432
15600
|
renameSync5(audioResult.audioOutputPath, planAudioPath);
|
|
15433
15601
|
}
|
|
15434
|
-
if (
|
|
15602
|
+
if (chunksCarryAudio && existsSync20(planAudioPath)) {
|
|
15435
15603
|
stageStarted = Date.now();
|
|
15436
|
-
|
|
15437
|
-
audioPath: planAudioPath,
|
|
15438
|
-
targetDurationSeconds: audioSeconds,
|
|
15439
|
-
signal: abortSignal,
|
|
15440
|
-
timeoutMs: cfg.ffmpegProcessTimeout
|
|
15441
|
-
});
|
|
15442
|
-
if (!peak.success) throw encoderFailureError("[plan] audio true-peak check failed", peak);
|
|
15604
|
+
await holdPlanAudioPeak(c, planAudioPath, planMixPcmPath, audioSeconds);
|
|
15443
15605
|
logPlanStage(log, "audio-peak", stageStarted);
|
|
15444
15606
|
if (options.sliceChunkAudio) {
|
|
15445
15607
|
stageStarted = Date.now();
|
|
@@ -15465,7 +15627,8 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15465
15627
|
effectiveChunkSize,
|
|
15466
15628
|
chunkCount,
|
|
15467
15629
|
runtimeEnv,
|
|
15468
|
-
chunksCarryAudio
|
|
15630
|
+
chunksCarryAudio,
|
|
15631
|
+
separateAudio
|
|
15469
15632
|
});
|
|
15470
15633
|
const compositionJson = {
|
|
15471
15634
|
durationSeconds: job.duration ?? 0,
|
|
@@ -15510,7 +15673,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15510
15673
|
fontSnapshotSha,
|
|
15511
15674
|
durationSeconds: job.duration ?? 0,
|
|
15512
15675
|
totalFrames,
|
|
15513
|
-
hasAudio: audioResult
|
|
15676
|
+
hasAudio: audioResult?.hasAudio ?? false,
|
|
15514
15677
|
digests
|
|
15515
15678
|
});
|
|
15516
15679
|
logPlanStage(log, "freeze", stageStarted);
|
|
@@ -16861,7 +17024,7 @@ function startServer(options = {}) {
|
|
|
16861
17024
|
});
|
|
16862
17025
|
async function shutdown(signal) {
|
|
16863
17026
|
log.info(`Received ${signal}, shutting down`);
|
|
16864
|
-
const { drainBrowserPool } = await import("./src-
|
|
17027
|
+
const { drainBrowserPool } = await import("./src-EL6HGIS4.js");
|
|
16865
17028
|
await drainBrowserPool().catch(() => {
|
|
16866
17029
|
});
|
|
16867
17030
|
const handle = await Promise.race([
|
|
@@ -17485,7 +17648,8 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
|
|
|
17485
17648
|
)
|
|
17486
17649
|
),
|
|
17487
17650
|
chunksCarryAudio: options.chunksCarryAudio,
|
|
17488
|
-
sliceChunkAudio: true
|
|
17651
|
+
sliceChunkAudio: true,
|
|
17652
|
+
deferAudio: options.deferAudio
|
|
17489
17653
|
});
|
|
17490
17654
|
return await publishExecutionPlan(stagingRoot, publisher, { digests, log: config.logger });
|
|
17491
17655
|
} catch (error) {
|
|
@@ -17811,7 +17975,8 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
17811
17975
|
return mergePngFrameDirs(chunkPaths, outputPath, plan2.totalFrames, audioPath, start);
|
|
17812
17976
|
}
|
|
17813
17977
|
if (chunksAreStitchedMp4(planDir, cfr)) {
|
|
17814
|
-
|
|
17978
|
+
const separateAudio = stitchesSeparateAudio(planDir) && audioPath !== null;
|
|
17979
|
+
await writeStitchedMp4(chunkPaths, outputPath, separateAudio ? audioPath : void 0);
|
|
17815
17980
|
return {
|
|
17816
17981
|
outputPath,
|
|
17817
17982
|
durationMs: Date.now() - start,
|
|
@@ -18009,16 +18174,20 @@ async function runAssembleFfmpeg(args, step, signal, timeout) {
|
|
|
18009
18174
|
}
|
|
18010
18175
|
}
|
|
18011
18176
|
function chunksAreStitchedMp4(planDir, cfr) {
|
|
18012
|
-
|
|
18177
|
+
const { chunksCarryAudio, separateAudio } = lockedAudio(planDir);
|
|
18178
|
+
if (!chunksCarryAudio && !separateAudio) return false;
|
|
18013
18179
|
if (cfr) {
|
|
18014
|
-
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");
|
|
18015
18181
|
}
|
|
18016
18182
|
return true;
|
|
18017
18183
|
}
|
|
18018
|
-
function
|
|
18184
|
+
function stitchesSeparateAudio(planDir) {
|
|
18185
|
+
return lockedAudio(planDir).separateAudio === true;
|
|
18186
|
+
}
|
|
18187
|
+
function lockedAudio(planDir) {
|
|
18019
18188
|
const encoderJsonPath = join40(planDir, "meta", "encoder.json");
|
|
18020
|
-
if (!existsSync26(encoderJsonPath)) return
|
|
18021
|
-
return JSON.parse(readFileSync13(encoderJsonPath, "utf-8"))
|
|
18189
|
+
if (!existsSync26(encoderJsonPath)) return {};
|
|
18190
|
+
return JSON.parse(readFileSync13(encoderJsonPath, "utf-8"));
|
|
18022
18191
|
}
|
|
18023
18192
|
function readCfrEncoder(planDir, format) {
|
|
18024
18193
|
if (format !== "mp4") {
|
|
@@ -18302,34 +18471,15 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18302
18471
|
const framesDir = join41(workDir, "captured-frames");
|
|
18303
18472
|
mkdirSync17(framesDir, { recursive: true });
|
|
18304
18473
|
const videoFramesDir = `${workDir}.video-frames`;
|
|
18305
|
-
const
|
|
18306
|
-
|
|
18307
|
-
|
|
18308
|
-
|
|
18309
|
-
fps: { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen },
|
|
18310
|
-
outputRoot: videoFramesDir,
|
|
18311
|
-
cfg,
|
|
18312
|
-
remoteSources
|
|
18313
|
-
}) : [];
|
|
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();
|
|
18314
18478
|
const remoteVideoIds = new Set(
|
|
18315
18479
|
planVideos?.extracted.filter(
|
|
18316
18480
|
(video) => video.deferredRange && Object.hasOwn(remoteSources, video.deferredRange.sourcePath)
|
|
18317
18481
|
).map((video) => video.videoId)
|
|
18318
18482
|
);
|
|
18319
|
-
const remoteVideos = deferredVideoFrames.filter((video) => remoteVideoIds.has(video.videoId));
|
|
18320
|
-
const videoFrameLookup = planVideos && planVideos.extracted.length > 0 ? createFrameLookupTable(
|
|
18321
|
-
planVideos.videos,
|
|
18322
|
-
[
|
|
18323
|
-
...rebuildExtractedFramesFromPlanDir(
|
|
18324
|
-
planDir,
|
|
18325
|
-
planVideos.extracted.filter((video) => !video.deferredRange),
|
|
18326
|
-
v2Manifest === null ? "dense-v1" : "sparse-v2"
|
|
18327
|
-
),
|
|
18328
|
-
...deferredVideoFrames
|
|
18329
|
-
],
|
|
18330
|
-
resolveRenderFpsConfig(job.config.fps).value
|
|
18331
|
-
) : null;
|
|
18332
|
-
const createChunkVideoFrameInjector = createChunkVideoFrameInjectorFactory(videoFrameLookup);
|
|
18333
18483
|
const fileServer = await createFileServer({
|
|
18334
18484
|
projectDir: compiledDir,
|
|
18335
18485
|
compiledDir,
|
|
@@ -18345,8 +18495,12 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18345
18495
|
videoCount: planVideos?.videos.length ?? 0,
|
|
18346
18496
|
html: readFileSync14(join41(compiledDir, "index.html"), "utf-8"),
|
|
18347
18497
|
// The plan ships a deferred source only to chunks that show it; don't wait on the rest.
|
|
18348
|
-
skipReadinessVideoIds:
|
|
18349
|
-
|
|
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
|
+
)
|
|
18350
18504
|
});
|
|
18351
18505
|
const chunkWorkerCount = calculateOptimalWorkers(framesInChunk, void 0, cfg);
|
|
18352
18506
|
let session = null;
|
|
@@ -18359,6 +18513,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18359
18513
|
const capturePerfs = [];
|
|
18360
18514
|
const captureAttempts = [];
|
|
18361
18515
|
let forceScreenshotForChunk = encoder.forceScreenshot;
|
|
18516
|
+
let shownBoxes;
|
|
18362
18517
|
try {
|
|
18363
18518
|
if (chunkWorkerCount === 1 || !forceScreenshotForChunk) {
|
|
18364
18519
|
const bootStarted = Date.now();
|
|
@@ -18369,6 +18524,11 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18369
18524
|
cfg
|
|
18370
18525
|
);
|
|
18371
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
|
+
);
|
|
18372
18532
|
const browserSelectedScreenshot = session.launchCaptureMode === "screenshot";
|
|
18373
18533
|
const beginFrameStalled = !browserSelectedScreenshot && await beginFrameSessionNeedsScreenshotFallback(session);
|
|
18374
18534
|
if (browserSelectedScreenshot) {
|
|
@@ -18410,6 +18570,29 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18410
18570
|
session = null;
|
|
18411
18571
|
}
|
|
18412
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);
|
|
18413
18596
|
const captureStarted = Date.now();
|
|
18414
18597
|
captureMode = await runCaptureWithScreenshotFallback({
|
|
18415
18598
|
forceScreenshot: forceScreenshotForChunk,
|
|
@@ -18600,6 +18783,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18600
18783
|
encodeStageMs,
|
|
18601
18784
|
workers: chunkWorkerCount,
|
|
18602
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 ?? []),
|
|
18603
18788
|
sha256,
|
|
18604
18789
|
outputKind,
|
|
18605
18790
|
producerVersion: plan2.producerVersion,
|
|
@@ -18669,9 +18854,10 @@ async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
|
|
|
18669
18854
|
}
|
|
18670
18855
|
|
|
18671
18856
|
// ../producer/src/services/distributed/projectHash.ts
|
|
18672
|
-
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";
|
|
18673
18858
|
import { createHash as createHash7 } from "crypto";
|
|
18674
18859
|
import { join as join43 } from "path";
|
|
18860
|
+
var READ_CHUNK_BYTES = 256 * 1024;
|
|
18675
18861
|
|
|
18676
18862
|
export {
|
|
18677
18863
|
createConsoleLogger,
|