From 884d2c39ae23b44d0d037aaff0f66ad9ae0807ba Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 26 Nov 2020 11:29:50 +0100 Subject: Fix live FPS limit --- server/helpers/ffmpeg-utils.ts | 43 +++++++++++++++-------------------------- server/helpers/ffprobe-utils.ts | 21 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 27 deletions(-) (limited to 'server/helpers') diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 9755dd67c..3cc062b8c 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts @@ -1,11 +1,11 @@ import * as ffmpeg from 'fluent-ffmpeg' import { readFile, remove, writeFile } from 'fs-extra' import { dirname, join } from 'path' -import { FFMPEG_NICE, VIDEO_LIVE, VIDEO_TRANSCODING_ENCODERS, VIDEO_TRANSCODING_FPS } from '@server/initializers/constants' +import { FFMPEG_NICE, VIDEO_LIVE, VIDEO_TRANSCODING_ENCODERS } from '@server/initializers/constants' import { VideoResolution } from '../../shared/models/videos' import { checkFFmpegEncoders } from '../initializers/checker-before-init' import { CONFIG } from '../initializers/config' -import { getAudioStream, getClosestFramerateStandard, getVideoFileFPS } from './ffprobe-utils' +import { computeFPS, getAudioStream, getVideoFileFPS } from './ffprobe-utils' import { processImage } from './image-utils' import { logger } from './logger' @@ -223,7 +223,17 @@ async function getLiveTranscodingCommand (options: { for (let i = 0; i < resolutions.length; i++) { const resolution = resolutions[i] - const baseEncoderBuilderParams = { input, availableEncoders, profile, fps, resolution, streamNum: i, videoType: 'live' as 'live' } + 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' })) @@ -233,7 +243,7 @@ async function getLiveTranscodingCommand (options: { command.outputOption(`-map [vout${resolution}]`) - addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps, streamNum: i }) + addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) logger.debug('Apply ffmpeg live video params from %s.', builderResult.encoder, builderResult) @@ -249,7 +259,7 @@ async function getLiveTranscodingCommand (options: { command.outputOption('-map a:0') - addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps, streamNum: i }) + addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) logger.debug('Apply ffmpeg live audio params from %s.', builderResult.encoder, builderResult) @@ -387,15 +397,7 @@ function addDefaultLiveHLSParams (command: ffmpeg.FfmpegCommand, outPath: string async function buildx264VODCommand (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { let fps = await getVideoFileFPS(options.inputPath) - if ( - // On small/medium resolutions, limit FPS - options.resolution !== undefined && - options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN && - fps > VIDEO_TRANSCODING_FPS.AVERAGE - ) { - // Get closest standard framerate by modulo: downsampling has to be done to a divisor of the nominal fps value - fps = getClosestFramerateStandard(fps, 'STANDARD') - } + fps = computeFPS(fps, options.resolution) command = await presetVideo(command, options.inputPath, options, fps) @@ -408,12 +410,6 @@ async function buildx264VODCommand (command: ffmpeg.FfmpegCommand, options: Tran command = command.size(size) } - // Hard FPS limits - if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = getClosestFramerateStandard(fps, 'HD_STANDARD') - else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN - - command = command.withFPS(fps) - return command } @@ -422,13 +418,6 @@ async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: M command = await presetVideo(command, options.audioPath, options) - /* - MAIN reference: https://slhck.info/video/2017/03/01/rate-control.html - Our target situation is closer to a livestream than a stream, - since we want to reduce as much a possible the encoding burden, - although not to the point of a livestream where there is a hard - constraint on the frames per second to be encoded. - */ command.outputOption('-preset:v veryfast') command = command.input(options.audioPath) diff --git a/server/helpers/ffprobe-utils.ts b/server/helpers/ffprobe-utils.ts index 16b295bbd..1cf397767 100644 --- a/server/helpers/ffprobe-utils.ts +++ b/server/helpers/ffprobe-utils.ts @@ -247,6 +247,26 @@ function getClosestFramerateStandard (fps: number, type: 'HD_STANDARD' | 'STANDA .sort((a, b) => fps % a - fps % b)[0] } +function computeFPS (fpsArg: number, resolution: VideoResolution) { + let fps = fpsArg + + if ( + // On small/medium resolutions, limit FPS + resolution !== undefined && + resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN && + fps > VIDEO_TRANSCODING_FPS.AVERAGE + ) { + // Get closest standard framerate by modulo: downsampling has to be done to a divisor of the nominal fps value + fps = getClosestFramerateStandard(fps, 'STANDARD') + } + + // Hard FPS limits + if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = getClosestFramerateStandard(fps, 'HD_STANDARD') + else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN + + return fps +} + // --------------------------------------------------------------------------- export { @@ -259,6 +279,7 @@ export { getVideoStreamFromFile, getDurationFromVideoFile, getAudioStream, + computeFPS, getVideoFileFPS, ffprobePromise, getClosestFramerateStandard, -- cgit v1.2.3