diff options
Diffstat (limited to 'server/helpers/ffmpeg-utils.ts')
-rw-r--r-- | server/helpers/ffmpeg-utils.ts | 53 |
1 files changed, 42 insertions, 11 deletions
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index c2581f460..ad6f2f867 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts | |||
@@ -1,16 +1,27 @@ | |||
1 | import * as ffmpeg from 'fluent-ffmpeg' | 1 | import * as ffmpeg from 'fluent-ffmpeg' |
2 | import { VideoResolution } from '../../shared/models/videos' | 2 | import { VideoResolution } from '../../shared/models/videos' |
3 | import { CONFIG } from '../initializers' | 3 | import { CONFIG, MAX_VIDEO_TRANSCODING_FPS } from '../initializers' |
4 | 4 | ||
5 | function getVideoFileHeight (path: string) { | 5 | async function getVideoFileHeight (path: string) { |
6 | return new Promise<number>((res, rej) => { | 6 | const videoStream = await getVideoFileStream(path) |
7 | ffmpeg.ffprobe(path, (err, metadata) => { | 7 | return videoStream.height |
8 | if (err) return rej(err) | 8 | } |
9 | 9 | ||
10 | const videoStream = metadata.streams.find(s => s.codec_type === 'video') | 10 | async function getVideoFileFPS (path: string) { |
11 | return res(videoStream.height) | 11 | const videoStream = await getVideoFileStream(path) |
12 | }) | 12 | |
13 | }) | 13 | for (const key of [ 'r_frame_rate' , 'avg_frame_rate' ]) { |
14 | const valuesText: string = videoStream[key] | ||
15 | if (!valuesText) continue | ||
16 | |||
17 | const [ frames, seconds ] = valuesText.split('/') | ||
18 | if (!frames || !seconds) continue | ||
19 | |||
20 | const result = parseInt(frames, 10) / parseInt(seconds, 10) | ||
21 | if (result > 0) return result | ||
22 | } | ||
23 | |||
24 | return 0 | ||
14 | } | 25 | } |
15 | 26 | ||
16 | function getDurationFromVideoFile (path: string) { | 27 | function getDurationFromVideoFile (path: string) { |
@@ -49,7 +60,9 @@ type TranscodeOptions = { | |||
49 | } | 60 | } |
50 | 61 | ||
51 | function transcode (options: TranscodeOptions) { | 62 | function transcode (options: TranscodeOptions) { |
52 | return new Promise<void>((res, rej) => { | 63 | return new Promise<void>(async (res, rej) => { |
64 | const fps = await getVideoFileFPS(options.inputPath) | ||
65 | |||
53 | let command = ffmpeg(options.inputPath) | 66 | let command = ffmpeg(options.inputPath) |
54 | .output(options.outputPath) | 67 | .output(options.outputPath) |
55 | .videoCodec('libx264') | 68 | .videoCodec('libx264') |
@@ -57,6 +70,8 @@ function transcode (options: TranscodeOptions) { | |||
57 | .outputOption('-movflags faststart') | 70 | .outputOption('-movflags faststart') |
58 | // .outputOption('-crf 18') | 71 | // .outputOption('-crf 18') |
59 | 72 | ||
73 | if (fps > MAX_VIDEO_TRANSCODING_FPS) command = command.withFPS(MAX_VIDEO_TRANSCODING_FPS) | ||
74 | |||
60 | if (options.resolution !== undefined) { | 75 | if (options.resolution !== undefined) { |
61 | const size = `?x${options.resolution}` // '?x720' for example | 76 | const size = `?x${options.resolution}` // '?x720' for example |
62 | command = command.size(size) | 77 | command = command.size(size) |
@@ -74,5 +89,21 @@ export { | |||
74 | getVideoFileHeight, | 89 | getVideoFileHeight, |
75 | getDurationFromVideoFile, | 90 | getDurationFromVideoFile, |
76 | generateImageFromVideoFile, | 91 | generateImageFromVideoFile, |
77 | transcode | 92 | transcode, |
93 | getVideoFileFPS | ||
94 | } | ||
95 | |||
96 | // --------------------------------------------------------------------------- | ||
97 | |||
98 | function getVideoFileStream (path: string) { | ||
99 | return new Promise<any>((res, rej) => { | ||
100 | ffmpeg.ffprobe(path, (err, metadata) => { | ||
101 | if (err) return rej(err) | ||
102 | |||
103 | const videoStream = metadata.streams.find(s => s.codec_type === 'video') | ||
104 | if (!videoStream) throw new Error('Cannot find video stream of ' + path) | ||
105 | |||
106 | return res(videoStream) | ||
107 | }) | ||
108 | }) | ||
78 | } | 109 | } |