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