aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-08-06 13:35:25 +0200
committerChocobozzz <me@florianbigard.com>2021-08-06 14:13:26 +0200
commit679c12e69c9f3a2d003ee3abe8b8da49f25b2bd3 (patch)
tree03abf589275db05e5b1fa1c89f57049cd807324a /server/helpers
parentc826f34a45757b324a20f71665b44ed10e6953b5 (diff)
downloadPeerTube-679c12e69c9f3a2d003ee3abe8b8da49f25b2bd3.tar.gz
PeerTube-679c12e69c9f3a2d003ee3abe8b8da49f25b2bd3.tar.zst
PeerTube-679c12e69c9f3a2d003ee3abe8b8da49f25b2bd3.zip
Improve target bitrate calculation
Diffstat (limited to 'server/helpers')
-rw-r--r--server/helpers/ffmpeg-utils.ts35
-rw-r--r--server/helpers/ffprobe-utils.ts16
2 files changed, 33 insertions, 18 deletions
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index 7f84a049f..830625cc6 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -3,10 +3,18 @@ import * as ffmpeg from 'fluent-ffmpeg'
3import { readFile, remove, writeFile } from 'fs-extra' 3import { readFile, remove, writeFile } from 'fs-extra'
4import { dirname, join } from 'path' 4import { dirname, join } from 'path'
5import { FFMPEG_NICE, VIDEO_LIVE } from '@server/initializers/constants' 5import { FFMPEG_NICE, VIDEO_LIVE } from '@server/initializers/constants'
6import { AvailableEncoders, EncoderOptions, EncoderOptionsBuilder, EncoderProfile, VideoResolution } from '../../shared/models/videos' 6import { pick } from '@shared/core-utils'
7import {
8 AvailableEncoders,
9 EncoderOptions,
10 EncoderOptionsBuilder,
11 EncoderOptionsBuilderParams,
12 EncoderProfile,
13 VideoResolution
14} from '../../shared/models/videos'
7import { CONFIG } from '../initializers/config' 15import { CONFIG } from '../initializers/config'
8import { execPromise, promisify0 } from './core-utils' 16import { execPromise, promisify0 } from './core-utils'
9import { computeFPS, ffprobePromise, getAudioStream, getVideoFileBitrate, getVideoFileFPS } from './ffprobe-utils' 17import { computeFPS, ffprobePromise, getAudioStream, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from './ffprobe-utils'
10import { processImage } from './image-utils' 18import { processImage } from './image-utils'
11import { logger } from './logger' 19import { logger } from './logger'
12 20
@@ -217,13 +225,16 @@ async function getLiveTranscodingCommand (options: {
217 masterPlaylistName: string 225 masterPlaylistName: string
218 226
219 resolutions: number[] 227 resolutions: number[]
228
229 // Input information
220 fps: number 230 fps: number
221 bitrate: number 231 bitrate: number
232 ratio: number
222 233
223 availableEncoders: AvailableEncoders 234 availableEncoders: AvailableEncoders
224 profile: string 235 profile: string
225}) { 236}) {
226 const { rtmpUrl, outPath, resolutions, fps, bitrate, availableEncoders, profile, masterPlaylistName } = options 237 const { rtmpUrl, outPath, resolutions, fps, bitrate, availableEncoders, profile, masterPlaylistName, ratio } = options
227 const input = rtmpUrl 238 const input = rtmpUrl
228 239
229 const command = getFFmpeg(input, 'live') 240 const command = getFFmpeg(input, 'live')
@@ -253,9 +264,12 @@ async function getLiveTranscodingCommand (options: {
253 availableEncoders, 264 availableEncoders,
254 profile, 265 profile,
255 266
256 fps: resolutionFPS,
257 inputBitrate: bitrate, 267 inputBitrate: bitrate,
268 inputRatio: ratio,
269
258 resolution, 270 resolution,
271 fps: resolutionFPS,
272
259 streamNum: i, 273 streamNum: i,
260 videoType: 'live' as 'live' 274 videoType: 'live' as 'live'
261 } 275 }
@@ -502,7 +516,7 @@ function getHLSVideoPath (options: HLSTranscodeOptions | HLSFromTSTranscodeOptio
502// Run encoder builder depending on available encoders 516// Run encoder builder depending on available encoders
503// Try encoders by priority: if the encoder is available, run the chosen profile or fallback to the default one 517// Try encoders by priority: if the encoder is available, run the chosen profile or fallback to the default one
504// If the default one does not exist, check the next encoder 518// If the default one does not exist, check the next encoder
505async function getEncoderBuilderResult (options: { 519async function getEncoderBuilderResult (options: EncoderOptionsBuilderParams & {
506 streamType: 'video' | 'audio' 520 streamType: 'video' | 'audio'
507 input: string 521 input: string
508 522
@@ -510,13 +524,8 @@ async function getEncoderBuilderResult (options: {
510 profile: string 524 profile: string
511 525
512 videoType: 'vod' | 'live' 526 videoType: 'vod' | 'live'
513
514 resolution: number
515 inputBitrate: number
516 fps?: number
517 streamNum?: number
518}) { 527}) {
519 const { availableEncoders, input, profile, resolution, streamType, fps, inputBitrate, streamNum, videoType } = options 528 const { availableEncoders, profile, streamType, videoType } = options
520 529
521 const encodersToTry = availableEncoders.encodersToTry[videoType][streamType] 530 const encodersToTry = availableEncoders.encodersToTry[videoType][streamType]
522 const encoders = availableEncoders.available[videoType] 531 const encoders = availableEncoders.available[videoType]
@@ -546,7 +555,7 @@ async function getEncoderBuilderResult (options: {
546 } 555 }
547 } 556 }
548 557
549 const result = await builder({ input, resolution, inputBitrate, fps, streamNum }) 558 const result = await builder(pick(options, [ 'input', 'resolution', 'inputBitrate', 'fps', 'inputRatio', 'streamNum' ]))
550 559
551 return { 560 return {
552 result, 561 result,
@@ -581,6 +590,7 @@ async function presetVideo (options: {
581 // Audio encoder 590 // Audio encoder
582 const parsedAudio = await getAudioStream(input, probe) 591 const parsedAudio = await getAudioStream(input, probe)
583 const bitrate = await getVideoFileBitrate(input, probe) 592 const bitrate = await getVideoFileBitrate(input, probe)
593 const { ratio } = await getVideoFileResolution(input, probe)
584 594
585 let streamsToProcess: StreamType[] = [ 'audio', 'video' ] 595 let streamsToProcess: StreamType[] = [ 'audio', 'video' ]
586 596
@@ -600,6 +610,7 @@ async function presetVideo (options: {
600 profile, 610 profile,
601 fps, 611 fps,
602 inputBitrate: bitrate, 612 inputBitrate: bitrate,
613 inputRatio: ratio,
603 videoType: 'vod' as 'vod' 614 videoType: 'vod' as 'vod'
604 }) 615 })
605 616
diff --git a/server/helpers/ffprobe-utils.ts b/server/helpers/ffprobe-utils.ts
index bc87e49b1..e58444b07 100644
--- a/server/helpers/ffprobe-utils.ts
+++ b/server/helpers/ffprobe-utils.ts
@@ -1,5 +1,6 @@
1import * as ffmpeg from 'fluent-ffmpeg' 1import * as ffmpeg from 'fluent-ffmpeg'
2import { getMaxBitrate, VideoFileMetadata, VideoResolution } from '../../shared/models/videos' 2import { getMaxBitrate } from '@shared/core-utils'
3import { VideoFileMetadata, VideoResolution, VideoTranscodingFPS } from '../../shared/models/videos'
3import { CONFIG } from '../initializers/config' 4import { CONFIG } from '../initializers/config'
4import { VIDEO_TRANSCODING_FPS } from '../initializers/constants' 5import { VIDEO_TRANSCODING_FPS } from '../initializers/constants'
5import { logger } from './logger' 6import { logger } from './logger'
@@ -75,7 +76,7 @@ function getMaxAudioBitrate (type: 'aac' | 'mp3' | string, bitrate: number) {
75 } 76 }
76} 77}
77 78
78async function getVideoStreamSize (path: string, existingProbe?: ffmpeg.FfprobeData) { 79async function getVideoStreamSize (path: string, existingProbe?: ffmpeg.FfprobeData): Promise<{ width: number, height: number }> {
79 const videoStream = await getVideoStreamFromFile(path, existingProbe) 80 const videoStream = await getVideoStreamFromFile(path, existingProbe)
80 81
81 return videoStream === null 82 return videoStream === null
@@ -146,7 +147,10 @@ async function getVideoFileResolution (path: string, existingProbe?: ffmpeg.Ffpr
146 const size = await getVideoStreamSize(path, existingProbe) 147 const size = await getVideoStreamSize(path, existingProbe)
147 148
148 return { 149 return {
149 videoFileResolution: Math.min(size.height, size.width), 150 width: size.width,
151 height: size.height,
152 ratio: Math.max(size.height, size.width) / Math.min(size.height, size.width),
153 resolution: Math.min(size.height, size.width),
150 isPortraitMode: size.height > size.width 154 isPortraitMode: size.height > size.width
151 } 155 }
152} 156}
@@ -243,7 +247,7 @@ async function canDoQuickVideoTranscode (path: string, probe?: ffmpeg.FfprobeDat
243 const videoStream = await getVideoStreamFromFile(path, probe) 247 const videoStream = await getVideoStreamFromFile(path, probe)
244 const fps = await getVideoFileFPS(path, probe) 248 const fps = await getVideoFileFPS(path, probe)
245 const bitRate = await getVideoFileBitrate(path, probe) 249 const bitRate = await getVideoFileBitrate(path, probe)
246 const resolution = await getVideoFileResolution(path, probe) 250 const resolutionData = await getVideoFileResolution(path, probe)
247 251
248 // If ffprobe did not manage to guess the bitrate 252 // If ffprobe did not manage to guess the bitrate
249 if (!bitRate) return false 253 if (!bitRate) return false
@@ -253,7 +257,7 @@ async function canDoQuickVideoTranscode (path: string, probe?: ffmpeg.FfprobeDat
253 if (videoStream['codec_name'] !== 'h264') return false 257 if (videoStream['codec_name'] !== 'h264') return false
254 if (videoStream['pix_fmt'] !== 'yuv420p') return false 258 if (videoStream['pix_fmt'] !== 'yuv420p') return false
255 if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false 259 if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false
256 if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false 260 if (bitRate > getMaxBitrate({ ...resolutionData, fps })) return false
257 261
258 return true 262 return true
259} 263}
@@ -278,7 +282,7 @@ async function canDoQuickAudioTranscode (path: string, probe?: ffmpeg.FfprobeDat
278 return true 282 return true
279} 283}
280 284
281function getClosestFramerateStandard (fps: number, type: 'HD_STANDARD' | 'STANDARD'): number { 285function getClosestFramerateStandard <K extends keyof Pick<VideoTranscodingFPS, 'HD_STANDARD' | 'STANDARD'>> (fps: number, type: K) {
282 return VIDEO_TRANSCODING_FPS[type].slice(0) 286 return VIDEO_TRANSCODING_FPS[type].slice(0)
283 .sort((a, b) => fps % a - fps % b)[0] 287 .sort((a, b) => fps % a - fps % b)[0]
284} 288}