]>
Commit | Line | Data |
---|---|---|
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | |
2 | ||
3 | import { expect } from 'chai' | |
4 | import { getAudioStream, getVideoStreamFPS, getVideoStream } from '@server/helpers/ffmpeg' | |
5 | import { VideoPrivacy } from '@shared/models' | |
6 | import { | |
7 | cleanupTests, | |
8 | createSingleServer, | |
9 | PeerTubeServer, | |
10 | PluginsCommand, | |
11 | setAccessTokensToServers, | |
12 | setDefaultVideoChannel, | |
13 | testFfmpegStreamError, | |
14 | waitJobs | |
15 | } from '@shared/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 | webtorrent: { | |
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.buildWebTorrentFilePath(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 | }) |