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