Downsample to the closest divisor standard framerate
authorRigel Kent <sendmemail@rigelk.eu>
Tue, 14 Jan 2020 22:34:03 +0000 (23:34 +0100)
committerChocobozzz <chocobozzz@cpy.re>
Wed, 29 Jan 2020 12:42:15 +0000 (13:42 +0100)
server/controllers/api/videos/index.ts
server/helpers/ffmpeg-utils.ts
server/initializers/constants.ts
server/middlewares/validators/videos/videos.ts
shared/models/videos/video-transcoding-fps.model.ts
support/doc/api/openapi.yaml

index 8d4ff07eb8b35daaeab6c672f6078e24e2dfccf9..a593f707663675bb14fe50cbd70dc0d50ca5f7d1 100644 (file)
@@ -12,7 +12,8 @@ import {
   VIDEO_CATEGORIES,
   VIDEO_LANGUAGES,
   VIDEO_LICENCES,
-  VIDEO_PRIVACIES
+  VIDEO_PRIVACIES,
+  VIDEO_TRANSCODING_FPS
 } from '../../../initializers/constants'
 import {
   changeVideoChannelShare,
index 00c32e99a7f2d20d6a86ced5f288105a763df527..78f9ba07cc2592f66e308f1aa8e673508cf02869 100644 (file)
@@ -286,13 +286,16 @@ export {
 
 async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) {
   let fps = await getVideoFileFPS(options.inputPath)
-  // On small/medium resolutions, limit FPS
   if (
+    // On small/medium resolutions, limit FPS
     options.resolution !== undefined &&
     options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN &&
-    fps > VIDEO_TRANSCODING_FPS.AVERAGE
+    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)
   ) {
-    fps = VIDEO_TRANSCODING_FPS.AVERAGE
+    // 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]
   }
 
   command = await presetH264(command, options.inputPath, options.resolution, fps)
@@ -305,7 +308,7 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco
 
   if (fps) {
     // Hard FPS limits
-    if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.MAX
+    if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.HD_STANDARD.sort((a, b) => fps % a - fps % b)[0]
     else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN
 
     command = command.withFPS(fps)
index e01ab8943534ffa2cb3086b48ceacf98aaf4e2cf..64803b1dbd9f6255e5367bbc694aeb96b46942b2 100644 (file)
@@ -310,6 +310,8 @@ let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour
 
 const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = {
   MIN: 10,
+  STANDARD: [24, 25, 30],
+  HD_STANDARD: [50, 60],
   AVERAGE: 30,
   MAX: 60,
   KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum)
index 6733d9dec4366cf32b821a7b3a03d715ca0e00d6..00ee375cb7f549970df88c4788edf456c777987d 100644 (file)
@@ -81,7 +81,7 @@ const videosAddValidator = getCommonVideoEditAttributes().concat([
       duration = await getDurationFromVideoFile(videoFile.path)
     } catch (err) {
       logger.error('Invalid input file in videosAddValidator.', { err })
-      res.status(400)
+      res.status(422)
          .json({ error: 'Invalid input file.' })
 
       return cleanUpReqFiles(req)
index 82022d2f18e14518537f0660d50a90dbcf18cd52..25fc1c2da7e54af96f8f50afec610797556ea6c5 100644 (file)
@@ -1,6 +1,8 @@
 export type VideoTranscodingFPS = {
-  MIN: number,
-  AVERAGE: number,
-  MAX: number,
+  MIN: number
+  STANDARD: number[]
+  HD_STANDARD: number[]
+  AVERAGE: number
+  MAX: number
   KEEP_ORIGIN_FPS_RESOLUTION_MIN: number
 }
index 43718e2a1537c3f4a0bf4f245352c0bd7851bd8d..907187e4c69b5def6072ffb74748777acd3f0b73 100644 (file)
@@ -977,6 +977,12 @@ paths:
             application/json:
               schema:
                 $ref: '#/components/schemas/VideoUploadResponse'
+        '403':
+          description: 'The user video quota is exceeded with this video.'
+        '408':
+          description: 'Upload has timed out'
+        '422':
+          description: 'Invalid input file.'
       requestBody:
         content:
           multipart/form-data: