From f443a74649174b2f9347c158e30f8ac7aa3e958a Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 4 Mar 2022 13:40:02 +0100 Subject: Add latency setting support --- server/helpers/activitypub.ts | 4 +++ .../custom-validators/activitypub/videos.ts | 4 ++- server/helpers/custom-validators/video-lives.ts | 11 ++++++ server/helpers/ffmpeg/ffmpeg-live.ts | 39 ++++++++++++++++++---- 4 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 server/helpers/custom-validators/video-lives.ts (limited to 'server/helpers') diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts index cbba2f51c..d0bcc6785 100644 --- a/server/helpers/activitypub.ts +++ b/server/helpers/activitypub.ts @@ -50,6 +50,10 @@ function getContextData (type: ContextType) { '@type': 'sc:Boolean', '@id': 'pt:permanentLive' }, + latencyMode: { + '@type': 'sc:Number', + '@id': 'pt:latencyMode' + }, Infohash: 'pt:Infohash', Playlist: 'pt:Playlist', diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts index a41d37810..80a321117 100644 --- a/server/helpers/custom-validators/activitypub/videos.ts +++ b/server/helpers/custom-validators/activitypub/videos.ts @@ -1,10 +1,11 @@ import validator from 'validator' import { logger } from '@server/helpers/logger' import { ActivityTrackerUrlObject, ActivityVideoFileMetadataUrlObject } from '@shared/models' -import { VideoState } from '../../../../shared/models/videos' +import { LiveVideoLatencyMode, VideoState } from '../../../../shared/models/videos' import { ACTIVITY_PUB, CONSTRAINTS_FIELDS } from '../../../initializers/constants' import { peertubeTruncate } from '../../core-utils' import { exists, isArray, isBooleanValid, isDateValid, isUUIDValid } from '../misc' +import { isLiveLatencyModeValid } from '../video-lives' import { isVideoDurationValid, isVideoNameValid, @@ -65,6 +66,7 @@ function sanitizeAndCheckVideoTorrentObject (video: any) { if (!isBooleanValid(video.isLiveBroadcast)) video.isLiveBroadcast = false if (!isBooleanValid(video.liveSaveReplay)) video.liveSaveReplay = false if (!isBooleanValid(video.permanentLive)) video.permanentLive = false + if (!isLiveLatencyModeValid(video.latencyMode)) video.latencyMode = LiveVideoLatencyMode.DEFAULT return isActivityPubUrlValid(video.id) && isVideoNameValid(video.name) && diff --git a/server/helpers/custom-validators/video-lives.ts b/server/helpers/custom-validators/video-lives.ts new file mode 100644 index 000000000..69d08ae68 --- /dev/null +++ b/server/helpers/custom-validators/video-lives.ts @@ -0,0 +1,11 @@ +import { LiveVideoLatencyMode } from '@shared/models' + +function isLiveLatencyModeValid (value: any) { + return [ LiveVideoLatencyMode.DEFAULT, LiveVideoLatencyMode.SMALL_LATENCY, LiveVideoLatencyMode.HIGH_LATENCY ].includes(value) +} + +// --------------------------------------------------------------------------- + +export { + isLiveLatencyModeValid +} diff --git a/server/helpers/ffmpeg/ffmpeg-live.ts b/server/helpers/ffmpeg/ffmpeg-live.ts index ff571626c..fd20971eb 100644 --- a/server/helpers/ffmpeg/ffmpeg-live.ts +++ b/server/helpers/ffmpeg/ffmpeg-live.ts @@ -1,7 +1,7 @@ import { FfmpegCommand, FilterSpecification } from 'fluent-ffmpeg' import { join } from 'path' import { VIDEO_LIVE } from '@server/initializers/constants' -import { AvailableEncoders } from '@shared/models' +import { AvailableEncoders, LiveVideoLatencyMode } from '@shared/models' import { logger, loggerTagsFactory } from '../logger' import { buildStreamSuffix, getFFmpeg, getScaleFilter, StreamType } from './ffmpeg-commons' import { getEncoderBuilderResult } from './ffmpeg-encoders' @@ -15,6 +15,7 @@ async function getLiveTranscodingCommand (options: { outPath: string masterPlaylistName: string + latencyMode: LiveVideoLatencyMode resolutions: number[] @@ -26,7 +27,7 @@ async function getLiveTranscodingCommand (options: { availableEncoders: AvailableEncoders profile: string }) { - const { inputUrl, outPath, resolutions, fps, bitrate, availableEncoders, profile, masterPlaylistName, ratio } = options + const { inputUrl, outPath, resolutions, fps, bitrate, availableEncoders, profile, masterPlaylistName, ratio, latencyMode } = options const command = getFFmpeg(inputUrl, 'live') @@ -120,14 +121,21 @@ async function getLiveTranscodingCommand (options: { command.complexFilter(complexFilter) - addDefaultLiveHLSParams(command, outPath, masterPlaylistName) + addDefaultLiveHLSParams({ command, outPath, masterPlaylistName, latencyMode }) command.outputOption('-var_stream_map', varStreamMap.join(' ')) return command } -function getLiveMuxingCommand (inputUrl: string, outPath: string, masterPlaylistName: string) { +function getLiveMuxingCommand (options: { + inputUrl: string + outPath: string + masterPlaylistName: string + latencyMode: LiveVideoLatencyMode +}) { + const { inputUrl, outPath, masterPlaylistName, latencyMode } = options + const command = getFFmpeg(inputUrl, 'live') command.outputOption('-c:v copy') @@ -135,22 +143,39 @@ function getLiveMuxingCommand (inputUrl: string, outPath: string, masterPlaylist command.outputOption('-map 0:a?') command.outputOption('-map 0:v?') - addDefaultLiveHLSParams(command, outPath, masterPlaylistName) + addDefaultLiveHLSParams({ command, outPath, masterPlaylistName, latencyMode }) return command } +function getLiveSegmentTime (latencyMode: LiveVideoLatencyMode) { + if (latencyMode === LiveVideoLatencyMode.SMALL_LATENCY) { + return VIDEO_LIVE.SEGMENT_TIME_SECONDS.SMALL_LATENCY + } + + return VIDEO_LIVE.SEGMENT_TIME_SECONDS.DEFAULT_LATENCY +} + // --------------------------------------------------------------------------- export { + getLiveSegmentTime, + getLiveTranscodingCommand, getLiveMuxingCommand } // --------------------------------------------------------------------------- -function addDefaultLiveHLSParams (command: FfmpegCommand, outPath: string, masterPlaylistName: string) { - command.outputOption('-hls_time ' + VIDEO_LIVE.SEGMENT_TIME_SECONDS) +function addDefaultLiveHLSParams (options: { + command: FfmpegCommand + outPath: string + masterPlaylistName: string + latencyMode: LiveVideoLatencyMode +}) { + const { command, outPath, masterPlaylistName, latencyMode } = options + + command.outputOption('-hls_time ' + getLiveSegmentTime(latencyMode)) command.outputOption('-hls_list_size ' + VIDEO_LIVE.SEGMENTS_LIST_SIZE) command.outputOption('-hls_flags delete_segments+independent_segments') command.outputOption(`-hls_segment_filename ${join(outPath, '%v-%06d.ts')}`) -- cgit v1.2.3