aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers/ffmpeg/ffmpeg-live.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-04-21 14:55:10 +0200
committerChocobozzz <chocobozzz@cpy.re>2023-05-09 08:57:34 +0200
commit0c9668f77901e7540e2c7045eb0f2974a4842a69 (patch)
tree226d3dd1565b0bb56588897af3b8530e6216e96b /server/helpers/ffmpeg/ffmpeg-live.ts
parent6bcb854cdea8688a32240bc5719c7d139806e00b (diff)
downloadPeerTube-0c9668f77901e7540e2c7045eb0f2974a4842a69.tar.gz
PeerTube-0c9668f77901e7540e2c7045eb0f2974a4842a69.tar.zst
PeerTube-0c9668f77901e7540e2c7045eb0f2974a4842a69.zip
Implement remote runner jobs in server
Move ffmpeg functions to @shared
Diffstat (limited to 'server/helpers/ffmpeg/ffmpeg-live.ts')
-rw-r--r--server/helpers/ffmpeg/ffmpeg-live.ts204
1 files changed, 0 insertions, 204 deletions
diff --git a/server/helpers/ffmpeg/ffmpeg-live.ts b/server/helpers/ffmpeg/ffmpeg-live.ts
deleted file mode 100644
index 379d7b1ad..000000000
--- a/server/helpers/ffmpeg/ffmpeg-live.ts
+++ /dev/null
@@ -1,204 +0,0 @@
1import { FfmpegCommand, FilterSpecification } from 'fluent-ffmpeg'
2import { join } from 'path'
3import { VIDEO_LIVE } from '@server/initializers/constants'
4import { AvailableEncoders, LiveVideoLatencyMode } from '@shared/models'
5import { logger, loggerTagsFactory } from '../logger'
6import { buildStreamSuffix, getFFmpeg, getScaleFilter, StreamType } from './ffmpeg-commons'
7import { getEncoderBuilderResult } from './ffmpeg-encoders'
8import { addDefaultEncoderGlobalParams, addDefaultEncoderParams, applyEncoderOptions } from './ffmpeg-presets'
9import { computeFPS } from './ffprobe-utils'
10
11const lTags = loggerTagsFactory('ffmpeg')
12
13async function getLiveTranscodingCommand (options: {
14 inputUrl: string
15
16 outPath: string
17 masterPlaylistName: string
18 latencyMode: LiveVideoLatencyMode
19
20 resolutions: number[]
21
22 // Input information
23 fps: number
24 bitrate: number
25 ratio: number
26 hasAudio: boolean
27
28 availableEncoders: AvailableEncoders
29 profile: string
30}) {
31 const {
32 inputUrl,
33 outPath,
34 resolutions,
35 fps,
36 bitrate,
37 availableEncoders,
38 profile,
39 masterPlaylistName,
40 ratio,
41 latencyMode,
42 hasAudio
43 } = options
44
45 const command = getFFmpeg(inputUrl, 'live')
46
47 const varStreamMap: string[] = []
48
49 const complexFilter: FilterSpecification[] = [
50 {
51 inputs: '[v:0]',
52 filter: 'split',
53 options: resolutions.length,
54 outputs: resolutions.map(r => `vtemp${r}`)
55 }
56 ]
57
58 command.outputOption('-sc_threshold 0')
59
60 addDefaultEncoderGlobalParams(command)
61
62 for (let i = 0; i < resolutions.length; i++) {
63 const streamMap: string[] = []
64 const resolution = resolutions[i]
65 const resolutionFPS = computeFPS(fps, resolution)
66
67 const baseEncoderBuilderParams = {
68 input: inputUrl,
69
70 availableEncoders,
71 profile,
72
73 canCopyAudio: true,
74 canCopyVideo: true,
75
76 inputBitrate: bitrate,
77 inputRatio: ratio,
78
79 resolution,
80 fps: resolutionFPS,
81
82 streamNum: i,
83 videoType: 'live' as 'live'
84 }
85
86 {
87 const streamType: StreamType = 'video'
88 const builderResult = await getEncoderBuilderResult({ ...baseEncoderBuilderParams, streamType })
89 if (!builderResult) {
90 throw new Error('No available live video encoder found')
91 }
92
93 command.outputOption(`-map [vout${resolution}]`)
94
95 addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i })
96
97 logger.debug(
98 'Apply ffmpeg live video params from %s using %s profile.', builderResult.encoder, profile,
99 { builderResult, fps: resolutionFPS, resolution, ...lTags() }
100 )
101
102 command.outputOption(`${buildStreamSuffix('-c:v', i)} ${builderResult.encoder}`)
103 applyEncoderOptions(command, builderResult.result)
104
105 complexFilter.push({
106 inputs: `vtemp${resolution}`,
107 filter: getScaleFilter(builderResult.result),
108 options: `w=-2:h=${resolution}`,
109 outputs: `vout${resolution}`
110 })
111
112 streamMap.push(`v:${i}`)
113 }
114
115 if (hasAudio) {
116 const streamType: StreamType = 'audio'
117 const builderResult = await getEncoderBuilderResult({ ...baseEncoderBuilderParams, streamType })
118 if (!builderResult) {
119 throw new Error('No available live audio encoder found')
120 }
121
122 command.outputOption('-map a:0')
123
124 addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i })
125
126 logger.debug(
127 'Apply ffmpeg live audio params from %s using %s profile.', builderResult.encoder, profile,
128 { builderResult, fps: resolutionFPS, resolution, ...lTags() }
129 )
130
131 command.outputOption(`${buildStreamSuffix('-c:a', i)} ${builderResult.encoder}`)
132 applyEncoderOptions(command, builderResult.result)
133
134 streamMap.push(`a:${i}`)
135 }
136
137 varStreamMap.push(streamMap.join(','))
138 }
139
140 command.complexFilter(complexFilter)
141
142 addDefaultLiveHLSParams({ command, outPath, masterPlaylistName, latencyMode })
143
144 command.outputOption('-var_stream_map', varStreamMap.join(' '))
145
146 return command
147}
148
149function getLiveMuxingCommand (options: {
150 inputUrl: string
151 outPath: string
152 masterPlaylistName: string
153 latencyMode: LiveVideoLatencyMode
154}) {
155 const { inputUrl, outPath, masterPlaylistName, latencyMode } = options
156
157 const command = getFFmpeg(inputUrl, 'live')
158
159 command.outputOption('-c:v copy')
160 command.outputOption('-c:a copy')
161 command.outputOption('-map 0:a?')
162 command.outputOption('-map 0:v?')
163
164 addDefaultLiveHLSParams({ command, outPath, masterPlaylistName, latencyMode })
165
166 return command
167}
168
169function getLiveSegmentTime (latencyMode: LiveVideoLatencyMode) {
170 if (latencyMode === LiveVideoLatencyMode.SMALL_LATENCY) {
171 return VIDEO_LIVE.SEGMENT_TIME_SECONDS.SMALL_LATENCY
172 }
173
174 return VIDEO_LIVE.SEGMENT_TIME_SECONDS.DEFAULT_LATENCY
175}
176
177// ---------------------------------------------------------------------------
178
179export {
180 getLiveSegmentTime,
181
182 getLiveTranscodingCommand,
183 getLiveMuxingCommand
184}
185
186// ---------------------------------------------------------------------------
187
188function addDefaultLiveHLSParams (options: {
189 command: FfmpegCommand
190 outPath: string
191 masterPlaylistName: string
192 latencyMode: LiveVideoLatencyMode
193}) {
194 const { command, outPath, masterPlaylistName, latencyMode } = options
195
196 command.outputOption('-hls_time ' + getLiveSegmentTime(latencyMode))
197 command.outputOption('-hls_list_size ' + VIDEO_LIVE.SEGMENTS_LIST_SIZE)
198 command.outputOption('-hls_flags delete_segments+independent_segments+program_date_time')
199 command.outputOption(`-hls_segment_filename ${join(outPath, '%v-%06d.ts')}`)
200 command.outputOption('-master_pl_name ' + masterPlaylistName)
201 command.outputOption(`-f hls`)
202
203 command.output(join(outPath, '%v.m3u8'))
204}