diff options
author | Chocobozzz <me@florianbigard.com> | 2021-11-10 11:04:00 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-11-10 11:04:00 +0100 |
commit | 67eeec8b955339120ff5d3c8286fdf0715e6270c (patch) | |
tree | ec28e8c218ed4e80f5f1f86f59fe2acb360950a9 | |
parent | 93904032506dd222404d9be60fd2e41763554665 (diff) | |
download | PeerTube-67eeec8b955339120ff5d3c8286fdf0715e6270c.tar.gz PeerTube-67eeec8b955339120ff5d3c8286fdf0715e6270c.tar.zst PeerTube-67eeec8b955339120ff5d3c8286fdf0715e6270c.zip |
Add minimum bitrate limit
-rw-r--r-- | server/helpers/ffmpeg-utils.ts | 12 | ||||
-rw-r--r-- | server/lib/transcoding/video-transcoding-profiles.ts | 27 | ||||
-rw-r--r-- | shared/core-utils/videos/bitrate.ts | 26 |
3 files changed, 55 insertions, 10 deletions
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index cc79828f6..ab29d4691 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts | |||
@@ -286,7 +286,10 @@ async function getLiveTranscodingCommand (options: { | |||
286 | 286 | ||
287 | addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) | 287 | addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) |
288 | 288 | ||
289 | logger.debug('Apply ffmpeg live video params from %s using %s profile.', builderResult.encoder, profile, builderResult, lTags()) | 289 | logger.debug( |
290 | 'Apply ffmpeg live video params from %s using %s profile.', builderResult.encoder, profile, builderResult, | ||
291 | { fps: resolutionFPS, resolution, ...lTags() } | ||
292 | ) | ||
290 | 293 | ||
291 | command.outputOption(`${buildStreamSuffix('-c:v', i)} ${builderResult.encoder}`) | 294 | command.outputOption(`${buildStreamSuffix('-c:v', i)} ${builderResult.encoder}`) |
292 | applyEncoderOptions(command, builderResult.result) | 295 | applyEncoderOptions(command, builderResult.result) |
@@ -310,7 +313,10 @@ async function getLiveTranscodingCommand (options: { | |||
310 | 313 | ||
311 | addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) | 314 | addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) |
312 | 315 | ||
313 | logger.debug('Apply ffmpeg live audio params from %s using %s profile.', builderResult.encoder, profile, builderResult, lTags()) | 316 | logger.debug( |
317 | 'Apply ffmpeg live audio params from %s using %s profile.', builderResult.encoder, profile, builderResult, | ||
318 | { fps: resolutionFPS, resolution, ...lTags() } | ||
319 | ) | ||
314 | 320 | ||
315 | command.outputOption(`${buildStreamSuffix('-c:a', i)} ${builderResult.encoder}`) | 321 | command.outputOption(`${buildStreamSuffix('-c:a', i)} ${builderResult.encoder}`) |
316 | applyEncoderOptions(command, builderResult.result) | 322 | applyEncoderOptions(command, builderResult.result) |
@@ -622,7 +628,7 @@ async function presetVideo (options: { | |||
622 | logger.debug( | 628 | logger.debug( |
623 | 'Apply ffmpeg params from %s for %s stream of input %s using %s profile.', | 629 | 'Apply ffmpeg params from %s for %s stream of input %s using %s profile.', |
624 | builderResult.encoder, streamType, input, profile, builderResult, | 630 | builderResult.encoder, streamType, input, profile, builderResult, |
625 | lTags() | 631 | { resolution, fps, ...lTags() } |
626 | ) | 632 | ) |
627 | 633 | ||
628 | if (streamType === 'video') { | 634 | if (streamType === 'video') { |
diff --git a/server/lib/transcoding/video-transcoding-profiles.ts b/server/lib/transcoding/video-transcoding-profiles.ts index 92971210c..34a364415 100644 --- a/server/lib/transcoding/video-transcoding-profiles.ts +++ b/server/lib/transcoding/video-transcoding-profiles.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | |||
1 | import { logger } from '@server/helpers/logger' | 2 | import { logger } from '@server/helpers/logger' |
2 | import { getAverageBitrate } from '@shared/core-utils' | 3 | import { getAverageBitrate, getMinLimitBitrate } from '@shared/core-utils' |
3 | import { AvailableEncoders, EncoderOptionsBuilder, EncoderOptionsBuilderParams } from '../../../shared/models/videos' | 4 | import { AvailableEncoders, EncoderOptionsBuilder, EncoderOptionsBuilderParams, VideoResolution } from '../../../shared/models/videos' |
4 | import { buildStreamSuffix, resetSupportedEncoders } from '../../helpers/ffmpeg-utils' | 5 | import { buildStreamSuffix, resetSupportedEncoders } from '../../helpers/ffmpeg-utils' |
5 | import { canDoQuickAudioTranscode, ffprobePromise, getAudioStream, getMaxAudioBitrate } from '../../helpers/ffprobe-utils' | 6 | import { canDoQuickAudioTranscode, ffprobePromise, getAudioStream, getMaxAudioBitrate } from '../../helpers/ffprobe-utils' |
6 | 7 | ||
@@ -15,10 +16,10 @@ import { canDoQuickAudioTranscode, ffprobePromise, getAudioStream, getMaxAudioBi | |||
15 | */ | 16 | */ |
16 | 17 | ||
17 | const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => { | 18 | const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => { |
18 | const { fps, inputRatio, inputBitrate } = options | 19 | const { fps, inputRatio, inputBitrate, resolution } = options |
19 | if (!fps) return { outputOptions: [ ] } | 20 | if (!fps) return { outputOptions: [ ] } |
20 | 21 | ||
21 | const targetBitrate = capBitrate(inputBitrate, getAverageBitrate({ ...options, fps, ratio: inputRatio })) | 22 | const targetBitrate = getTargetBitrate({ inputBitrate, ratio: inputRatio, fps, resolution }) |
22 | 23 | ||
23 | return { | 24 | return { |
24 | outputOptions: [ | 25 | outputOptions: [ |
@@ -31,9 +32,9 @@ const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOpt | |||
31 | } | 32 | } |
32 | 33 | ||
33 | const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => { | 34 | const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => { |
34 | const { streamNum, fps, inputBitrate, inputRatio } = options | 35 | const { streamNum, fps, inputBitrate, inputRatio, resolution } = options |
35 | 36 | ||
36 | const targetBitrate = capBitrate(inputBitrate, getAverageBitrate({ ...options, fps, ratio: inputRatio })) | 37 | const targetBitrate = getTargetBitrate({ inputBitrate, ratio: inputRatio, fps, resolution }) |
37 | 38 | ||
38 | return { | 39 | return { |
39 | outputOptions: [ | 40 | outputOptions: [ |
@@ -234,6 +235,20 @@ export { | |||
234 | 235 | ||
235 | // --------------------------------------------------------------------------- | 236 | // --------------------------------------------------------------------------- |
236 | 237 | ||
238 | function getTargetBitrate (options: { | ||
239 | inputBitrate: number | ||
240 | resolution: VideoResolution | ||
241 | ratio: number | ||
242 | fps: number | ||
243 | }) { | ||
244 | const { inputBitrate, resolution, ratio, fps } = options | ||
245 | |||
246 | const capped = capBitrate(inputBitrate, getAverageBitrate({ resolution, fps, ratio })) | ||
247 | const limit = getMinLimitBitrate({ resolution, fps, ratio }) | ||
248 | |||
249 | return Math.max(limit, capped) | ||
250 | } | ||
251 | |||
237 | function capBitrate (inputBitrate: number, targetBitrate: number) { | 252 | function capBitrate (inputBitrate: number, targetBitrate: number) { |
238 | if (!inputBitrate) return targetBitrate | 253 | if (!inputBitrate) return targetBitrate |
239 | 254 | ||
diff --git a/shared/core-utils/videos/bitrate.ts b/shared/core-utils/videos/bitrate.ts index 18c6e2f6c..c1891188f 100644 --- a/shared/core-utils/videos/bitrate.ts +++ b/shared/core-utils/videos/bitrate.ts | |||
@@ -4,6 +4,18 @@ type BitPerPixel = { [ id in VideoResolution ]: number } | |||
4 | 4 | ||
5 | // https://bitmovin.com/video-bitrate-streaming-hls-dash/ | 5 | // https://bitmovin.com/video-bitrate-streaming-hls-dash/ |
6 | 6 | ||
7 | const minLimitBitPerPixel: BitPerPixel = { | ||
8 | [VideoResolution.H_NOVIDEO]: 0, | ||
9 | [VideoResolution.H_144P]: 0.02, | ||
10 | [VideoResolution.H_240P]: 0.02, | ||
11 | [VideoResolution.H_360P]: 0.02, | ||
12 | [VideoResolution.H_480P]: 0.02, | ||
13 | [VideoResolution.H_720P]: 0.02, | ||
14 | [VideoResolution.H_1080P]: 0.02, | ||
15 | [VideoResolution.H_1440P]: 0.02, | ||
16 | [VideoResolution.H_4K]: 0.02 | ||
17 | } | ||
18 | |||
7 | const averageBitPerPixel: BitPerPixel = { | 19 | const averageBitPerPixel: BitPerPixel = { |
8 | [VideoResolution.H_NOVIDEO]: 0, | 20 | [VideoResolution.H_NOVIDEO]: 0, |
9 | [VideoResolution.H_144P]: 0.19, | 21 | [VideoResolution.H_144P]: 0.19, |
@@ -50,11 +62,23 @@ function getMaxBitrate (options: { | |||
50 | return targetBitrate | 62 | return targetBitrate |
51 | } | 63 | } |
52 | 64 | ||
65 | function getMinLimitBitrate (options: { | ||
66 | resolution: VideoResolution | ||
67 | ratio: number | ||
68 | fps: number | ||
69 | }) { | ||
70 | const minLimitBitrate = calculateBitrate({ ...options, bitPerPixel: minLimitBitPerPixel }) | ||
71 | if (!minLimitBitrate) return 10 * 1000 | ||
72 | |||
73 | return minLimitBitrate | ||
74 | } | ||
75 | |||
53 | // --------------------------------------------------------------------------- | 76 | // --------------------------------------------------------------------------- |
54 | 77 | ||
55 | export { | 78 | export { |
56 | getAverageBitrate, | 79 | getAverageBitrate, |
57 | getMaxBitrate | 80 | getMaxBitrate, |
81 | getMinLimitBitrate | ||
58 | } | 82 | } |
59 | 83 | ||
60 | // --------------------------------------------------------------------------- | 84 | // --------------------------------------------------------------------------- |