+
import { logger } from '@server/helpers/logger'
-import { getAverageBitrate } from '@shared/core-utils'
-import { AvailableEncoders, EncoderOptionsBuilder, EncoderOptionsBuilderParams } from '../../../shared/models/videos'
+import { getAverageBitrate, getMinLimitBitrate } from '@shared/core-utils'
+import { AvailableEncoders, EncoderOptionsBuilder, EncoderOptionsBuilderParams, VideoResolution } from '../../../shared/models/videos'
import { buildStreamSuffix, resetSupportedEncoders } from '../../helpers/ffmpeg-utils'
import { canDoQuickAudioTranscode, ffprobePromise, getAudioStream, getMaxAudioBitrate } from '../../helpers/ffprobe-utils'
*/
const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => {
- const { fps, inputRatio, inputBitrate } = options
+ const { fps, inputRatio, inputBitrate, resolution } = options
if (!fps) return { outputOptions: [ ] }
- const targetBitrate = capBitrate(inputBitrate, getAverageBitrate({ ...options, fps, ratio: inputRatio }))
+ const targetBitrate = getTargetBitrate({ inputBitrate, ratio: inputRatio, fps, resolution })
return {
outputOptions: [
- `-preset veryfast`,
- `-r ${fps}`,
- `-maxrate ${targetBitrate}`,
- `-bufsize ${targetBitrate * 2}`
+ ...getCommonOutputOptions(targetBitrate),
+
+ `-r ${fps}`
]
}
}
const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => {
- const { streamNum, fps, inputBitrate, inputRatio } = options
+ const { streamNum, fps, inputBitrate, inputRatio, resolution } = options
- const targetBitrate = capBitrate(inputBitrate, getAverageBitrate({ ...options, fps, ratio: inputRatio }))
+ const targetBitrate = getTargetBitrate({ inputBitrate, ratio: inputRatio, fps, resolution })
return {
outputOptions: [
- `-preset veryfast`,
+ ...getCommonOutputOptions(targetBitrate),
+
`${buildStreamSuffix('-r:v', streamNum)} ${fps}`,
- `${buildStreamSuffix('-b:v', streamNum)} ${targetBitrate}`,
- `-maxrate ${targetBitrate}`,
- `-bufsize ${targetBitrate * 2}`
+ `${buildStreamSuffix('-b:v', streamNum)} ${targetBitrate}`
]
}
}
logger.debug('Calculating audio bitrate of %s by AAC encoder.', input, { bitrate: parsedAudio.bitrate, audioCodecName })
- if (bitrate !== undefined && bitrate !== -1) {
+ if (bitrate !== -1) {
return { outputOptions: [ buildStreamSuffix('-b:a', streamNum), bitrate + 'k' ] }
}
// ---------------------------------------------------------------------------
+function getTargetBitrate (options: {
+ inputBitrate: number
+ resolution: VideoResolution
+ ratio: number
+ fps: number
+}) {
+ const { inputBitrate, resolution, ratio, fps } = options
+
+ const capped = capBitrate(inputBitrate, getAverageBitrate({ resolution, fps, ratio }))
+ const limit = getMinLimitBitrate({ resolution, fps, ratio })
+
+ return Math.max(limit, capped)
+}
+
function capBitrate (inputBitrate: number, targetBitrate: number) {
if (!inputBitrate) return targetBitrate
return Math.min(targetBitrate, inputBitrateWithMargin)
}
+
+function getCommonOutputOptions (targetBitrate: number) {
+ return [
+ `-preset veryfast`,
+ `-maxrate ${targetBitrate}`,
+ `-bufsize ${targetBitrate * 2}`,
+
+ // NOTE: b-strategy 1 - heuristic algorithm, 16 is optimal B-frames for it
+ `-b_strategy 1`,
+ // NOTE: Why 16: https://github.com/Chocobozzz/PeerTube/pull/774. b-strategy 2 -> B-frames<16
+ `-bf 16`
+ ]
+}