diff --git a/scripts/patch_avci_classes.py b/scripts/patch_avci_classes.py new file mode 100644 index 0000000..27180b6 --- /dev/null +++ b/scripts/patch_avci_classes.py @@ -0,0 +1,113 @@ +import sys + +path = '/opt/wild-dragon/services/capture/src/capture-manager.js' +src = open(path).read() + +patches = [ + # 1. Replace static GROWING_VIDEO_ELEMENTARY_ARGS with a function + ( + """const GROWING_VIDEO_ELEMENTARY_ARGS = [ + '-c:v', 'libx264', '-profile:v', 'high422', '-level', '4.2', + '-preset', 'ultrafast', '-tune', 'zerolatency', + '-pix_fmt', 'yuv422p10le', + '-x264-params', 'avcintra-class=100:bframes=0:keyint=1:scenecut=0', + '-aud', '1', +]; +const GROWING_DEFAULT_BITRATE = '25M';""", + """// AVC-Intra elementary encode args per class (50 / 100 / 200). +const GROWING_AVCI_CLASS = { avci50: 50, avci100: 100, avci200: 200 }; +function growingVideoElementaryArgs(codec) { + const cls = GROWING_AVCI_CLASS[codec] || 100; + return [ + '-c:v', 'libx264', '-profile:v', 'high422', '-level', '4.2', + '-preset', 'ultrafast', '-tune', 'zerolatency', + '-pix_fmt', 'yuv422p10le', + '-x264-params', `avcintra-class=${cls}:bframes=0:keyint=1:scenecut=0`, + '-aud', '1', + ]; +} +const GROWING_DEFAULT_BITRATE = '25M';""", + 'GROWING_VIDEO_ELEMENTARY_ARGS -> growingVideoElementaryArgs()', + ), + # 2. growingCodec() / growingExtFor() — 4-way + ( + """const growingCodec = () => (process.env.GROWING_CODEC === 'hevc_nvenc' ? 'hevc_nvenc' : 'avci100'); +// File extension per growing codec. +const growingExtFor = (codec) => (codec === 'hevc_nvenc' ? 'mov' : 'mxf');""", + """// Valid growing codec values: 'avci50' | 'avci100' | 'avci200' | 'hevc_nvenc' +const GROWING_AVC_CODECS = new Set(['avci50', 'avci100', 'avci200']); +const growingCodec = () => { + const v = process.env.GROWING_CODEC; + if (v === 'hevc_nvenc') return 'hevc_nvenc'; + if (v === 'avci50') return 'avci50'; + if (v === 'avci200') return 'avci200'; + return 'avci100'; // default +}; +// File extension per growing codec. +const growingExtFor = (codec) => (codec === 'hevc_nvenc' ? 'mov' : 'mxf');""", + 'growingCodec() 4-way', + ), + # 3. deriveGrowingRaster signature — add codec param + ( + 'function deriveGrowingRaster(resolution, framerate, scanHint = null) {', + "function deriveGrowingRaster(resolution, framerate, scanHint = null, codec = 'avci100') {", + 'deriveGrowingRaster signature', + ), + # 4. rawFlag block — class-switch + ( + """ // AVC-Intra 100 raster flags. --avci100_1080p accepts true 1080p59.94 (verified). + let rawFlag; + if (height >= 1080) { + rawFlag = (scan === 'i') ? '--avci100_1080i' : '--avci100_1080p'; + } else if (height >= 720) { + rawFlag = '--avci100_720p'; + if (fpsNum == null) { r.ff = '60000/1001'; r.raw = '60000/1001'; } + } else { + rawFlag = '--mpeg2lg_422p_ml_576i'; + r.ff = '25'; r.raw = '25'; + }""", + """ // AVC-Intra raster flags — class from codec name ('avci50'/'avci100'/'avci200'). + const avciClass = GROWING_AVCI_CLASS[codec] || 100; + let rawFlag; + if (height >= 1080) { + rawFlag = (scan === 'i') ? `--avci${avciClass}_1080i` : `--avci${avciClass}_1080p`; + } else if (height >= 720) { + rawFlag = `--avci${avciClass}_720p`; + if (fpsNum == null) { r.ff = '60000/1001'; r.raw = '60000/1001'; } + } else { + rawFlag = '--mpeg2lg_422p_ml_576i'; + r.ff = '25'; r.raw = '25'; + }""", + 'rawFlag class-switch', + ), + # 5. _buildGrowingOrchestrator signature + deriveGrowingRaster call + ( + """ _buildGrowingOrchestrator({ inputArgs, videoBitrate, resolution, framerate, audioChannels, outPath, hlsDir, videoCodec, audioMap = '0:a:0?', interlaced = false }) { + const { rawFlag, frameRate, ffRate } = deriveGrowingRaster(resolution, framerate, interlaced ? 'i' : 'p');""", + """ _buildGrowingOrchestrator({ inputArgs, videoBitrate, resolution, framerate, audioChannels, outPath, hlsDir, videoCodec, growingCodecName = 'avci100', audioMap = '0:a:0?', interlaced = false }) { + const { rawFlag, frameRate, ffRate } = deriveGrowingRaster(resolution, framerate, interlaced ? 'i' : 'p', growingCodecName);""", + '_buildGrowingOrchestrator signature', + ), + # 6. Spread GROWING_VIDEO_ELEMENTARY_ARGS -> function call + ( + ' ...GROWING_VIDEO_ELEMENTARY_ARGS,', + ' ...growingVideoElementaryArgs(growingCodecName),', + 'spread -> growingVideoElementaryArgs(growingCodecName)', + ), +] + +ok = True +for old, new, label in patches: + if old in src: + src = src.replace(old, new, 1) + print(f' OK {label}') + else: + print(f' FAIL {label}') + ok = False + +if ok: + open(path, 'w').write(src) + print('capture-manager.js written OK') +else: + print('ABORTED — not writing (some patches failed)') + sys.exit(1)