-function transcode (options: TranscodeOptions) {
- return new Promise<void>(async (res, rej) => {
- let fps = await getVideoFileFPS(options.inputPath)
- // On small/medium resolutions, limit FPS
- // if (
- // options.resolution !== undefined &&
- // options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN &&
- // fps > VIDEO_TRANSCODING_FPS.AVERAGE
- // ) {
- // fps = VIDEO_TRANSCODING_FPS.AVERAGE
- // }
-
- let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING })
- .output(options.outputPath)
- command = await presetH264(command, options.resolution, fps)
-
- if (CONFIG.TRANSCODING.THREADS > 0) {
- // if we don't set any threads ffmpeg will chose automatically
- command = command.outputOption('-threads ' + CONFIG.TRANSCODING.THREADS)
+interface HLSTranscodeOptions extends BaseTranscodeOptions {
+ type: 'hls'
+ copyCodecs: boolean
+ hlsPlaylist: {
+ videoFilename: string
+ }
+}
+
+interface HLSFromTSTranscodeOptions extends BaseTranscodeOptions {
+ type: 'hls-from-ts'
+
+ isAAC: boolean
+
+ hlsPlaylist: {
+ videoFilename: string
+ }
+}
+
+interface QuickTranscodeOptions extends BaseTranscodeOptions {
+ type: 'quick-transcode'
+}
+
+interface VideoTranscodeOptions extends BaseTranscodeOptions {
+ type: 'video'
+}
+
+interface MergeAudioTranscodeOptions extends BaseTranscodeOptions {
+ type: 'merge-audio'
+ audioPath: string
+}
+
+interface OnlyAudioTranscodeOptions extends BaseTranscodeOptions {
+ type: 'only-audio'
+}
+
+type TranscodeOptions =
+ HLSTranscodeOptions
+ | HLSFromTSTranscodeOptions
+ | VideoTranscodeOptions
+ | MergeAudioTranscodeOptions
+ | OnlyAudioTranscodeOptions
+ | QuickTranscodeOptions
+
+const builders: {
+ [ type in TranscodeOptionsType ]: (c: ffmpeg.FfmpegCommand, o?: TranscodeOptions) => Promise<ffmpeg.FfmpegCommand> | ffmpeg.FfmpegCommand
+} = {
+ 'quick-transcode': buildQuickTranscodeCommand,
+ 'hls': buildHLSVODCommand,
+ 'hls-from-ts': buildHLSVODFromTSCommand,
+ 'merge-audio': buildAudioMergeCommand,
+ 'only-audio': buildOnlyAudioCommand,
+ 'video': buildx264VODCommand
+}
+
+async function transcode (options: TranscodeOptions) {
+ logger.debug('Will run transcode.', { options })
+
+ let command = getFFmpeg(options.inputPath, 'vod')
+ .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
+
+ availableEncoders: AvailableEncoders
+ profile: string
+}) {
+ const { rtmpUrl, outPath, resolutions, fps, availableEncoders, profile } = options
+ const input = rtmpUrl
+
+ const command = getFFmpeg(input, 'live')
+
+ 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')
+ command.outputOption('-sc_threshold 0')
+
+ addDefaultEncoderGlobalParams({ command })
+
+ 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'