mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2024-11-22 08:46:54 -06:00
Optimize transcoding profile building
This commit is contained in:
parent
4e98d843da
commit
c09e27d77a
@ -107,7 +107,8 @@ export class ProcessLiveRTMPHLSTranscoding {
|
|||||||
bitrate,
|
bitrate,
|
||||||
ratio,
|
ratio,
|
||||||
|
|
||||||
hasAudio
|
hasAudio,
|
||||||
|
probe
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.info(`Running live transcoding for ${payload.input.rtmpUrl}`)
|
logger.info(`Running live transcoding for ${payload.input.rtmpUrl}`)
|
||||||
|
@ -73,7 +73,7 @@ export class FFmpegCommandWrapper {
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
debugLog (msg: string, meta: any) {
|
debugLog (msg: string, meta: any = {}) {
|
||||||
this.logger.debug(msg, { ...meta, ...this.lTags })
|
this.logger.debug(msg, { ...meta, ...this.lTags })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,6 +199,7 @@ export class FFmpegCommandWrapper {
|
|||||||
'canCopyVideo',
|
'canCopyVideo',
|
||||||
'resolution',
|
'resolution',
|
||||||
'inputBitrate',
|
'inputBitrate',
|
||||||
|
'inputProbe',
|
||||||
'fps',
|
'fps',
|
||||||
'inputRatio',
|
'inputRatio',
|
||||||
'streamNum'
|
'streamNum'
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { FfprobeData } from 'fluent-ffmpeg'
|
|
||||||
import { getAverageTheoreticalBitrate, getMaxTheoreticalBitrate, getMinTheoreticalBitrate } from '@peertube/peertube-core-utils'
|
import { getAverageTheoreticalBitrate, getMaxTheoreticalBitrate, getMinTheoreticalBitrate } from '@peertube/peertube-core-utils'
|
||||||
import {
|
import {
|
||||||
buildStreamSuffix,
|
buildStreamSuffix,
|
||||||
ffprobePromise,
|
|
||||||
getAudioStream,
|
getAudioStream,
|
||||||
getMaxAudioBitrate,
|
getMaxAudioBitrate,
|
||||||
getVideoStream,
|
getVideoStream,
|
||||||
@ -11,6 +9,7 @@ import {
|
|||||||
getVideoStreamFPS
|
getVideoStreamFPS
|
||||||
} from '@peertube/peertube-ffmpeg'
|
} from '@peertube/peertube-ffmpeg'
|
||||||
import { EncoderOptionsBuilder, EncoderOptionsBuilderParams } from '@peertube/peertube-models'
|
import { EncoderOptionsBuilder, EncoderOptionsBuilderParams } from '@peertube/peertube-models'
|
||||||
|
import { FfprobeData } from 'fluent-ffmpeg'
|
||||||
|
|
||||||
const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => {
|
const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOptionsBuilderParams) => {
|
||||||
const { fps, inputRatio, inputBitrate, resolution } = options
|
const { fps, inputRatio, inputBitrate, resolution } = options
|
||||||
@ -41,14 +40,12 @@ const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNum, canCopyAudio }) => {
|
const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNum, canCopyAudio, inputProbe }) => {
|
||||||
const probe = await ffprobePromise(input)
|
if (canCopyAudio && await canDoQuickAudioTranscode(input, inputProbe)) {
|
||||||
|
|
||||||
if (canCopyAudio && await canDoQuickAudioTranscode(input, probe)) {
|
|
||||||
return { copy: true, outputOptions: [ ] }
|
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
|
// 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
|
// Of course this is far from perfect, but it might save some space in the end
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { FilterSpecification } from 'fluent-ffmpeg'
|
|
||||||
import { join } from 'path'
|
|
||||||
import { pick } from '@peertube/peertube-core-utils'
|
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 { 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'
|
import { addDefaultEncoderGlobalParams, addDefaultEncoderParams, applyEncoderOptions } from './shared/index.js'
|
||||||
|
|
||||||
export class FFmpegLive {
|
export class FFmpegLive {
|
||||||
@ -27,6 +27,7 @@ export class FFmpegLive {
|
|||||||
bitrate: number
|
bitrate: number
|
||||||
ratio: number
|
ratio: number
|
||||||
hasAudio: boolean
|
hasAudio: boolean
|
||||||
|
probe: FfprobeData
|
||||||
|
|
||||||
segmentListSize: number
|
segmentListSize: number
|
||||||
segmentDuration: number
|
segmentDuration: number
|
||||||
@ -38,7 +39,8 @@ export class FFmpegLive {
|
|||||||
bitrate,
|
bitrate,
|
||||||
masterPlaylistName,
|
masterPlaylistName,
|
||||||
ratio,
|
ratio,
|
||||||
hasAudio
|
hasAudio,
|
||||||
|
probe
|
||||||
} = options
|
} = options
|
||||||
const command = this.commandWrapper.buildCommand(inputUrl)
|
const command = this.commandWrapper.buildCommand(inputUrl)
|
||||||
|
|
||||||
@ -69,6 +71,7 @@ export class FFmpegLive {
|
|||||||
|
|
||||||
inputBitrate: bitrate,
|
inputBitrate: bitrate,
|
||||||
inputRatio: ratio,
|
inputRatio: ratio,
|
||||||
|
inputProbe: probe,
|
||||||
|
|
||||||
resolution,
|
resolution,
|
||||||
fps,
|
fps,
|
||||||
@ -79,6 +82,7 @@ export class FFmpegLive {
|
|||||||
|
|
||||||
{
|
{
|
||||||
const streamType: StreamType = 'video'
|
const streamType: StreamType = 'video'
|
||||||
|
|
||||||
const builderResult = await this.commandWrapper.getEncoderBuilderResult({ ...baseEncoderBuilderParams, streamType })
|
const builderResult = await this.commandWrapper.getEncoderBuilderResult({ ...baseEncoderBuilderParams, streamType })
|
||||||
if (!builderResult) {
|
if (!builderResult) {
|
||||||
throw new Error('No available live video encoder found')
|
throw new Error('No available live video encoder found')
|
||||||
@ -108,6 +112,7 @@ export class FFmpegLive {
|
|||||||
|
|
||||||
if (hasAudio) {
|
if (hasAudio) {
|
||||||
const streamType: StreamType = 'audio'
|
const streamType: StreamType = 'audio'
|
||||||
|
|
||||||
const builderResult = await this.commandWrapper.getEncoderBuilderResult({ ...baseEncoderBuilderParams, streamType })
|
const builderResult = await this.commandWrapper.getEncoderBuilderResult({ ...baseEncoderBuilderParams, streamType })
|
||||||
if (!builderResult) {
|
if (!builderResult) {
|
||||||
throw new Error('No available live audio encoder found')
|
throw new Error('No available live audio encoder found')
|
||||||
|
@ -45,6 +45,7 @@ export async function presetVOD (options: {
|
|||||||
input,
|
input,
|
||||||
inputBitrate: bitrate,
|
inputBitrate: bitrate,
|
||||||
inputRatio: videoStreamDimensions?.ratio || 0,
|
inputRatio: videoStreamDimensions?.ratio || 0,
|
||||||
|
inputProbe: probe,
|
||||||
|
|
||||||
resolution,
|
resolution,
|
||||||
fps,
|
fps,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// Types used by plugins and ffmpeg-utils
|
// Types used by plugins and ffmpeg-utils
|
||||||
|
|
||||||
|
import { FfprobeData } from 'fluent-ffmpeg'
|
||||||
|
|
||||||
export type EncoderOptionsBuilderParams = {
|
export type EncoderOptionsBuilderParams = {
|
||||||
input: string
|
input: string
|
||||||
|
|
||||||
@ -14,6 +16,7 @@ export type EncoderOptionsBuilderParams = {
|
|||||||
// Could be undefined if we could not get input bitrate (some RTMP streams for example)
|
// Could be undefined if we could not get input bitrate (some RTMP streams for example)
|
||||||
inputBitrate: number
|
inputBitrate: number
|
||||||
inputRatio: number
|
inputRatio: number
|
||||||
|
inputProbe: FfprobeData
|
||||||
|
|
||||||
// For lives
|
// For lives
|
||||||
streamNum?: number
|
streamNum?: number
|
||||||
|
@ -36,6 +36,7 @@ import { computeResolutionsToTranscode } from '../transcoding/transcoding-resolu
|
|||||||
import { LiveQuotaStore } from './live-quota-store.js'
|
import { LiveQuotaStore } from './live-quota-store.js'
|
||||||
import { cleanupAndDestroyPermanentLive, getLiveSegmentTime } from './live-utils.js'
|
import { cleanupAndDestroyPermanentLive, getLiveSegmentTime } from './live-utils.js'
|
||||||
import { MuxingSession } from './shared/index.js'
|
import { MuxingSession } from './shared/index.js'
|
||||||
|
import { FfprobeData } from 'fluent-ffmpeg'
|
||||||
|
|
||||||
// Disable node media server logs
|
// Disable node media server logs
|
||||||
nodeMediaServerLogger.setLogType(0)
|
nodeMediaServerLogger.setLogType(0)
|
||||||
@ -319,7 +320,8 @@ class LiveManager {
|
|||||||
bitrate,
|
bitrate,
|
||||||
ratio,
|
ratio,
|
||||||
allResolutions,
|
allResolutions,
|
||||||
hasAudio
|
hasAudio,
|
||||||
|
probe
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,6 +339,7 @@ class LiveManager {
|
|||||||
ratio: number
|
ratio: number
|
||||||
allResolutions: number[]
|
allResolutions: number[]
|
||||||
hasAudio: boolean
|
hasAudio: boolean
|
||||||
|
probe: FfprobeData
|
||||||
}) {
|
}) {
|
||||||
const { sessionId, videoLive, user, ratio } = options
|
const { sessionId, videoLive, user, ratio } = options
|
||||||
const videoUUID = videoLive.Video.uuid
|
const videoUUID = videoLive.Video.uuid
|
||||||
@ -352,7 +355,7 @@ class LiveManager {
|
|||||||
videoLive,
|
videoLive,
|
||||||
user,
|
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 }))
|
muxingSession.on('live-ready', () => this.publishAndFederateLive({ live: videoLive, ratio, localLTags }))
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
import Bluebird from 'bluebird'
|
import { wait } from '@peertube/peertube-core-utils'
|
||||||
import { FSWatcher, watch } from 'chokidar'
|
import { FileStorage, LiveVideoError, VideoStreamingPlaylistType } from '@peertube/peertube-models'
|
||||||
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 { computeOutputFPS } from '@server/helpers/ffmpeg/index.js'
|
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 { CONFIG } from '@server/initializers/config.js'
|
||||||
import { MEMOIZE_TTL, P2P_MEDIA_LOADER_PEER_VERSION, VIDEO_LIVE } from '@server/initializers/constants.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 { removeHLSFileObjectStorageByPath, storeHLSFileFromContent, storeHLSFileFromPath } from '@server/lib/object-storage/index.js'
|
||||||
import { VideoFileModel } from '@server/models/video/video-file.js'
|
import { VideoFileModel } from '@server/models/video/video-file.js'
|
||||||
import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist.js'
|
import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist.js'
|
||||||
import { MStreamingPlaylistVideo, MUserId, MVideoLiveVideo } from '@server/types/models/index.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 {
|
import {
|
||||||
generateHLSMasterPlaylistFilename,
|
generateHLSMasterPlaylistFilename,
|
||||||
generateHlsSha256SegmentsFilename,
|
generateHlsSha256SegmentsFilename,
|
||||||
@ -26,7 +28,6 @@ import { LiveQuotaStore } from '../live-quota-store.js'
|
|||||||
import { LiveSegmentShaStore } from '../live-segment-sha-store.js'
|
import { LiveSegmentShaStore } from '../live-segment-sha-store.js'
|
||||||
import { buildConcatenatedName, getLiveSegmentTime } from '../live-utils.js'
|
import { buildConcatenatedName, getLiveSegmentTime } from '../live-utils.js'
|
||||||
import { AbstractTranscodingWrapper, FFmpegTranscodingWrapper, RemoteTranscodingWrapper } from './transcoding-wrapper/index.js'
|
import { AbstractTranscodingWrapper, FFmpegTranscodingWrapper, RemoteTranscodingWrapper } from './transcoding-wrapper/index.js'
|
||||||
import { wait } from '@peertube/peertube-core-utils'
|
|
||||||
|
|
||||||
interface MuxingSessionEvents {
|
interface MuxingSessionEvents {
|
||||||
'live-ready': (options: { videoUUID: string }) => void
|
'live-ready': (options: { videoUUID: string }) => void
|
||||||
@ -71,6 +72,8 @@ class MuxingSession extends EventEmitter {
|
|||||||
|
|
||||||
private readonly hasAudio: boolean
|
private readonly hasAudio: boolean
|
||||||
|
|
||||||
|
private readonly probe: FfprobeData
|
||||||
|
|
||||||
private readonly videoUUID: string
|
private readonly videoUUID: string
|
||||||
private readonly saveReplay: boolean
|
private readonly saveReplay: boolean
|
||||||
|
|
||||||
@ -116,6 +119,7 @@ class MuxingSession extends EventEmitter {
|
|||||||
ratio: number
|
ratio: number
|
||||||
allResolutions: number[]
|
allResolutions: number[]
|
||||||
hasAudio: boolean
|
hasAudio: boolean
|
||||||
|
probe: FfprobeData
|
||||||
}) {
|
}) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
@ -131,6 +135,7 @@ class MuxingSession extends EventEmitter {
|
|||||||
|
|
||||||
this.bitrate = options.bitrate
|
this.bitrate = options.bitrate
|
||||||
this.ratio = options.ratio
|
this.ratio = options.ratio
|
||||||
|
this.probe = options.probe
|
||||||
|
|
||||||
this.hasAudio = options.hasAudio
|
this.hasAudio = options.hasAudio
|
||||||
|
|
||||||
@ -510,6 +515,7 @@ class MuxingSession extends EventEmitter {
|
|||||||
bitrate: this.bitrate,
|
bitrate: this.bitrate,
|
||||||
ratio: this.ratio,
|
ratio: this.ratio,
|
||||||
hasAudio: this.hasAudio,
|
hasAudio: this.hasAudio,
|
||||||
|
probe: this.probe,
|
||||||
|
|
||||||
segmentListSize: VIDEO_LIVE.SEGMENTS_LIST_SIZE,
|
segmentListSize: VIDEO_LIVE.SEGMENTS_LIST_SIZE,
|
||||||
segmentDuration: getLiveSegmentTime(this.videoLive.latencyMode),
|
segmentDuration: getLiveSegmentTime(this.videoLive.latencyMode),
|
||||||
|
@ -2,6 +2,7 @@ import { LiveVideoErrorType } from '@peertube/peertube-models'
|
|||||||
import { LoggerTagsFn } from '@server/helpers/logger.js'
|
import { LoggerTagsFn } from '@server/helpers/logger.js'
|
||||||
import { MStreamingPlaylistVideo, MVideoLiveVideo } from '@server/types/models/index.js'
|
import { MStreamingPlaylistVideo, MVideoLiveVideo } from '@server/types/models/index.js'
|
||||||
import EventEmitter from 'events'
|
import EventEmitter from 'events'
|
||||||
|
import { FfprobeData } from 'fluent-ffmpeg'
|
||||||
|
|
||||||
interface TranscodingWrapperEvents {
|
interface TranscodingWrapperEvents {
|
||||||
'end': () => void
|
'end': () => void
|
||||||
@ -38,6 +39,7 @@ interface AbstractTranscodingWrapperOptions {
|
|||||||
bitrate: number
|
bitrate: number
|
||||||
ratio: number
|
ratio: number
|
||||||
hasAudio: boolean
|
hasAudio: boolean
|
||||||
|
probe: FfprobeData
|
||||||
|
|
||||||
segmentListSize: number
|
segmentListSize: number
|
||||||
segmentDuration: number
|
segmentDuration: number
|
||||||
@ -61,6 +63,7 @@ abstract class AbstractTranscodingWrapper extends EventEmitter {
|
|||||||
protected readonly bitrate: number
|
protected readonly bitrate: number
|
||||||
protected readonly ratio: number
|
protected readonly ratio: number
|
||||||
protected readonly hasAudio: boolean
|
protected readonly hasAudio: boolean
|
||||||
|
protected readonly probe: FfprobeData
|
||||||
|
|
||||||
protected readonly segmentListSize: number
|
protected readonly segmentListSize: number
|
||||||
protected readonly segmentDuration: number
|
protected readonly segmentDuration: number
|
||||||
@ -92,6 +95,7 @@ abstract class AbstractTranscodingWrapper extends EventEmitter {
|
|||||||
this.bitrate = options.bitrate
|
this.bitrate = options.bitrate
|
||||||
this.ratio = options.ratio
|
this.ratio = options.ratio
|
||||||
this.hasAudio = options.hasAudio
|
this.hasAudio = options.hasAudio
|
||||||
|
this.probe = options.probe
|
||||||
|
|
||||||
this.segmentListSize = options.segmentListSize
|
this.segmentListSize = options.segmentListSize
|
||||||
this.segmentDuration = options.segmentDuration
|
this.segmentDuration = options.segmentDuration
|
||||||
|
@ -30,6 +30,7 @@ export class FFmpegTranscodingWrapper extends AbstractTranscodingWrapper {
|
|||||||
|
|
||||||
bitrate: this.bitrate,
|
bitrate: this.bitrate,
|
||||||
ratio: this.ratio,
|
ratio: this.ratio,
|
||||||
|
probe: this.probe,
|
||||||
|
|
||||||
hasAudio: this.hasAudio
|
hasAudio: this.hasAudio
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user