Add tests for video downscale framerate matching
authorRigel Kent <sendmemail@rigelk.eu>
Mon, 20 Jan 2020 19:40:30 +0000 (20:40 +0100)
committerChocobozzz <chocobozzz@cpy.re>
Wed, 29 Jan 2020 12:42:15 +0000 (13:42 +0100)
server/helpers/ffmpeg-utils.ts
server/helpers/logger.ts
server/tests/api/videos/video-transcoder.ts
shared/extra-utils/miscs/miscs.ts

index 78f9ba07cc2592f66e308f1aa8e673508cf02869..63dc5b6a3af39ac92ed9e8893fea1ccc31a1492c 100644 (file)
@@ -263,6 +263,10 @@ async function canDoQuickTranscode (path: string): Promise<boolean> {
   return true
 }
 
+function getClosestFramerateStandard (fps: number, hd = false): number {
+  return VIDEO_TRANSCODING_FPS[hd ? 'HD_STANDARD' : 'STANDARD'].slice(0).sort((a, b) => fps % a - fps % b)[0]
+}
+
 // ---------------------------------------------------------------------------
 
 export {
@@ -291,11 +295,11 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco
     options.resolution !== undefined &&
     options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN &&
     fps > VIDEO_TRANSCODING_FPS.AVERAGE ||
-    // If the video is doesn't match had standard
-    !VIDEO_TRANSCODING_FPS.HD_STANDARD.map(value => fps % value).includes(0)
+    // If the video is doesn't match hd standard
+    !VIDEO_TRANSCODING_FPS.HD_STANDARD.some(value => fps % value === 0)
   ) {
     // Get closest standard framerate by modulo: downsampling has to be done to a divisor of the nominal fps value
-    fps = VIDEO_TRANSCODING_FPS.STANDARD.sort((a, b) => fps % a - fps % b)[0]
+    fps = getClosestFramerateStandard(fps)
   }
 
   command = await presetH264(command, options.inputPath, options.resolution, fps)
@@ -308,7 +312,7 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco
 
   if (fps) {
     // Hard FPS limits
-    if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.HD_STANDARD.sort((a, b) => fps % a - fps % b)[0]
+    if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = getClosestFramerateStandard(fps, true)
     else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN
 
     command = command.withFPS(fps)
index 3954176121cf2458a37a85e2fd5a639f0b85e2ab..fd2988ad0badd08a7695b1011b58d27c2377ce39 100644 (file)
@@ -5,7 +5,7 @@ import * as winston from 'winston'
 import { FileTransportOptions } from 'winston/lib/winston/transports'
 import { CONFIG } from '../initializers/config'
 import { omit } from 'lodash'
-import { LOG_FILENAME } from '@server/initializers/constants'
+import { LOG_FILENAME } from '../initializers/constants'
 
 const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT
 
index 4be74901a8f37d9196c90a6724f010706b59d5ca..0104c94fcb9b228f4cf90bcc1f84d792ec92204d 100644 (file)
@@ -11,6 +11,7 @@ import {
   doubleFollow,
   flushAndRunMultipleServers,
   generateHighBitrateVideo,
+  generateVideoWithFramerate,
   getMyVideos,
   getVideo,
   getVideosList,
@@ -416,6 +417,39 @@ describe('Test video transcoding', function () {
     }
   })
 
+  it('Should downscale to the closest divisor standard framerate', async function () {
+    this.timeout(160000)
+
+    let tempFixturePath: string
+
+    {
+      tempFixturePath = await generateVideoWithFramerate()
+
+      const fps = await getVideoFileFPS(tempFixturePath)
+      expect(fps).to.be.equal(59)
+    }
+
+    const videoAttributes = {
+      name: '59fps video',
+      description: '59fps video',
+      fixture: tempFixturePath
+    }
+
+    await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes)
+
+    await waitJobs(servers)
+
+    for (const server of servers) {
+      const res = await getVideosList(server.url)
+
+      const video = res.body.data.find(v => v.name === videoAttributes.name)
+      const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
+      const fps = await getVideoFileFPS(path)
+
+      expect(fps).to.be.equal(25)
+    }
+  })
+
   after(async function () {
     await cleanupTests(servers)
   })
index 6b0f6d990a940164b708884c097934a12d3bce98..c957a6abea2d78d83f1b20a7ff4ebc09a22aa50d 100644 (file)
@@ -104,6 +104,28 @@ async function generateHighBitrateVideo () {
   return tempFixturePath
 }
 
+async function generateVideoWithFramerate (fps = 60) {
+  const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true)
+
+  await ensureDir(dirname(tempFixturePath))
+
+  const exists = await pathExists(tempFixturePath)
+  if (!exists) {
+    return new Promise<string>(async (res, rej) => {
+      ffmpeg()
+        .outputOptions([ '-f rawvideo', '-video_size 320x240', '-i /dev/urandom' ])
+        .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
+        .outputOptions([ `-r ${fps}` ])
+        .output(tempFixturePath)
+        .on('error', rej)
+        .on('end', () => res(tempFixturePath))
+        .run()
+    })
+  }
+
+  return tempFixturePath
+}
+
 // ---------------------------------------------------------------------------
 
 export {
@@ -115,5 +137,6 @@ export {
   testImage,
   buildAbsoluteFixturePath,
   root,
-  generateHighBitrateVideo
+  generateHighBitrateVideo,
+  generateVideoWithFramerate
 }