diff options
Diffstat (limited to 'server/helpers/ffmpeg-utils.ts')
-rw-r--r-- | server/helpers/ffmpeg-utils.ts | 54 |
1 files changed, 23 insertions, 31 deletions
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 2d9ce2bfa..ff80991b2 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts | |||
@@ -35,15 +35,9 @@ function computeResolutionsToTranscode (videoFileHeight: number) { | |||
35 | async function getVideoFileSize (path: string) { | 35 | async function getVideoFileSize (path: string) { |
36 | const videoStream = await getVideoStreamFromFile(path) | 36 | const videoStream = await getVideoStreamFromFile(path) |
37 | 37 | ||
38 | return videoStream == null | 38 | return videoStream === null |
39 | ? { | 39 | ? { width: 0, height: 0 } |
40 | width: 0, | 40 | : { width: videoStream.width, height: videoStream.height } |
41 | height: 0 | ||
42 | } | ||
43 | : { | ||
44 | width: videoStream.width, | ||
45 | height: videoStream.height | ||
46 | } | ||
47 | } | 41 | } |
48 | 42 | ||
49 | async function getVideoFileResolution (path: string) { | 43 | async function getVideoFileResolution (path: string) { |
@@ -57,13 +51,10 @@ async function getVideoFileResolution (path: string) { | |||
57 | 51 | ||
58 | async function getVideoFileFPS (path: string) { | 52 | async function getVideoFileFPS (path: string) { |
59 | const videoStream = await getVideoStreamFromFile(path) | 53 | const videoStream = await getVideoStreamFromFile(path) |
60 | 54 | if (videoStream === null) return 0 | |
61 | if (videoStream == null) { | ||
62 | return 0 | ||
63 | } | ||
64 | 55 | ||
65 | for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { | 56 | for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { |
66 | const valuesText: string = videoStream[key] | 57 | const valuesText: string = videoStream[ key ] |
67 | if (!valuesText) continue | 58 | if (!valuesText) continue |
68 | 59 | ||
69 | const [ frames, seconds ] = valuesText.split('/') | 60 | const [ frames, seconds ] = valuesText.split('/') |
@@ -128,7 +119,7 @@ async function generateImageFromVideoFile (fromPath: string, folder: string, ima | |||
128 | } | 119 | } |
129 | } | 120 | } |
130 | 121 | ||
131 | type TranscodeOptionsType = 'hls' | 'quick-transcode' | 'video' | 'merge-audio' | 'split-audio' | 122 | type TranscodeOptionsType = 'hls' | 'quick-transcode' | 'video' | 'merge-audio' | 'only-audio' |
132 | 123 | ||
133 | interface BaseTranscodeOptions { | 124 | interface BaseTranscodeOptions { |
134 | type: TranscodeOptionsType | 125 | type: TranscodeOptionsType |
@@ -159,11 +150,15 @@ interface MergeAudioTranscodeOptions extends BaseTranscodeOptions { | |||
159 | audioPath: string | 150 | audioPath: string |
160 | } | 151 | } |
161 | 152 | ||
162 | interface SplitAudioTranscodeOptions extends BaseTranscodeOptions { | 153 | interface OnlyAudioTranscodeOptions extends BaseTranscodeOptions { |
163 | type: 'split-audio' | 154 | type: 'only-audio' |
164 | } | 155 | } |
165 | 156 | ||
166 | type TranscodeOptions = HLSTranscodeOptions | VideoTranscodeOptions | MergeAudioTranscodeOptions | SplitAudioTranscodeOptions | QuickTranscodeOptions | 157 | type TranscodeOptions = HLSTranscodeOptions |
158 | | VideoTranscodeOptions | ||
159 | | MergeAudioTranscodeOptions | ||
160 | | OnlyAudioTranscodeOptions | ||
161 | | QuickTranscodeOptions | ||
167 | 162 | ||
168 | function transcode (options: TranscodeOptions) { | 163 | function transcode (options: TranscodeOptions) { |
169 | return new Promise<void>(async (res, rej) => { | 164 | return new Promise<void>(async (res, rej) => { |
@@ -177,8 +172,8 @@ function transcode (options: TranscodeOptions) { | |||
177 | command = await buildHLSCommand(command, options) | 172 | command = await buildHLSCommand(command, options) |
178 | } else if (options.type === 'merge-audio') { | 173 | } else if (options.type === 'merge-audio') { |
179 | command = await buildAudioMergeCommand(command, options) | 174 | command = await buildAudioMergeCommand(command, options) |
180 | } else if (options.type === 'split-audio') { | 175 | } else if (options.type === 'only-audio') { |
181 | command = await buildAudioSplitCommand(command, options) | 176 | command = await buildOnlyAudioCommand(command, options) |
182 | } else { | 177 | } else { |
183 | command = await buildx264Command(command, options) | 178 | command = await buildx264Command(command, options) |
184 | } | 179 | } |
@@ -220,7 +215,7 @@ async function canDoQuickTranscode (path: string): Promise<boolean> { | |||
220 | if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false | 215 | if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false |
221 | if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false | 216 | if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false |
222 | 217 | ||
223 | // check audio params (if audio stream exists) | 218 | // check audio params (if audio stream exists) |
224 | if (parsedAudio.audioStream) { | 219 | if (parsedAudio.audioStream) { |
225 | if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false | 220 | if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false |
226 | 221 | ||
@@ -293,8 +288,8 @@ async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: M | |||
293 | return command | 288 | return command |
294 | } | 289 | } |
295 | 290 | ||
296 | async function buildAudioSplitCommand (command: ffmpeg.FfmpegCommand, options: SplitAudioTranscodeOptions) { | 291 | async function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) { |
297 | command = await presetAudioSplit(command) | 292 | command = await presetOnlyAudio(command) |
298 | 293 | ||
299 | return command | 294 | return command |
300 | } | 295 | } |
@@ -350,9 +345,7 @@ function getVideoStreamFromFile (path: string) { | |||
350 | if (err) return rej(err) | 345 | if (err) return rej(err) |
351 | 346 | ||
352 | const videoStream = metadata.streams.find(s => s.codec_type === 'video') | 347 | const videoStream = metadata.streams.find(s => s.codec_type === 'video') |
353 | //if (!videoStream) return rej(new Error('Cannot find video stream of ' + path)) | 348 | return res(videoStream || null) |
354 | |||
355 | return res(videoStream) | ||
356 | }) | 349 | }) |
357 | }) | 350 | }) |
358 | } | 351 | } |
@@ -384,7 +377,7 @@ async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, input: string, | |||
384 | * A toolbox to play with audio | 377 | * A toolbox to play with audio |
385 | */ | 378 | */ |
386 | namespace audio { | 379 | namespace audio { |
387 | export const get = (option: string) => { | 380 | export const get = (videoPath: string) => { |
388 | // without position, ffprobe considers the last input only | 381 | // without position, ffprobe considers the last input only |
389 | // we make it consider the first input only | 382 | // we make it consider the first input only |
390 | // if you pass a file path to pos, then ffprobe acts on that file directly | 383 | // if you pass a file path to pos, then ffprobe acts on that file directly |
@@ -394,7 +387,7 @@ namespace audio { | |||
394 | if (err) return rej(err) | 387 | if (err) return rej(err) |
395 | 388 | ||
396 | if ('streams' in data) { | 389 | if ('streams' in data) { |
397 | const audioStream = data.streams.find(stream => stream['codec_type'] === 'audio') | 390 | const audioStream = data.streams.find(stream => stream[ 'codec_type' ] === 'audio') |
398 | if (audioStream) { | 391 | if (audioStream) { |
399 | return res({ | 392 | return res({ |
400 | absolutePath: data.format.filename, | 393 | absolutePath: data.format.filename, |
@@ -406,7 +399,7 @@ namespace audio { | |||
406 | return res({ absolutePath: data.format.filename }) | 399 | return res({ absolutePath: data.format.filename }) |
407 | } | 400 | } |
408 | 401 | ||
409 | return ffmpeg.ffprobe(option, parseFfprobe) | 402 | return ffmpeg.ffprobe(videoPath, parseFfprobe) |
410 | }) | 403 | }) |
411 | } | 404 | } |
412 | 405 | ||
@@ -506,8 +499,7 @@ async function presetCopy (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.Ffmpeg | |||
506 | .audioCodec('copy') | 499 | .audioCodec('copy') |
507 | } | 500 | } |
508 | 501 | ||
509 | 502 | async function presetOnlyAudio (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { | |
510 | async function presetAudioSplit (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { | ||
511 | return command | 503 | return command |
512 | .format('mp4') | 504 | .format('mp4') |
513 | .audioCodec('copy') | 505 | .audioCodec('copy') |