]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/plugins/plugin-transcoding.ts
Introduce config command
[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 buildServerDirectory,
9 cleanupTests,
10 createLive,
11 flushAndRunServer,
12 getVideo,
13 PluginsCommand,
14 sendRTMPStreamInVideo,
15 ServerInfo,
16 setAccessTokensToServers,
17 setDefaultVideoChannel,
18 testFfmpegStreamError,
19 uploadVideoAndGetId,
20 waitJobs,
21 waitUntilLivePublished
22 } from '@shared/extra-utils'
23 import { VideoDetails, VideoPrivacy } from '@shared/models'
24
25 async function createLiveWrapper (server: ServerInfo) {
26 const liveAttributes = {
27 name: 'live video',
28 channelId: server.videoChannel.id,
29 privacy: VideoPrivacy.PUBLIC
30 }
31
32 const res = await createLive(server.url, server.accessToken, liveAttributes)
33 return res.body.video.uuid
34 }
35
36 function updateConf (server: ServerInfo, vodProfile: string, liveProfile: string) {
37 return server.configCommand.updateCustomSubConfig({
38 newConfig: {
39 transcoding: {
40 enabled: true,
41 profile: vodProfile,
42 hls: {
43 enabled: true
44 },
45 webtorrent: {
46 enabled: true
47 },
48 resolutions: {
49 '240p': true,
50 '360p': false,
51 '480p': false,
52 '720p': true
53 }
54 },
55 live: {
56 transcoding: {
57 profile: liveProfile,
58 enabled: true,
59 resolutions: {
60 '240p': true,
61 '360p': false,
62 '480p': false,
63 '720p': true
64 }
65 }
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 server.pluginsCommand.install({ path: PluginsCommand.getPluginTestPath('-transcoding-one') })
113 })
114
115 it('Should have the appropriate available profiles', async function () {
116 const config = await server.configCommand.getConfig()
117
118 expect(config.transcoding.availableProfiles).to.have.members([ 'default', 'low-vod', 'input-options-vod', 'bad-scale-vod' ])
119 expect(config.live.transcoding.availableProfiles).to.have.members([ 'default', 'low-live', 'input-options-live', 'bad-scale-live' ])
120 })
121
122 it('Should not use the plugin profile if not chosen by the admin', async function () {
123 this.timeout(240000)
124
125 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
126 await waitJobs([ server ])
127
128 await checkVideoFPS(videoUUID, 'above', 20)
129 })
130
131 it('Should use the vod profile', async function () {
132 this.timeout(240000)
133
134 await updateConf(server, 'low-vod', 'default')
135
136 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
137 await waitJobs([ server ])
138
139 await checkVideoFPS(videoUUID, 'below', 12)
140 })
141
142 it('Should apply input options in vod profile', async function () {
143 this.timeout(240000)
144
145 await updateConf(server, 'input-options-vod', 'default')
146
147 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
148 await waitJobs([ server ])
149
150 await checkVideoFPS(videoUUID, 'below', 6)
151 })
152
153 it('Should apply the scale filter in vod profile', async function () {
154 this.timeout(240000)
155
156 await updateConf(server, 'bad-scale-vod', 'default')
157
158 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
159 await waitJobs([ server ])
160
161 // Transcoding failed
162 const res = await getVideo(server.url, videoUUID)
163 const video: VideoDetails = res.body
164
165 expect(video.files).to.have.lengthOf(1)
166 expect(video.streamingPlaylists).to.have.lengthOf(0)
167 })
168
169 it('Should not use the plugin profile if not chosen by the admin', async function () {
170 this.timeout(240000)
171
172 const liveVideoId = await createLiveWrapper(server)
173
174 await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm')
175 await waitUntilLivePublished(server.url, server.accessToken, liveVideoId)
176 await waitJobs([ server ])
177
178 await checkLiveFPS(liveVideoId, 'above', 20)
179 })
180
181 it('Should use the live profile', async function () {
182 this.timeout(240000)
183
184 await updateConf(server, 'low-vod', 'low-live')
185
186 const liveVideoId = await createLiveWrapper(server)
187
188 await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm')
189 await waitUntilLivePublished(server.url, server.accessToken, liveVideoId)
190 await waitJobs([ server ])
191
192 await checkLiveFPS(liveVideoId, 'below', 12)
193 })
194
195 it('Should apply the input options on live profile', async function () {
196 this.timeout(240000)
197
198 await updateConf(server, 'low-vod', 'input-options-live')
199
200 const liveVideoId = await createLiveWrapper(server)
201
202 await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm')
203 await waitUntilLivePublished(server.url, server.accessToken, liveVideoId)
204 await waitJobs([ server ])
205
206 await checkLiveFPS(liveVideoId, 'below', 6)
207 })
208
209 it('Should apply the scale filter name on live profile', async function () {
210 this.timeout(240000)
211
212 await updateConf(server, 'low-vod', 'bad-scale-live')
213
214 const liveVideoId = await createLiveWrapper(server)
215
216 const command = await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm')
217 await testFfmpegStreamError(command, true)
218 })
219
220 it('Should default to the default profile if the specified profile does not exist', async function () {
221 this.timeout(240000)
222
223 await server.pluginsCommand.uninstall({ npmName: 'peertube-plugin-test-transcoding-one' })
224
225 const config = await server.configCommand.getConfig()
226
227 expect(config.transcoding.availableProfiles).to.deep.equal([ 'default' ])
228 expect(config.live.transcoding.availableProfiles).to.deep.equal([ 'default' ])
229
230 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
231 await waitJobs([ server ])
232
233 await checkVideoFPS(videoUUID, 'above', 20)
234 })
235
236 })
237
238 describe('When using a plugin adding new encoders', function () {
239
240 before(async function () {
241 await server.pluginsCommand.install({ path: PluginsCommand.getPluginTestPath('-transcoding-two') })
242
243 await updateConf(server, 'test-vod-profile', 'test-live-profile')
244 })
245
246 it('Should use the new vod encoders', async function () {
247 this.timeout(240000)
248
249 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video', fixture: 'video_short_240p.mp4' })).uuid
250 await waitJobs([ server ])
251
252 const path = buildServerDirectory(server, join('videos', videoUUID + '-240.mp4'))
253 const audioProbe = await getAudioStream(path)
254 expect(audioProbe.audioStream.codec_name).to.equal('opus')
255
256 const videoProbe = await getVideoStreamFromFile(path)
257 expect(videoProbe.codec_name).to.equal('vp9')
258 })
259
260 it('Should use the new live encoders', async function () {
261 this.timeout(240000)
262
263 const liveVideoId = await createLiveWrapper(server)
264
265 await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm')
266 await waitUntilLivePublished(server.url, server.accessToken, liveVideoId)
267 await waitJobs([ server ])
268
269 const playlistUrl = `${server.url}/static/streaming-playlists/hls/${liveVideoId}/0.m3u8`
270 const audioProbe = await getAudioStream(playlistUrl)
271 expect(audioProbe.audioStream.codec_name).to.equal('opus')
272
273 const videoProbe = await getVideoStreamFromFile(playlistUrl)
274 expect(videoProbe.codec_name).to.equal('h264')
275 })
276 })
277
278 after(async function () {
279 await cleanupTests([ server ])
280 })
281 })