diff --git a/server/helpers/ffmpeg/ffmpeg-live.ts b/server/helpers/ffmpeg/ffmpeg-live.ts index 8377dc7e2..379d7b1ad 100644 --- a/server/helpers/ffmpeg/ffmpeg-live.ts +++ b/server/helpers/ffmpeg/ffmpeg-live.ts @@ -23,11 +23,24 @@ async function getLiveTranscodingCommand (options: { fps: number bitrate: number ratio: number + hasAudio: boolean availableEncoders: AvailableEncoders profile: string }) { - const { inputUrl, outPath, resolutions, fps, bitrate, availableEncoders, profile, masterPlaylistName, ratio, latencyMode } = options + const { + inputUrl, + outPath, + resolutions, + fps, + bitrate, + availableEncoders, + profile, + masterPlaylistName, + ratio, + latencyMode, + hasAudio + } = options const command = getFFmpeg(inputUrl, 'live') @@ -47,6 +60,7 @@ async function getLiveTranscodingCommand (options: { addDefaultEncoderGlobalParams(command) for (let i = 0; i < resolutions.length; i++) { + const streamMap: string[] = [] const resolution = resolutions[i] const resolutionFPS = computeFPS(fps, resolution) @@ -94,9 +108,11 @@ async function getLiveTranscodingCommand (options: { options: `w=-2:h=${resolution}`, outputs: `vout${resolution}` }) + + streamMap.push(`v:${i}`) } - { + if (hasAudio) { const streamType: StreamType = 'audio' const builderResult = await getEncoderBuilderResult({ ...baseEncoderBuilderParams, streamType }) if (!builderResult) { @@ -114,9 +130,11 @@ async function getLiveTranscodingCommand (options: { command.outputOption(`${buildStreamSuffix('-c:a', i)} ${builderResult.encoder}`) applyEncoderOptions(command, builderResult.result) + + streamMap.push(`a:${i}`) } - varStreamMap.push(`v:${i},a:${i}`) + varStreamMap.push(streamMap.join(',')) } command.complexFilter(complexFilter) diff --git a/server/lib/live/live-manager.ts b/server/lib/live/live-manager.ts index aadd8e308..16715862b 100644 --- a/server/lib/live/live-manager.ts +++ b/server/lib/live/live-manager.ts @@ -1,4 +1,3 @@ - import { readdir, readFile } from 'fs-extra' import { createServer, Server } from 'net' import { join } from 'path' @@ -9,7 +8,8 @@ import { getLiveSegmentTime, getVideoStreamBitrate, getVideoStreamDimensionsInfo, - getVideoStreamFPS + getVideoStreamFPS, + hasAudioStream } from '@server/helpers/ffmpeg' import { logger, loggerTagsFactory } from '@server/helpers/logger' import { CONFIG, registerConfigChangedHandler } from '@server/initializers/config' @@ -20,7 +20,7 @@ import { VideoLiveModel } from '@server/models/video/video-live' import { VideoLiveSessionModel } from '@server/models/video/video-live-session' import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' import { MStreamingPlaylistVideo, MVideo, MVideoLiveSession, MVideoLiveVideo } from '@server/types/models' -import { wait } from '@shared/core-utils' +import { pick, wait } from '@shared/core-utils' import { LiveVideoError, VideoState, VideoStreamingPlaylistType } from '@shared/models' import { federateVideoIfNeeded } from '../activitypub/videos' import { JobQueue } from '../job-queue' @@ -232,10 +232,11 @@ class LiveManager { const now = Date.now() const probe = await ffprobePromise(inputUrl) - const [ { resolution, ratio }, fps, bitrate ] = await Promise.all([ + const [ { resolution, ratio }, fps, bitrate, hasAudio ] = await Promise.all([ getVideoStreamDimensionsInfo(inputUrl, probe), getVideoStreamFPS(inputUrl, probe), - getVideoStreamBitrate(inputUrl, probe) + getVideoStreamBitrate(inputUrl, probe), + hasAudioStream(inputUrl, probe) ]) logger.info( @@ -259,26 +260,30 @@ class LiveManager { return this.runMuxingSession({ sessionId, videoLive, + streamingPlaylist, inputUrl, fps, bitrate, ratio, - allResolutions + allResolutions, + hasAudio }) } private async runMuxingSession (options: { sessionId: string videoLive: MVideoLiveVideo + streamingPlaylist: MStreamingPlaylistVideo inputUrl: string fps: number bitrate: number ratio: number allResolutions: number[] + hasAudio: boolean }) { - const { sessionId, videoLive, streamingPlaylist, allResolutions, fps, bitrate, ratio, inputUrl } = options + const { sessionId, videoLive } = options const videoUUID = videoLive.Video.uuid const localLTags = lTags(sessionId, videoUUID) @@ -289,15 +294,11 @@ class LiveManager { const muxingSession = new MuxingSession({ context: this.getContext(), - user, sessionId, videoLive, - streamingPlaylist, - inputUrl, - bitrate, - ratio, - fps, - allResolutions + user, + + ...pick(options, [ 'streamingPlaylist', 'inputUrl', 'bitrate', 'ratio', 'fps', 'allResolutions', 'hasAudio' ]) }) muxingSession.on('master-playlist-created', () => this.publishAndFederateLive(videoLive, localLTags)) diff --git a/server/lib/live/shared/muxing-session.ts b/server/lib/live/shared/muxing-session.ts index 310a7026d..505717dce 100644 --- a/server/lib/live/shared/muxing-session.ts +++ b/server/lib/live/shared/muxing-session.ts @@ -59,6 +59,8 @@ class MuxingSession extends EventEmitter { private readonly bitrate: number private readonly ratio: number + private readonly hasAudio: boolean + private readonly videoId: number private readonly videoUUID: string private readonly saveReplay: boolean @@ -94,6 +96,7 @@ class MuxingSession extends EventEmitter { bitrate: number ratio: number allResolutions: number[] + hasAudio: boolean }) { super() @@ -108,6 +111,8 @@ class MuxingSession extends EventEmitter { this.bitrate = options.bitrate this.ratio = options.ratio + this.hasAudio = options.hasAudio + this.allResolutions = options.allResolutions this.videoId = this.videoLive.Video.id @@ -140,6 +145,8 @@ class MuxingSession extends EventEmitter { bitrate: this.bitrate, ratio: this.ratio, + hasAudio: this.hasAudio, + availableEncoders: VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), profile: CONFIG.LIVE.TRANSCODING.PROFILE })