From 14aed608f540b587b3ab2529d06690815214d232 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 8 Apr 2019 10:03:23 +0200 Subject: [PATCH] Copy video/audio codec for HLS --- server/helpers/ffmpeg-utils.ts | 96 +++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index b6b64de3f..c477e2e89 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts @@ -130,51 +130,20 @@ type TranscodeOptions = { function transcode (options: TranscodeOptions) { return new Promise(async (res, rej) => { try { - 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 (options.hlsPlaylist) { + command = await buildHLSCommand(command, options) + } else { + command = await buildx264Command(command, options) + } if (CONFIG.TRANSCODING.THREADS > 0) { // if we don't set any threads ffmpeg will chose automatically command = command.outputOption('-threads ' + CONFIG.TRANSCODING.THREADS) } - if (options.resolution !== undefined) { - // '?x720' or '720x?' for example - const size = options.isPortraitMode === true ? `${options.resolution}x?` : `?x${options.resolution}` - command = command.size(size) - } - - if (fps) { - // Hard FPS limits - if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.MAX - else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN - - command = command.withFPS(fps) - } - - if (options.hlsPlaylist) { - const videoPath = getHLSVideoPath(options) - - command = command.outputOption('-hls_time 4') - .outputOption('-hls_list_size 0') - .outputOption('-hls_playlist_type vod') - .outputOption('-hls_segment_filename ' + videoPath) - .outputOption('-hls_segment_type fmp4') - .outputOption('-f hls') - .outputOption('-hls_flags single_file') - } - command .on('error', (err, stdout, stderr) => { logger.error('Error in transcoding job.', { stdout, stderr }) @@ -208,6 +177,52 @@ export { // --------------------------------------------------------------------------- +async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { + 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 + } + + command = await presetH264(command, options.resolution, fps) + + if (options.resolution !== undefined) { + // '?x720' or '720x?' for example + const size = options.isPortraitMode === true ? `${options.resolution}x?` : `?x${options.resolution}` + command = command.size(size) + } + + if (fps) { + // Hard FPS limits + if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.MAX + else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN + + command = command.withFPS(fps) + } + + return command +} + +async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { + const videoPath = getHLSVideoPath(options) + + command = await presetCopy(command) + + command = command.outputOption('-hls_time 4') + .outputOption('-hls_list_size 0') + .outputOption('-hls_playlist_type vod') + .outputOption('-hls_segment_filename ' + videoPath) + .outputOption('-hls_segment_type fmp4') + .outputOption('-f hls') + .outputOption('-hls_flags single_file') + + return command +} + function getHLSVideoPath (options: TranscodeOptions) { return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` } @@ -397,3 +412,10 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResol return localCommand } + +async function presetCopy (command: ffmpeg.FfmpegCommand): Promise { + return command + .format('mp4') + .videoCodec('copy') + .audioCodec('copy') +} -- 2.25.1