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