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