mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 10:34:17 +00:00
147 lines
3.9 KiB
JavaScript
147 lines
3.9 KiB
JavaScript
import fs from "node:fs"
|
|
import path from "node:path"
|
|
import { exec } from "node:child_process"
|
|
import { EventEmitter } from "node:events"
|
|
|
|
export default class MultiqualityHLSJob {
|
|
constructor({
|
|
input,
|
|
outputDir,
|
|
outputMasterName = "master.m3u8",
|
|
levels,
|
|
}) {
|
|
this.input = input
|
|
this.outputDir = outputDir
|
|
this.levels = levels
|
|
this.outputMasterName = outputMasterName
|
|
|
|
this.bin = require("ffmpeg-static")
|
|
|
|
return this
|
|
}
|
|
|
|
events = new EventEmitter()
|
|
|
|
buildCommand = () => {
|
|
const cmdStr = [
|
|
this.bin,
|
|
`-v quiet -stats`,
|
|
`-i ${this.input}`,
|
|
`-filter_complex`,
|
|
]
|
|
|
|
// set split args
|
|
let splitLevels = [
|
|
`[0:v]split=${this.levels.length}`
|
|
]
|
|
|
|
this.levels.forEach((level, i) => {
|
|
splitLevels[0] += (`[v${i + 1}]`)
|
|
})
|
|
|
|
for (const [index, level] of this.levels.entries()) {
|
|
if (level.original) {
|
|
splitLevels.push(`[v1]copy[v1out]`)
|
|
continue
|
|
}
|
|
|
|
let scaleFilter = `[v${index + 1}]scale=w=${level.width}:h=trunc(ow/a/2)*2[v${index + 1}out]`
|
|
|
|
splitLevels.push(scaleFilter)
|
|
}
|
|
|
|
cmdStr.push(`"${splitLevels.join(";")}"`)
|
|
|
|
// set levels map
|
|
for (const [index, level] of this.levels.entries()) {
|
|
let mapArgs = [
|
|
`-map "[v${index + 1}out]"`,
|
|
`-x264-params "nal-hrd=cbr:force-cfr=1"`,
|
|
`-c:v:${index} ${level.codec}`,
|
|
`-b:v:${index} ${level.bitrate}`,
|
|
`-maxrate:v:${index} ${level.bitrate}`,
|
|
`-minrate:v:${index} ${level.bitrate}`,
|
|
`-bufsize:v:${index} ${level.bitrate}`,
|
|
`-preset ${level.preset}`,
|
|
`-g 48`,
|
|
`-sc_threshold 0`,
|
|
`-keyint_min 48`,
|
|
]
|
|
|
|
cmdStr.push(...mapArgs)
|
|
}
|
|
|
|
// set output
|
|
cmdStr.push(`-f hls`)
|
|
cmdStr.push(`-hls_time 2`)
|
|
cmdStr.push(`-hls_playlist_type vod`)
|
|
cmdStr.push(`-hls_flags independent_segments`)
|
|
cmdStr.push(`-hls_segment_type mpegts`)
|
|
cmdStr.push(`-hls_segment_filename stream_%v/data%02d.ts`)
|
|
cmdStr.push(`-master_pl_name ${this.outputMasterName}`)
|
|
|
|
cmdStr.push(`-var_stream_map`)
|
|
|
|
let streamMapVar = []
|
|
|
|
for (const [index, level] of this.levels.entries()) {
|
|
streamMapVar.push(`v:${index}`)
|
|
}
|
|
|
|
cmdStr.push(`"${streamMapVar.join(" ")}"`)
|
|
cmdStr.push(`"stream_%v/stream.m3u8"`)
|
|
|
|
return cmdStr.join(" ")
|
|
}
|
|
|
|
run = () => {
|
|
const cmdStr = this.buildCommand()
|
|
|
|
console.log(cmdStr)
|
|
|
|
const cwd = `${path.dirname(this.input)}/hls`
|
|
|
|
if (!fs.existsSync(cwd)) {
|
|
fs.mkdirSync(cwd, { recursive: true })
|
|
}
|
|
|
|
console.log(`[HLS] Started multiquality transcode`, {
|
|
input: this.input,
|
|
cwd: cwd,
|
|
})
|
|
|
|
const process = exec(
|
|
cmdStr,
|
|
{
|
|
cwd: cwd,
|
|
},
|
|
(error, stdout, stderr) => {
|
|
if (error) {
|
|
console.log(`[HLS] Failed to transcode >`, error)
|
|
|
|
return this.events.emit("error", error)
|
|
}
|
|
|
|
if (stderr) {
|
|
//return this.events.emit("error", stderr)
|
|
}
|
|
|
|
console.log(`[HLS] Finished transcode >`, cwd)
|
|
|
|
return this.events.emit("end", {
|
|
filepath: path.join(cwd, this.outputMasterName),
|
|
isDirectory: true,
|
|
})
|
|
}
|
|
)
|
|
|
|
process.stdout.on("data", (data) => {
|
|
console.log(data.toString())
|
|
})
|
|
}
|
|
|
|
on = (key, cb) => {
|
|
this.events.on(key, cb)
|
|
return this
|
|
}
|
|
} |