aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers/ffmpeg-utils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/helpers/ffmpeg-utils.ts')
-rw-r--r--server/helpers/ffmpeg-utils.ts54
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) {
35async function getVideoFileSize (path: string) { 35async 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
49async function getVideoFileResolution (path: string) { 43async function getVideoFileResolution (path: string) {
@@ -57,13 +51,10 @@ async function getVideoFileResolution (path: string) {
57 51
58async function getVideoFileFPS (path: string) { 52async 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
131type TranscodeOptionsType = 'hls' | 'quick-transcode' | 'video' | 'merge-audio' | 'split-audio' 122type TranscodeOptionsType = 'hls' | 'quick-transcode' | 'video' | 'merge-audio' | 'only-audio'
132 123
133interface BaseTranscodeOptions { 124interface 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
162interface SplitAudioTranscodeOptions extends BaseTranscodeOptions { 153interface OnlyAudioTranscodeOptions extends BaseTranscodeOptions {
163 type: 'split-audio' 154 type: 'only-audio'
164} 155}
165 156
166type TranscodeOptions = HLSTranscodeOptions | VideoTranscodeOptions | MergeAudioTranscodeOptions | SplitAudioTranscodeOptions | QuickTranscodeOptions 157type TranscodeOptions = HLSTranscodeOptions
158 | VideoTranscodeOptions
159 | MergeAudioTranscodeOptions
160 | OnlyAudioTranscodeOptions
161 | QuickTranscodeOptions
167 162
168function transcode (options: TranscodeOptions) { 163function 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
296async function buildAudioSplitCommand (command: ffmpeg.FfmpegCommand, options: SplitAudioTranscodeOptions) { 291async 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 */
386namespace audio { 379namespace 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 502async function presetOnlyAudio (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> {
510async 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')