aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/video-transcoding-profiles.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib/video-transcoding-profiles.ts')
-rw-r--r--server/lib/video-transcoding-profiles.ts119
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 @@
1import { logger } from '@server/helpers/logger' 1import { logger } from '@server/helpers/logger'
2import { getTargetBitrate, VideoResolution } from '../../shared/models/videos' 2import { AvailableEncoders, EncoderOptionsBuilder, getTargetBitrate, VideoResolution } from '../../shared/models/videos'
3import { AvailableEncoders, buildStreamSuffix, EncoderOptionsBuilder } from '../helpers/ffmpeg-utils' 3import { buildStreamSuffix, resetSupportedEncoders } from '../helpers/ffmpeg-utils'
4import { 4import {
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 }