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