aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared/ffmpeg/ffmpeg-default-transcoding-profile.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-05-04 15:55:51 +0200
committerChocobozzz <chocobozzz@cpy.re>2023-05-09 08:57:34 +0200
commitab14f0e0dca878dbaccc8f6a895a68e4269c9873 (patch)
tree078247f8620ee1f3260b8c3e3336059863273eb8 /shared/ffmpeg/ffmpeg-default-transcoding-profile.ts
parent5e47f6ab984a7d00782e4c7030afffa1ba480add (diff)
downloadPeerTube-ab14f0e0dca878dbaccc8f6a895a68e4269c9873.tar.gz
PeerTube-ab14f0e0dca878dbaccc8f6a895a68e4269c9873.tar.zst
PeerTube-ab14f0e0dca878dbaccc8f6a895a68e4269c9873.zip
Prefer video studio instead of video edition
Clearer and easier to find in the project
Diffstat (limited to 'shared/ffmpeg/ffmpeg-default-transcoding-profile.ts')
-rw-r--r--shared/ffmpeg/ffmpeg-default-transcoding-profile.ts134
1 files changed, 134 insertions, 0 deletions
diff --git a/shared/ffmpeg/ffmpeg-default-transcoding-profile.ts b/shared/ffmpeg/ffmpeg-default-transcoding-profile.ts
new file mode 100644
index 000000000..f7fc49465
--- /dev/null
+++ b/shared/ffmpeg/ffmpeg-default-transcoding-profile.ts
@@ -0,0 +1,134 @@
1import { getAverageBitrate, getMinLimitBitrate } from '@shared/core-utils'
2import { buildStreamSuffix, ffprobePromise, getAudioStream, getMaxAudioBitrate } from '@shared/ffmpeg'
3import { EncoderOptionsBuilder, EncoderOptionsBuilderParams, VideoResolution } from '@shared/models'
4
5const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => {
6 const { fps, inputRatio, inputBitrate, resolution } = options
7
8 const targetBitrate = getTargetBitrate({ inputBitrate, ratio: inputRatio, fps, resolution })
9
10 return {
11 outputOptions: [
12 ...getCommonOutputOptions(targetBitrate),
13
14 `-r ${fps}`
15 ]
16 }
17}
18
19const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => {
20 const { streamNum, fps, inputBitrate, inputRatio, resolution } = options
21
22 const targetBitrate = getTargetBitrate({ inputBitrate, ratio: inputRatio, fps, resolution })
23
24 return {
25 outputOptions: [
26 ...getCommonOutputOptions(targetBitrate, streamNum),
27
28 `${buildStreamSuffix('-r:v', streamNum)} ${fps}`,
29 `${buildStreamSuffix('-b:v', streamNum)} ${targetBitrate}`
30 ]
31 }
32}
33
34const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNum, canCopyAudio }) => {
35 const probe = await ffprobePromise(input)
36
37 const parsedAudio = await getAudioStream(input, probe)
38
39 // We try to reduce the ceiling bitrate by making rough matches of bitrates
40 // Of course this is far from perfect, but it might save some space in the end
41
42 const audioCodecName = parsedAudio.audioStream['codec_name']
43
44 const bitrate = getMaxAudioBitrate(audioCodecName, parsedAudio.bitrate)
45
46 // Force stereo as it causes some issues with HLS playback in Chrome
47 const base = [ '-channel_layout', 'stereo' ]
48
49 if (bitrate !== -1) {
50 return { outputOptions: base.concat([ buildStreamSuffix('-b:a', streamNum), bitrate + 'k' ]) }
51 }
52
53 return { outputOptions: base }
54}
55
56const defaultLibFDKAACVODOptionsBuilder: EncoderOptionsBuilder = ({ streamNum }) => {
57 return { outputOptions: [ buildStreamSuffix('-q:a', streamNum), '5' ] }
58}
59
60export function getDefaultAvailableEncoders () {
61 return {
62 vod: {
63 libx264: {
64 default: defaultX264VODOptionsBuilder
65 },
66 aac: {
67 default: defaultAACOptionsBuilder
68 },
69 libfdk_aac: {
70 default: defaultLibFDKAACVODOptionsBuilder
71 }
72 },
73 live: {
74 libx264: {
75 default: defaultX264LiveOptionsBuilder
76 },
77 aac: {
78 default: defaultAACOptionsBuilder
79 }
80 }
81 }
82}
83
84export function getDefaultEncodersToTry () {
85 return {
86 vod: {
87 video: [ 'libx264' ],
88 audio: [ 'libfdk_aac', 'aac' ]
89 },
90
91 live: {
92 video: [ 'libx264' ],
93 audio: [ 'libfdk_aac', 'aac' ]
94 }
95 }
96}
97
98// ---------------------------------------------------------------------------
99
100function getTargetBitrate (options: {
101 inputBitrate: number
102 resolution: VideoResolution
103 ratio: number
104 fps: number
105}) {
106 const { inputBitrate, resolution, ratio, fps } = options
107
108 const capped = capBitrate(inputBitrate, getAverageBitrate({ resolution, fps, ratio }))
109 const limit = getMinLimitBitrate({ resolution, fps, ratio })
110
111 return Math.max(limit, capped)
112}
113
114function capBitrate (inputBitrate: number, targetBitrate: number) {
115 if (!inputBitrate) return targetBitrate
116
117 // Add 30% margin to input bitrate
118 const inputBitrateWithMargin = inputBitrate + (inputBitrate * 0.3)
119
120 return Math.min(targetBitrate, inputBitrateWithMargin)
121}
122
123function getCommonOutputOptions (targetBitrate: number, streamNum?: number) {
124 return [
125 `-preset veryfast`,
126 `${buildStreamSuffix('-maxrate:v', streamNum)} ${targetBitrate}`,
127 `${buildStreamSuffix('-bufsize:v', streamNum)} ${targetBitrate * 2}`,
128
129 // NOTE: b-strategy 1 - heuristic algorithm, 16 is optimal B-frames for it
130 `-b_strategy 1`,
131 // NOTE: Why 16: https://github.com/Chocobozzz/PeerTube/pull/774. b-strategy 2 -> B-frames<16
132 `-bf 16`
133 ]
134}