hyperframes 0.8.181 → 0.8.184
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-5ZTD3MUZ.js} +22 -22
- package/dist/{animatedGifPrep-SENXJ7TN.js → animatedGifPrep-AGASIWVA.js} +14 -13
- package/dist/api.js +29 -28
- package/dist/{asset-XBH3MN3Y.js → asset-LSTEMPIB.js} +3 -3
- package/dist/{assetCataloger-KH4X2CRO.js → assetCataloger-BKBMNL3A.js} +16 -13
- package/dist/{audio-Q7I473UN.js → audio-KGK44XE4.js} +31 -30
- package/dist/{auth-I7CBTEUS.js → auth-MJWKYK77.js} +4 -4
- package/dist/{autoUpdate-KY5TLSN7.js → autoUpdate-2GGDKYR2.js} +2 -2
- package/dist/{backgroundChecks-4Q3VVK5W.js → backgroundChecks-7GRX5VQY.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-3AYDQRBI.js → batchRender-BCV2LELR.js} +7 -7
- package/dist/{beats-P4LENNVT.js → beats-7BCFRBAL.js} +12 -12
- package/dist/{benchmark-AXOAECN3.js → benchmark-2R6CN5MQ.js} +24 -24
- package/dist/{browser-XZKB5HGJ.js → browser-6AFGOI7G.js} +20 -20
- package/dist/{bundleWithLocalizedFonts-2WCR57IN.js → bundleWithLocalizedFonts-2EGPA5ZO.js} +2 -2
- package/dist/{capture-NWARHRHR.js → capture-HA2UHLIU.js} +8 -5
- package/dist/{capture-4RN4APDF.js → capture-HOIAW6MO.js} +50 -41
- package/dist/{captureCompositionFrame-QOF5BRF4.js → captureCompositionFrame-4236FVWJ.js} +22 -20
- package/dist/{captureTimeout-K2JNVVCI.js → captureTimeout-RIMG6IYH.js} +1 -1
- package/dist/{catalog-CRPOPVD5.js → catalog-A6CZAWW4.js} +42 -42
- package/dist/{catch-up-MHWGUQ42.js → catch-up-TNA4DJOA.js} +15 -15
- package/dist/check-5E5U2EQZ.js +117 -0
- package/dist/checkBrowser-FNINXBMZ.js +118 -0
- package/dist/{chunk-OJTDUF4W.js → chunk-2PVE4WS2.js} +1 -1
- package/dist/{checkBrowser-VES2NF3K.js → chunk-2ULXZ4PG.js} +187 -114
- package/dist/{chunk-WITHUCCB.js → chunk-2XA7KXQO.js} +2 -2
- package/dist/{chunk-HODBPO4A.js → chunk-3MDJIWOV.js} +626 -328
- package/dist/{chunk-JBCU6NR5.js → chunk-3QVMJ7GX.js} +56 -55
- package/dist/{chunk-OR5WCFWZ.js → chunk-3TXNNBI2.js} +2 -2
- package/dist/{chunk-IZM562YJ.js → chunk-4KKKBEP3.js} +4 -4
- package/dist/{chunk-XEWHUPFS.js → chunk-4N4P3ZWL.js} +2 -2
- package/dist/{chunk-537IYAEE.js → chunk-4UMPIPCQ.js} +9 -1
- package/dist/{chunk-J4L5TPLS.js → chunk-5UDRPPN2.js} +48 -6
- package/dist/{chunk-L3YOGIPG.js → chunk-66LREXGS.js} +1 -1
- package/dist/{chunk-6I7V6Q7F.js → chunk-74JMKLVU.js} +103 -20
- package/dist/{chunk-3PULCIY5.js → chunk-7HJALUIO.js} +5 -5
- package/dist/{chunk-GZVP4TWN.js → chunk-7JAD4MEW.js} +1 -1
- package/dist/{chunk-NAMGMP3R.js → chunk-7KVVNF7B.js} +1 -1
- package/dist/{chunk-TO6JNTML.js → chunk-7MB2ZAQF.js} +13 -8
- package/dist/{chunk-55IG255C.js → chunk-7NRI7HYX.js} +1 -1
- package/dist/{chunk-VAJIPSN6.js → chunk-ABZYYUUH.js} +1 -1
- package/dist/{chunk-GK2FIKIQ.js → chunk-ADDHW2FS.js} +214 -37
- package/dist/{chunk-ZUOSILUE.js → chunk-BCHSTE7U.js} +1 -1
- package/dist/{chunk-AOWDVB2T.js → chunk-CXABAXB3.js} +1 -1
- package/dist/{chunk-E24HSMZV.js → chunk-CYBXXSC4.js} +65 -14
- package/dist/{chunk-NZZYJOMJ.js → chunk-CZUAX3BV.js} +6 -5
- package/dist/{chunk-GV5R5B7Q.js → chunk-DGECWPTL.js} +1 -1
- package/dist/{chunk-BRHI7EIA.js → chunk-DKPNNYBZ.js} +4 -0
- package/dist/{chunk-UIDZRCBG.js → chunk-DWUGKEHR.js} +1 -1
- package/dist/{chunk-D3ZWBHZP.js → chunk-DYAPHNV6.js} +3 -2
- package/dist/{chunk-T7UHTUUE.js → chunk-E32ZQ2WO.js} +9 -9
- package/dist/{chunk-RGHQID2E.js → chunk-EHSBBBR2.js} +5 -3
- package/dist/{chunk-DJJ7SK4F.js → chunk-EM7C7H7S.js} +8 -8
- package/dist/{chunk-XSRUVMXK.js → chunk-ES426XRJ.js} +4 -4
- package/dist/chunk-FG4BBFZI.js +122 -0
- package/dist/{chunk-JMFJI26U.js → chunk-FGJEUV4S.js} +2 -2
- package/dist/{check-DJCUOUDI.js → chunk-GDEV42FA.js} +198 -142
- package/dist/{chunk-RXQHSGAQ.js → chunk-HR23IKLZ.js} +2 -2
- package/dist/{chunk-KMAAOHLO.js → chunk-HRPWRZGF.js} +1 -1
- package/dist/{chunk-UPFUC4DB.js → chunk-HTIUNMTP.js} +1 -1
- package/dist/{chunk-V2UNZ7QP.js → chunk-ICJEAFPD.js} +25 -14
- package/dist/{chunk-EOADENKV.js → chunk-IWTNTUPQ.js} +16 -14
- package/dist/chunk-IZCW2NKT.js +29 -0
- package/dist/{chunk-XFCLWWL3.js → chunk-J36JVBLR.js} +11 -4
- package/dist/{chunk-LBQFLUIY.js → chunk-J3QM7AHP.js} +9 -49
- package/dist/{chunk-DUN63LHY.js → chunk-JB6ARMQS.js} +2 -2
- package/dist/{chunk-5E5EYPZO.js → chunk-JIUTXKWA.js} +7 -7
- package/dist/{chunk-YJDB4FLT.js → chunk-JQYJXUJW.js} +1 -1
- package/dist/{chunk-PBN6GBJE.js → chunk-JVBRJMOP.js} +14 -1
- package/dist/{chunk-RHWJKSGH.js → chunk-KANNRHY7.js} +1 -1
- package/dist/{chunk-IL3GTCQY.js → chunk-KN46TGHV.js} +72 -140
- package/dist/{chunk-OFY6JTZC.js → chunk-LLC4CS6I.js} +2 -2
- package/dist/{chunk-OJDXABUF.js → chunk-LRGYPXHF.js} +2 -2
- package/dist/{chunk-GNE57O7U.js → chunk-MFAETWIF.js} +1 -1
- 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-B4VT6YU2.js → chunk-OLZENUPI.js} +50 -7
- package/dist/{chunk-H4YZZ2VQ.js → chunk-PFD25NAC.js} +1 -1
- package/dist/{chunk-XH262OWN.js → chunk-PFYWVUHA.js} +1 -1
- package/dist/{chunk-S3RYRF3W.js → chunk-PSKEKWVU.js} +1 -1
- package/dist/{chunk-N5SXQCJL.js → chunk-Q33P4EAC.js} +3 -3
- package/dist/{chunk-3DKN5WKL.js → chunk-QH3T4WI2.js} +77 -6
- package/dist/{chunk-O5AE7HOP.js → chunk-QL2PNIXC.js} +37 -33
- package/dist/{chunk-WUUCEFL5.js → chunk-R2BFTECP.js} +5 -5
- package/dist/chunk-R2SQBPMH.js +3805 -0
- package/dist/{chunk-YPBIAONI.js → chunk-RGXVEYHI.js} +230 -162
- package/dist/{chunk-YMS6CJCD.js → chunk-SAX7HQ5E.js} +1 -1
- package/dist/{chunk-KIO3R4QN.js → chunk-SN7KI5JA.js} +27 -14
- package/dist/{chunk-4USWWI2Y.js → chunk-TE427YID.js} +2 -2
- package/dist/{chunk-ICMXC3MI.js → chunk-U6RXZNZE.js} +31 -18
- package/dist/{chunk-X7CCSMRR.js → chunk-UJKUB2LH.js} +16 -16
- package/dist/{chunk-K26FR4SM.js → chunk-UKOTVJFV.js} +12 -12
- package/dist/{chunk-4OT3FWVV.js → chunk-UNNXFKVG.js} +2 -2
- package/dist/{chunk-PF7OWVTL.js → chunk-VDM3FEDP.js} +2 -2
- package/dist/{chunk-Y5GY6Y7A.js → chunk-VNVQGDPC.js} +2 -2
- package/dist/{chunk-22QHO26F.js → chunk-W64L7IFS.js} +1 -1
- package/dist/{chunk-Y2RXRPL2.js → chunk-WHPN2TIT.js} +5 -5
- package/dist/{chunk-65WIUIHL.js → chunk-WTFUDNW2.js} +7 -15
- package/dist/{chunk-3XDOGSRD.js → chunk-X3CG5YQA.js} +3 -3
- package/dist/{chunk-UZOZ2W2E.js → chunk-XGHHVYC7.js} +96 -34
- package/dist/{chunk-4IEH6EAC.js → chunk-YALM6XN4.js} +203 -58
- package/dist/{chunk-B6JLCPT3.js → chunk-YOZPQCSR.js} +6 -6
- package/dist/{chunk-5JMZLQT6.js → chunk-YWHCXIMD.js} +16 -16
- package/dist/{chunk-UVEQLDKB.js → chunk-YWNJTZGN.js} +3 -2
- package/dist/{chunk-WUQUR33W.js → chunk-ZOCHDXDG.js} +1 -1
- package/dist/{chunk-IWTRHPTP.js → chunk-ZRHO6YMM.js} +8 -8
- package/dist/{clean-GJNDVVDI.js → clean-HGASSMWI.js} +41 -40
- package/dist/cli.js +68 -64
- package/dist/{cloud-JCWNMKXC.js → cloud-JPDVNXHN.js} +4 -4
- package/dist/{cloudrun-2BKGY53X.js → cloudrun-AMMGSDRP.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-LHHVHUN3.js} +51 -47
- package/dist/{compiler-U3W6CJW7.js → compiler-Q3N6QXMT.js} +6 -6
- package/dist/{component-CBRAE325.js → component-D72J32Q7.js} +4 -4
- package/dist/{compositions-EZYJEHQ3.js → compositions-UQRJ5ROG.js} +29 -29
- package/dist/{contactSheet-27SRU7A4.js → contactSheet-CAGMKI3E.js} +3 -1
- package/dist/{delete-JWWMOITI.js → delete-P42VIDDA.js} +9 -9
- package/dist/{deploy-UGOV76OH.js → deploy-WZTH57O4.js} +11 -11
- package/dist/{destroy-QBLMYDBF.js → destroy-4B5HW5FH.js} +5 -5
- package/dist/{deterministicFonts-L7YEEFGI.js → deterministicFonts-VQ5UBMXY.js} +2 -2
- package/dist/{dist-VO7OXOFK.js → dist-DYS24AMA.js} +5 -5
- package/dist/{dist-2FMTAVGL.js → dist-SENYPQGW.js} +4 -4
- package/dist/{docs-MPOM3PHH.js → docs-UEWLIP6D.js} +1 -1
- package/dist/{doctor-XSKSZRR7.js → doctor-KEJIG2SK.js} +28 -27
- package/dist/{events-RGS4MAH4.js → events-CYKSNR7N.js} +6 -6
- package/dist/{events-AIZODZMP.js → events-UZXFQPMT.js} +9 -9
- package/dist/{feedback-GE3VDZOH.js → feedback-LXNQF7CA.js} +35 -35
- package/dist/{ffmpeg-SCXZTR6X.js → ffmpeg-BYHON577.js} +16 -15
- package/dist/{figma-3R4XST4Y.js → figma-EIQ35PS6.js} +3 -3
- package/dist/fontLocalizeCli.js +24 -23
- package/dist/{get-4FKJP6IM.js → get-CC2YL7QO.js} +9 -9
- package/dist/{gpuPolicy-4NNXESM7.js → gpuPolicy-VFSACUQV.js} +14 -13
- package/dist/{grade-compare-FAYVPXUR.js → grade-compare-TUQL7IV2.js} +56 -50
- package/dist/{help-C3UQMYXK.js → help-ROROO5K6.js} +1 -1
- package/dist/{history-LDGQ2IZJ.js → history-PNELYLXX.js} +15 -15
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +59 -59
- package/dist/hyperframes-player.global.js +8 -3
- package/dist/{info-KMXFLD3Q.js → info-4FZTH6AS.js} +20 -20
- package/dist/{init-D7GYHSX5.js → init-I43GHHVP.js} +69 -68
- package/dist/{inspect-CUKWHCGS.js → inspect-IT4TYIZ3.js} +46 -44
- package/dist/{installer-EPRSH6QI.js → installer-CWOJVK5K.js} +7 -7
- package/dist/{keyframes-XCUPHBW3.js → keyframes-3FBOGVD4.js} +16 -16
- package/dist/{lambda-IMORFJHN.js → lambda-H3V32I7M.js} +15 -15
- package/dist/{layout-JD2IOBMS.js → layout-BZ5LYJ5C.js} +46 -44
- package/dist/{lint-FHLER36Y.js → lint-ZTNSGP2S.js} +23 -23
- package/dist/{lintProject-ARKJXDQF.js → lintProject-C2ONSH2U.js} +4 -4
- package/dist/{list-MGCFG5MA.js → list-XM4GWJYY.js} +10 -10
- package/dist/{login-QX6M4UTR.js → login-H6HYKMWX.js} +7 -7
- package/dist/{logout-DKJANASY.js → logout-DDC4QLVK.js} +3 -3
- package/dist/{manager-IETAVBZS.js → manager-TWVDSJXO.js} +17 -16
- package/dist/{manager-V2QCCPOJ.js → manager-UHWEKPXC.js} +8 -3
- package/dist/{media-treatment-MDAQRITV.js → media-treatment-N7MY5NXB.js} +34 -33
- package/dist/{media-use-4XXGABIL.js → media-use-JBN57JE3.js} +1 -1
- package/dist/{models-NZAOSI5A.js → models-WEMIMYBD.js} +25 -24
- package/dist/{motionShot-6ZDUM2K4.js → motionShot-RHICTVPU.js} +29 -26
- package/dist/{normalize-audio-7PRYX6QM.js → normalize-audio-ZFUZCJE3.js} +12 -12
- package/dist/{open-I254NY5J.js → open-IBJ4FL3G.js} +24 -24
- package/dist/{parakeetRunner-TL3TOGUS.js → parakeetRunner-XXO4WSLR.js} +26 -25
- package/dist/{pipeline-YPERVOQM.js → pipeline-6ML3LUVK.js} +19 -18
- package/dist/{play-MYI7BYKS.js → play-RV4NAVF5.js} +40 -38
- package/dist/{policies-5NTZOHJA.js → policies-XXNGXWHV.js} +1 -1
- package/dist/{preflight-HRCSZ52D.js → preflight-R3DEFMLA.js} +19 -18
- package/dist/{present-WYXQDV4Q.js → present-5TBJGE6B.js} +34 -33
- package/dist/{preview-535HTWQO.js → preview-FLKZ5CXJ.js} +56 -55
- package/dist/{producer-C76CRJ5O.js → producer-7XYSPVKH.js} +1 -1
- package/dist/{progress-I37JB7R4.js → progress-NHJIHAAG.js} +2 -2
- package/dist/{projectConfig-5QCNTGQT.js → projectConfig-TBU2VWZX.js} +9 -9
- package/dist/{publication-2QT7VVE2.js → publication-CWWUJYJ5.js} +5 -5
- package/dist/{publish-53EBL7OO.js → publish-FSNE4FEB.js} +28 -27
- package/dist/{refresh-MGCVWX56.js → refresh-RXTOPRBB.js} +3 -3
- package/dist/{remove-background-OBYHMPD4.js → remove-background-MDFWRWCT.js} +32 -31
- package/dist/render-DBGQZAZT.js +1516 -0
- package/dist/{render-3MELF6Y3.js → render-F4JQ553X.js} +102 -96
- package/dist/{render-75CRB3BW.js → render-LWZKXCLY.js} +8 -8
- package/dist/{render-batch-CEVWUYBP.js → render-batch-PU7NMLIJ.js} +8 -8
- package/dist/renderSetupWorker.js +12 -9
- package/dist/{resolver-4ICE2AT6.js → resolver-RUBGFXPC.js} +7 -7
- package/dist/{screenshotCapture-HXEZ3TNJ.js → screenshotCapture-UBY6TT75.js} +33 -6
- package/dist/{sherpa-L4UACXT3.js → sherpa-X2TBNO6P.js} +25 -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-WHKMWO2D.js} +17 -17
- package/dist/{skillsUpdateCheck-ULXRGLDU.js → skillsUpdateCheck-XQGZGJJG.js} +3 -3
- package/dist/{snapshot-PWFHQU5E.js → snapshot-M4NUUSNU.js} +73 -71
- package/dist/{src-RDSWHMJS.js → src-4UYM2K3S.js} +34 -26
- package/dist/{src-S7NVL5VF.js → src-6MSC62U2.js} +23 -19
- package/dist/{state-KAXGHF77.js → state-ORRPOLMQ.js} +2 -2
- package/dist/{staticProjectServer-GYPUQGI7.js → staticProjectServer-ERDTFP45.js} +21 -20
- package/dist/{status-BV7QAUQD.js → status-CM7IQTU2.js} +6 -6
- package/dist/studio/assets/{hyperframes-player-DcD3NXpX.js → hyperframes-player-DEncBxR7.js} +7 -2
- package/dist/studio/assets/{index-CFrZAwKo.js → index-BABXr78Q.js} +4 -4
- package/dist/studio/assets/{index-BIDKYk0h.js → index-Cc22mgvY.js} +1 -1
- package/dist/studio/index.html +1 -1
- package/dist/{studio-api-IXGX5ZFI.js → studio-api-SAKD3VKC.js} +18 -17
- package/dist/{studioServer-LA5Z7RSS.js → studioServer-IRI7EVOM.js} +91 -84
- package/dist/{telemetry-STEMAMAX.js → telemetry-F4XADVAF.js} +10 -10
- package/dist/{telemetry-CQYHCCPL.js → telemetry-QG5AANZ4.js} +1 -1
- package/dist/{timeline-KLD24EN6.js → timeline-5I444RRE.js} +42 -41
- package/dist/{tokens-ICLORAA4.js → tokens-LRRYM35A.js} +3 -3
- package/dist/{transcribe-A6IKK7VS.js → transcribe-44XDFNVU.js} +48 -47
- package/dist/{transcribe-CTHZLRXF.js → transcribe-WHYHWAB2.js} +20 -19
- package/dist/{tts-EDK3QS7M.js → tts-A2WILYGN.js} +6 -6
- package/dist/{updateCheck-FHCAAAXA.js → updateCheck-7CPH3CAZ.js} +2 -2
- package/dist/{upgrade-7EV4F2R7.js → upgrade-WW4GQ2RI.js} +3 -3
- package/dist/{urlDownloader-MIMGVASJ.js → urlDownloader-OHLLP45A.js} +13 -12
- package/dist/{validate-LZF46W3V.js → validate-VNCDH2LW.js} +40 -38
- package/dist/{video-ZC47NFOL.js → video-5OHTLL2D.js} +17 -14
- package/dist/warmCheck.js +228 -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/render-5BXTEEG7.js +0 -719
- 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-TE427YID.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-OLZENUPI.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-RGXVEYHI.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-J3QM7AHP.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-YALM6XN4.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-R2SQBPMH.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-VQ5UBMXY.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({
|
|
@@ -8573,6 +8623,7 @@ async function runCaptureStage(input) {
|
|
|
8573
8623
|
if (progress.capturedFrames === 0) reportWorkerStartup(job, progress, onProgress);
|
|
8574
8624
|
return;
|
|
8575
8625
|
}
|
|
8626
|
+
if (progress.landedFrame) input.onFrameLanded?.(progress.landedFrame);
|
|
8576
8627
|
job.framesRendered = progress.capturedFrames;
|
|
8577
8628
|
checkDiskProjection(progress.capturedFrames);
|
|
8578
8629
|
const frameProgress = progress.capturedFrames / progress.totalFrames;
|
|
@@ -9719,6 +9770,7 @@ import {
|
|
|
9719
9770
|
statSync as statSync4,
|
|
9720
9771
|
writeFileSync as writeFileSync4
|
|
9721
9772
|
} from "fs";
|
|
9773
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
9722
9774
|
import { dirname as dirname7, join as join23 } from "path";
|
|
9723
9775
|
|
|
9724
9776
|
// ../producer/src/services/render/stages/gifEncodeArgs.ts
|
|
@@ -9728,8 +9780,10 @@ function fpsToFfmpegArg2(fps) {
|
|
|
9728
9780
|
}
|
|
9729
9781
|
var KEEP_FILTER_GRAPH_WHEN_FRAMES_DROP_ALPHA = ["-reinit_filter", "0"];
|
|
9730
9782
|
var WRITE_EVERY_FRAME_WHOLE = ["-gifflags", "0"];
|
|
9783
|
+
var FAIL_ON_UNREADABLE_FRAME_INSTEAD_OF_ENDING_THERE = ["-xerror"];
|
|
9731
9784
|
function framesInput(input, fpsArg) {
|
|
9732
9785
|
return [
|
|
9786
|
+
...FAIL_ON_UNREADABLE_FRAME_INSTEAD_OF_ENDING_THERE,
|
|
9733
9787
|
"-framerate",
|
|
9734
9788
|
fpsArg,
|
|
9735
9789
|
...KEEP_FILTER_GRAPH_WHEN_FRAMES_DROP_ALPHA,
|
|
@@ -9848,6 +9902,124 @@ function startEncodeProgress(job, stage, onProgress) {
|
|
|
9848
9902
|
});
|
|
9849
9903
|
return (frames = total) => reportEncodeProgress(job, frames, total, onProgress, 75);
|
|
9850
9904
|
}
|
|
9905
|
+
function resolveEngineConfig(input) {
|
|
9906
|
+
return input.engineConfig ?? input.job.config.producerConfig ?? resolveConfig();
|
|
9907
|
+
}
|
|
9908
|
+
function videoEncoderOptions(input, engineCfg) {
|
|
9909
|
+
const { job, preset } = input;
|
|
9910
|
+
return {
|
|
9911
|
+
fps: job.config.fps,
|
|
9912
|
+
width: input.width,
|
|
9913
|
+
height: input.height,
|
|
9914
|
+
codec: preset.codec,
|
|
9915
|
+
preset: preset.preset,
|
|
9916
|
+
quality: input.effectiveQuality,
|
|
9917
|
+
bitrate: input.effectiveBitrate,
|
|
9918
|
+
pixelFormat: preset.pixelFormat,
|
|
9919
|
+
vp9CpuUsed: engineCfg.vp9CpuUsed,
|
|
9920
|
+
useGpu: job.config.useGpu,
|
|
9921
|
+
hdr: preset.hdr,
|
|
9922
|
+
// Distributed chunk renders pass these so the encoder writes closed-GOP
|
|
9923
|
+
// keyframes that survive `-f concat -c copy` at assemble time. In-process
|
|
9924
|
+
// renders leave both undefined → preserves the existing open-GOP output.
|
|
9925
|
+
lockGopForChunkConcat: input.lockGopForChunkConcat === true,
|
|
9926
|
+
gopSize: input.gopSize
|
|
9927
|
+
};
|
|
9928
|
+
}
|
|
9929
|
+
function canEncodeWhileCapturing(input, workerCount, cpuCount) {
|
|
9930
|
+
return workerCount > 1 && workerCount < cpuCount && !input.isPngSequence && !input.isGif && !input.enableChunkedEncode && input.preset.codec === "h264" && !input.preset.hdr && input.job.config.useGpu !== true && input.captureImageFormat === "jpeg" && input.lockGopForChunkConcat !== true;
|
|
9931
|
+
}
|
|
9932
|
+
async function readLandedFrame(workerPath, mergedPath) {
|
|
9933
|
+
if (workerPath !== void 0) {
|
|
9934
|
+
try {
|
|
9935
|
+
return await readFile2(workerPath);
|
|
9936
|
+
} catch (error) {
|
|
9937
|
+
if (error.code !== "ENOENT") throw error;
|
|
9938
|
+
}
|
|
9939
|
+
}
|
|
9940
|
+
return readFile2(mergedPath);
|
|
9941
|
+
}
|
|
9942
|
+
function encodeWhileCapturing(input, totalFrames) {
|
|
9943
|
+
const engineCfg = resolveEngineConfig(input);
|
|
9944
|
+
const stop = new AbortController();
|
|
9945
|
+
const signal = input.abortSignal ? AbortSignal.any([input.abortSignal, stop.signal]) : stop.signal;
|
|
9946
|
+
const landed = /* @__PURE__ */ new Map();
|
|
9947
|
+
let captureDone = false;
|
|
9948
|
+
let framesFed = 0;
|
|
9949
|
+
let wake = null;
|
|
9950
|
+
const nudge = () => {
|
|
9951
|
+
wake?.();
|
|
9952
|
+
wake = null;
|
|
9953
|
+
};
|
|
9954
|
+
signal.addEventListener("abort", nudge, { once: true });
|
|
9955
|
+
let reportFed = null;
|
|
9956
|
+
const encoder = spawnStreamingEncoder(
|
|
9957
|
+
input.videoOnlyPath,
|
|
9958
|
+
{ ...videoEncoderOptions(input, engineCfg), imageFormat: "jpeg" },
|
|
9959
|
+
signal,
|
|
9960
|
+
engineCfg
|
|
9961
|
+
);
|
|
9962
|
+
const fed = (async () => {
|
|
9963
|
+
const stream = await encoder;
|
|
9964
|
+
for (let next = 0; next < totalFrames; next++) {
|
|
9965
|
+
while (!landed.has(next) && !captureDone && !signal.aborted) {
|
|
9966
|
+
await new Promise((resolve11) => wake = resolve11);
|
|
9967
|
+
}
|
|
9968
|
+
if (signal.aborted) return;
|
|
9969
|
+
const mergedPath = join23(input.framesDir, formatCaptureFrameName(next, "jpg"));
|
|
9970
|
+
const frame = await readLandedFrame(landed.get(next), mergedPath);
|
|
9971
|
+
landed.delete(next);
|
|
9972
|
+
if (!await stream.writeFrame(frame)) {
|
|
9973
|
+
throw new Error(stream.getExitError() ?? "encoder exited before the last frame");
|
|
9974
|
+
}
|
|
9975
|
+
framesFed++;
|
|
9976
|
+
reportFed?.(framesFed);
|
|
9977
|
+
}
|
|
9978
|
+
})().then(
|
|
9979
|
+
() => void 0,
|
|
9980
|
+
(error) => error ?? new Error("encode failed")
|
|
9981
|
+
);
|
|
9982
|
+
const closeEncoder = async () => (await encoder.catch(() => null))?.close();
|
|
9983
|
+
return {
|
|
9984
|
+
onFrameLanded: (frame) => {
|
|
9985
|
+
landed.set(frame.index, frame.path);
|
|
9986
|
+
nudge();
|
|
9987
|
+
},
|
|
9988
|
+
finish: async () => {
|
|
9989
|
+
const start = Date.now();
|
|
9990
|
+
captureDone = true;
|
|
9991
|
+
input.log.info("[Render] Encoded frames while capturing", {
|
|
9992
|
+
framesFed,
|
|
9993
|
+
totalFrames
|
|
9994
|
+
});
|
|
9995
|
+
const encoded = startEncodeProgress(input.job, "Encoding video", input.onProgress);
|
|
9996
|
+
reportFed = encoded;
|
|
9997
|
+
nudge();
|
|
9998
|
+
const failure = await fed;
|
|
9999
|
+
const result = await closeEncoder();
|
|
10000
|
+
input.assertNotAborted();
|
|
10001
|
+
if (failure === void 0 && result?.success) {
|
|
10002
|
+
encoded();
|
|
10003
|
+
return { encodeMs: Date.now() - start };
|
|
10004
|
+
}
|
|
10005
|
+
input.log.warn(
|
|
10006
|
+
"[Render] Encoding while capturing failed; encoding the frames after capture",
|
|
10007
|
+
{
|
|
10008
|
+
error: String(failure ?? result?.error)
|
|
10009
|
+
}
|
|
10010
|
+
);
|
|
10011
|
+
return runEncodeStage(input);
|
|
10012
|
+
},
|
|
10013
|
+
abort: async () => {
|
|
10014
|
+
stop.abort();
|
|
10015
|
+
await fed;
|
|
10016
|
+
await closeEncoder();
|
|
10017
|
+
},
|
|
10018
|
+
get framesFed() {
|
|
10019
|
+
return framesFed;
|
|
10020
|
+
}
|
|
10021
|
+
};
|
|
10022
|
+
}
|
|
9851
10023
|
async function runEncodeStage(input) {
|
|
9852
10024
|
const {
|
|
9853
10025
|
job,
|
|
@@ -9855,16 +10027,11 @@ async function runEncodeStage(input) {
|
|
|
9855
10027
|
outputPath,
|
|
9856
10028
|
framesDir,
|
|
9857
10029
|
videoOnlyPath,
|
|
9858
|
-
width,
|
|
9859
|
-
height,
|
|
9860
10030
|
needsAlpha,
|
|
9861
10031
|
hasAudio,
|
|
9862
10032
|
audioOutputPath,
|
|
9863
10033
|
isPngSequence,
|
|
9864
10034
|
isGif,
|
|
9865
|
-
preset,
|
|
9866
|
-
effectiveQuality,
|
|
9867
|
-
effectiveBitrate,
|
|
9868
10035
|
enableChunkedEncode,
|
|
9869
10036
|
chunkedEncodeSize,
|
|
9870
10037
|
abortSignal,
|
|
@@ -9894,7 +10061,7 @@ async function runEncodeStage(input) {
|
|
|
9894
10061
|
encoded();
|
|
9895
10062
|
return { encodeMs: Date.now() - stage5Start };
|
|
9896
10063
|
}
|
|
9897
|
-
const engineCfg = input
|
|
10064
|
+
const engineCfg = resolveEngineConfig(input);
|
|
9898
10065
|
if (isGif) {
|
|
9899
10066
|
const encoded = startEncodeProgress(job, "Encoding GIF", onProgress);
|
|
9900
10067
|
if (hasAudio) {
|
|
@@ -9924,24 +10091,7 @@ async function runEncodeStage(input) {
|
|
|
9924
10091
|
const videoEngineCfg = scaledEncodeTimeout > engineCfg.ffmpegEncodeTimeout ? { ...engineCfg, ffmpegEncodeTimeout: scaledEncodeTimeout } : engineCfg;
|
|
9925
10092
|
const frameExt = frameFileExtension(input.captureImageFormat);
|
|
9926
10093
|
const framePattern = `frame_%06d.${frameExt}`;
|
|
9927
|
-
const encoderOpts =
|
|
9928
|
-
fps: job.config.fps,
|
|
9929
|
-
width,
|
|
9930
|
-
height,
|
|
9931
|
-
codec: preset.codec,
|
|
9932
|
-
preset: preset.preset,
|
|
9933
|
-
quality: effectiveQuality,
|
|
9934
|
-
bitrate: effectiveBitrate,
|
|
9935
|
-
pixelFormat: preset.pixelFormat,
|
|
9936
|
-
vp9CpuUsed: engineCfg.vp9CpuUsed,
|
|
9937
|
-
useGpu: job.config.useGpu,
|
|
9938
|
-
hdr: preset.hdr,
|
|
9939
|
-
// Distributed chunk renders pass these so the encoder writes closed-GOP
|
|
9940
|
-
// keyframes that survive `-f concat -c copy` at assemble time. In-process
|
|
9941
|
-
// renders leave both undefined → preserves the existing open-GOP output.
|
|
9942
|
-
lockGopForChunkConcat: input.lockGopForChunkConcat === true,
|
|
9943
|
-
gopSize: input.gopSize
|
|
9944
|
-
};
|
|
10094
|
+
const encoderOpts = videoEncoderOptions(input, engineCfg);
|
|
9945
10095
|
const encodeResult = enableChunkedEncode ? await encodeFramesChunkedConcat(
|
|
9946
10096
|
framesDir,
|
|
9947
10097
|
framePattern,
|
|
@@ -10014,12 +10164,13 @@ async function scanTruePeak(audioPath, trim, timeoutMs, signal) {
|
|
|
10014
10164
|
};
|
|
10015
10165
|
}
|
|
10016
10166
|
async function measureTruePeakDbfs(audioPath, options) {
|
|
10017
|
-
const { timeoutMs, signal
|
|
10167
|
+
const { timeoutMs, signal } = options;
|
|
10018
10168
|
const wholeFile = async () => (await scanTruePeak(audioPath, "", timeoutMs, signal)).peak;
|
|
10169
|
+
const { durationSeconds, sampleRate } = await extractAudioMetadata(audioPath, { signal });
|
|
10019
10170
|
const block = 4800;
|
|
10020
|
-
const count =
|
|
10021
|
-
if (
|
|
10022
|
-
const cut = (k) => k * Math.floor(
|
|
10171
|
+
const count = sampleRate === 48e3 && Number.isFinite(durationSeconds) ? aacSegmentCount(durationSeconds) : 1;
|
|
10172
|
+
if (count === 1) return wholeFile();
|
|
10173
|
+
const cut = (k) => k * Math.floor(durationSeconds * 10 / count) * block;
|
|
10023
10174
|
const peers = new AbortController();
|
|
10024
10175
|
const segmentSignal = signal ? AbortSignal.any([signal, peers.signal]) : peers.signal;
|
|
10025
10176
|
const scans = await Promise.all(
|
|
@@ -10048,24 +10199,8 @@ var AUDIO_DURATION_TOLERANCE_SECONDS = 1e-3;
|
|
|
10048
10199
|
var AAC_DELIVERY_TRUE_PEAK_DBFS = -1;
|
|
10049
10200
|
var AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB = 0.5;
|
|
10050
10201
|
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
|
-
];
|
|
10202
|
+
function aacTruePeakCorrectionFilter(targetDurationSeconds, attenuationDb) {
|
|
10203
|
+
return `volume=${attenuationDb.toFixed(3)}dB,apad,atrim=0:${formatSeconds(targetDurationSeconds)}`;
|
|
10069
10204
|
}
|
|
10070
10205
|
function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, targetDurationSeconds) {
|
|
10071
10206
|
const delta = targetDurationSeconds - sourceDurationSeconds;
|
|
@@ -10080,53 +10215,13 @@ function buildPadTrimAudioPlan(audioPath, outputPath, sourceDurationSeconds, tar
|
|
|
10080
10215
|
if (delta > 0) {
|
|
10081
10216
|
return {
|
|
10082
10217
|
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
|
-
],
|
|
10218
|
+
steps: [{ kind: "normalize", filter: `apad,atrim=0:${targetSec}` }],
|
|
10102
10219
|
cleanupPaths: []
|
|
10103
10220
|
};
|
|
10104
10221
|
}
|
|
10105
10222
|
return {
|
|
10106
10223
|
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
|
-
],
|
|
10224
|
+
steps: [{ kind: "trim", filter: `atrim=duration=${targetSec},asetpts=PTS-STARTPTS` }],
|
|
10130
10225
|
cleanupPaths: []
|
|
10131
10226
|
};
|
|
10132
10227
|
}
|
|
@@ -10143,7 +10238,8 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
10143
10238
|
const probeAudio = input.probeAudioInfo ?? defaultProbeAudioInfo;
|
|
10144
10239
|
const timeoutMs = input.timeoutMs ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
|
|
10145
10240
|
const runner = input.runFfmpeg ?? ((args) => defaultRunFfmpeg(args, timeoutMs, input.signal));
|
|
10146
|
-
const
|
|
10241
|
+
const encode = input.encodeAac ?? defaultAacEncoder(timeoutMs, input.signal);
|
|
10242
|
+
const probeTruePeak = input.probeAudioTruePeakDbfs ?? (input.runFfmpeg || input.encodeAac ? void 0 : (audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal }));
|
|
10147
10243
|
const [videoResult, audioResult] = await Promise.allSettled([
|
|
10148
10244
|
probeVideo(input.videoPath),
|
|
10149
10245
|
probeAudio(input.audioPath, input.signal)
|
|
@@ -10190,7 +10286,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
10190
10286
|
);
|
|
10191
10287
|
try {
|
|
10192
10288
|
for (const step of plan2.steps) {
|
|
10193
|
-
const ffmpegResult = await runner(step.args);
|
|
10289
|
+
const ffmpegResult = step.kind === "copy" ? await runner(step.args) : await encode(input.audioPath, input.outputPath, targetDurationSeconds, step.filter);
|
|
10194
10290
|
if (!ffmpegResult.success) {
|
|
10195
10291
|
return {
|
|
10196
10292
|
success: false,
|
|
@@ -10222,7 +10318,7 @@ async function padOrTrimAudioToVideoFrameCount(input) {
|
|
|
10222
10318
|
targetDurationSeconds,
|
|
10223
10319
|
signal: input.signal,
|
|
10224
10320
|
probeTruePeak,
|
|
10225
|
-
|
|
10321
|
+
encode
|
|
10226
10322
|
});
|
|
10227
10323
|
if (!correction.success) {
|
|
10228
10324
|
return {
|
|
@@ -10252,12 +10348,8 @@ async function constrainAacTruePeak(input) {
|
|
|
10252
10348
|
audioPath: input.audioPath,
|
|
10253
10349
|
targetDurationSeconds: input.targetDurationSeconds,
|
|
10254
10350
|
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)
|
|
10351
|
+
probeTruePeak: (audioPath, signal) => measureTruePeakDbfs(audioPath, { timeoutMs, signal }),
|
|
10352
|
+
encode: defaultAacEncoder(timeoutMs, input.signal, input.sourcePath)
|
|
10261
10353
|
});
|
|
10262
10354
|
}
|
|
10263
10355
|
async function enforceAacTruePeak(input) {
|
|
@@ -10284,13 +10376,11 @@ async function enforceAacTruePeak(input) {
|
|
|
10284
10376
|
}
|
|
10285
10377
|
if (pass === MAX_TRUE_PEAK_CORRECTION_PASSES) break;
|
|
10286
10378
|
attenuationDb += correctionTargetDbfs - truePeakDbfs;
|
|
10287
|
-
const result = await input.
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
attenuationDb
|
|
10293
|
-
)
|
|
10379
|
+
const result = await input.encode(
|
|
10380
|
+
input.audioPath,
|
|
10381
|
+
correctedPath,
|
|
10382
|
+
input.targetDurationSeconds,
|
|
10383
|
+
aacTruePeakCorrectionFilter(input.targetDurationSeconds, attenuationDb)
|
|
10294
10384
|
);
|
|
10295
10385
|
if (!result.success) {
|
|
10296
10386
|
return {
|
|
@@ -10394,7 +10484,18 @@ async function defaultProbeAudioInfo(audioPath, signal) {
|
|
|
10394
10484
|
};
|
|
10395
10485
|
}
|
|
10396
10486
|
async function defaultRunFfmpeg(args, timeoutMs, signal) {
|
|
10397
|
-
|
|
10487
|
+
return toStepResult(await runFfmpeg(args, { signal, timeout: timeoutMs }), timeoutMs);
|
|
10488
|
+
}
|
|
10489
|
+
function defaultAacEncoder(timeoutMs, signal, pcmSourcePath) {
|
|
10490
|
+
return async (inputPath, outputPath, durationSeconds, filter) => {
|
|
10491
|
+
const options = pcmSourcePath ? { signal, timeout: timeoutMs, filter } : { signal, timeout: timeoutMs, filter, segments: 1 };
|
|
10492
|
+
return toStepResult(
|
|
10493
|
+
await encodeAac(pcmSourcePath ?? inputPath, outputPath, durationSeconds, options),
|
|
10494
|
+
timeoutMs
|
|
10495
|
+
);
|
|
10496
|
+
};
|
|
10497
|
+
}
|
|
10498
|
+
function toStepResult(result, timeoutMs) {
|
|
10398
10499
|
if (result.success) return { success: true };
|
|
10399
10500
|
return {
|
|
10400
10501
|
success: false,
|
|
@@ -10582,7 +10683,7 @@ function assertOutputScaleSupported(deviceScaleFactor, route) {
|
|
|
10582
10683
|
const reason = UNSUPPORTED_REASON2[route];
|
|
10583
10684
|
if (reason === null) return;
|
|
10584
10685
|
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
|
|
10686
|
+
`[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
10687
|
);
|
|
10587
10688
|
}
|
|
10588
10689
|
|
|
@@ -10800,7 +10901,7 @@ function getNextRetryWorkerCount(currentWorkers) {
|
|
|
10800
10901
|
return Math.max(1, Math.floor(currentWorkers / 2));
|
|
10801
10902
|
}
|
|
10802
10903
|
function resolveRenderWorkDirPrefix(outputPath, jobId, platform2 = process.platform, systemTempDir = tmpdir2()) {
|
|
10803
|
-
if (platform2 === "win32") return join25(systemTempDir, "hf-render-");
|
|
10904
|
+
if (platform2 === "win32" || platform2 === "darwin") return join25(systemTempDir, "hf-render-");
|
|
10804
10905
|
return join25(dirname9(outputPath), `work-${jobId}-`);
|
|
10805
10906
|
}
|
|
10806
10907
|
var MAX_TRANSIENT_CAPTURE_RETRIES = 1;
|
|
@@ -11294,6 +11395,9 @@ function resolveDeShortBand(args) {
|
|
|
11294
11395
|
function shouldPreferSingleWorkerDrawElement(args) {
|
|
11295
11396
|
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
11397
|
}
|
|
11398
|
+
function isProbeDeGated(session) {
|
|
11399
|
+
return session !== null && session.captureMode !== "drawelement" && !session.deInitDeferred;
|
|
11400
|
+
}
|
|
11297
11401
|
function resolveInversionRetryPlan(args) {
|
|
11298
11402
|
if (args.deWorkerInversion !== "inverted") return null;
|
|
11299
11403
|
const workerCount = args.isMemoryExhaustion ? 1 : args.preInversionWorkerCount;
|
|
@@ -11375,7 +11479,8 @@ async function closeOrphanedProbeForRetry(probe, closer, log, retryContext) {
|
|
|
11375
11479
|
}
|
|
11376
11480
|
function resolveParallelCaptureMode(args) {
|
|
11377
11481
|
const supersampling = (args.deviceScaleFactor ?? 1) !== 1;
|
|
11378
|
-
|
|
11482
|
+
const headlessShell = args.headlessShellPath !== void 0;
|
|
11483
|
+
return headlessShell && args.platform === "linux" && !args.forceScreenshot && !supersampling ? "beginframe" : "screenshot";
|
|
11379
11484
|
}
|
|
11380
11485
|
function isCaptureParallelStreamRouterEnabled(env, resolvedMode) {
|
|
11381
11486
|
const raw = env.HF_CAPTURE_PARALLEL_STREAM?.trim().toLowerCase();
|
|
@@ -11983,6 +12088,7 @@ async function executeRenderPipeline(input) {
|
|
|
11983
12088
|
);
|
|
11984
12089
|
const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
|
|
11985
12090
|
const hasHdrContent = Boolean(effectiveHdr && nativeHdrIds.size > 0);
|
|
12091
|
+
if (hasHdrContent) assertOutputScaleSupported(deviceScaleFactor, "hdr_layered");
|
|
11986
12092
|
const deSingleMinFramesRaw = process.env.HF_DE_SINGLE_MIN_FRAMES;
|
|
11987
12093
|
const deSingleMinFramesNum = deSingleMinFramesRaw === void 0 || deSingleMinFramesRaw.trim() === "" ? 900 : Number(deSingleMinFramesRaw);
|
|
11988
12094
|
const deSingleMinFrames = Number.isFinite(deSingleMinFramesNum) ? deSingleMinFramesNum : 900;
|
|
@@ -12023,7 +12129,7 @@ async function executeRenderPipeline(input) {
|
|
|
12023
12129
|
singleWorkerStreamingOk: shouldUseStreamingEncode(cfg, outputFormat, 1, job.duration),
|
|
12024
12130
|
layeredOrEffectRoute: hasHdrContent || compiled.hasShaderTransitions,
|
|
12025
12131
|
supersampling: deviceScaleFactor !== 1,
|
|
12026
|
-
probeDeGated: probeSession
|
|
12132
|
+
probeDeGated: isProbeDeGated(probeSession),
|
|
12027
12133
|
experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || // Verified parallel DE streaming (opt-in) wants its parallelism kept.
|
|
12028
12134
|
process.env.HF_DE_PARALLEL_STREAM === "true"
|
|
12029
12135
|
};
|
|
@@ -12032,14 +12138,14 @@ async function executeRenderPipeline(input) {
|
|
|
12032
12138
|
...deInversionArgs,
|
|
12033
12139
|
minFrames: Math.min(deSingleMinFrames, deShortBandMinFrames)
|
|
12034
12140
|
});
|
|
12035
|
-
|
|
12141
|
+
let deShortBand = resolveDeShortBand({
|
|
12036
12142
|
invertAtBaseFloor,
|
|
12037
12143
|
invertAtBandFloor,
|
|
12038
12144
|
bandEnabled: deShortBandEnabled,
|
|
12039
12145
|
bandOpen: deShortBandOpen,
|
|
12040
12146
|
elementCountSource: compositionElementCountSource
|
|
12041
12147
|
});
|
|
12042
|
-
|
|
12148
|
+
let deInversionEligible = deShortBandRoute && deShortBand === "applied" ? invertAtBandFloor : invertAtBaseFloor;
|
|
12043
12149
|
const deInversionEffectiveMinFrames = deShortBandRoute && deShortBand === "applied" ? Math.min(deSingleMinFrames, deShortBandMinFrames) : deSingleMinFrames;
|
|
12044
12150
|
const deParallelRouterEnabled = isDeParallelRouterEnabled(process.env);
|
|
12045
12151
|
const deParallelMinFramesRaw = process.env.HF_DE_PARALLEL_MIN_FRAMES;
|
|
@@ -12048,7 +12154,7 @@ async function executeRenderPipeline(input) {
|
|
|
12048
12154
|
const deParallelMinMemRaw = process.env.HF_DE_PARALLEL_MIN_MEM_MB;
|
|
12049
12155
|
const deParallelMinMemNum = deParallelMinMemRaw === void 0 || deParallelMinMemRaw.trim() === "" ? 24576 : Number(deParallelMinMemRaw);
|
|
12050
12156
|
const deParallelMinMemoryMb = Number.isFinite(deParallelMinMemNum) ? deParallelMinMemNum : 24576;
|
|
12051
|
-
|
|
12157
|
+
let deParallelRouterEligible = shouldPreferParallelDrawElement({
|
|
12052
12158
|
workerCount: WOULD_RESOLVE_MULTI_WORKER,
|
|
12053
12159
|
requestedWorkers: job.config.workers,
|
|
12054
12160
|
useDrawElement: cfg.useDrawElement,
|
|
@@ -12059,7 +12165,7 @@ async function executeRenderPipeline(input) {
|
|
|
12059
12165
|
minFrames: deParallelMinFrames,
|
|
12060
12166
|
layeredOrEffectRoute: hasHdrContent || compiled.hasShaderTransitions,
|
|
12061
12167
|
supersampling: deviceScaleFactor !== 1,
|
|
12062
|
-
probeDeGated: probeSession
|
|
12168
|
+
probeDeGated: isProbeDeGated(probeSession),
|
|
12063
12169
|
experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || process.env.HF_DE_PARALLEL_STREAM === "true",
|
|
12064
12170
|
routerEnabled: deParallelRouterEnabled,
|
|
12065
12171
|
// Router pins 3 workers for the streaming path; don't pin when a
|
|
@@ -12075,6 +12181,35 @@ async function executeRenderPipeline(input) {
|
|
|
12075
12181
|
totalMemoryMb: Math.round(totalmem2() / (1024 * 1024)),
|
|
12076
12182
|
minMemoryMb: deParallelMinMemoryMb
|
|
12077
12183
|
});
|
|
12184
|
+
if (probeSession === null && (deInversionEligible || deParallelRouterEligible)) {
|
|
12185
|
+
try {
|
|
12186
|
+
probeSession = await createCaptureSession(
|
|
12187
|
+
activeFileServer.url,
|
|
12188
|
+
framesDir,
|
|
12189
|
+
buildCaptureOptions(),
|
|
12190
|
+
null,
|
|
12191
|
+
{ ...cfg, forceScreenshot: captureForceScreenshot }
|
|
12192
|
+
);
|
|
12193
|
+
await initializeSession(probeSession);
|
|
12194
|
+
} catch (error) {
|
|
12195
|
+
assertNotAborted();
|
|
12196
|
+
if (probeSession) {
|
|
12197
|
+
lastBrowserConsole = probeSession.browserConsoleBuffer;
|
|
12198
|
+
await closeCaptureSession(probeSession).catch(() => {
|
|
12199
|
+
});
|
|
12200
|
+
probeSession = null;
|
|
12201
|
+
}
|
|
12202
|
+
log.warn("[Render] Fast capture gate check failed; routing without it.", {
|
|
12203
|
+
error: error instanceof Error ? error.message : String(error)
|
|
12204
|
+
});
|
|
12205
|
+
}
|
|
12206
|
+
if (isProbeDeGated(probeSession)) {
|
|
12207
|
+
deInversionEligible = false;
|
|
12208
|
+
deParallelRouterEligible = false;
|
|
12209
|
+
deShortBand = void 0;
|
|
12210
|
+
}
|
|
12211
|
+
}
|
|
12212
|
+
const deProbeGateReason = isProbeDeGated(probeSession) ? probeSession.deGateReason : void 0;
|
|
12078
12213
|
let workerCount;
|
|
12079
12214
|
const captureStageObservationData = (extra = {}) => ({
|
|
12080
12215
|
stagePhase: "capturing",
|
|
@@ -12262,7 +12397,7 @@ async function executeRenderPipeline(input) {
|
|
|
12262
12397
|
}
|
|
12263
12398
|
const parallelCaptureMode = resolveParallelCaptureMode({
|
|
12264
12399
|
platform: process.platform,
|
|
12265
|
-
|
|
12400
|
+
headlessShellPath: resolveHeadlessShellPath(cfg),
|
|
12266
12401
|
forceScreenshot: captureForceScreenshot,
|
|
12267
12402
|
deviceScaleFactor: captureOptions.deviceScaleFactor
|
|
12268
12403
|
});
|
|
@@ -12864,6 +12999,34 @@ async function executeRenderPipeline(input) {
|
|
|
12864
12999
|
throw new Error(`Disk capture requires sdr_disk plan; got ${capturePlan.kind}`);
|
|
12865
13000
|
}
|
|
12866
13001
|
resetCaptureAttemptProgress(job);
|
|
13002
|
+
const encodeInput = {
|
|
13003
|
+
job,
|
|
13004
|
+
log,
|
|
13005
|
+
outputPath: stagedOutputPath,
|
|
13006
|
+
framesDir,
|
|
13007
|
+
videoOnlyPath,
|
|
13008
|
+
width,
|
|
13009
|
+
height,
|
|
13010
|
+
needsAlpha,
|
|
13011
|
+
captureImageFormat: captureOptions.format ?? "jpeg",
|
|
13012
|
+
hasAudio,
|
|
13013
|
+
audioOutputPath,
|
|
13014
|
+
isPngSequence,
|
|
13015
|
+
isGif,
|
|
13016
|
+
preset,
|
|
13017
|
+
effectiveQuality,
|
|
13018
|
+
effectiveBitrate,
|
|
13019
|
+
enableChunkedEncode,
|
|
13020
|
+
chunkedEncodeSize,
|
|
13021
|
+
engineConfig: cfg,
|
|
13022
|
+
// Same value the streaming encoder above spreads — the disk and
|
|
13023
|
+
// chunked-concat encoders need an identical GOP lock for HLS.
|
|
13024
|
+
...hlsEncoderGopLock,
|
|
13025
|
+
abortSignal: executionSignal,
|
|
13026
|
+
assertNotAborted,
|
|
13027
|
+
onProgress
|
|
13028
|
+
};
|
|
13029
|
+
const overlap = !cfg.useDrawElement && workerSizing !== void 0 && canEncodeWhileCapturing(encodeInput, capturePlan.workerCount, workerSizing.cpuCount) ? encodeWhileCapturing(encodeInput, totalFrames) : null;
|
|
12867
13030
|
const captureFrameStart = Date.now();
|
|
12868
13031
|
const invokeDiskCapture = (diskPlan) => observeRenderStage(
|
|
12869
13032
|
observability,
|
|
@@ -12885,13 +13048,15 @@ async function executeRenderPipeline(input) {
|
|
|
12885
13048
|
createRenderVideoFrameInjector,
|
|
12886
13049
|
abortSignal: executionSignal,
|
|
12887
13050
|
assertNotAborted,
|
|
12888
|
-
onProgress
|
|
13051
|
+
onProgress,
|
|
13052
|
+
onFrameLanded: (frame) => overlap?.onFrameLanded(frame)
|
|
12889
13053
|
})
|
|
12890
13054
|
);
|
|
12891
13055
|
let captureRes;
|
|
12892
13056
|
try {
|
|
12893
13057
|
captureRes = await invokeDiskCapture(capturePlan);
|
|
12894
13058
|
} catch (err) {
|
|
13059
|
+
await overlap?.abort();
|
|
12895
13060
|
if (!isDrawElementVerificationError(err) && !isDrawElementCaptureError(err) || err instanceof RenderCancelledError || executionSignal?.aborted === true) {
|
|
12896
13061
|
throw err;
|
|
12897
13062
|
}
|
|
@@ -12960,33 +13125,7 @@ async function executeRenderPipeline(input) {
|
|
|
12960
13125
|
isGif,
|
|
12961
13126
|
chunkedEncode: enableChunkedEncode
|
|
12962
13127
|
}),
|
|
12963
|
-
() => runEncodeStage(
|
|
12964
|
-
job,
|
|
12965
|
-
log,
|
|
12966
|
-
outputPath: stagedOutputPath,
|
|
12967
|
-
framesDir,
|
|
12968
|
-
videoOnlyPath,
|
|
12969
|
-
width,
|
|
12970
|
-
height,
|
|
12971
|
-
needsAlpha,
|
|
12972
|
-
captureImageFormat: captureOptions.format ?? "jpeg",
|
|
12973
|
-
hasAudio,
|
|
12974
|
-
audioOutputPath,
|
|
12975
|
-
isPngSequence,
|
|
12976
|
-
isGif,
|
|
12977
|
-
preset,
|
|
12978
|
-
effectiveQuality,
|
|
12979
|
-
effectiveBitrate,
|
|
12980
|
-
enableChunkedEncode,
|
|
12981
|
-
chunkedEncodeSize,
|
|
12982
|
-
engineConfig: cfg,
|
|
12983
|
-
// Same value the streaming encoder above spreads — the disk and
|
|
12984
|
-
// chunked-concat encoders need an identical GOP lock for HLS.
|
|
12985
|
-
...hlsEncoderGopLock,
|
|
12986
|
-
abortSignal: executionSignal,
|
|
12987
|
-
assertNotAborted,
|
|
12988
|
-
onProgress
|
|
12989
|
-
})
|
|
13128
|
+
() => overlap ? overlap.finish() : runEncodeStage(encodeInput)
|
|
12990
13129
|
);
|
|
12991
13130
|
perfStages.encodeMs = encodeRes.encodeMs;
|
|
12992
13131
|
}
|
|
@@ -13034,7 +13173,9 @@ async function executeRenderPipeline(input) {
|
|
|
13034
13173
|
outputFormat,
|
|
13035
13174
|
durationSeconds: job.duration,
|
|
13036
13175
|
fps: fpsToNumber(job.config.fps),
|
|
13037
|
-
expectedFrames: captureTotalFrames
|
|
13176
|
+
expectedFrames: captureTotalFrames,
|
|
13177
|
+
width: outputWidth,
|
|
13178
|
+
height: outputHeight
|
|
13038
13179
|
})
|
|
13039
13180
|
);
|
|
13040
13181
|
const totalElapsed = Date.now() - pipelineStart;
|
|
@@ -13070,6 +13211,7 @@ async function executeRenderPipeline(input) {
|
|
|
13070
13211
|
drawElement: {
|
|
13071
13212
|
compileGate: deCompileGate,
|
|
13072
13213
|
clampReason: deClampReason,
|
|
13214
|
+
probeGateReason: deProbeGateReason,
|
|
13073
13215
|
workerInversion: deWorkerInversion,
|
|
13074
13216
|
preInversionWorkers: deWorkerInversion ? preRoutingWorkerCount : void 0,
|
|
13075
13217
|
compositionElementCount,
|
|
@@ -13622,6 +13764,29 @@ function buildChunkCaptureOptions(input) {
|
|
|
13622
13764
|
requiresWebGpu: compositionRequiresWebGpu(input.html)
|
|
13623
13765
|
};
|
|
13624
13766
|
}
|
|
13767
|
+
function shownDeferredFrameIndexes(planVideos, frames, fps) {
|
|
13768
|
+
const shown = /* @__PURE__ */ new Map();
|
|
13769
|
+
const deferred = planVideos.extracted.filter((video) => video.deferredRange);
|
|
13770
|
+
if (deferred.length === 0) return shown;
|
|
13771
|
+
const table = createFrameLookupTable(
|
|
13772
|
+
planVideos.videos,
|
|
13773
|
+
deferred.map((video) => ({
|
|
13774
|
+
...video,
|
|
13775
|
+
outputDir: "",
|
|
13776
|
+
framePaths: new Map(Array.from({ length: video.totalFrames }, (_, i) => [i, String(i)]))
|
|
13777
|
+
})),
|
|
13778
|
+
resolveRenderFpsConfig(fps).value
|
|
13779
|
+
);
|
|
13780
|
+
for (const frame of frames) {
|
|
13781
|
+
const globalTime = frame * fps.den / fps.num;
|
|
13782
|
+
for (const [videoId, payload] of table.getActiveFramePayloads(globalTime)) {
|
|
13783
|
+
const indexes = shown.get(videoId) ?? /* @__PURE__ */ new Set();
|
|
13784
|
+
indexes.add(payload.frameIndex);
|
|
13785
|
+
shown.set(videoId, indexes);
|
|
13786
|
+
}
|
|
13787
|
+
}
|
|
13788
|
+
return shown;
|
|
13789
|
+
}
|
|
13625
13790
|
async function extractDeferredVideoFramesForChunk(input) {
|
|
13626
13791
|
const deferred = input.planVideos.extracted.filter((video) => video.deferredRange);
|
|
13627
13792
|
const remoteSources = input.remoteSources ?? {};
|
|
@@ -13638,24 +13803,7 @@ async function extractDeferredVideoFramesForChunk(input) {
|
|
|
13638
13803
|
});
|
|
13639
13804
|
}
|
|
13640
13805
|
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
|
-
}
|
|
13806
|
+
const shown = shownDeferredFrameIndexes(input.planVideos, input.frames, input.fps);
|
|
13659
13807
|
return Promise.all(
|
|
13660
13808
|
deferred.map(async (video) => {
|
|
13661
13809
|
const outputDir = join27(input.outputRoot, video.videoId);
|
|
@@ -13681,7 +13829,8 @@ async function extractDeferredVideoFramesForChunk(input) {
|
|
|
13681
13829
|
fps: input.fps,
|
|
13682
13830
|
outputDir: input.outputRoot,
|
|
13683
13831
|
format: range.format,
|
|
13684
|
-
frameRanges: contiguousRuns(indexes)
|
|
13832
|
+
frameRanges: contiguousRuns(indexes),
|
|
13833
|
+
shownBox: input.shownBoxes?.get(video.videoId)
|
|
13685
13834
|
},
|
|
13686
13835
|
void 0,
|
|
13687
13836
|
input.cfg
|
|
@@ -14333,6 +14482,20 @@ function withDuration(buf, target, duration) {
|
|
|
14333
14482
|
function timescaleOf(buf, header) {
|
|
14334
14483
|
return buf.readUInt32BE(header.bodyStart + (buf[header.bodyStart] === 1 ? 20 : 12));
|
|
14335
14484
|
}
|
|
14485
|
+
var TRACK_ID_AT = { tkhd: [12, 20], mvhd: [96, 108] };
|
|
14486
|
+
function idOf(buf, target) {
|
|
14487
|
+
return buf.readUInt32BE(
|
|
14488
|
+
target.bodyStart + TRACK_ID_AT[target.type][buf[target.bodyStart] === 1 ? 1 : 0]
|
|
14489
|
+
);
|
|
14490
|
+
}
|
|
14491
|
+
function withId(boxBytes, type, id) {
|
|
14492
|
+
const header = boxAt(boxBytes, 0, 0, boxBytes.length);
|
|
14493
|
+
boxBytes.writeUInt32BE(
|
|
14494
|
+
id,
|
|
14495
|
+
header.bodyStart + TRACK_ID_AT[type][boxBytes[header.bodyStart] === 1 ? 1 : 0]
|
|
14496
|
+
);
|
|
14497
|
+
return boxBytes;
|
|
14498
|
+
}
|
|
14336
14499
|
function buildStbl(stsd, track) {
|
|
14337
14500
|
const stts = runs(track.durations);
|
|
14338
14501
|
const stsc = [];
|
|
@@ -14374,24 +14537,48 @@ function planTracksOf(tracks, plan2, index) {
|
|
|
14374
14537
|
}
|
|
14375
14538
|
return matched;
|
|
14376
14539
|
}
|
|
14377
|
-
function
|
|
14378
|
-
const
|
|
14379
|
-
const
|
|
14540
|
+
function sourceTracks(layouts, audio) {
|
|
14541
|
+
const chunkPlan = readTracks(layouts[0].moov);
|
|
14542
|
+
const audioTracks = audio ? readTracks(audio.moov) : [];
|
|
14543
|
+
if (audio && (audioTracks.length !== 1 || audioTracks[0].handler !== "soun")) {
|
|
14544
|
+
throw new Error("[mp4Stitch] the separate audio file must hold one audio track");
|
|
14545
|
+
}
|
|
14546
|
+
const plan2 = [...chunkPlan, ...audioTracks];
|
|
14547
|
+
const chunks = layouts.map((layout, i) => {
|
|
14548
|
+
const tracks = readTracks(layout.moov);
|
|
14549
|
+
if (audio && tracks.some((track) => track.handler === "soun")) {
|
|
14550
|
+
throw new Error(`[mp4Stitch] chunk ${i} carries its own audio`);
|
|
14551
|
+
}
|
|
14552
|
+
return planTracksOf(tracks, plan2, i);
|
|
14553
|
+
});
|
|
14554
|
+
return {
|
|
14555
|
+
plan: plan2,
|
|
14556
|
+
chunkTrackCount: chunkPlan.length,
|
|
14557
|
+
sources: audio ? [[...chunkPlan.map(() => null), audioTracks[0]], ...chunks] : chunks
|
|
14558
|
+
};
|
|
14559
|
+
}
|
|
14560
|
+
function buildStitchedHeader(layouts, audio) {
|
|
14561
|
+
const { plan: plan2, chunkTrackCount, sources } = sourceTracks(layouts, audio);
|
|
14562
|
+
const sourceLayouts = audio ? [audio, ...layouts] : layouts;
|
|
14380
14563
|
const payloadBases = [];
|
|
14381
14564
|
let payloadBytes = 0;
|
|
14382
|
-
for (const layout of
|
|
14565
|
+
for (const layout of sourceLayouts) {
|
|
14383
14566
|
payloadBases.push(payloadBytes);
|
|
14384
14567
|
payloadBytes += layout.payloadEnd - layout.payloadStart;
|
|
14385
14568
|
}
|
|
14386
14569
|
const template = layouts[0].moov;
|
|
14387
14570
|
const root = boxAt(template, 0, 0, template.length);
|
|
14388
|
-
const
|
|
14571
|
+
const mvhd = child(template, root, "mvhd");
|
|
14572
|
+
const movieTimescale = timescaleOf(template, mvhd);
|
|
14573
|
+
const chunkTrackIds = plan2.slice(0, chunkTrackCount).map((track) => idOf(template, child(template, track.trak, "tkhd")));
|
|
14574
|
+
const audioTrackId = Math.max(...chunkTrackIds) + 1;
|
|
14389
14575
|
const buildMoov = (dataStart2) => {
|
|
14390
14576
|
const traks = plan2.map((track, t) => {
|
|
14391
|
-
const parts =
|
|
14577
|
+
const parts = sources.flatMap((tracks, chunk) => {
|
|
14392
14578
|
const part = tracks[t];
|
|
14393
14579
|
return part ? [{ ...part, chunk }] : [];
|
|
14394
14580
|
});
|
|
14581
|
+
const moov = t < chunkTrackCount ? template : audio.moov;
|
|
14395
14582
|
const merged = {
|
|
14396
14583
|
durations: parts.flatMap((part) => part.durations),
|
|
14397
14584
|
sizes: parts.flatMap((part) => part.sizes),
|
|
@@ -14400,9 +14587,9 @@ function buildStitchedHeader(layouts) {
|
|
|
14400
14587
|
chunkOffsets: parts.flatMap(
|
|
14401
14588
|
(part) => part.chunkOffsets.map((offset) => {
|
|
14402
14589
|
const i = part.chunk;
|
|
14403
|
-
const { payloadStart, payloadEnd } =
|
|
14590
|
+
const { payloadStart, payloadEnd } = sourceLayouts[i];
|
|
14404
14591
|
if (offset < payloadStart || offset >= payloadEnd) {
|
|
14405
|
-
throw new Error(`[mp4Stitch]
|
|
14592
|
+
throw new Error(`[mp4Stitch] source ${i} has samples outside its mdat`);
|
|
14406
14593
|
}
|
|
14407
14594
|
return offset - payloadStart + payloadBases[i] + dataStart2;
|
|
14408
14595
|
})
|
|
@@ -14418,20 +14605,25 @@ function buildStitchedHeader(layouts) {
|
|
|
14418
14605
|
elst.writeBigInt64BE(BigInt(track.mediaTime), 12);
|
|
14419
14606
|
elst.writeUInt32BE(65536, 20);
|
|
14420
14607
|
const edts = track.mediaTime ? box("edts", fullBox("elst", 1, elst)) : Buffer.alloc(0);
|
|
14421
|
-
const
|
|
14422
|
-
|
|
14608
|
+
const tkhdOf = (tkhd) => {
|
|
14609
|
+
const timed = withDuration(moov, tkhd, shown);
|
|
14610
|
+
return t < chunkTrackCount ? timed : withId(timed, "tkhd", audioTrackId);
|
|
14611
|
+
};
|
|
14612
|
+
const trak = rebuild(moov, track.trak, {
|
|
14613
|
+
tkhd: (tkhd) => Buffer.concat([tkhdOf(tkhd), edts]),
|
|
14423
14614
|
edts: () => Buffer.alloc(0),
|
|
14424
|
-
mdia: (mdia) => rebuild(
|
|
14425
|
-
mdhd: (mdhd) => withDuration(
|
|
14426
|
-
minf: (minf) => rebuild(
|
|
14615
|
+
mdia: (mdia) => rebuild(moov, mdia, {
|
|
14616
|
+
mdhd: (mdhd) => withDuration(moov, mdhd, mediaDuration),
|
|
14617
|
+
minf: (minf) => rebuild(moov, minf, { stbl: () => buildStbl(track.stsd, merged) })
|
|
14427
14618
|
})
|
|
14428
14619
|
});
|
|
14429
14620
|
return { trak, shown };
|
|
14430
14621
|
});
|
|
14431
14622
|
let next = 0;
|
|
14623
|
+
const movieHeader = withDuration(template, mvhd, Math.max(...traks.map((t) => t.shown)));
|
|
14432
14624
|
return rebuild(template, root, {
|
|
14433
|
-
mvhd: (
|
|
14434
|
-
trak: () => traks[next
|
|
14625
|
+
mvhd: () => audio ? withId(movieHeader, "mvhd", audioTrackId + 1) : movieHeader,
|
|
14626
|
+
trak: () => ++next < chunkTrackCount ? traks[next - 1].trak : Buffer.concat(traks.slice(next - 1).map((t) => t.trak))
|
|
14435
14627
|
});
|
|
14436
14628
|
};
|
|
14437
14629
|
const ftyp = layouts[0].ftyp;
|
|
@@ -14464,15 +14656,16 @@ async function copyPayload(path, layout, index, out) {
|
|
|
14464
14656
|
);
|
|
14465
14657
|
}
|
|
14466
14658
|
}
|
|
14467
|
-
async function writeStitchedMp4(chunkPaths, outputPath) {
|
|
14468
|
-
const
|
|
14469
|
-
const
|
|
14659
|
+
async function writeStitchedMp4(chunkPaths, outputPath, audioPath) {
|
|
14660
|
+
const sourcePaths = audioPath ? [audioPath, ...chunkPaths] : chunkPaths;
|
|
14661
|
+
const layouts = await Promise.all(sourcePaths.map((path) => readMp4Layout(fileRange(path))));
|
|
14662
|
+
const header = audioPath ? buildStitchedHeader(layouts.slice(1), layouts[0]) : buildStitchedHeader(layouts);
|
|
14470
14663
|
mkdirSync10(dirname11(outputPath), { recursive: true });
|
|
14471
14664
|
const workDir = mkdtempSync4(`${outputPath}.stitch-`);
|
|
14472
14665
|
const out = createWriteStream(join30(workDir, "out.mp4"));
|
|
14473
14666
|
try {
|
|
14474
14667
|
out.write(header);
|
|
14475
|
-
for (const [i, path] of
|
|
14668
|
+
for (const [i, path] of sourcePaths.entries()) await copyPayload(path, layouts[i], i, out);
|
|
14476
14669
|
out.end();
|
|
14477
14670
|
await finished(out);
|
|
14478
14671
|
renameSync4(join30(workDir, "out.mp4"), outputPath);
|
|
@@ -15043,7 +15236,8 @@ function buildLockedRenderConfig(input) {
|
|
|
15043
15236
|
chunkCount: input.chunkCount,
|
|
15044
15237
|
runtimeEnv: input.runtimeEnv,
|
|
15045
15238
|
variables: config.variables,
|
|
15046
|
-
...input.chunksCarryAudio ? { chunksCarryAudio: true } : {}
|
|
15239
|
+
...input.chunksCarryAudio ? { chunksCarryAudio: true } : {},
|
|
15240
|
+
...input.separateAudio ? { separateAudio: true } : {}
|
|
15047
15241
|
};
|
|
15048
15242
|
}
|
|
15049
15243
|
function carriesChunkAudio(config, options) {
|
|
@@ -15138,8 +15332,10 @@ function createVideoSourceShipper(input) {
|
|
|
15138
15332
|
return result;
|
|
15139
15333
|
};
|
|
15140
15334
|
}
|
|
15141
|
-
|
|
15142
|
-
|
|
15335
|
+
function plansSeparateAudio(config, options) {
|
|
15336
|
+
return options.deferAudio === true && config.format === "mp4" && config.cfr !== true;
|
|
15337
|
+
}
|
|
15338
|
+
async function compilePlanComposition(projectDir, config, planDir, options) {
|
|
15143
15339
|
rejectUnsupportedDistributedFormat(config);
|
|
15144
15340
|
validateNoGpuEncode({
|
|
15145
15341
|
useGpu: false,
|
|
@@ -15267,7 +15463,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15267
15463
|
if (probeResult.fileServer) closeFileServerSafely(probeResult.fileServer, "plan", log);
|
|
15268
15464
|
if (probeResult.probeSession) {
|
|
15269
15465
|
try {
|
|
15270
|
-
const { closeCaptureSession: closeCaptureSession2 } = await import("./src-
|
|
15466
|
+
const { closeCaptureSession: closeCaptureSession2 } = await import("./src-4UYM2K3S.js");
|
|
15271
15467
|
await closeCaptureSession2(probeResult.probeSession);
|
|
15272
15468
|
} catch (err) {
|
|
15273
15469
|
log.warn("[plan] probe session close failed", {
|
|
@@ -15275,6 +15471,100 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15275
15471
|
});
|
|
15276
15472
|
}
|
|
15277
15473
|
}
|
|
15474
|
+
return {
|
|
15475
|
+
projectDir,
|
|
15476
|
+
log,
|
|
15477
|
+
sizeLimitBytes,
|
|
15478
|
+
abortSignal,
|
|
15479
|
+
assertNotAborted,
|
|
15480
|
+
cfg,
|
|
15481
|
+
job,
|
|
15482
|
+
workDir,
|
|
15483
|
+
compiledDir,
|
|
15484
|
+
finalCompiledDir,
|
|
15485
|
+
remoteFiles,
|
|
15486
|
+
urlByAbsentLocalPath,
|
|
15487
|
+
localPathByUrl,
|
|
15488
|
+
compileResult,
|
|
15489
|
+
compiled,
|
|
15490
|
+
composition,
|
|
15491
|
+
deviceScaleFactor,
|
|
15492
|
+
forceScreenshot,
|
|
15493
|
+
width,
|
|
15494
|
+
height,
|
|
15495
|
+
probeResult,
|
|
15496
|
+
totalFrames
|
|
15497
|
+
};
|
|
15498
|
+
}
|
|
15499
|
+
function mixPlanAudio(c, compiledDir, seconds, pcmPath) {
|
|
15500
|
+
return runAudioStage({
|
|
15501
|
+
projectDir: c.projectDir,
|
|
15502
|
+
workDir: c.workDir,
|
|
15503
|
+
compiledDir,
|
|
15504
|
+
urlByAbsentLocalPath: c.urlByAbsentLocalPath,
|
|
15505
|
+
duration: seconds,
|
|
15506
|
+
ffmpegProcessTimeout: c.cfg.ffmpegProcessTimeout,
|
|
15507
|
+
audioGain: c.cfg.audioGain,
|
|
15508
|
+
audios: c.composition.audios,
|
|
15509
|
+
masterFxChain: c.composition.masterFxChain,
|
|
15510
|
+
...pcmPath ? { keepEncoderInputAt: pcmPath } : {},
|
|
15511
|
+
abortSignal: c.abortSignal,
|
|
15512
|
+
assertNotAborted: c.assertNotAborted
|
|
15513
|
+
});
|
|
15514
|
+
}
|
|
15515
|
+
async function extractPlanVideos(c, deferRangeExtraction) {
|
|
15516
|
+
const extractResult = await runExtractVideosStage({
|
|
15517
|
+
projectDir: c.projectDir,
|
|
15518
|
+
compiledDir: c.compiledDir,
|
|
15519
|
+
job: c.job,
|
|
15520
|
+
cfg: c.cfg,
|
|
15521
|
+
composition: c.composition,
|
|
15522
|
+
abortSignal: c.abortSignal,
|
|
15523
|
+
assertNotAborted: c.assertNotAborted,
|
|
15524
|
+
materializeSymlinks: true,
|
|
15525
|
+
deferRangeExtraction,
|
|
15526
|
+
urlByAbsentLocalPath: c.urlByAbsentLocalPath
|
|
15527
|
+
});
|
|
15528
|
+
if (extractResult.failureToEnforce) throw extractResult.failureToEnforce;
|
|
15529
|
+
if (extractResult.extractionResult) {
|
|
15530
|
+
assertVideoExtractionSucceeded(extractResult.extractionResult);
|
|
15531
|
+
}
|
|
15532
|
+
return extractResult;
|
|
15533
|
+
}
|
|
15534
|
+
async function holdPlanAudioPeak(c, audioPath, pcmPath, seconds) {
|
|
15535
|
+
const peak = await constrainAacTruePeak({
|
|
15536
|
+
audioPath,
|
|
15537
|
+
...existsSync20(pcmPath) ? { sourcePath: pcmPath } : {},
|
|
15538
|
+
targetDurationSeconds: seconds,
|
|
15539
|
+
signal: c.abortSignal,
|
|
15540
|
+
timeoutMs: c.cfg.ffmpegProcessTimeout
|
|
15541
|
+
}).finally(() => rmSync10(pcmPath, { force: true }));
|
|
15542
|
+
if (!peak.success) throw encoderFailureError("[plan] audio true-peak check failed", peak);
|
|
15543
|
+
}
|
|
15544
|
+
async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, options = {}) {
|
|
15545
|
+
const planDir = executionPlanDir;
|
|
15546
|
+
const c = await compilePlanComposition(projectDir, config, planDir, options);
|
|
15547
|
+
const {
|
|
15548
|
+
log,
|
|
15549
|
+
sizeLimitBytes,
|
|
15550
|
+
cfg,
|
|
15551
|
+
job,
|
|
15552
|
+
workDir,
|
|
15553
|
+
compiledDir,
|
|
15554
|
+
finalCompiledDir,
|
|
15555
|
+
remoteFiles,
|
|
15556
|
+
urlByAbsentLocalPath,
|
|
15557
|
+
localPathByUrl,
|
|
15558
|
+
compileResult,
|
|
15559
|
+
compiled,
|
|
15560
|
+
composition,
|
|
15561
|
+
deviceScaleFactor,
|
|
15562
|
+
forceScreenshot,
|
|
15563
|
+
width,
|
|
15564
|
+
height,
|
|
15565
|
+
probeResult,
|
|
15566
|
+
totalFrames
|
|
15567
|
+
} = c;
|
|
15278
15568
|
const megapixels = compileResult.outputWidth * compileResult.outputHeight / 1e6;
|
|
15279
15569
|
let maxParallel = resolveMaxParallelChunks(config, totalFrames, megapixels, log);
|
|
15280
15570
|
const measureFrameCost = chunkSizingUsesFrameCost(config) && planNeedsFrameCostMeasurement(compiled.html);
|
|
@@ -15285,24 +15575,9 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15285
15575
|
observedAt: "pre-extract",
|
|
15286
15576
|
log
|
|
15287
15577
|
});
|
|
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
|
-
});
|
|
15578
|
+
let stageStarted = Date.now();
|
|
15579
|
+
const extractResult = await extractPlanVideos(c, options.deferVideoExtraction);
|
|
15301
15580
|
logPlanStage(log, "extract", stageStarted);
|
|
15302
|
-
if (extractResult.failureToEnforce) throw extractResult.failureToEnforce;
|
|
15303
|
-
if (extractResult.extractionResult) {
|
|
15304
|
-
assertVideoExtractionSucceeded(extractResult.extractionResult);
|
|
15305
|
-
}
|
|
15306
15581
|
const stagedVideoFrames = join33(compiledDir, "__hyperframes_video_frames");
|
|
15307
15582
|
const videoFramesDst = join33(planDir, "video-frames");
|
|
15308
15583
|
if (existsSync20(videoFramesDst)) rmSync10(videoFramesDst, { recursive: true, force: true });
|
|
@@ -15358,23 +15633,18 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15358
15633
|
"utf-8"
|
|
15359
15634
|
);
|
|
15360
15635
|
const digests = options.digests ?? /* @__PURE__ */ new Map();
|
|
15361
|
-
const
|
|
15362
|
-
const
|
|
15636
|
+
const separateAudio = plansSeparateAudio(config, options);
|
|
15637
|
+
const chunksCarryAudio = !separateAudio && carriesChunkAudio(config, options);
|
|
15638
|
+
const audioSeconds = chunksCarryAudio ? totalFrames / config.fps : probeResult.duration;
|
|
15639
|
+
const planMixPcmPath = join33(workDir, "plan-mix.wav");
|
|
15363
15640
|
stageStarted = Date.now();
|
|
15364
15641
|
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)),
|
|
15642
|
+
separateAudio ? null : mixPlanAudio(
|
|
15643
|
+
c,
|
|
15644
|
+
finalCompiledDir,
|
|
15645
|
+
audioSeconds,
|
|
15646
|
+
chunksCarryAudio ? planMixPcmPath : void 0
|
|
15647
|
+
).finally(() => logPlanStage(log, "audio", stageStarted)),
|
|
15378
15648
|
(async () => {
|
|
15379
15649
|
for (const dir of [finalCompiledDir, videoFramesDst, videoSourcesDir]) {
|
|
15380
15650
|
await prehashPlanFiles(dir, digests);
|
|
@@ -15424,22 +15694,16 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15424
15694
|
);
|
|
15425
15695
|
const chunks = buildChunkSlices(totalFrames, chunkCount, effectiveChunkSize);
|
|
15426
15696
|
const audioResult = audioOutcome.value;
|
|
15427
|
-
if (audioResult
|
|
15697
|
+
if (audioResult?.audioError) {
|
|
15428
15698
|
applyDistributedAudioWarningPolicy(job, audioResult.audioError, audioResult.audioFailures, log);
|
|
15429
15699
|
}
|
|
15430
15700
|
const planAudioPath = join33(planDir, PLAN_AUDIO_RELATIVE_PATH);
|
|
15431
|
-
if (audioResult
|
|
15701
|
+
if (audioResult?.hasAudio && existsSync20(audioResult.audioOutputPath)) {
|
|
15432
15702
|
renameSync5(audioResult.audioOutputPath, planAudioPath);
|
|
15433
15703
|
}
|
|
15434
|
-
if (
|
|
15704
|
+
if (chunksCarryAudio && existsSync20(planAudioPath)) {
|
|
15435
15705
|
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);
|
|
15706
|
+
await holdPlanAudioPeak(c, planAudioPath, planMixPcmPath, audioSeconds);
|
|
15443
15707
|
logPlanStage(log, "audio-peak", stageStarted);
|
|
15444
15708
|
if (options.sliceChunkAudio) {
|
|
15445
15709
|
stageStarted = Date.now();
|
|
@@ -15465,7 +15729,8 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15465
15729
|
effectiveChunkSize,
|
|
15466
15730
|
chunkCount,
|
|
15467
15731
|
runtimeEnv,
|
|
15468
|
-
chunksCarryAudio
|
|
15732
|
+
chunksCarryAudio,
|
|
15733
|
+
separateAudio
|
|
15469
15734
|
});
|
|
15470
15735
|
const compositionJson = {
|
|
15471
15736
|
durationSeconds: job.duration ?? 0,
|
|
@@ -15510,7 +15775,7 @@ async function buildLocalExecutionPlan(projectDir, config, executionPlanDir, opt
|
|
|
15510
15775
|
fontSnapshotSha,
|
|
15511
15776
|
durationSeconds: job.duration ?? 0,
|
|
15512
15777
|
totalFrames,
|
|
15513
|
-
hasAudio: audioResult
|
|
15778
|
+
hasAudio: audioResult?.hasAudio ?? false,
|
|
15514
15779
|
digests
|
|
15515
15780
|
});
|
|
15516
15781
|
logPlanStage(log, "freeze", stageStarted);
|
|
@@ -16861,7 +17126,7 @@ function startServer(options = {}) {
|
|
|
16861
17126
|
});
|
|
16862
17127
|
async function shutdown(signal) {
|
|
16863
17128
|
log.info(`Received ${signal}, shutting down`);
|
|
16864
|
-
const { drainBrowserPool } = await import("./src-
|
|
17129
|
+
const { drainBrowserPool } = await import("./src-4UYM2K3S.js");
|
|
16865
17130
|
await drainBrowserPool().catch(() => {
|
|
16866
17131
|
});
|
|
16867
17132
|
const handle = await Promise.race([
|
|
@@ -17485,7 +17750,8 @@ async function planV2WithPublisher(projectDir, config, publisher, options = {})
|
|
|
17485
17750
|
)
|
|
17486
17751
|
),
|
|
17487
17752
|
chunksCarryAudio: options.chunksCarryAudio,
|
|
17488
|
-
sliceChunkAudio: true
|
|
17753
|
+
sliceChunkAudio: true,
|
|
17754
|
+
deferAudio: options.deferAudio
|
|
17489
17755
|
});
|
|
17490
17756
|
return await publishExecutionPlan(stagingRoot, publisher, { digests, log: config.logger });
|
|
17491
17757
|
} catch (error) {
|
|
@@ -17811,7 +18077,8 @@ async function assemble(planDir, chunkOutputs, audioPath, outputPath, options) {
|
|
|
17811
18077
|
return mergePngFrameDirs(chunkPaths, outputPath, plan2.totalFrames, audioPath, start);
|
|
17812
18078
|
}
|
|
17813
18079
|
if (chunksAreStitchedMp4(planDir, cfr)) {
|
|
17814
|
-
|
|
18080
|
+
const separateAudio = stitchesSeparateAudio(planDir) && audioPath !== null;
|
|
18081
|
+
await writeStitchedMp4(chunkPaths, outputPath, separateAudio ? audioPath : void 0);
|
|
17815
18082
|
return {
|
|
17816
18083
|
outputPath,
|
|
17817
18084
|
durationMs: Date.now() - start,
|
|
@@ -18009,16 +18276,20 @@ async function runAssembleFfmpeg(args, step, signal, timeout) {
|
|
|
18009
18276
|
}
|
|
18010
18277
|
}
|
|
18011
18278
|
function chunksAreStitchedMp4(planDir, cfr) {
|
|
18012
|
-
|
|
18279
|
+
const { chunksCarryAudio, separateAudio } = lockedAudio(planDir);
|
|
18280
|
+
if (!chunksCarryAudio && !separateAudio) return false;
|
|
18013
18281
|
if (cfr) {
|
|
18014
|
-
throw new Error("[assemble] cfr=true cannot re-encode a plan whose mp4 chunks
|
|
18282
|
+
throw new Error("[assemble] cfr=true cannot re-encode a plan whose mp4 chunks are stitched");
|
|
18015
18283
|
}
|
|
18016
18284
|
return true;
|
|
18017
18285
|
}
|
|
18018
|
-
function
|
|
18286
|
+
function stitchesSeparateAudio(planDir) {
|
|
18287
|
+
return lockedAudio(planDir).separateAudio === true;
|
|
18288
|
+
}
|
|
18289
|
+
function lockedAudio(planDir) {
|
|
18019
18290
|
const encoderJsonPath = join40(planDir, "meta", "encoder.json");
|
|
18020
|
-
if (!existsSync26(encoderJsonPath)) return
|
|
18021
|
-
return JSON.parse(readFileSync13(encoderJsonPath, "utf-8"))
|
|
18291
|
+
if (!existsSync26(encoderJsonPath)) return {};
|
|
18292
|
+
return JSON.parse(readFileSync13(encoderJsonPath, "utf-8"));
|
|
18022
18293
|
}
|
|
18023
18294
|
function readCfrEncoder(planDir, format) {
|
|
18024
18295
|
if (format !== "mp4") {
|
|
@@ -18097,6 +18368,12 @@ function validatePlanVideosForChunk(value) {
|
|
|
18097
18368
|
);
|
|
18098
18369
|
}
|
|
18099
18370
|
}
|
|
18371
|
+
var MIN_FRAMES_PER_CHUNK_BROWSER = 20;
|
|
18372
|
+
function resolveChunkCaptureWorkers(framesInChunk, machineSized, maxCaptureWorkers) {
|
|
18373
|
+
if (maxCaptureWorkers === void 0) return machineSized;
|
|
18374
|
+
const byFrames = Math.floor(framesInChunk / MIN_FRAMES_PER_CHUNK_BROWSER);
|
|
18375
|
+
return Math.max(machineSized, Math.floor(Math.min(maxCaptureWorkers, byFrames)));
|
|
18376
|
+
}
|
|
18100
18377
|
function resolveChunkFrameRange(slice, chunkIndex, frameRange) {
|
|
18101
18378
|
if (frameRange === void 0) return { startFrame: slice.startFrame, endFrame: slice.endFrame };
|
|
18102
18379
|
const { startFrame, endFrame } = frameRange;
|
|
@@ -18302,34 +18579,15 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18302
18579
|
const framesDir = join41(workDir, "captured-frames");
|
|
18303
18580
|
mkdirSync17(framesDir, { recursive: true });
|
|
18304
18581
|
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
|
-
}) : [];
|
|
18582
|
+
const chunkFrameNumbers = Array.from({ length: framesInChunk }, (_, i) => range.startFrame + i);
|
|
18583
|
+
const chunkFps = { num: plan2.dimensions.fpsNum, den: plan2.dimensions.fpsDen };
|
|
18584
|
+
const deferredVideos = planVideos?.extracted.filter((video) => video.deferredRange) ?? [];
|
|
18585
|
+
const shownFrames = planVideos ? shownDeferredFrameIndexes(planVideos, chunkFrameNumbers, chunkFps) : /* @__PURE__ */ new Map();
|
|
18314
18586
|
const remoteVideoIds = new Set(
|
|
18315
18587
|
planVideos?.extracted.filter(
|
|
18316
18588
|
(video) => video.deferredRange && Object.hasOwn(remoteSources, video.deferredRange.sourcePath)
|
|
18317
18589
|
).map((video) => video.videoId)
|
|
18318
18590
|
);
|
|
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
18591
|
const fileServer = await createFileServer({
|
|
18334
18592
|
projectDir: compiledDir,
|
|
18335
18593
|
compiledDir,
|
|
@@ -18345,10 +18603,18 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18345
18603
|
videoCount: planVideos?.videos.length ?? 0,
|
|
18346
18604
|
html: readFileSync14(join41(compiledDir, "index.html"), "utf-8"),
|
|
18347
18605
|
// The plan ships a deferred source only to chunks that show it; don't wait on the rest.
|
|
18348
|
-
skipReadinessVideoIds:
|
|
18349
|
-
|
|
18606
|
+
skipReadinessVideoIds: deferredVideos.filter(
|
|
18607
|
+
(video) => !shownFrames.get(video.videoId)?.size || remoteVideoIds.has(video.videoId)
|
|
18608
|
+
).map((video) => video.videoId),
|
|
18609
|
+
videoMetadataHints: collectVideoMetadataHints(
|
|
18610
|
+
deferredVideos.filter((video) => remoteVideoIds.has(video.videoId))
|
|
18611
|
+
)
|
|
18350
18612
|
});
|
|
18351
|
-
const chunkWorkerCount =
|
|
18613
|
+
const chunkWorkerCount = resolveChunkCaptureWorkers(
|
|
18614
|
+
framesInChunk,
|
|
18615
|
+
calculateOptimalWorkers(framesInChunk, void 0, cfg),
|
|
18616
|
+
options?.maxCaptureWorkers
|
|
18617
|
+
);
|
|
18352
18618
|
let session = null;
|
|
18353
18619
|
let outputKind;
|
|
18354
18620
|
let framesEncoded = 0;
|
|
@@ -18359,6 +18625,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18359
18625
|
const capturePerfs = [];
|
|
18360
18626
|
const captureAttempts = [];
|
|
18361
18627
|
let forceScreenshotForChunk = encoder.forceScreenshot;
|
|
18628
|
+
let shownBoxes;
|
|
18362
18629
|
try {
|
|
18363
18630
|
if (chunkWorkerCount === 1 || !forceScreenshotForChunk) {
|
|
18364
18631
|
const bootStarted = Date.now();
|
|
@@ -18369,6 +18636,11 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18369
18636
|
cfg
|
|
18370
18637
|
);
|
|
18371
18638
|
sessionBootMs = Date.now() - bootStarted;
|
|
18639
|
+
shownBoxes = await measureVideoShownBoxes(
|
|
18640
|
+
session.page,
|
|
18641
|
+
[...shownFrames.keys()],
|
|
18642
|
+
chunkFrameNumbers.map((frame) => frame * chunkFps.den / chunkFps.num)
|
|
18643
|
+
);
|
|
18372
18644
|
const browserSelectedScreenshot = session.launchCaptureMode === "screenshot";
|
|
18373
18645
|
const beginFrameStalled = !browserSelectedScreenshot && await beginFrameSessionNeedsScreenshotFallback(session);
|
|
18374
18646
|
if (browserSelectedScreenshot) {
|
|
@@ -18410,6 +18682,29 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18410
18682
|
session = null;
|
|
18411
18683
|
}
|
|
18412
18684
|
}
|
|
18685
|
+
const deferredVideoFrames = planVideos ? await extractDeferredVideoFramesForChunk({
|
|
18686
|
+
planDir,
|
|
18687
|
+
planVideos,
|
|
18688
|
+
frames: chunkFrameNumbers,
|
|
18689
|
+
fps: chunkFps,
|
|
18690
|
+
outputRoot: videoFramesDir,
|
|
18691
|
+
cfg,
|
|
18692
|
+
remoteSources,
|
|
18693
|
+
shownBoxes
|
|
18694
|
+
}) : [];
|
|
18695
|
+
const videoFrameLookup = planVideos && planVideos.extracted.length > 0 ? createFrameLookupTable(
|
|
18696
|
+
planVideos.videos,
|
|
18697
|
+
[
|
|
18698
|
+
...rebuildExtractedFramesFromPlanDir(
|
|
18699
|
+
planDir,
|
|
18700
|
+
planVideos.extracted.filter((video) => !video.deferredRange),
|
|
18701
|
+
v2Manifest === null ? "dense-v1" : "sparse-v2"
|
|
18702
|
+
),
|
|
18703
|
+
...deferredVideoFrames
|
|
18704
|
+
],
|
|
18705
|
+
resolveRenderFpsConfig(job.config.fps).value
|
|
18706
|
+
) : null;
|
|
18707
|
+
const createChunkVideoFrameInjector = createChunkVideoFrameInjectorFactory(videoFrameLookup);
|
|
18413
18708
|
const captureStarted = Date.now();
|
|
18414
18709
|
captureMode = await runCaptureWithScreenshotFallback({
|
|
18415
18710
|
forceScreenshot: forceScreenshotForChunk,
|
|
@@ -18600,6 +18895,8 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath, options) {
|
|
|
18600
18895
|
encodeStageMs,
|
|
18601
18896
|
workers: chunkWorkerCount,
|
|
18602
18897
|
captureMode,
|
|
18898
|
+
// Device-pixel box each video's frames were extracted to cover; a video not listed kept full size.
|
|
18899
|
+
videoShownBoxes: Object.fromEntries(shownBoxes ?? []),
|
|
18603
18900
|
sha256,
|
|
18604
18901
|
outputKind,
|
|
18605
18902
|
producerVersion: plan2.producerVersion,
|
|
@@ -18669,9 +18966,10 @@ async function assembleV2(planV2Dir, chunkPaths, outputPath, options) {
|
|
|
18669
18966
|
}
|
|
18670
18967
|
|
|
18671
18968
|
// ../producer/src/services/distributed/projectHash.ts
|
|
18672
|
-
import { readdirSync as readdirSync12,
|
|
18969
|
+
import { closeSync as closeSync8, openSync as openSync7, readdirSync as readdirSync12, readSync as readSync5, realpathSync as realpathSync2, statSync as statSync11 } from "fs";
|
|
18673
18970
|
import { createHash as createHash7 } from "crypto";
|
|
18674
18971
|
import { join as join43 } from "path";
|
|
18972
|
+
var READ_CHUNK_BYTES = 256 * 1024;
|
|
18675
18973
|
|
|
18676
18974
|
export {
|
|
18677
18975
|
createConsoleLogger,
|