From c09e27d77a2dc269d22c1e9785a38c2ba40d3752 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 19 Mar 2024 09:53:59 +0100 Subject: [PATCH] Optimize transcoding profile building --- .../src/server/process/shared/process-live.ts | 3 +- packages/ffmpeg/src/ffmpeg-command-wrapper.ts | 3 +- .../src/ffmpeg-default-transcoding-profile.ts | 11 +++----- packages/ffmpeg/src/ffmpeg-live.ts | 13 ++++++--- packages/ffmpeg/src/shared/presets.ts | 1 + .../transcoding/video-transcoding.model.ts | 3 ++ server/core/lib/live/live-manager.ts | 7 +++-- server/core/lib/live/shared/muxing-session.ts | 28 +++++++++++-------- .../abstract-transcoding-wrapper.ts | 4 +++ .../ffmpeg-transcoding-wrapper.ts | 1 + 10 files changed, 48 insertions(+), 26 deletions(-) diff --git a/apps/peertube-runner/src/server/process/shared/process-live.ts b/apps/peertube-runner/src/server/process/shared/process-live.ts index d6c7f8f12..ffb3c0c5a 100644 --- a/apps/peertube-runner/src/server/process/shared/process-live.ts +++ b/apps/peertube-runner/src/server/process/shared/process-live.ts @@ -107,7 +107,8 @@ export class ProcessLiveRTMPHLSTranscoding { bitrate, ratio, - hasAudio + hasAudio, + probe }) logger.info(`Running live transcoding for ${payload.input.rtmpUrl}`) diff --git a/packages/ffmpeg/src/ffmpeg-command-wrapper.ts b/packages/ffmpeg/src/ffmpeg-command-wrapper.ts index 50e842f76..6c4ab035d 100644 --- a/packages/ffmpeg/src/ffmpeg-command-wrapper.ts +++ b/packages/ffmpeg/src/ffmpeg-command-wrapper.ts @@ -73,7 +73,7 @@ export class FFmpegCommandWrapper { // --------------------------------------------------------------------------- - debugLog (msg: string, meta: any) { + debugLog (msg: string, meta: any = {}) { this.logger.debug(msg, { ...meta, ...this.lTags }) } @@ -199,6 +199,7 @@ export class FFmpegCommandWrapper { 'canCopyVideo', 'resolution', 'inputBitrate', + 'inputProbe', 'fps', 'inputRatio', 'streamNum' diff --git a/packages/ffmpeg/src/ffmpeg-default-transcoding-profile.ts b/packages/ffmpeg/src/ffmpeg-default-transcoding-profile.ts index 0d3538512..2104a6217 100644 --- a/packages/ffmpeg/src/ffmpeg-default-transcoding-profile.ts +++ b/packages/ffmpeg/src/ffmpeg-default-transcoding-profile.ts @@ -1,8 +1,6 @@ -import { FfprobeData } from 'fluent-ffmpeg' import { getAverageTheoreticalBitrate, getMaxTheoreticalBitrate, getMinTheoreticalBitrate } from '@peertube/peertube-core-utils' import { buildStreamSuffix, - ffprobePromise, getAudioStream, getMaxAudioBitrate, getVideoStream, @@ -11,6 +9,7 @@ import { getVideoStreamFPS } from '@peertube/peertube-ffmpeg' import { EncoderOptionsBuilder, EncoderOptionsBuilderParams } from '@peertube/peertube-models' +import { FfprobeData } from 'fluent-ffmpeg' const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => { const { fps, inputRatio, inputBitrate, resolution } = options @@ -41,14 +40,12 @@ const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOp } } -const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNum, canCopyAudio }) => { - const probe = await ffprobePromise(input) - - if (canCopyAudio && await canDoQuickAudioTranscode(input, probe)) { +const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNum, canCopyAudio, inputProbe }) => { + if (canCopyAudio && await canDoQuickAudioTranscode(input, inputProbe)) { return { copy: true, outputOptions: [ ] } } - const parsedAudio = await getAudioStream(input, probe) + const parsedAudio = await getAudioStream(input, inputProbe) // We try to reduce the ceiling bitrate by making rough matches of bitrates // Of course this is far from perfect, but it might save some space in the end diff --git a/packages/ffmpeg/src/ffmpeg-live.ts b/packages/ffmpeg/src/ffmpeg-live.ts index 20318f63c..7c3d89b5b 100644 --- a/packages/ffmpeg/src/ffmpeg-live.ts +++ b/packages/ffmpeg/src/ffmpeg-live.ts @@ -1,8 +1,8 @@ -import { FilterSpecification } from 'fluent-ffmpeg' -import { join } from 'path' import { pick } from '@peertube/peertube-core-utils' +import { FfprobeData, FilterSpecification } from 'fluent-ffmpeg' +import { join } from 'path' import { FFmpegCommandWrapper, FFmpegCommandWrapperOptions } from './ffmpeg-command-wrapper.js' -import { buildStreamSuffix, getScaleFilter, StreamType } from './ffmpeg-utils.js' +import { StreamType, buildStreamSuffix, getScaleFilter } from './ffmpeg-utils.js' import { addDefaultEncoderGlobalParams, addDefaultEncoderParams, applyEncoderOptions } from './shared/index.js' export class FFmpegLive { @@ -27,6 +27,7 @@ export class FFmpegLive { bitrate: number ratio: number hasAudio: boolean + probe: FfprobeData segmentListSize: number segmentDuration: number @@ -38,7 +39,8 @@ export class FFmpegLive { bitrate, masterPlaylistName, ratio, - hasAudio + hasAudio, + probe } = options const command = this.commandWrapper.buildCommand(inputUrl) @@ -69,6 +71,7 @@ export class FFmpegLive { inputBitrate: bitrate, inputRatio: ratio, + inputProbe: probe, resolution, fps, @@ -79,6 +82,7 @@ export class FFmpegLive { { const streamType: StreamType = 'video' + const builderResult = await this.commandWrapper.getEncoderBuilderResult({ ...baseEncoderBuilderParams, streamType }) if (!builderResult) { throw new Error('No available live video encoder found') @@ -108,6 +112,7 @@ export class FFmpegLive { if (hasAudio) { const streamType: StreamType = 'audio' + const builderResult = await this.commandWrapper.getEncoderBuilderResult({ ...baseEncoderBuilderParams, streamType }) if (!builderResult) { throw new Error('No available live audio encoder found') diff --git a/packages/ffmpeg/src/shared/presets.ts b/packages/ffmpeg/src/shared/presets.ts index 17bd7b031..009a65078 100644 --- a/packages/ffmpeg/src/shared/presets.ts +++ b/packages/ffmpeg/src/shared/presets.ts @@ -45,6 +45,7 @@ export async function presetVOD (options: { input, inputBitrate: bitrate, inputRatio: videoStreamDimensions?.ratio || 0, + inputProbe: probe, resolution, fps, diff --git a/packages/models/src/videos/transcoding/video-transcoding.model.ts b/packages/models/src/videos/transcoding/video-transcoding.model.ts index e2c2a56e5..ea9297681 100644 --- a/packages/models/src/videos/transcoding/video-transcoding.model.ts +++ b/packages/models/src/videos/transcoding/video-transcoding.model.ts @@ -1,5 +1,7 @@ // Types used by plugins and ffmpeg-utils +import { FfprobeData } from 'fluent-ffmpeg' + export type EncoderOptionsBuilderParams = { input: string @@ -14,6 +16,7 @@ export type EncoderOptionsBuilderParams = { // Could be undefined if we could not get input bitrate (some RTMP streams for example) inputBitrate: number inputRatio: number + inputProbe: FfprobeData // For lives streamNum?: number diff --git a/server/core/lib/live/live-manager.ts b/server/core/lib/live/live-manager.ts index 3e20d33e6..2480d1795 100644 --- a/server/core/lib/live/live-manager.ts +++ b/server/core/lib/live/live-manager.ts @@ -36,6 +36,7 @@ import { computeResolutionsToTranscode } from '../transcoding/transcoding-resolu import { LiveQuotaStore } from './live-quota-store.js' import { cleanupAndDestroyPermanentLive, getLiveSegmentTime } from './live-utils.js' import { MuxingSession } from './shared/index.js' +import { FfprobeData } from 'fluent-ffmpeg' // Disable node media server logs nodeMediaServerLogger.setLogType(0) @@ -319,7 +320,8 @@ class LiveManager { bitrate, ratio, allResolutions, - hasAudio + hasAudio, + probe }) } @@ -337,6 +339,7 @@ class LiveManager { ratio: number allResolutions: number[] hasAudio: boolean + probe: FfprobeData }) { const { sessionId, videoLive, user, ratio } = options const videoUUID = videoLive.Video.uuid @@ -352,7 +355,7 @@ class LiveManager { videoLive, user, - ...pick(options, [ 'inputLocalUrl', 'inputPublicUrl', 'bitrate', 'ratio', 'fps', 'allResolutions', 'hasAudio' ]) + ...pick(options, [ 'inputLocalUrl', 'inputPublicUrl', 'bitrate', 'ratio', 'fps', 'allResolutions', 'hasAudio', 'probe' ]) }) muxingSession.on('live-ready', () => this.publishAndFederateLive({ live: videoLive, ratio, localLTags })) diff --git a/server/core/lib/live/shared/muxing-session.ts b/server/core/lib/live/shared/muxing-session.ts index c1678c27e..8ff2d51a7 100644 --- a/server/core/lib/live/shared/muxing-session.ts +++ b/server/core/lib/live/shared/muxing-session.ts @@ -1,20 +1,22 @@ -import Bluebird from 'bluebird' -import { FSWatcher, watch } from 'chokidar' -import { EventEmitter } from 'events' -import { ensureDir } from 'fs-extra/esm' -import { appendFile, readFile, stat } from 'fs/promises' -import memoizee from 'memoizee' -import PQueue from 'p-queue' -import { basename, join } from 'path' +import { wait } from '@peertube/peertube-core-utils' +import { FileStorage, LiveVideoError, VideoStreamingPlaylistType } from '@peertube/peertube-models' import { computeOutputFPS } from '@server/helpers/ffmpeg/index.js' -import { logger, loggerTagsFactory, LoggerTagsFn } from '@server/helpers/logger.js' +import { LoggerTagsFn, logger, loggerTagsFactory } from '@server/helpers/logger.js' import { CONFIG } from '@server/initializers/config.js' import { MEMOIZE_TTL, P2P_MEDIA_LOADER_PEER_VERSION, VIDEO_LIVE } from '@server/initializers/constants.js' import { removeHLSFileObjectStorageByPath, storeHLSFileFromContent, storeHLSFileFromPath } from '@server/lib/object-storage/index.js' import { VideoFileModel } from '@server/models/video/video-file.js' import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist.js' import { MStreamingPlaylistVideo, MUserId, MVideoLiveVideo } from '@server/types/models/index.js' -import { LiveVideoError, FileStorage, VideoStreamingPlaylistType } from '@peertube/peertube-models' +import Bluebird from 'bluebird' +import { FSWatcher, watch } from 'chokidar' +import { EventEmitter } from 'events' +import { FfprobeData } from 'fluent-ffmpeg' +import { ensureDir } from 'fs-extra/esm' +import { appendFile, readFile, stat } from 'fs/promises' +import memoizee from 'memoizee' +import PQueue from 'p-queue' +import { basename, join } from 'path' import { generateHLSMasterPlaylistFilename, generateHlsSha256SegmentsFilename, @@ -26,7 +28,6 @@ import { LiveQuotaStore } from '../live-quota-store.js' import { LiveSegmentShaStore } from '../live-segment-sha-store.js' import { buildConcatenatedName, getLiveSegmentTime } from '../live-utils.js' import { AbstractTranscodingWrapper, FFmpegTranscodingWrapper, RemoteTranscodingWrapper } from './transcoding-wrapper/index.js' -import { wait } from '@peertube/peertube-core-utils' interface MuxingSessionEvents { 'live-ready': (options: { videoUUID: string }) => void @@ -71,6 +72,8 @@ class MuxingSession extends EventEmitter { private readonly hasAudio: boolean + private readonly probe: FfprobeData + private readonly videoUUID: string private readonly saveReplay: boolean @@ -116,6 +119,7 @@ class MuxingSession extends EventEmitter { ratio: number allResolutions: number[] hasAudio: boolean + probe: FfprobeData }) { super() @@ -131,6 +135,7 @@ class MuxingSession extends EventEmitter { this.bitrate = options.bitrate this.ratio = options.ratio + this.probe = options.probe this.hasAudio = options.hasAudio @@ -510,6 +515,7 @@ class MuxingSession extends EventEmitter { bitrate: this.bitrate, ratio: this.ratio, hasAudio: this.hasAudio, + probe: this.probe, segmentListSize: VIDEO_LIVE.SEGMENTS_LIST_SIZE, segmentDuration: getLiveSegmentTime(this.videoLive.latencyMode), diff --git a/server/core/lib/live/shared/transcoding-wrapper/abstract-transcoding-wrapper.ts b/server/core/lib/live/shared/transcoding-wrapper/abstract-transcoding-wrapper.ts index 8cae0c45b..30377d6e0 100644 --- a/server/core/lib/live/shared/transcoding-wrapper/abstract-transcoding-wrapper.ts +++ b/server/core/lib/live/shared/transcoding-wrapper/abstract-transcoding-wrapper.ts @@ -2,6 +2,7 @@ import { LiveVideoErrorType } from '@peertube/peertube-models' import { LoggerTagsFn } from '@server/helpers/logger.js' import { MStreamingPlaylistVideo, MVideoLiveVideo } from '@server/types/models/index.js' import EventEmitter from 'events' +import { FfprobeData } from 'fluent-ffmpeg' interface TranscodingWrapperEvents { 'end': () => void @@ -38,6 +39,7 @@ interface AbstractTranscodingWrapperOptions { bitrate: number ratio: number hasAudio: boolean + probe: FfprobeData segmentListSize: number segmentDuration: number @@ -61,6 +63,7 @@ abstract class AbstractTranscodingWrapper extends EventEmitter { protected readonly bitrate: number protected readonly ratio: number protected readonly hasAudio: boolean + protected readonly probe: FfprobeData protected readonly segmentListSize: number protected readonly segmentDuration: number @@ -92,6 +95,7 @@ abstract class AbstractTranscodingWrapper extends EventEmitter { this.bitrate = options.bitrate this.ratio = options.ratio this.hasAudio = options.hasAudio + this.probe = options.probe this.segmentListSize = options.segmentListSize this.segmentDuration = options.segmentDuration diff --git a/server/core/lib/live/shared/transcoding-wrapper/ffmpeg-transcoding-wrapper.ts b/server/core/lib/live/shared/transcoding-wrapper/ffmpeg-transcoding-wrapper.ts index e8fd192ff..d5b73dd59 100644 --- a/server/core/lib/live/shared/transcoding-wrapper/ffmpeg-transcoding-wrapper.ts +++ b/server/core/lib/live/shared/transcoding-wrapper/ffmpeg-transcoding-wrapper.ts @@ -30,6 +30,7 @@ export class FFmpegTranscodingWrapper extends AbstractTranscodingWrapper { bitrate: this.bitrate, ratio: this.ratio, + probe: this.probe, hasAudio: this.hasAudio })