-function transcode (options: TranscodeOptions) {
- return new Promise<void>(async (res, rej) => {
- try {
- let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING })
- .output(options.outputPath)
-
- if (options.type === 'quick-transcode') {
- command = await buildQuickTranscodeCommand(command)
- } else if (options.type === 'hls') {
- command = await buildHLSCommand(command, options)
- } else if (options.type === 'merge-audio') {
- command = await buildAudioMergeCommand(command, options)
- } else {
- command = await buildx264Command(command, options)
+async function transcode (options: TranscodeOptions) {
+ logger.debug('Will run transcode.', { options })
+
+ let command = getFFmpeg(options.inputPath)
+ .output(options.outputPath)
+
+ command = await builders[options.type](command, options)
+
+ await runCommand(command)
+
+ await fixHLSPlaylistIfNeeded(options)
+}
+
+// ---------------------------------------------------------------------------
+// Live muxing/transcoding functions
+// ---------------------------------------------------------------------------
+
+async function getLiveTranscodingCommand (options: {
+ rtmpUrl: string
+ outPath: string
+ resolutions: number[]
+ fps: number
+ deleteSegments: boolean
+
+ availableEncoders: AvailableEncoders
+ profile: string
+}) {
+ const { rtmpUrl, outPath, resolutions, fps, deleteSegments, availableEncoders, profile } = options
+ const input = rtmpUrl
+
+ const command = getFFmpeg(input)
+ command.inputOption('-fflags nobuffer')
+
+ const varStreamMap: string[] = []
+
+ command.complexFilter([
+ {
+ inputs: '[v:0]',
+ filter: 'split',
+ options: resolutions.length,
+ outputs: resolutions.map(r => `vtemp${r}`)
+ },
+
+ ...resolutions.map(r => ({
+ inputs: `vtemp${r}`,
+ filter: 'scale',
+ options: `w=-2:h=${r}`,
+ outputs: `vout${r}`
+ }))
+ ])
+
+ command.outputOption('-preset superfast')
+
+ for (let i = 0; i < resolutions.length; i++) {
+ const resolution = resolutions[i]
+ const resolutionFPS = computeFPS(fps, resolution)
+
+ const baseEncoderBuilderParams = {
+ input,
+ availableEncoders,
+ profile,
+ fps: resolutionFPS,
+ resolution,
+ streamNum: i,
+ videoType: 'live' as 'live'
+ }
+
+ {
+ const builderResult = await getEncoderBuilderResult(Object.assign({}, baseEncoderBuilderParams, { streamType: 'VIDEO' }))
+ if (!builderResult) {
+ throw new Error('No available live video encoder found')