]>
Commit | Line | Data |
---|---|---|
c729caf6 C |
1 | import { getAvailableEncoders } from 'fluent-ffmpeg' |
2 | import { pick } from '@shared/core-utils' | |
3 | import { AvailableEncoders, EncoderOptionsBuilder, EncoderOptionsBuilderParams, EncoderProfile } from '@shared/models' | |
4 | import { promisify0 } from '../core-utils' | |
5 | import { logger, loggerTagsFactory } from '../logger' | |
6 | ||
7 | const lTags = loggerTagsFactory('ffmpeg') | |
8 | ||
9 | // Detect supported encoders by ffmpeg | |
10 | let supportedEncoders: Map<string, boolean> | |
11 | async function checkFFmpegEncoders (peertubeAvailableEncoders: AvailableEncoders): Promise<Map<string, boolean>> { | |
12 | if (supportedEncoders !== undefined) { | |
13 | return supportedEncoders | |
14 | } | |
15 | ||
16 | const getAvailableEncodersPromise = promisify0(getAvailableEncoders) | |
17 | const availableFFmpegEncoders = await getAvailableEncodersPromise() | |
18 | ||
19 | const searchEncoders = new Set<string>() | |
20 | for (const type of [ 'live', 'vod' ]) { | |
21 | for (const streamType of [ 'audio', 'video' ]) { | |
22 | for (const encoder of peertubeAvailableEncoders.encodersToTry[type][streamType]) { | |
23 | searchEncoders.add(encoder) | |
24 | } | |
25 | } | |
26 | } | |
27 | ||
28 | supportedEncoders = new Map<string, boolean>() | |
29 | ||
30 | for (const searchEncoder of searchEncoders) { | |
31 | supportedEncoders.set(searchEncoder, availableFFmpegEncoders[searchEncoder] !== undefined) | |
32 | } | |
33 | ||
34 | logger.info('Built supported ffmpeg encoders.', { supportedEncoders, searchEncoders, ...lTags() }) | |
35 | ||
36 | return supportedEncoders | |
37 | } | |
38 | ||
39 | function resetSupportedEncoders () { | |
40 | supportedEncoders = undefined | |
41 | } | |
42 | ||
43 | // Run encoder builder depending on available encoders | |
44 | // Try encoders by priority: if the encoder is available, run the chosen profile or fallback to the default one | |
45 | // If the default one does not exist, check the next encoder | |
46 | async function getEncoderBuilderResult (options: EncoderOptionsBuilderParams & { | |
47 | streamType: 'video' | 'audio' | |
48 | input: string | |
49 | ||
50 | availableEncoders: AvailableEncoders | |
51 | profile: string | |
52 | ||
53 | videoType: 'vod' | 'live' | |
54 | }) { | |
55 | const { availableEncoders, profile, streamType, videoType } = options | |
56 | ||
57 | const encodersToTry = availableEncoders.encodersToTry[videoType][streamType] | |
58 | const encoders = availableEncoders.available[videoType] | |
59 | ||
60 | for (const encoder of encodersToTry) { | |
61 | if (!(await checkFFmpegEncoders(availableEncoders)).get(encoder)) { | |
62 | logger.debug('Encoder %s not available in ffmpeg, skipping.', encoder, lTags()) | |
63 | continue | |
64 | } | |
65 | ||
66 | if (!encoders[encoder]) { | |
67 | logger.debug('Encoder %s not available in peertube encoders, skipping.', encoder, lTags()) | |
68 | continue | |
69 | } | |
70 | ||
71 | // An object containing available profiles for this encoder | |
72 | const builderProfiles: EncoderProfile<EncoderOptionsBuilder> = encoders[encoder] | |
73 | let builder = builderProfiles[profile] | |
74 | ||
75 | if (!builder) { | |
76 | logger.debug('Profile %s for encoder %s not available. Fallback to default.', profile, encoder, lTags()) | |
77 | builder = builderProfiles.default | |
78 | ||
79 | if (!builder) { | |
80 | logger.debug('Default profile for encoder %s not available. Try next available encoder.', encoder, lTags()) | |
81 | continue | |
82 | } | |
83 | } | |
84 | ||
85 | const result = await builder( | |
86 | pick(options, [ | |
87 | 'input', | |
88 | 'canCopyAudio', | |
89 | 'canCopyVideo', | |
90 | 'resolution', | |
91 | 'inputBitrate', | |
92 | 'fps', | |
93 | 'inputRatio', | |
94 | 'streamNum' | |
95 | ]) | |
96 | ) | |
97 | ||
98 | return { | |
99 | result, | |
100 | ||
101 | // If we don't have output options, then copy the input stream | |
102 | encoder: result.copy === true | |
103 | ? 'copy' | |
104 | : encoder | |
105 | } | |
106 | } | |
107 | ||
108 | return null | |
109 | } | |
110 | ||
111 | export { | |
112 | checkFFmpegEncoders, | |
113 | resetSupportedEncoders, | |
114 | ||
115 | getEncoderBuilderResult | |
116 | } |