]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/helpers/ffprobe-utils.ts
Reformat sql console output
[github/Chocobozzz/PeerTube.git] / server / helpers / ffprobe-utils.ts
index 5545ddbbfd5a4abca0cc7e5161f8e34a8c918f4e..adb459ed39042b67e13c0f8b8af8a0e9fb6b1bd4 100644 (file)
@@ -5,6 +5,12 @@ import { CONFIG } from '../initializers/config'
 import { VIDEO_TRANSCODING_FPS } from '../initializers/constants'
 import { logger } from './logger'
 
+/**
+ *
+ * Helpers to run ffprobe and extract data from the JSON output
+ *
+ */
+
 function ffprobePromise (path: string) {
   return new Promise<ffmpeg.FfprobeData>((res, rej) => {
     ffmpeg.ffprobe(path, (err, data) => {
@@ -37,38 +43,37 @@ async function getAudioStream (videoPath: string, existingProbe?: ffmpeg.Ffprobe
 }
 
 function getMaxAudioBitrate (type: 'aac' | 'mp3' | string, bitrate: number) {
-  const baseKbitrate = 384
-  const toBits = (kbits: number) => kbits * 8000
+  const maxKBitrate = 384
+  const kToBits = (kbits: number) => kbits * 1000
+
+  // If we did not manage to get the bitrate, use an average value
+  if (!bitrate) return 256
 
   if (type === 'aac') {
     switch (true) {
-      case bitrate > toBits(baseKbitrate):
-        return baseKbitrate
+      case bitrate > kToBits(maxKBitrate):
+        return maxKBitrate
 
       default:
         return -1 // we interpret it as a signal to copy the audio stream as is
     }
   }
 
-  if (type === 'mp3') {
-    /*
-      a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac.
-      That's why, when using aac, we can go to lower kbit/sec. The equivalences
-      made here are not made to be accurate, especially with good mp3 encoders.
-      */
-    switch (true) {
-      case bitrate <= toBits(192):
-        return 128
+  /*
+    a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac.
+    That's why, when using aac, we can go to lower kbit/sec. The equivalences
+    made here are not made to be accurate, especially with good mp3 encoders.
+    */
+  switch (true) {
+    case bitrate <= kToBits(192):
+      return 128
 
-      case bitrate <= toBits(384):
-        return 256
+    case bitrate <= kToBits(384):
+      return 256
 
-      default:
-        return baseKbitrate
-    }
+    default:
+      return maxKBitrate
   }
-
-  return undefined
 }
 
 async function getVideoStreamSize (path: string, existingProbe?: ffmpeg.FfprobeData) {
@@ -159,7 +164,7 @@ async function getVideoFileBitrate (path: string, existingProbe?: ffmpeg.Ffprobe
 async function getDurationFromVideoFile (path: string, existingProbe?: ffmpeg.FfprobeData) {
   const metadata = await getMetadataFromFile(path, existingProbe)
 
-  return Math.floor(metadata.format.duration)
+  return Math.round(metadata.format.duration)
 }
 
 async function getVideoStreamFromFile (path: string, existingProbe?: ffmpeg.FfprobeData) {
@@ -183,6 +188,7 @@ function computeResolutionsToTranscode (videoFileResolution: number, type: 'vod'
     VideoResolution.H_720P,
     VideoResolution.H_240P,
     VideoResolution.H_1080P,
+    VideoResolution.H_1440P,
     VideoResolution.H_4K
   ]
 
@@ -208,6 +214,9 @@ async function canDoQuickVideoTranscode (path: string, probe?: ffmpeg.FfprobeDat
   const bitRate = await getVideoFileBitrate(path, probe)
   const resolution = await getVideoFileResolution(path, probe)
 
+  // If ffprobe did not manage to guess the bitrate
+  if (!bitRate) return false
+
   // check video params
   if (videoStream == null) return false
   if (videoStream['codec_name'] !== 'h264') return false
@@ -221,15 +230,15 @@ async function canDoQuickVideoTranscode (path: string, probe?: ffmpeg.FfprobeDat
 async function canDoQuickAudioTranscode (path: string, probe?: ffmpeg.FfprobeData): Promise<boolean> {
   const parsedAudio = await getAudioStream(path, probe)
 
-  // check audio params (if audio stream exists)
-  if (parsedAudio.audioStream) {
-    if (parsedAudio.audioStream['codec_name'] !== 'aac') return false
+  if (!parsedAudio.audioStream) return true
 
-    const audioBitrate = parsedAudio.bitrate
+  if (parsedAudio.audioStream['codec_name'] !== 'aac') return false
 
-    const maxAudioBitrate = getMaxAudioBitrate('aac', audioBitrate)
-    if (maxAudioBitrate !== -1 && audioBitrate > maxAudioBitrate) return false
-  }
+  const audioBitrate = parsedAudio.bitrate
+  if (!audioBitrate) return false
+
+  const maxAudioBitrate = getMaxAudioBitrate('aac', audioBitrate)
+  if (maxAudioBitrate !== -1 && audioBitrate > maxAudioBitrate) return false
 
   return true
 }
@@ -239,6 +248,26 @@ function getClosestFramerateStandard (fps: number, type: 'HD_STANDARD' | 'STANDA
                                     .sort((a, b) => fps % a - fps % b)[0]
 }
 
+function computeFPS (fpsArg: number, resolution: VideoResolution) {
+  let fps = fpsArg
+
+  if (
+    // On small/medium resolutions, limit FPS
+    resolution !== undefined &&
+    resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN &&
+    fps > VIDEO_TRANSCODING_FPS.AVERAGE
+  ) {
+    // Get closest standard framerate by modulo: downsampling has to be done to a divisor of the nominal fps value
+    fps = getClosestFramerateStandard(fps, 'STANDARD')
+  }
+
+  // Hard FPS limits
+  if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = getClosestFramerateStandard(fps, 'HD_STANDARD')
+  else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN
+
+  return fps
+}
+
 // ---------------------------------------------------------------------------
 
 export {
@@ -251,6 +280,7 @@ export {
   getVideoStreamFromFile,
   getDurationFromVideoFile,
   getAudioStream,
+  computeFPS,
   getVideoFileFPS,
   ffprobePromise,
   getClosestFramerateStandard,