aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/videos/video-transcoder.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/tests/api/videos/video-transcoder.ts')
-rw-r--r--server/tests/api/videos/video-transcoder.ts155
1 files changed, 132 insertions, 23 deletions
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts
index 4be74901a..13b3530b1 100644
--- a/server/tests/api/videos/video-transcoder.ts
+++ b/server/tests/api/videos/video-transcoder.ts
@@ -1,29 +1,40 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { omit } from 'lodash' 5import { omit } from 'lodash'
6import { getMaxBitrate, VideoDetails, VideoResolution, VideoState } from '../../../../shared/models/videos' 6import { getMaxBitrate, VideoDetails, VideoResolution, VideoState } from '../../../../shared/models/videos'
7import { audio, canDoQuickTranscode, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' 7import {
8 audio,
9 canDoQuickTranscode,
10 getVideoFileBitrate,
11 getVideoFileFPS,
12 getVideoFileResolution,
13 getMetadataFromFile
14} from '../../../helpers/ffmpeg-utils'
8import { 15import {
9 buildAbsoluteFixturePath, 16 buildAbsoluteFixturePath,
10 cleanupTests, 17 cleanupTests,
11 doubleFollow, 18 doubleFollow,
12 flushAndRunMultipleServers, 19 flushAndRunMultipleServers,
13 generateHighBitrateVideo, 20 generateHighBitrateVideo,
21 generateVideoWithFramerate,
14 getMyVideos, 22 getMyVideos,
15 getVideo, 23 getVideo,
24 getVideoFileMetadataUrl,
16 getVideosList, 25 getVideosList,
17 makeGetRequest, 26 makeGetRequest,
18 root, 27 root,
19 ServerInfo, 28 ServerInfo,
20 setAccessTokensToServers, 29 setAccessTokensToServers,
21 uploadVideo, 30 uploadVideo, uploadVideoAndGetId,
22 waitJobs, 31 waitJobs,
23 webtorrentAdd 32 webtorrentAdd
24} from '../../../../shared/extra-utils' 33} from '../../../../shared/extra-utils'
25import { join } from 'path' 34import { join } from 'path'
26import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants' 35import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants'
36import { FfprobeData } from 'fluent-ffmpeg'
37import { VideoFileMetadata } from '@shared/models/videos/video-file-metadata'
27 38
28const expect = chai.expect 39const expect = chai.expect
29 40
@@ -55,19 +66,19 @@ describe('Test video transcoding', function () {
55 66
56 for (const server of servers) { 67 for (const server of servers) {
57 const res = await getVideosList(server.url) 68 const res = await getVideosList(server.url)
58 const video = res.body.data[ 0 ] 69 const video = res.body.data[0]
59 70
60 const res2 = await getVideo(server.url, video.id) 71 const res2 = await getVideo(server.url, video.id)
61 const videoDetails = res2.body 72 const videoDetails = res2.body
62 expect(videoDetails.files).to.have.lengthOf(1) 73 expect(videoDetails.files).to.have.lengthOf(1)
63 74
64 const magnetUri = videoDetails.files[ 0 ].magnetUri 75 const magnetUri = videoDetails.files[0].magnetUri
65 expect(magnetUri).to.match(/\.webm/) 76 expect(magnetUri).to.match(/\.webm/)
66 77
67 const torrent = await webtorrentAdd(magnetUri, true) 78 const torrent = await webtorrentAdd(magnetUri, true)
68 expect(torrent.files).to.be.an('array') 79 expect(torrent.files).to.be.an('array')
69 expect(torrent.files.length).to.equal(1) 80 expect(torrent.files.length).to.equal(1)
70 expect(torrent.files[ 0 ].path).match(/\.webm$/) 81 expect(torrent.files[0].path).match(/\.webm$/)
71 } 82 }
72 }) 83 })
73 84
@@ -92,13 +103,13 @@ describe('Test video transcoding', function () {
92 103
93 expect(videoDetails.files).to.have.lengthOf(4) 104 expect(videoDetails.files).to.have.lengthOf(4)
94 105
95 const magnetUri = videoDetails.files[ 0 ].magnetUri 106 const magnetUri = videoDetails.files[0].magnetUri
96 expect(magnetUri).to.match(/\.mp4/) 107 expect(magnetUri).to.match(/\.mp4/)
97 108
98 const torrent = await webtorrentAdd(magnetUri, true) 109 const torrent = await webtorrentAdd(magnetUri, true)
99 expect(torrent.files).to.be.an('array') 110 expect(torrent.files).to.be.an('array')
100 expect(torrent.files.length).to.equal(1) 111 expect(torrent.files.length).to.equal(1)
101 expect(torrent.files[ 0 ].path).match(/\.mp4$/) 112 expect(torrent.files[0].path).match(/\.mp4$/)
102 } 113 }
103 }) 114 })
104 115
@@ -126,8 +137,8 @@ describe('Test video transcoding', function () {
126 const probe = await audio.get(path) 137 const probe = await audio.get(path)
127 138
128 if (probe.audioStream) { 139 if (probe.audioStream) {
129 expect(probe.audioStream[ 'codec_name' ]).to.be.equal('aac') 140 expect(probe.audioStream['codec_name']).to.be.equal('aac')
130 expect(probe.audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000) 141 expect(probe.audioStream['bit_rate']).to.be.at.most(384 * 8000)
131 } else { 142 } else {
132 this.fail('Could not retrieve the audio stream on ' + probe.absolutePath) 143 this.fail('Could not retrieve the audio stream on ' + probe.absolutePath)
133 } 144 }
@@ -211,10 +222,10 @@ describe('Test video transcoding', function () {
211 const videoDetails: VideoDetails = res2.body 222 const videoDetails: VideoDetails = res2.body
212 223
213 expect(videoDetails.files).to.have.lengthOf(4) 224 expect(videoDetails.files).to.have.lengthOf(4)
214 expect(videoDetails.files[ 0 ].fps).to.be.above(58).and.below(62) 225 expect(videoDetails.files[0].fps).to.be.above(58).and.below(62)
215 expect(videoDetails.files[ 1 ].fps).to.be.below(31) 226 expect(videoDetails.files[1].fps).to.be.below(31)
216 expect(videoDetails.files[ 2 ].fps).to.be.below(31) 227 expect(videoDetails.files[2].fps).to.be.below(31)
217 expect(videoDetails.files[ 3 ].fps).to.be.below(31) 228 expect(videoDetails.files[3].fps).to.be.below(31)
218 229
219 for (const resolution of [ '240', '360', '480' ]) { 230 for (const resolution of [ '240', '360', '480' ]) {
220 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') 231 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
@@ -240,11 +251,11 @@ describe('Test video transcoding', function () {
240 fixture: 'video_short1.webm', 251 fixture: 'video_short1.webm',
241 waitTranscoding: true 252 waitTranscoding: true
242 } 253 }
243 const resVideo = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes) 254 const resVideo = await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes)
244 const videoId = resVideo.body.video.uuid 255 const videoId = resVideo.body.video.uuid
245 256
246 // Should be in transcode state 257 // Should be in transcode state
247 const { body } = await getVideo(servers[ 1 ].url, videoId) 258 const { body } = await getVideo(servers[1].url, videoId)
248 expect(body.name).to.equal('waiting video') 259 expect(body.name).to.equal('waiting video')
249 expect(body.state.id).to.equal(VideoState.TO_TRANSCODE) 260 expect(body.state.id).to.equal(VideoState.TO_TRANSCODE)
250 expect(body.state.label).to.equal('To transcode') 261 expect(body.state.label).to.equal('To transcode')
@@ -310,7 +321,7 @@ describe('Test video transcoding', function () {
310 321
311 const video = res.body.data.find(v => v.name === videoAttributes.name) 322 const video = res.body.data.find(v => v.name === videoAttributes.name)
312 323
313 for (const resolution of ['240', '360', '480', '720', '1080']) { 324 for (const resolution of [ '240', '360', '480', '720', '1080' ]) {
314 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') 325 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
315 const bitrate = await getVideoFileBitrate(path) 326 const bitrate = await getVideoFileBitrate(path)
316 const fps = await getVideoFileFPS(path) 327 const fps = await getVideoFileFPS(path)
@@ -340,7 +351,7 @@ describe('Test video transcoding', function () {
340 fixture 351 fixture
341 } 352 }
342 353
343 await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes) 354 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes)
344 355
345 await waitJobs(servers) 356 await waitJobs(servers)
346 357
@@ -353,7 +364,7 @@ describe('Test video transcoding', function () {
353 364
354 expect(videoDetails.files).to.have.lengthOf(4) 365 expect(videoDetails.files).to.have.lengthOf(4)
355 366
356 const magnetUri = videoDetails.files[ 0 ].magnetUri 367 const magnetUri = videoDetails.files[0].magnetUri
357 expect(magnetUri).to.contain('.mp4') 368 expect(magnetUri).to.contain('.mp4')
358 } 369 }
359 } 370 }
@@ -370,7 +381,7 @@ describe('Test video transcoding', function () {
370 this.timeout(60000) 381 this.timeout(60000)
371 382
372 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } 383 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
373 await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) 384 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg)
374 385
375 await waitJobs(servers) 386 await waitJobs(servers)
376 387
@@ -386,7 +397,7 @@ describe('Test video transcoding', function () {
386 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) 397 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
387 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) 398 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
388 399
389 const magnetUri = videoDetails.files[ 0 ].magnetUri 400 const magnetUri = videoDetails.files[0].magnetUri
390 expect(magnetUri).to.contain('.mp4') 401 expect(magnetUri).to.contain('.mp4')
391 } 402 }
392 }) 403 })
@@ -395,7 +406,7 @@ describe('Test video transcoding', function () {
395 this.timeout(60000) 406 this.timeout(60000)
396 407
397 const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' } 408 const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' }
398 await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) 409 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg)
399 410
400 await waitJobs(servers) 411 await waitJobs(servers)
401 412
@@ -411,11 +422,109 @@ describe('Test video transcoding', function () {
411 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) 422 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
412 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) 423 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
413 424
414 const magnetUri = videoDetails.files[ 0 ].magnetUri 425 const magnetUri = videoDetails.files[0].magnetUri
415 expect(magnetUri).to.contain('.mp4') 426 expect(magnetUri).to.contain('.mp4')
416 } 427 }
417 }) 428 })
418 429
430 it('Should downscale to the closest divisor standard framerate', async function () {
431 this.timeout(160000)
432
433 let tempFixturePath: string
434
435 {
436 tempFixturePath = await generateVideoWithFramerate(59)
437
438 const fps = await getVideoFileFPS(tempFixturePath)
439 expect(fps).to.be.equal(59)
440 }
441
442 const videoAttributes = {
443 name: '59fps video',
444 description: '59fps video',
445 fixture: tempFixturePath
446 }
447
448 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes)
449
450 await waitJobs(servers)
451
452 for (const server of servers) {
453 const res = await getVideosList(server.url)
454
455 const video = res.body.data.find(v => v.name === videoAttributes.name)
456
457 {
458 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
459 const fps = await getVideoFileFPS(path)
460 expect(fps).to.be.equal(25)
461 }
462
463 {
464 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-720.mp4')
465 const fps = await getVideoFileFPS(path)
466 expect(fps).to.be.equal(59)
467 }
468 }
469 })
470
471 it('Should provide valid ffprobe data', async function () {
472 this.timeout(160000)
473
474 const videoUUID = (await uploadVideoAndGetId({ server: servers[1], videoName: 'ffprobe data' })).uuid
475 await waitJobs(servers)
476
477 {
478 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', videoUUID + '-240.mp4')
479 const metadata = await getMetadataFromFile<VideoFileMetadata>(path)
480
481 // expected format properties
482 for (const p of [
483 'tags.encoder',
484 'format_long_name',
485 'size',
486 'bit_rate'
487 ]) {
488 expect(metadata.format).to.have.nested.property(p)
489 }
490
491 // expected stream properties
492 for (const p of [
493 'codec_long_name',
494 'profile',
495 'width',
496 'height',
497 'display_aspect_ratio',
498 'avg_frame_rate',
499 'pix_fmt'
500 ]) {
501 expect(metadata.streams[0]).to.have.nested.property(p)
502 }
503
504 expect(metadata).to.not.have.nested.property('format.filename')
505 }
506
507 for (const server of servers) {
508 const res2 = await getVideo(server.url, videoUUID)
509 const videoDetails: VideoDetails = res2.body
510
511 const videoFiles = videoDetails.files
512 .concat(videoDetails.streamingPlaylists[0].files)
513 expect(videoFiles).to.have.lengthOf(8)
514
515 for (const file of videoFiles) {
516 expect(file.metadata).to.be.undefined
517 expect(file.metadataUrl).to.exist
518 expect(file.metadataUrl).to.contain(servers[1].url)
519 expect(file.metadataUrl).to.contain(videoUUID)
520
521 const res3 = await getVideoFileMetadataUrl(file.metadataUrl)
522 const metadata: FfprobeData = res3.body
523 expect(metadata).to.have.nested.property('format.size')
524 }
525 }
526 })
527
419 after(async function () { 528 after(async function () {
420 await cleanupTests(servers) 529 await cleanupTests(servers)
421 }) 530 })