1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
4 import { expect } from 'chai'
5 import { join } from 'path'
6 import { getAudioStream, getVideoFileFPS, getVideoStreamFromFile } from '@server/helpers/ffprobe-utils'
13 setAccessTokensToServers,
14 setDefaultVideoChannel,
15 testFfmpegStreamError,
18 } from '@shared/extra-utils'
19 import { VideoDetails, VideoPrivacy } from '@shared/models'
21 async function createLiveWrapper (server: ServerInfo) {
22 const liveAttributes = {
24 channelId: server.videoChannel.id,
25 privacy: VideoPrivacy.PUBLIC
28 const { uuid } = await server.liveCommand.create({ fields: liveAttributes })
33 function updateConf (server: ServerInfo, vodProfile: string, liveProfile: string) {
34 return server.configCommand.updateCustomSubConfig({
68 describe('Test transcoding plugins', function () {
69 let server: ServerInfo
71 before(async function () {
74 server = await flushAndRunServer(1)
75 await setAccessTokensToServers([ server ])
76 await setDefaultVideoChannel([ server ])
78 await updateConf(server, 'default', 'default')
81 describe('When using a plugin adding profiles to existing encoders', function () {
83 async function checkVideoFPS (uuid: string, type: 'above' | 'below', fps: number) {
84 const res = await getVideo(server.url, uuid)
85 const video = res.body as VideoDetails
86 const files = video.files.concat(...video.streamingPlaylists.map(p => p.files))
88 for (const file of files) {
89 if (type === 'above') {
90 expect(file.fps).to.be.above(fps)
92 expect(file.fps).to.be.below(fps)
97 async function checkLiveFPS (uuid: string, type: 'above' | 'below', fps: number) {
98 const playlistUrl = `${server.url}/static/streaming-playlists/hls/${uuid}/0.m3u8`
99 const videoFPS = await getVideoFileFPS(playlistUrl)
101 if (type === 'above') {
102 expect(videoFPS).to.be.above(fps)
104 expect(videoFPS).to.be.below(fps)
108 before(async function () {
109 await server.pluginsCommand.install({ path: PluginsCommand.getPluginTestPath('-transcoding-one') })
112 it('Should have the appropriate available profiles', async function () {
113 const config = await server.configCommand.getConfig()
115 expect(config.transcoding.availableProfiles).to.have.members([ 'default', 'low-vod', 'input-options-vod', 'bad-scale-vod' ])
116 expect(config.live.transcoding.availableProfiles).to.have.members([ 'default', 'low-live', 'input-options-live', 'bad-scale-live' ])
119 it('Should not use the plugin profile if not chosen by the admin', async function () {
122 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
123 await waitJobs([ server ])
125 await checkVideoFPS(videoUUID, 'above', 20)
128 it('Should use the vod profile', async function () {
131 await updateConf(server, 'low-vod', 'default')
133 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
134 await waitJobs([ server ])
136 await checkVideoFPS(videoUUID, 'below', 12)
139 it('Should apply input options in vod profile', async function () {
142 await updateConf(server, 'input-options-vod', 'default')
144 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
145 await waitJobs([ server ])
147 await checkVideoFPS(videoUUID, 'below', 6)
150 it('Should apply the scale filter in vod profile', async function () {
153 await updateConf(server, 'bad-scale-vod', 'default')
155 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
156 await waitJobs([ server ])
158 // Transcoding failed
159 const res = await getVideo(server.url, videoUUID)
160 const video: VideoDetails = res.body
162 expect(video.files).to.have.lengthOf(1)
163 expect(video.streamingPlaylists).to.have.lengthOf(0)
166 it('Should not use the plugin profile if not chosen by the admin', async function () {
169 const liveVideoId = await createLiveWrapper(server)
171 await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
172 await server.liveCommand.waitUntilPublished({ videoId: liveVideoId })
173 await waitJobs([ server ])
175 await checkLiveFPS(liveVideoId, 'above', 20)
178 it('Should use the live profile', async function () {
181 await updateConf(server, 'low-vod', 'low-live')
183 const liveVideoId = await createLiveWrapper(server)
185 await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
186 await server.liveCommand.waitUntilPublished({ videoId: liveVideoId })
187 await waitJobs([ server ])
189 await checkLiveFPS(liveVideoId, 'below', 12)
192 it('Should apply the input options on live profile', async function () {
195 await updateConf(server, 'low-vod', 'input-options-live')
197 const liveVideoId = await createLiveWrapper(server)
199 await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
200 await server.liveCommand.waitUntilPublished({ videoId: liveVideoId })
201 await waitJobs([ server ])
203 await checkLiveFPS(liveVideoId, 'below', 6)
206 it('Should apply the scale filter name on live profile', async function () {
209 await updateConf(server, 'low-vod', 'bad-scale-live')
211 const liveVideoId = await createLiveWrapper(server)
213 const command = await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
214 await testFfmpegStreamError(command, true)
217 it('Should default to the default profile if the specified profile does not exist', async function () {
220 await server.pluginsCommand.uninstall({ npmName: 'peertube-plugin-test-transcoding-one' })
222 const config = await server.configCommand.getConfig()
224 expect(config.transcoding.availableProfiles).to.deep.equal([ 'default' ])
225 expect(config.live.transcoding.availableProfiles).to.deep.equal([ 'default' ])
227 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
228 await waitJobs([ server ])
230 await checkVideoFPS(videoUUID, 'above', 20)
235 describe('When using a plugin adding new encoders', function () {
237 before(async function () {
238 await server.pluginsCommand.install({ path: PluginsCommand.getPluginTestPath('-transcoding-two') })
240 await updateConf(server, 'test-vod-profile', 'test-live-profile')
243 it('Should use the new vod encoders', async function () {
246 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video', fixture: 'video_short_240p.mp4' })).uuid
247 await waitJobs([ server ])
249 const path = server.serversCommand.buildDirectory(join('videos', videoUUID + '-240.mp4'))
250 const audioProbe = await getAudioStream(path)
251 expect(audioProbe.audioStream.codec_name).to.equal('opus')
253 const videoProbe = await getVideoStreamFromFile(path)
254 expect(videoProbe.codec_name).to.equal('vp9')
257 it('Should use the new live encoders', async function () {
260 const liveVideoId = await createLiveWrapper(server)
262 await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
263 await server.liveCommand.waitUntilPublished({ videoId: liveVideoId })
264 await waitJobs([ server ])
266 const playlistUrl = `${server.url}/static/streaming-playlists/hls/${liveVideoId}/0.m3u8`
267 const audioProbe = await getAudioStream(playlistUrl)
268 expect(audioProbe.audioStream.codec_name).to.equal('opus')
270 const videoProbe = await getVideoStreamFromFile(playlistUrl)
271 expect(videoProbe.codec_name).to.equal('h264')
275 after(async function () {
276 await cleanupTests([ server ])