diff options
-rw-r--r-- | server/helpers/ffmpeg-utils.ts | 12 | ||||
-rw-r--r-- | server/helpers/logger.ts | 2 | ||||
-rw-r--r-- | server/tests/api/videos/video-transcoder.ts | 34 | ||||
-rw-r--r-- | shared/extra-utils/miscs/miscs.ts | 25 |
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 | ||
266 | function 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 | ||
268 | export { | 272 | export { |
@@ -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' | |||
5 | import { FileTransportOptions } from 'winston/lib/winston/transports' | 5 | import { FileTransportOptions } from 'winston/lib/winston/transports' |
6 | import { CONFIG } from '../initializers/config' | 6 | import { CONFIG } from '../initializers/config' |
7 | import { omit } from 'lodash' | 7 | import { omit } from 'lodash' |
8 | import { LOG_FILENAME } from '@server/initializers/constants' | 8 | import { LOG_FILENAME } from '../initializers/constants' |
9 | 9 | ||
10 | const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT | 10 | const 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 | ||
107 | async 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 | ||
109 | export { | 131 | export { |
@@ -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 | } |