availableEncoders,
profile: getProfile(type),
- niceness: FFMPEG_NICE[type],
+ niceness: FFMPEG_NICE[type.toUpperCase()],
tmpDirectory: CONFIG.STORAGE.TMP_DIR,
threads: getThreads(type),
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
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
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
-}
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,
expect(resolution).to.equal(resolution)
- const maxBitrate = getMaxBitrate({ ...dataResolution, fps })
+ const maxBitrate = getMaxTheoreticalBitrate({ ...dataResolution, fps })
expect(bitrate).to.be.below(maxBitrate)
}
}
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
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'
]
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)
}
})
]
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)
}
})
})
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' })
})
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' })
})
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) {
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)
}
[VideoResolution.H_4K]: 0.14
}
-function getAverageBitrate (options: {
+function getAverageTheoreticalBitrate (options: {
resolution: VideoResolution
ratio: number
fps: number
return targetBitrate
}
-function getMaxBitrate (options: {
+function getMaxTheoreticalBitrate (options: {
resolution: VideoResolution
ratio: number
fps: number
return targetBitrate
}
-function getMinLimitBitrate (options: {
+function getMinTheoreticalBitrate (options: {
resolution: VideoResolution
ratio: number
fps: number
// ---------------------------------------------------------------------------
export {
- getAverageBitrate,
- getMaxBitrate,
- getMinLimitBitrate
+ getAverageTheoreticalBitrate,
+ getMaxTheoreticalBitrate,
+ getMinTheoreticalBitrate
}
// ---------------------------------------------------------------------------
-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) => {
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
}
}
+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: {
}) {
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)
}