]>
Commit | Line | Data |
---|---|---|
67eeec8b | 1 | |
6b67897e | 2 | import { logger } from '@server/helpers/logger' |
ab14f0e0 C |
3 | import { FFmpegCommandWrapper, getDefaultAvailableEncoders } from '@shared/ffmpeg' |
4 | import { AvailableEncoders, EncoderOptionsBuilder } from '@shared/models' | |
5a547f69 | 5 | |
c729caf6 C |
6 | // --------------------------------------------------------------------------- |
7 | // Profile manager to get and change default profiles | |
8 | // --------------------------------------------------------------------------- | |
9 | ||
529b3752 C |
10 | class VideoTranscodingProfilesManager { |
11 | private static instance: VideoTranscodingProfilesManager | |
12 | ||
13 | // 1 === less priority | |
14 | private readonly encodersPriorities = { | |
1896bca0 C |
15 | vod: this.buildDefaultEncodersPriorities(), |
16 | live: this.buildDefaultEncodersPriorities() | |
529b3752 C |
17 | } |
18 | ||
ab14f0e0 | 19 | private readonly availableEncoders = getDefaultAvailableEncoders() |
529b3752 | 20 | |
1896bca0 C |
21 | private availableProfiles = { |
22 | vod: [] as string[], | |
23 | live: [] as string[] | |
24 | } | |
529b3752 | 25 | |
1896bca0 C |
26 | private constructor () { |
27 | this.buildAvailableProfiles() | |
529b3752 C |
28 | } |
29 | ||
30 | getAvailableEncoders (): AvailableEncoders { | |
1896bca0 C |
31 | return { |
32 | available: this.availableEncoders, | |
33 | encodersToTry: { | |
34 | vod: { | |
35 | video: this.getEncodersByPriority('vod', 'video'), | |
36 | audio: this.getEncodersByPriority('vod', 'audio') | |
37 | }, | |
38 | live: { | |
39 | video: this.getEncodersByPriority('live', 'video'), | |
40 | audio: this.getEncodersByPriority('live', 'audio') | |
41 | } | |
42 | } | |
5a547f69 | 43 | } |
529b3752 C |
44 | } |
45 | ||
46 | getAvailableProfiles (type: 'vod' | 'live') { | |
1896bca0 C |
47 | return this.availableProfiles[type] |
48 | } | |
49 | ||
50 | addProfile (options: { | |
51 | type: 'vod' | 'live' | |
52 | encoder: string | |
53 | profile: string | |
54 | builder: EncoderOptionsBuilder | |
55 | }) { | |
56 | const { type, encoder, profile, builder } = options | |
57 | ||
58 | const encoders = this.availableEncoders[type] | |
59 | ||
60 | if (!encoders[encoder]) encoders[encoder] = {} | |
61 | encoders[encoder][profile] = builder | |
62 | ||
63 | this.buildAvailableProfiles() | |
64 | } | |
65 | ||
66 | removeProfile (options: { | |
67 | type: 'vod' | 'live' | |
68 | encoder: string | |
69 | profile: string | |
70 | }) { | |
71 | const { type, encoder, profile } = options | |
72 | ||
73 | delete this.availableEncoders[type][encoder][profile] | |
74 | this.buildAvailableProfiles() | |
529b3752 C |
75 | } |
76 | ||
1896bca0 C |
77 | addEncoderPriority (type: 'vod' | 'live', streamType: 'audio' | 'video', encoder: string, priority: number) { |
78 | this.encodersPriorities[type][streamType].push({ name: encoder, priority }) | |
79 | ||
0c9668f7 | 80 | FFmpegCommandWrapper.resetSupportedEncoders() |
1896bca0 C |
81 | } |
82 | ||
83 | removeEncoderPriority (type: 'vod' | 'live', streamType: 'audio' | 'video', encoder: string, priority: number) { | |
84 | this.encodersPriorities[type][streamType] = this.encodersPriorities[type][streamType] | |
85 | .filter(o => o.name !== encoder && o.priority !== priority) | |
86 | ||
0c9668f7 | 87 | FFmpegCommandWrapper.resetSupportedEncoders() |
1896bca0 C |
88 | } |
89 | ||
90 | private getEncodersByPriority (type: 'vod' | 'live', streamType: 'audio' | 'video') { | |
91 | return this.encodersPriorities[type][streamType] | |
529b3752 C |
92 | .sort((e1, e2) => { |
93 | if (e1.priority > e2.priority) return -1 | |
94 | else if (e1.priority === e2.priority) return 0 | |
95 | ||
96 | return 1 | |
97 | }) | |
98 | .map(e => e.name) | |
99 | } | |
100 | ||
1896bca0 C |
101 | private buildAvailableProfiles () { |
102 | for (const type of [ 'vod', 'live' ]) { | |
103 | const result = new Set() | |
104 | ||
105 | const encoders = this.availableEncoders[type] | |
106 | ||
107 | for (const encoderName of Object.keys(encoders)) { | |
108 | for (const profile of Object.keys(encoders[encoderName])) { | |
109 | result.add(profile) | |
110 | } | |
111 | } | |
112 | ||
113 | this.availableProfiles[type] = Array.from(result) | |
114 | } | |
115 | ||
116 | logger.debug('Available transcoding profiles built.', { availableProfiles: this.availableProfiles }) | |
117 | } | |
118 | ||
119 | private buildDefaultEncodersPriorities () { | |
120 | return { | |
121 | video: [ | |
122 | { name: 'libx264', priority: 100 } | |
123 | ], | |
124 | ||
125 | // Try the first one, if not available try the second one etc | |
126 | audio: [ | |
127 | // we favor VBR, if a good AAC encoder is available | |
128 | { name: 'libfdk_aac', priority: 200 }, | |
129 | { name: 'aac', priority: 100 } | |
130 | ] | |
131 | } | |
132 | } | |
133 | ||
529b3752 C |
134 | static get Instance () { |
135 | return this.instance || (this.instance = new this()) | |
5a547f69 C |
136 | } |
137 | } | |
138 | ||
139 | // --------------------------------------------------------------------------- | |
140 | ||
141 | export { | |
529b3752 | 142 | VideoTranscodingProfilesManager |
5a547f69 | 143 | } |