]>
Commit | Line | Data |
---|---|---|
1896bca0 C |
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | ||
3 | import 'mocha' | |
4 | import { expect } from 'chai' | |
5 | import { join } from 'path' | |
6 | import { getAudioStream, getVideoFileFPS, getVideoStreamFromFile } from '@server/helpers/ffprobe-utils' | |
7 | import { ServerConfig, VideoDetails, VideoPrivacy } from '@shared/models' | |
8 | import { | |
9 | buildServerDirectory, | |
10 | createLive, | |
11 | getConfig, | |
12 | getPluginTestPath, | |
13 | getVideo, | |
14 | installPlugin, | |
15 | sendRTMPStreamInVideo, | |
16 | setAccessTokensToServers, | |
17 | setDefaultVideoChannel, | |
3e03b961 | 18 | testFfmpegStreamError, |
1896bca0 C |
19 | uninstallPlugin, |
20 | updateCustomSubConfig, | |
21 | uploadVideoAndGetId, | |
22 | waitJobs, | |
23 | waitUntilLivePublished | |
24 | } from '../../../shared/extra-utils' | |
25 | import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers' | |
26 | ||
27 | async function createLiveWrapper (server: ServerInfo) { | |
28 | const liveAttributes = { | |
29 | name: 'live video', | |
30 | channelId: server.videoChannel.id, | |
31 | privacy: VideoPrivacy.PUBLIC | |
32 | } | |
33 | ||
34 | const res = await createLive(server.url, server.accessToken, liveAttributes) | |
35 | return res.body.video.uuid | |
36 | } | |
37 | ||
38 | function updateConf (server: ServerInfo, vodProfile: string, liveProfile: string) { | |
39 | return updateCustomSubConfig(server.url, server.accessToken, { | |
40 | transcoding: { | |
41 | enabled: true, | |
42 | profile: vodProfile, | |
43 | hls: { | |
44 | enabled: true | |
45 | }, | |
46 | webtorrent: { | |
47 | enabled: true | |
b3eafc5f C |
48 | }, |
49 | resolutions: { | |
50 | '240p': true, | |
51 | '360p': false, | |
52 | '480p': false, | |
53 | '720p': true | |
1896bca0 C |
54 | } |
55 | }, | |
56 | live: { | |
57 | transcoding: { | |
58 | profile: liveProfile, | |
b3eafc5f C |
59 | enabled: true, |
60 | resolutions: { | |
61 | '240p': true, | |
62 | '360p': false, | |
63 | '480p': false, | |
64 | '720p': true | |
65 | } | |
1896bca0 C |
66 | } |
67 | } | |
68 | }) | |
69 | } | |
70 | ||
71 | describe('Test transcoding plugins', function () { | |
72 | let server: ServerInfo | |
73 | ||
74 | before(async function () { | |
75 | this.timeout(60000) | |
76 | ||
77 | server = await flushAndRunServer(1) | |
78 | await setAccessTokensToServers([ server ]) | |
79 | await setDefaultVideoChannel([ server ]) | |
80 | ||
81 | await updateConf(server, 'default', 'default') | |
82 | }) | |
83 | ||
84 | describe('When using a plugin adding profiles to existing encoders', function () { | |
85 | ||
86 | async function checkVideoFPS (uuid: string, type: 'above' | 'below', fps: number) { | |
87 | const res = await getVideo(server.url, uuid) | |
88 | const video = res.body as VideoDetails | |
89 | const files = video.files.concat(...video.streamingPlaylists.map(p => p.files)) | |
90 | ||
91 | for (const file of files) { | |
92 | if (type === 'above') { | |
93 | expect(file.fps).to.be.above(fps) | |
94 | } else { | |
95 | expect(file.fps).to.be.below(fps) | |
96 | } | |
97 | } | |
98 | } | |
99 | ||
100 | async function checkLiveFPS (uuid: string, type: 'above' | 'below', fps: number) { | |
101 | const playlistUrl = `${server.url}/static/streaming-playlists/hls/${uuid}/0.m3u8` | |
102 | const videoFPS = await getVideoFileFPS(playlistUrl) | |
103 | ||
104 | if (type === 'above') { | |
105 | expect(videoFPS).to.be.above(fps) | |
106 | } else { | |
107 | expect(videoFPS).to.be.below(fps) | |
108 | } | |
109 | } | |
110 | ||
111 | before(async function () { | |
112 | await installPlugin({ | |
113 | url: server.url, | |
114 | accessToken: server.accessToken, | |
115 | path: getPluginTestPath('-transcoding-one') | |
116 | }) | |
117 | }) | |
118 | ||
119 | it('Should have the appropriate available profiles', async function () { | |
120 | const res = await getConfig(server.url) | |
121 | const config = res.body as ServerConfig | |
122 | ||
3e03b961 C |
123 | expect(config.transcoding.availableProfiles).to.have.members([ 'default', 'low-vod', 'input-options-vod', 'bad-scale-vod' ]) |
124 | expect(config.live.transcoding.availableProfiles).to.have.members([ 'default', 'low-live', 'input-options-live', 'bad-scale-live' ]) | |
1896bca0 C |
125 | }) |
126 | ||
127 | it('Should not use the plugin profile if not chosen by the admin', async function () { | |
fc8f15d2 | 128 | this.timeout(240000) |
1896bca0 C |
129 | |
130 | const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid | |
131 | await waitJobs([ server ]) | |
132 | ||
133 | await checkVideoFPS(videoUUID, 'above', 20) | |
134 | }) | |
135 | ||
136 | it('Should use the vod profile', async function () { | |
fc8f15d2 | 137 | this.timeout(240000) |
1896bca0 C |
138 | |
139 | await updateConf(server, 'low-vod', 'default') | |
140 | ||
141 | const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid | |
142 | await waitJobs([ server ]) | |
143 | ||
144 | await checkVideoFPS(videoUUID, 'below', 12) | |
145 | }) | |
146 | ||
3e03b961 | 147 | it('Should apply input options in vod profile', async function () { |
fc8f15d2 | 148 | this.timeout(240000) |
d2351bcf | 149 | |
3e03b961 | 150 | await updateConf(server, 'input-options-vod', 'default') |
d2351bcf TLC |
151 | |
152 | const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid | |
153 | await waitJobs([ server ]) | |
154 | ||
3e03b961 | 155 | await checkVideoFPS(videoUUID, 'below', 6) |
d2351bcf TLC |
156 | }) |
157 | ||
3e03b961 | 158 | it('Should apply the scale filter in vod profile', async function () { |
fc8f15d2 | 159 | this.timeout(240000) |
d2351bcf | 160 | |
3e03b961 | 161 | await updateConf(server, 'bad-scale-vod', 'default') |
d2351bcf TLC |
162 | |
163 | const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid | |
164 | await waitJobs([ server ]) | |
165 | ||
3e03b961 C |
166 | // Transcoding failed |
167 | const res = await getVideo(server.url, videoUUID) | |
168 | const video: VideoDetails = res.body | |
169 | ||
170 | expect(video.files).to.have.lengthOf(1) | |
171 | expect(video.streamingPlaylists).to.have.lengthOf(0) | |
d2351bcf TLC |
172 | }) |
173 | ||
1896bca0 | 174 | it('Should not use the plugin profile if not chosen by the admin', async function () { |
fc8f15d2 | 175 | this.timeout(240000) |
1896bca0 C |
176 | |
177 | const liveVideoId = await createLiveWrapper(server) | |
178 | ||
179 | await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') | |
180 | await waitUntilLivePublished(server.url, server.accessToken, liveVideoId) | |
181 | await waitJobs([ server ]) | |
182 | ||
183 | await checkLiveFPS(liveVideoId, 'above', 20) | |
184 | }) | |
185 | ||
186 | it('Should use the live profile', async function () { | |
fc8f15d2 | 187 | this.timeout(240000) |
1896bca0 C |
188 | |
189 | await updateConf(server, 'low-vod', 'low-live') | |
190 | ||
191 | const liveVideoId = await createLiveWrapper(server) | |
192 | ||
193 | await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') | |
194 | await waitUntilLivePublished(server.url, server.accessToken, liveVideoId) | |
195 | await waitJobs([ server ]) | |
196 | ||
197 | await checkLiveFPS(liveVideoId, 'below', 12) | |
198 | }) | |
199 | ||
d2351bcf | 200 | it('Should apply the input options on live profile', async function () { |
fc8f15d2 | 201 | this.timeout(240000) |
d2351bcf TLC |
202 | |
203 | await updateConf(server, 'low-vod', 'input-options-live') | |
204 | ||
205 | const liveVideoId = await createLiveWrapper(server) | |
206 | ||
207 | await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') | |
208 | await waitUntilLivePublished(server.url, server.accessToken, liveVideoId) | |
209 | await waitJobs([ server ]) | |
210 | ||
211 | await checkLiveFPS(liveVideoId, 'below', 6) | |
212 | }) | |
213 | ||
3e03b961 | 214 | it('Should apply the scale filter name on live profile', async function () { |
fc8f15d2 | 215 | this.timeout(240000) |
3e03b961 C |
216 | |
217 | await updateConf(server, 'low-vod', 'bad-scale-live') | |
218 | ||
219 | const liveVideoId = await createLiveWrapper(server) | |
220 | ||
221 | const command = await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') | |
222 | await testFfmpegStreamError(command, true) | |
223 | }) | |
224 | ||
1896bca0 | 225 | it('Should default to the default profile if the specified profile does not exist', async function () { |
fc8f15d2 | 226 | this.timeout(240000) |
1896bca0 C |
227 | |
228 | await uninstallPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-plugin-test-transcoding-one' }) | |
229 | ||
230 | const res = await getConfig(server.url) | |
231 | const config = res.body as ServerConfig | |
232 | ||
233 | expect(config.transcoding.availableProfiles).to.deep.equal([ 'default' ]) | |
234 | expect(config.live.transcoding.availableProfiles).to.deep.equal([ 'default' ]) | |
235 | ||
236 | const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid | |
237 | await waitJobs([ server ]) | |
238 | ||
239 | await checkVideoFPS(videoUUID, 'above', 20) | |
240 | }) | |
241 | ||
242 | }) | |
243 | ||
244 | describe('When using a plugin adding new encoders', function () { | |
245 | ||
246 | before(async function () { | |
247 | await installPlugin({ | |
248 | url: server.url, | |
249 | accessToken: server.accessToken, | |
250 | path: getPluginTestPath('-transcoding-two') | |
251 | }) | |
252 | ||
253 | await updateConf(server, 'test-vod-profile', 'test-live-profile') | |
254 | }) | |
255 | ||
256 | it('Should use the new vod encoders', async function () { | |
257 | this.timeout(240000) | |
258 | ||
a8537c62 | 259 | const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video', fixture: 'video_short_240p.mp4' })).uuid |
1896bca0 C |
260 | await waitJobs([ server ]) |
261 | ||
a8537c62 | 262 | const path = buildServerDirectory(server, join('videos', videoUUID + '-240.mp4')) |
1896bca0 C |
263 | const audioProbe = await getAudioStream(path) |
264 | expect(audioProbe.audioStream.codec_name).to.equal('opus') | |
265 | ||
266 | const videoProbe = await getVideoStreamFromFile(path) | |
267 | expect(videoProbe.codec_name).to.equal('vp9') | |
268 | }) | |
269 | ||
270 | it('Should use the new live encoders', async function () { | |
fc8f15d2 | 271 | this.timeout(240000) |
1896bca0 C |
272 | |
273 | const liveVideoId = await createLiveWrapper(server) | |
274 | ||
275 | await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') | |
276 | await waitUntilLivePublished(server.url, server.accessToken, liveVideoId) | |
277 | await waitJobs([ server ]) | |
278 | ||
279 | const playlistUrl = `${server.url}/static/streaming-playlists/hls/${liveVideoId}/0.m3u8` | |
280 | const audioProbe = await getAudioStream(playlistUrl) | |
281 | expect(audioProbe.audioStream.codec_name).to.equal('opus') | |
282 | ||
283 | const videoProbe = await getVideoStreamFromFile(playlistUrl) | |
284 | expect(videoProbe.codec_name).to.equal('h264') | |
285 | }) | |
286 | }) | |
287 | ||
288 | after(async function () { | |
289 | await cleanupTests([ server ]) | |
290 | }) | |
291 | }) |