diff options
Diffstat (limited to 'server/lib/video-transcoding-profiles.ts')
-rw-r--r-- | server/lib/video-transcoding-profiles.ts | 119 |
1 files changed, 98 insertions, 21 deletions
diff --git a/server/lib/video-transcoding-profiles.ts b/server/lib/video-transcoding-profiles.ts index bbe556e75..76d38b6ca 100644 --- a/server/lib/video-transcoding-profiles.ts +++ b/server/lib/video-transcoding-profiles.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { logger } from '@server/helpers/logger' | 1 | import { logger } from '@server/helpers/logger' |
2 | import { getTargetBitrate, VideoResolution } from '../../shared/models/videos' | 2 | import { AvailableEncoders, EncoderOptionsBuilder, getTargetBitrate, VideoResolution } from '../../shared/models/videos' |
3 | import { AvailableEncoders, buildStreamSuffix, EncoderOptionsBuilder } from '../helpers/ffmpeg-utils' | 3 | import { buildStreamSuffix, resetSupportedEncoders } from '../helpers/ffmpeg-utils' |
4 | import { | 4 | import { |
5 | canDoQuickAudioTranscode, | 5 | canDoQuickAudioTranscode, |
6 | ffprobePromise, | 6 | ffprobePromise, |
@@ -84,16 +84,8 @@ class VideoTranscodingProfilesManager { | |||
84 | 84 | ||
85 | // 1 === less priority | 85 | // 1 === less priority |
86 | private readonly encodersPriorities = { | 86 | private readonly encodersPriorities = { |
87 | video: [ | 87 | vod: this.buildDefaultEncodersPriorities(), |
88 | { name: 'libx264', priority: 100 } | 88 | live: this.buildDefaultEncodersPriorities() |
89 | ], | ||
90 | |||
91 | // Try the first one, if not available try the second one etc | ||
92 | audio: [ | ||
93 | // we favor VBR, if a good AAC encoder is available | ||
94 | { name: 'libfdk_aac', priority: 200 }, | ||
95 | { name: 'aac', priority: 100 } | ||
96 | ] | ||
97 | } | 89 | } |
98 | 90 | ||
99 | private readonly availableEncoders = { | 91 | private readonly availableEncoders = { |
@@ -118,25 +110,77 @@ class VideoTranscodingProfilesManager { | |||
118 | } | 110 | } |
119 | } | 111 | } |
120 | 112 | ||
121 | private constructor () { | 113 | private availableProfiles = { |
114 | vod: [] as string[], | ||
115 | live: [] as string[] | ||
116 | } | ||
122 | 117 | ||
118 | private constructor () { | ||
119 | this.buildAvailableProfiles() | ||
123 | } | 120 | } |
124 | 121 | ||
125 | getAvailableEncoders (): AvailableEncoders { | 122 | getAvailableEncoders (): AvailableEncoders { |
126 | const encodersToTry = { | 123 | return { |
127 | video: this.getEncodersByPriority('video'), | 124 | available: this.availableEncoders, |
128 | audio: this.getEncodersByPriority('audio') | 125 | encodersToTry: { |
126 | vod: { | ||
127 | video: this.getEncodersByPriority('vod', 'video'), | ||
128 | audio: this.getEncodersByPriority('vod', 'audio') | ||
129 | }, | ||
130 | live: { | ||
131 | video: this.getEncodersByPriority('live', 'video'), | ||
132 | audio: this.getEncodersByPriority('live', 'audio') | ||
133 | } | ||
134 | } | ||
129 | } | 135 | } |
130 | |||
131 | return Object.assign({}, this.availableEncoders, { encodersToTry }) | ||
132 | } | 136 | } |
133 | 137 | ||
134 | getAvailableProfiles (type: 'vod' | 'live') { | 138 | getAvailableProfiles (type: 'vod' | 'live') { |
135 | return this.availableEncoders[type] | 139 | return this.availableProfiles[type] |
140 | } | ||
141 | |||
142 | addProfile (options: { | ||
143 | type: 'vod' | 'live' | ||
144 | encoder: string | ||
145 | profile: string | ||
146 | builder: EncoderOptionsBuilder | ||
147 | }) { | ||
148 | const { type, encoder, profile, builder } = options | ||
149 | |||
150 | const encoders = this.availableEncoders[type] | ||
151 | |||
152 | if (!encoders[encoder]) encoders[encoder] = {} | ||
153 | encoders[encoder][profile] = builder | ||
154 | |||
155 | this.buildAvailableProfiles() | ||
156 | } | ||
157 | |||
158 | removeProfile (options: { | ||
159 | type: 'vod' | 'live' | ||
160 | encoder: string | ||
161 | profile: string | ||
162 | }) { | ||
163 | const { type, encoder, profile } = options | ||
164 | |||
165 | delete this.availableEncoders[type][encoder][profile] | ||
166 | this.buildAvailableProfiles() | ||
136 | } | 167 | } |
137 | 168 | ||
138 | private getEncodersByPriority (type: 'video' | 'audio') { | 169 | addEncoderPriority (type: 'vod' | 'live', streamType: 'audio' | 'video', encoder: string, priority: number) { |
139 | return this.encodersPriorities[type] | 170 | this.encodersPriorities[type][streamType].push({ name: encoder, priority }) |
171 | |||
172 | resetSupportedEncoders() | ||
173 | } | ||
174 | |||
175 | removeEncoderPriority (type: 'vod' | 'live', streamType: 'audio' | 'video', encoder: string, priority: number) { | ||
176 | this.encodersPriorities[type][streamType] = this.encodersPriorities[type][streamType] | ||
177 | .filter(o => o.name !== encoder && o.priority !== priority) | ||
178 | |||
179 | resetSupportedEncoders() | ||
180 | } | ||
181 | |||
182 | private getEncodersByPriority (type: 'vod' | 'live', streamType: 'audio' | 'video') { | ||
183 | return this.encodersPriorities[type][streamType] | ||
140 | .sort((e1, e2) => { | 184 | .sort((e1, e2) => { |
141 | if (e1.priority > e2.priority) return -1 | 185 | if (e1.priority > e2.priority) return -1 |
142 | else if (e1.priority === e2.priority) return 0 | 186 | else if (e1.priority === e2.priority) return 0 |
@@ -146,6 +190,39 @@ class VideoTranscodingProfilesManager { | |||
146 | .map(e => e.name) | 190 | .map(e => e.name) |
147 | } | 191 | } |
148 | 192 | ||
193 | private buildAvailableProfiles () { | ||
194 | for (const type of [ 'vod', 'live' ]) { | ||
195 | const result = new Set() | ||
196 | |||
197 | const encoders = this.availableEncoders[type] | ||
198 | |||
199 | for (const encoderName of Object.keys(encoders)) { | ||
200 | for (const profile of Object.keys(encoders[encoderName])) { | ||
201 | result.add(profile) | ||
202 | } | ||
203 | } | ||
204 | |||
205 | this.availableProfiles[type] = Array.from(result) | ||
206 | } | ||
207 | |||
208 | logger.debug('Available transcoding profiles built.', { availableProfiles: this.availableProfiles }) | ||
209 | } | ||
210 | |||
211 | private buildDefaultEncodersPriorities () { | ||
212 | return { | ||
213 | video: [ | ||
214 | { name: 'libx264', priority: 100 } | ||
215 | ], | ||
216 | |||
217 | // Try the first one, if not available try the second one etc | ||
218 | audio: [ | ||
219 | // we favor VBR, if a good AAC encoder is available | ||
220 | { name: 'libfdk_aac', priority: 200 }, | ||
221 | { name: 'aac', priority: 100 } | ||
222 | ] | ||
223 | } | ||
224 | } | ||
225 | |||
149 | static get Instance () { | 226 | static get Instance () { |
150 | return this.instance || (this.instance = new this()) | 227 | return this.instance || (this.instance = new this()) |
151 | } | 228 | } |