]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Fix audio transcoding copy
authorChocobozzz <me@florianbigard.com>
Fri, 5 May 2023 08:53:04 +0000 (10:53 +0200)
committerChocobozzz <chocobozzz@cpy.re>
Tue, 9 May 2023 06:57:34 +0000 (08:57 +0200)
server/helpers/ffmpeg/ffmpeg-options.ts
server/initializers/constants.ts
server/lib/transcoding/transcoding-quick-transcode.ts
server/tests/api/transcoding/transcoder.ts
server/tests/helpers/core-utils.ts
server/tests/peertube-runner/live-transcoding.ts
server/tests/peertube-runner/studio-transcoding.ts
server/tests/shared/generate.ts
shared/core-utils/videos/bitrate.ts
shared/ffmpeg/ffmpeg-default-transcoding-profile.ts

index db6350d3940a53f3cdf1ee568409da30289cc3f6..64d7c417998390baa54e3ff7a5d988cd173e14f9 100644 (file)
@@ -11,7 +11,7 @@ export function getFFmpegCommandWrapperOptions (type: CommandType, availableEnco
     availableEncoders,
     profile: getProfile(type),
 
-    niceness: FFMPEG_NICE[type],
+    niceness: FFMPEG_NICE[type.toUpperCase()],
     tmpDirectory: CONFIG.STORAGE.TMP_DIR,
     threads: getThreads(type),
 
index 6a757a0ffc2c71c125ee063a2bf3988caa800221..adf24b73f65be994844a93baa8289acb2068005e 100644 (file)
@@ -469,7 +469,7 @@ const VIDEO_RATE_TYPES: { [ id: string ]: VideoRateType } = {
   DISLIKE: 'dislike'
 }
 
-const FFMPEG_NICE: { [ id: string ]: number } = {
+const FFMPEG_NICE = {
   // parent process defaults to niceness = 0
   // reminder: lower = higher priority, max value is 19, lowest is -20
   LIVE: 5, // prioritize over VOD and THUMBNAIL
index b7f921890d380a01bf772a9d46fb45481348b0ed..53f12cd06fa23e34e1a8432062ea2d127ccf58cd 100644 (file)
@@ -1,16 +1,6 @@
 import { FfprobeData } from 'fluent-ffmpeg'
 import { CONFIG } from '@server/initializers/config'
-import { VIDEO_TRANSCODING_FPS } from '@server/initializers/constants'
-import { getMaxBitrate } from '@shared/core-utils'
-import {
-  ffprobePromise,
-  getAudioStream,
-  getMaxAudioBitrate,
-  getVideoStream,
-  getVideoStreamBitrate,
-  getVideoStreamDimensionsInfo,
-  getVideoStreamFPS
-} from '@shared/ffmpeg'
+import { canDoQuickAudioTranscode, canDoQuickVideoTranscode, ffprobePromise } from '@shared/ffmpeg'
 
 export async function canDoQuickTranscode (path: string, existingProbe?: FfprobeData): Promise<boolean> {
   if (CONFIG.TRANSCODING.PROFILE !== 'default') return false
@@ -20,42 +10,3 @@ export async function canDoQuickTranscode (path: string, existingProbe?: Ffprobe
   return await canDoQuickVideoTranscode(path, probe) &&
          await canDoQuickAudioTranscode(path, probe)
 }
-
-export async function canDoQuickAudioTranscode (path: string, probe?: FfprobeData): Promise<boolean> {
-  const parsedAudio = await getAudioStream(path, probe)
-
-  if (!parsedAudio.audioStream) return true
-
-  if (parsedAudio.audioStream['codec_name'] !== 'aac') return false
-
-  const audioBitrate = parsedAudio.bitrate
-  if (!audioBitrate) return false
-
-  const maxAudioBitrate = getMaxAudioBitrate('aac', audioBitrate)
-  if (maxAudioBitrate !== -1 && audioBitrate > maxAudioBitrate) return false
-
-  const channelLayout = parsedAudio.audioStream['channel_layout']
-  // Causes playback issues with Chrome
-  if (!channelLayout || channelLayout === 'unknown' || channelLayout === 'quad') return false
-
-  return true
-}
-
-export async function canDoQuickVideoTranscode (path: string, probe?: FfprobeData): Promise<boolean> {
-  const videoStream = await getVideoStream(path, probe)
-  const fps = await getVideoStreamFPS(path, probe)
-  const bitRate = await getVideoStreamBitrate(path, probe)
-  const resolutionData = await getVideoStreamDimensionsInfo(path, probe)
-
-  // If ffprobe did not manage to guess the bitrate
-  if (!bitRate) return false
-
-  // check video params
-  if (!videoStream) return false
-  if (videoStream['codec_name'] !== 'h264') return false
-  if (videoStream['pix_fmt'] !== 'yuv420p') return false
-  if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false
-  if (bitRate > getMaxBitrate({ ...resolutionData, fps })) return false
-
-  return true
-}
index fa78b58bb438c7fa9414f28f5c1943550d240405..8a0a7f6d20fb34ce75e979f3ecc7fae270b881eb 100644 (file)
@@ -3,7 +3,7 @@
 import { expect } from 'chai'
 import { canDoQuickTranscode } from '@server/lib/transcoding/transcoding-quick-transcode'
 import { checkWebTorrentWorks, generateHighBitrateVideo, generateVideoWithFramerate } from '@server/tests/shared'
-import { buildAbsoluteFixturePath, getAllFiles, getMaxBitrate, getMinLimitBitrate, omit } from '@shared/core-utils'
+import { buildAbsoluteFixturePath, getAllFiles, getMaxTheoreticalBitrate, getMinTheoreticalBitrate, omit } from '@shared/core-utils'
 import {
   ffprobePromise,
   getAudioStream,
@@ -564,7 +564,7 @@ describe('Test video transcoding', function () {
 
           expect(resolution).to.equal(resolution)
 
-          const maxBitrate = getMaxBitrate({ ...dataResolution, fps })
+          const maxBitrate = getMaxTheoreticalBitrate({ ...dataResolution, fps })
           expect(bitrate).to.be.below(maxBitrate)
         }
       }
@@ -611,7 +611,7 @@ describe('Test video transcoding', function () {
         const bitrate = await getVideoStreamBitrate(path)
 
         const inputBitrate = 60_000
-        const limit = getMinLimitBitrate({ fps: 10, ratio: 1, resolution: r })
+        const limit = getMinTheoreticalBitrate({ fps: 10, ratio: 1, resolution: r })
         let belowValue = Math.max(inputBitrate, limit)
         belowValue += belowValue * 0.20 // Apply 20% margin because bitrate control is not very precise
 
index de6ba4f82f22e545f81864be1a138936d93b6d3a..cd2f07e4a5a58c6575bdf0c24e313bed7e5b1072 100644 (file)
@@ -3,7 +3,7 @@
 import { expect } from 'chai'
 import { snakeCase } from 'lodash'
 import validator from 'validator'
-import { getAverageBitrate, getMaxBitrate } from '@shared/core-utils'
+import { getAverageTheoreticalBitrate, getMaxTheoreticalBitrate } from '@shared/core-utils'
 import { VideoResolution } from '@shared/models'
 import { objectConverter, parseBytes, parseDurationToMs } from '../../helpers/core-utils'
 
@@ -128,7 +128,7 @@ describe('Bitrate', function () {
     ]
 
     for (const test of tests) {
-      expect(getMaxBitrate(test)).to.be.above(test.min * 1000).and.below(test.max * 1000)
+      expect(getMaxTheoreticalBitrate(test)).to.be.above(test.min * 1000).and.below(test.max * 1000)
     }
   })
 
@@ -144,7 +144,7 @@ describe('Bitrate', function () {
     ]
 
     for (const test of tests) {
-      expect(getAverageBitrate(test)).to.be.above(test.min * 1000).and.below(test.max * 1000)
+      expect(getAverageTheoreticalBitrate(test)).to.be.above(test.min * 1000).and.below(test.max * 1000)
     }
   })
 })
index 1e94eabcdd89c8304f4e38d88d6870d17d3b6f2a..31716d54539b1da6f5278b3ed7dd3f6c3a7f1690 100644 (file)
@@ -145,7 +145,7 @@ describe('Test Live transcoding in peertube-runner program', function () {
     const registrationToken = await servers[0].runnerRegistrationTokens.getFirstRegistrationToken()
 
     peertubeRunner = new PeerTubeRunnerProcess()
-    await peertubeRunner.runServer({ hideLogs: false })
+    await peertubeRunner.runServer()
     await peertubeRunner.registerPeerTubeInstance({ server: servers[0], registrationToken, runnerName: 'runner' })
   })
 
index cca905e2fc2394de036f4d38d119731fcd3cf174..204836c4d45e7958cdc49c03267be897d4fafb45 100644 (file)
@@ -75,7 +75,7 @@ describe('Test studio transcoding in peertube-runner program', function () {
     const registrationToken = await servers[0].runnerRegistrationTokens.getFirstRegistrationToken()
 
     peertubeRunner = new PeerTubeRunnerProcess()
-    await peertubeRunner.runServer({ hideLogs: false })
+    await peertubeRunner.runServer()
     await peertubeRunner.registerPeerTubeInstance({ server: servers[0], registrationToken, runnerName: 'runner' })
   })
 
index b0c8dba66972b9147025bc63807d24cd68265621..3788b049f89eb2ec2311b0869ddfa0e611cc60eb 100644 (file)
@@ -2,7 +2,7 @@ import { expect } from 'chai'
 import ffmpeg from 'fluent-ffmpeg'
 import { ensureDir, pathExists } from 'fs-extra'
 import { dirname } from 'path'
-import { buildAbsoluteFixturePath, getMaxBitrate } from '@shared/core-utils'
+import { buildAbsoluteFixturePath, getMaxTheoreticalBitrate } from '@shared/core-utils'
 import { getVideoStreamBitrate, getVideoStreamDimensionsInfo, getVideoStreamFPS } from '@shared/ffmpeg'
 
 async function ensureHasTooBigBitrate (fixturePath: string) {
@@ -10,7 +10,7 @@ async function ensureHasTooBigBitrate (fixturePath: string) {
   const dataResolution = await getVideoStreamDimensionsInfo(fixturePath)
   const fps = await getVideoStreamFPS(fixturePath)
 
-  const maxBitrate = getMaxBitrate({ ...dataResolution, fps })
+  const maxBitrate = getMaxTheoreticalBitrate({ ...dataResolution, fps })
   expect(bitrate).to.be.above(maxBitrate)
 }
 
index 30d22df095da6aa2ae367b2b854ad2c11f1af8f3..6be0278267a6f88edbcc59c3ba57679ff3b460f4 100644 (file)
@@ -40,7 +40,7 @@ const maxBitPerPixel: BitPerPixel = {
   [VideoResolution.H_4K]: 0.14
 }
 
-function getAverageBitrate (options: {
+function getAverageTheoreticalBitrate (options: {
   resolution: VideoResolution
   ratio: number
   fps: number
@@ -51,7 +51,7 @@ function getAverageBitrate (options: {
   return targetBitrate
 }
 
-function getMaxBitrate (options: {
+function getMaxTheoreticalBitrate (options: {
   resolution: VideoResolution
   ratio: number
   fps: number
@@ -62,7 +62,7 @@ function getMaxBitrate (options: {
   return targetBitrate
 }
 
-function getMinLimitBitrate (options: {
+function getMinTheoreticalBitrate (options: {
   resolution: VideoResolution
   ratio: number
   fps: number
@@ -76,9 +76,9 @@ function getMinLimitBitrate (options: {
 // ---------------------------------------------------------------------------
 
 export {
-  getAverageBitrate,
-  getMaxBitrate,
-  getMinLimitBitrate
+  getAverageTheoreticalBitrate,
+  getMaxTheoreticalBitrate,
+  getMinTheoreticalBitrate
 }
 
 // ---------------------------------------------------------------------------
index f7fc49465e7f2d0fa5dab38d2a2bca08f3fc775f..8a3f320114e25b30ea55c41a3cc96cda7113d36f 100644 (file)
@@ -1,5 +1,15 @@
-import { getAverageBitrate, getMinLimitBitrate } from '@shared/core-utils'
-import { buildStreamSuffix, ffprobePromise, getAudioStream, getMaxAudioBitrate } from '@shared/ffmpeg'
+import { FfprobeData } from 'fluent-ffmpeg'
+import { getAverageTheoreticalBitrate, getMaxTheoreticalBitrate, getMinTheoreticalBitrate } from '@shared/core-utils'
+import {
+  buildStreamSuffix,
+  ffprobePromise,
+  getAudioStream,
+  getMaxAudioBitrate,
+  getVideoStream,
+  getVideoStreamBitrate,
+  getVideoStreamDimensionsInfo,
+  getVideoStreamFPS
+} from '@shared/ffmpeg'
 import { EncoderOptionsBuilder, EncoderOptionsBuilderParams, VideoResolution } from '@shared/models'
 
 const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => {
@@ -34,6 +44,10 @@ const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOp
 const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNum, canCopyAudio }) => {
   const probe = await ffprobePromise(input)
 
+  if (canCopyAudio && await canDoQuickAudioTranscode(input, probe)) {
+    return { copy: true, outputOptions: [ ] }
+  }
+
   const parsedAudio = await getAudioStream(input, probe)
 
   // We try to reduce the ceiling bitrate by making rough matches of bitrates
@@ -95,6 +109,45 @@ export function getDefaultEncodersToTry () {
   }
 }
 
+export async function canDoQuickAudioTranscode (path: string, probe?: FfprobeData): Promise<boolean> {
+  const parsedAudio = await getAudioStream(path, probe)
+
+  if (!parsedAudio.audioStream) return true
+
+  if (parsedAudio.audioStream['codec_name'] !== 'aac') return false
+
+  const audioBitrate = parsedAudio.bitrate
+  if (!audioBitrate) return false
+
+  const maxAudioBitrate = getMaxAudioBitrate('aac', audioBitrate)
+  if (maxAudioBitrate !== -1 && audioBitrate > maxAudioBitrate) return false
+
+  const channelLayout = parsedAudio.audioStream['channel_layout']
+  // Causes playback issues with Chrome
+  if (!channelLayout || channelLayout === 'unknown' || channelLayout === 'quad') return false
+
+  return true
+}
+
+export async function canDoQuickVideoTranscode (path: string, probe?: FfprobeData): Promise<boolean> {
+  const videoStream = await getVideoStream(path, probe)
+  const fps = await getVideoStreamFPS(path, probe)
+  const bitRate = await getVideoStreamBitrate(path, probe)
+  const resolutionData = await getVideoStreamDimensionsInfo(path, probe)
+
+  // If ffprobe did not manage to guess the bitrate
+  if (!bitRate) return false
+
+  // check video params
+  if (!videoStream) return false
+  if (videoStream['codec_name'] !== 'h264') return false
+  if (videoStream['pix_fmt'] !== 'yuv420p') return false
+  if (fps < 2 || fps > 65) return false
+  if (bitRate > getMaxTheoreticalBitrate({ ...resolutionData, fps })) return false
+
+  return true
+}
+
 // ---------------------------------------------------------------------------
 
 function getTargetBitrate (options: {
@@ -105,8 +158,8 @@ function getTargetBitrate (options: {
 }) {
   const { inputBitrate, resolution, ratio, fps } = options
 
-  const capped = capBitrate(inputBitrate, getAverageBitrate({ resolution, fps, ratio }))
-  const limit = getMinLimitBitrate({ resolution, fps, ratio })
+  const capped = capBitrate(inputBitrate, getAverageTheoreticalBitrate({ resolution, fps, ratio }))
+  const limit = getMinTheoreticalBitrate({ resolution, fps, ratio })
 
   return Math.max(limit, capped)
 }