aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/helpers/ffmpeg-utils.ts96
1 files changed, 59 insertions, 37 deletions
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index b6b64de3f..c477e2e89 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -130,51 +130,20 @@ type TranscodeOptions = {
130function transcode (options: TranscodeOptions) { 130function transcode (options: TranscodeOptions) {
131 return new Promise<void>(async (res, rej) => { 131 return new Promise<void>(async (res, rej) => {
132 try { 132 try {
133 let fps = await getVideoFileFPS(options.inputPath)
134 // On small/medium resolutions, limit FPS
135 if (
136 options.resolution !== undefined &&
137 options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN &&
138 fps > VIDEO_TRANSCODING_FPS.AVERAGE
139 ) {
140 fps = VIDEO_TRANSCODING_FPS.AVERAGE
141 }
142
143 let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING }) 133 let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING })
144 .output(options.outputPath) 134 .output(options.outputPath)
145 command = await presetH264(command, options.resolution, fps) 135
136 if (options.hlsPlaylist) {
137 command = await buildHLSCommand(command, options)
138 } else {
139 command = await buildx264Command(command, options)
140 }
146 141
147 if (CONFIG.TRANSCODING.THREADS > 0) { 142 if (CONFIG.TRANSCODING.THREADS > 0) {
148 // if we don't set any threads ffmpeg will chose automatically 143 // if we don't set any threads ffmpeg will chose automatically
149 command = command.outputOption('-threads ' + CONFIG.TRANSCODING.THREADS) 144 command = command.outputOption('-threads ' + CONFIG.TRANSCODING.THREADS)
150 } 145 }
151 146
152 if (options.resolution !== undefined) {
153 // '?x720' or '720x?' for example
154 const size = options.isPortraitMode === true ? `${options.resolution}x?` : `?x${options.resolution}`
155 command = command.size(size)
156 }
157
158 if (fps) {
159 // Hard FPS limits
160 if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.MAX
161 else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN
162
163 command = command.withFPS(fps)
164 }
165
166 if (options.hlsPlaylist) {
167 const videoPath = getHLSVideoPath(options)
168
169 command = command.outputOption('-hls_time 4')
170 .outputOption('-hls_list_size 0')
171 .outputOption('-hls_playlist_type vod')
172 .outputOption('-hls_segment_filename ' + videoPath)
173 .outputOption('-hls_segment_type fmp4')
174 .outputOption('-f hls')
175 .outputOption('-hls_flags single_file')
176 }
177
178 command 147 command
179 .on('error', (err, stdout, stderr) => { 148 .on('error', (err, stdout, stderr) => {
180 logger.error('Error in transcoding job.', { stdout, stderr }) 149 logger.error('Error in transcoding job.', { stdout, stderr })
@@ -208,6 +177,52 @@ export {
208 177
209// --------------------------------------------------------------------------- 178// ---------------------------------------------------------------------------
210 179
180async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) {
181 let fps = await getVideoFileFPS(options.inputPath)
182 // On small/medium resolutions, limit FPS
183 if (
184 options.resolution !== undefined &&
185 options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN &&
186 fps > VIDEO_TRANSCODING_FPS.AVERAGE
187 ) {
188 fps = VIDEO_TRANSCODING_FPS.AVERAGE
189 }
190
191 command = await presetH264(command, options.resolution, fps)
192
193 if (options.resolution !== undefined) {
194 // '?x720' or '720x?' for example
195 const size = options.isPortraitMode === true ? `${options.resolution}x?` : `?x${options.resolution}`
196 command = command.size(size)
197 }
198
199 if (fps) {
200 // Hard FPS limits
201 if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.MAX
202 else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN
203
204 command = command.withFPS(fps)
205 }
206
207 return command
208}
209
210async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) {
211 const videoPath = getHLSVideoPath(options)
212
213 command = await presetCopy(command)
214
215 command = command.outputOption('-hls_time 4')
216 .outputOption('-hls_list_size 0')
217 .outputOption('-hls_playlist_type vod')
218 .outputOption('-hls_segment_filename ' + videoPath)
219 .outputOption('-hls_segment_type fmp4')
220 .outputOption('-f hls')
221 .outputOption('-hls_flags single_file')
222
223 return command
224}
225
211function getHLSVideoPath (options: TranscodeOptions) { 226function getHLSVideoPath (options: TranscodeOptions) {
212 return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` 227 return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}`
213} 228}
@@ -397,3 +412,10 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResol
397 412
398 return localCommand 413 return localCommand
399} 414}
415
416async function presetCopy (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> {
417 return command
418 .format('mp4')
419 .videoCodec('copy')
420 .audioCodec('copy')
421}