aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/helpers/ffmpeg-utils.ts12
-rw-r--r--server/helpers/logger.ts2
-rw-r--r--server/tests/api/videos/video-transcoder.ts34
-rw-r--r--shared/extra-utils/miscs/miscs.ts25
4 files changed, 67 insertions, 6 deletions
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index 78f9ba07c..63dc5b6a3 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -263,6 +263,10 @@ async function canDoQuickTranscode (path: string): Promise<boolean> {
263 return true 263 return true
264} 264}
265 265
266function getClosestFramerateStandard (fps: number, hd = false): number {
267 return VIDEO_TRANSCODING_FPS[hd ? 'HD_STANDARD' : 'STANDARD'].slice(0).sort((a, b) => fps % a - fps % b)[0]
268}
269
266// --------------------------------------------------------------------------- 270// ---------------------------------------------------------------------------
267 271
268export { 272export {
@@ -291,11 +295,11 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco
291 options.resolution !== undefined && 295 options.resolution !== undefined &&
292 options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN && 296 options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN &&
293 fps > VIDEO_TRANSCODING_FPS.AVERAGE || 297 fps > VIDEO_TRANSCODING_FPS.AVERAGE ||
294 // If the video is doesn't match had standard 298 // If the video is doesn't match hd standard
295 !VIDEO_TRANSCODING_FPS.HD_STANDARD.map(value => fps % value).includes(0) 299 !VIDEO_TRANSCODING_FPS.HD_STANDARD.some(value => fps % value === 0)
296 ) { 300 ) {
297 // Get closest standard framerate by modulo: downsampling has to be done to a divisor of the nominal fps value 301 // Get closest standard framerate by modulo: downsampling has to be done to a divisor of the nominal fps value
298 fps = VIDEO_TRANSCODING_FPS.STANDARD.sort((a, b) => fps % a - fps % b)[0] 302 fps = getClosestFramerateStandard(fps)
299 } 303 }
300 304
301 command = await presetH264(command, options.inputPath, options.resolution, fps) 305 command = await presetH264(command, options.inputPath, options.resolution, fps)
@@ -308,7 +312,7 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco
308 312
309 if (fps) { 313 if (fps) {
310 // Hard FPS limits 314 // Hard FPS limits
311 if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.HD_STANDARD.sort((a, b) => fps % a - fps % b)[0] 315 if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = getClosestFramerateStandard(fps, true)
312 else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN 316 else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN
313 317
314 command = command.withFPS(fps) 318 command = command.withFPS(fps)
diff --git a/server/helpers/logger.ts b/server/helpers/logger.ts
index 395417612..fd2988ad0 100644
--- a/server/helpers/logger.ts
+++ b/server/helpers/logger.ts
@@ -5,7 +5,7 @@ import * as winston from 'winston'
5import { FileTransportOptions } from 'winston/lib/winston/transports' 5import { FileTransportOptions } from 'winston/lib/winston/transports'
6import { CONFIG } from '../initializers/config' 6import { CONFIG } from '../initializers/config'
7import { omit } from 'lodash' 7import { omit } from 'lodash'
8import { LOG_FILENAME } from '@server/initializers/constants' 8import { LOG_FILENAME } from '../initializers/constants'
9 9
10const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT 10const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT
11 11
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts
index 4be74901a..0104c94fc 100644
--- a/server/tests/api/videos/video-transcoder.ts
+++ b/server/tests/api/videos/video-transcoder.ts
@@ -11,6 +11,7 @@ import {
11 doubleFollow, 11 doubleFollow,
12 flushAndRunMultipleServers, 12 flushAndRunMultipleServers,
13 generateHighBitrateVideo, 13 generateHighBitrateVideo,
14 generateVideoWithFramerate,
14 getMyVideos, 15 getMyVideos,
15 getVideo, 16 getVideo,
16 getVideosList, 17 getVideosList,
@@ -416,6 +417,39 @@ describe('Test video transcoding', function () {
416 } 417 }
417 }) 418 })
418 419
420 it('Should downscale to the closest divisor standard framerate', async function () {
421 this.timeout(160000)
422
423 let tempFixturePath: string
424
425 {
426 tempFixturePath = await generateVideoWithFramerate()
427
428 const fps = await getVideoFileFPS(tempFixturePath)
429 expect(fps).to.be.equal(59)
430 }
431
432 const videoAttributes = {
433 name: '59fps video',
434 description: '59fps video',
435 fixture: tempFixturePath
436 }
437
438 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes)
439
440 await waitJobs(servers)
441
442 for (const server of servers) {
443 const res = await getVideosList(server.url)
444
445 const video = res.body.data.find(v => v.name === videoAttributes.name)
446 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
447 const fps = await getVideoFileFPS(path)
448
449 expect(fps).to.be.equal(25)
450 }
451 })
452
419 after(async function () { 453 after(async function () {
420 await cleanupTests(servers) 454 await cleanupTests(servers)
421 }) 455 })
diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts
index 6b0f6d990..c957a6abe 100644
--- a/shared/extra-utils/miscs/miscs.ts
+++ b/shared/extra-utils/miscs/miscs.ts
@@ -104,6 +104,28 @@ async function generateHighBitrateVideo () {
104 return tempFixturePath 104 return tempFixturePath
105} 105}
106 106
107async function generateVideoWithFramerate (fps = 60) {
108 const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true)
109
110 await ensureDir(dirname(tempFixturePath))
111
112 const exists = await pathExists(tempFixturePath)
113 if (!exists) {
114 return new Promise<string>(async (res, rej) => {
115 ffmpeg()
116 .outputOptions([ '-f rawvideo', '-video_size 320x240', '-i /dev/urandom' ])
117 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
118 .outputOptions([ `-r ${fps}` ])
119 .output(tempFixturePath)
120 .on('error', rej)
121 .on('end', () => res(tempFixturePath))
122 .run()
123 })
124 }
125
126 return tempFixturePath
127}
128
107// --------------------------------------------------------------------------- 129// ---------------------------------------------------------------------------
108 130
109export { 131export {
@@ -115,5 +137,6 @@ export {
115 testImage, 137 testImage,
116 buildAbsoluteFixturePath, 138 buildAbsoluteFixturePath,
117 root, 139 root,
118 generateHighBitrateVideo 140 generateHighBitrateVideo,
141 generateVideoWithFramerate
119} 142}