aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-11-24 16:29:39 +0100
committerChocobozzz <chocobozzz@cpy.re>2020-11-25 10:07:51 +0100
commit6b67897e2eab96978daee40aeaf716835856d65d (patch)
tree2a203bf589599061a62c4e42b0e580a1c61b47ee
parent33ff70baa64c6315856066682595878a27b7ed8c (diff)
downloadPeerTube-6b67897e2eab96978daee40aeaf716835856d65d.tar.gz
PeerTube-6b67897e2eab96978daee40aeaf716835856d65d.tar.zst
PeerTube-6b67897e2eab96978daee40aeaf716835856d65d.zip
Add transcoding module comments
-rw-r--r--server/helpers/ffmpeg-utils.ts7
-rw-r--r--server/helpers/ffprobe-utils.ts6
-rw-r--r--server/lib/video-transcoding-profiles.ts35
-rw-r--r--server/lib/video-transcoding.ts13
-rw-r--r--server/tests/api/live/live.ts12
-rw-r--r--shared/extra-utils/videos/live.ts13
6 files changed, 68 insertions, 18 deletions
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index 712ec757e..69defccc4 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -9,6 +9,13 @@ import { getAudioStream, getClosestFramerateStandard, getVideoFileFPS } from './
9import { processImage } from './image-utils' 9import { processImage } from './image-utils'
10import { logger } from './logger' 10import { logger } from './logger'
11 11
12/**
13 *
14 * Functions that run transcoding/muxing ffmpeg processes
15 * Mainly called by lib/video-transcoding.ts and lib/live-manager.ts
16 *
17 */
18
12// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
13// Encoder options 20// Encoder options
14// --------------------------------------------------------------------------- 21// ---------------------------------------------------------------------------
diff --git a/server/helpers/ffprobe-utils.ts b/server/helpers/ffprobe-utils.ts
index d03ab91ac..16b295bbd 100644
--- a/server/helpers/ffprobe-utils.ts
+++ b/server/helpers/ffprobe-utils.ts
@@ -5,6 +5,12 @@ import { CONFIG } from '../initializers/config'
5import { VIDEO_TRANSCODING_FPS } from '../initializers/constants' 5import { VIDEO_TRANSCODING_FPS } from '../initializers/constants'
6import { logger } from './logger' 6import { logger } from './logger'
7 7
8/**
9 *
10 * Helpers to run ffprobe and extract data from the JSON output
11 *
12 */
13
8function ffprobePromise (path: string) { 14function ffprobePromise (path: string) {
9 return new Promise<ffmpeg.FfprobeData>((res, rej) => { 15 return new Promise<ffmpeg.FfprobeData>((res, rej) => {
10 ffmpeg.ffprobe(path, (err, data) => { 16 ffmpeg.ffprobe(path, (err, data) => {
diff --git a/server/lib/video-transcoding-profiles.ts b/server/lib/video-transcoding-profiles.ts
index 91a5c65f2..03c26f236 100644
--- a/server/lib/video-transcoding-profiles.ts
+++ b/server/lib/video-transcoding-profiles.ts
@@ -1,11 +1,22 @@
1import { logger } from '@server/helpers/logger'
1import { getTargetBitrate } from '../../shared/models/videos' 2import { getTargetBitrate } from '../../shared/models/videos'
2import { AvailableEncoders, buildStreamSuffix, EncoderOptionsBuilder } from '../helpers/ffmpeg-utils' 3import { AvailableEncoders, buildStreamSuffix, EncoderOptionsBuilder } from '../helpers/ffmpeg-utils'
3import { ffprobePromise, getAudioStream, getMaxAudioBitrate, getVideoFileBitrate, getVideoStreamFromFile } from '../helpers/ffprobe-utils' 4import {
5 canDoQuickAudioTranscode,
6 ffprobePromise,
7 getAudioStream,
8 getMaxAudioBitrate,
9 getVideoFileBitrate,
10 getVideoStreamFromFile
11} from '../helpers/ffprobe-utils'
4import { VIDEO_TRANSCODING_FPS } from '../initializers/constants' 12import { VIDEO_TRANSCODING_FPS } from '../initializers/constants'
5 13
6// --------------------------------------------------------------------------- 14/**
7// Available encoders profiles 15 *
8// --------------------------------------------------------------------------- 16 * Available encoders and profiles for the transcoding jobs
17 * These functions are used by ffmpeg-utils that will get the encoders and options depending on the chosen profile
18 *
19 */
9 20
10// Resources: 21// Resources:
11// * https://slhck.info/video/2017/03/01/rate-control.html 22// * https://slhck.info/video/2017/03/01/rate-control.html
@@ -27,7 +38,8 @@ const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = async ({ input, reso
27 38
28 return { 39 return {
29 outputOptions: [ 40 outputOptions: [
30 `-maxrate ${targetBitrate}`, `-bufsize ${targetBitrate * 2}` 41 `-maxrate ${targetBitrate}`,
42 `-bufsize ${targetBitrate * 2}`
31 ] 43 ]
32 } 44 }
33} 45}
@@ -45,7 +57,14 @@ const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = async ({ resolution
45} 57}
46 58
47const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNum }) => { 59const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNum }) => {
48 const parsedAudio = await getAudioStream(input) 60 const probe = await ffprobePromise(input)
61
62 if (await canDoQuickAudioTranscode(input, probe)) {
63 logger.debug('Copy audio stream %s by AAC encoder.', input)
64 return { copy: true, outputOptions: [] }
65 }
66
67 const parsedAudio = await getAudioStream(input, probe)
49 68
50 // We try to reduce the ceiling bitrate by making rough matches of bitrates 69 // We try to reduce the ceiling bitrate by making rough matches of bitrates
51 // Of course this is far from perfect, but it might save some space in the end 70 // Of course this is far from perfect, but it might save some space in the end
@@ -54,11 +73,13 @@ const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNu
54 73
55 const bitrate = getMaxAudioBitrate(audioCodecName, parsedAudio.bitrate) 74 const bitrate = getMaxAudioBitrate(audioCodecName, parsedAudio.bitrate)
56 75
76 logger.debug('Calculating audio bitrate of %s by AAC encoder.', input, { bitrate: parsedAudio.bitrate, audioCodecName })
77
57 if (bitrate !== undefined && bitrate !== -1) { 78 if (bitrate !== undefined && bitrate !== -1) {
58 return { outputOptions: [ buildStreamSuffix('-b:a', streamNum), bitrate + 'k' ] } 79 return { outputOptions: [ buildStreamSuffix('-b:a', streamNum), bitrate + 'k' ] }
59 } 80 }
60 81
61 return { copy: true, outputOptions: [] } 82 return { outputOptions: [ ] }
62} 83}
63 84
64const defaultLibFDKAACVODOptionsBuilder: EncoderOptionsBuilder = ({ streamNum }) => { 85const defaultLibFDKAACVODOptionsBuilder: EncoderOptionsBuilder = ({ streamNum }) => {
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts
index aaad219dd..e022f2a68 100644
--- a/server/lib/video-transcoding.ts
+++ b/server/lib/video-transcoding.ts
@@ -16,8 +16,13 @@ import { generateVideoStreamingPlaylistName, getVideoFilename, getVideoFilePath
16import { availableEncoders } from './video-transcoding-profiles' 16import { availableEncoders } from './video-transcoding-profiles'
17 17
18/** 18/**
19 * Optimize the original video file and replace it. The resolution is not changed. 19 *
20 * Functions that run transcoding functions, update the database, cleanup files, create torrent files...
21 * Mainly called by the job queue
22 *
20 */ 23 */
24
25// Optimize the original video file and replace it. The resolution is not changed.
21async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFileArg?: MVideoFile) { 26async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFileArg?: MVideoFile) {
22 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR 27 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
23 const newExtname = '.mp4' 28 const newExtname = '.mp4'
@@ -62,9 +67,7 @@ async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFileA
62 } 67 }
63} 68}
64 69
65/** 70// Transcode the original video file to a lower resolution.
66 * Transcode the original video file to a lower resolution.
67 */
68async function transcodeNewResolution (video: MVideoWithFile, resolution: VideoResolution, isPortrait: boolean) { 71async function transcodeNewResolution (video: MVideoWithFile, resolution: VideoResolution, isPortrait: boolean) {
69 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR 72 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
70 const extname = '.mp4' 73 const extname = '.mp4'
@@ -110,6 +113,7 @@ async function transcodeNewResolution (video: MVideoWithFile, resolution: VideoR
110 return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath) 113 return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath)
111} 114}
112 115
116// Merge an image with an audio file to create a video
113async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: VideoResolution) { 117async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: VideoResolution) {
114 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR 118 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
115 const newExtname = '.mp4' 119 const newExtname = '.mp4'
@@ -159,6 +163,7 @@ async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: Video
159 return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) 163 return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath)
160} 164}
161 165
166// Generate an HLS playlist from an input file, and update the master playlist
162async function generateHlsPlaylist (options: { 167async function generateHlsPlaylist (options: {
163 video: MVideoWithFile 168 video: MVideoWithFile
164 videoInputPath: string 169 videoInputPath: string
diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts
index e685be08e..0786db554 100644
--- a/server/tests/api/live/live.ts
+++ b/server/tests/api/live/live.ts
@@ -39,6 +39,7 @@ import {
39 viewVideo, 39 viewVideo,
40 wait, 40 wait,
41 waitJobs, 41 waitJobs,
42 waitUntilLivePublished,
42 waitUntilLiveStarts, 43 waitUntilLiveStarts,
43 waitUntilLog 44 waitUntilLog
44} from '../../../../shared/extra-utils' 45} from '../../../../shared/extra-utils'
@@ -396,7 +397,7 @@ describe('Test live', function () {
396 }) 397 })
397 398
398 it('Should enable transcoding with some resolutions and correctly save them', async function () { 399 it('Should enable transcoding with some resolutions and correctly save them', async function () {
399 this.timeout(60000) 400 this.timeout(120000)
400 401
401 const resolutions = [ 240, 360, 720 ] 402 const resolutions = [ 240, 360, 720 ]
402 403
@@ -410,13 +411,14 @@ describe('Test live', function () {
410 await testVideoResolutions(liveVideoId, resolutions) 411 await testVideoResolutions(liveVideoId, resolutions)
411 412
412 await stopFfmpeg(command) 413 await stopFfmpeg(command)
414 await waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoId)
413 415
414 await waitJobs(servers) 416 await waitJobs(servers)
415 417
416 const bitrateLimits = { 418 const bitrateLimits = {
417 720: 2800 * 1000, 419 720: 3000 * 1000,
418 360: 780 * 1000, 420 360: 1100 * 1000,
419 240: 320 * 1000 421 240: 600 * 1000
420 } 422 }
421 423
422 for (const server of servers) { 424 for (const server of servers) {
@@ -442,7 +444,7 @@ describe('Test live', function () {
442 444
443 const probe = await ffprobePromise(segmentPath) 445 const probe = await ffprobePromise(segmentPath)
444 const videoStream = await getVideoStreamFromFile(segmentPath, probe) 446 const videoStream = await getVideoStreamFromFile(segmentPath, probe)
445 console.log(videoStream) 447
446 expect(probe.format.bit_rate).to.be.below(bitrateLimits[videoStream.height]) 448 expect(probe.format.bit_rate).to.be.below(bitrateLimits[videoStream.height])
447 449
448 await makeRawRequest(file.torrentUrl, 200) 450 await makeRawRequest(file.torrentUrl, 200)
diff --git a/shared/extra-utils/videos/live.ts b/shared/extra-utils/videos/live.ts
index 85c83c5bb..c8acb90da 100644
--- a/shared/extra-utils/videos/live.ts
+++ b/shared/extra-utils/videos/live.ts
@@ -128,7 +128,15 @@ async function stopFfmpeg (command: ffmpeg.FfmpegCommand) {
128 await wait(500) 128 await wait(500)
129} 129}
130 130
131async function waitUntilLiveStarts (url: string, token: string, videoId: number | string) { 131function waitUntilLiveStarts (url: string, token: string, videoId: number | string) {
132 return waitWhileLiveState(url, token, videoId, VideoState.WAITING_FOR_LIVE)
133}
134
135function waitUntilLivePublished (url: string, token: string, videoId: number | string) {
136 return waitWhileLiveState(url, token, videoId, VideoState.PUBLISHED)
137}
138
139async function waitWhileLiveState (url: string, token: string, videoId: number | string, state: VideoState) {
132 let video: VideoDetails 140 let video: VideoDetails
133 141
134 do { 142 do {
@@ -136,7 +144,7 @@ async function waitUntilLiveStarts (url: string, token: string, videoId: number
136 video = res.body 144 video = res.body
137 145
138 await wait(500) 146 await wait(500)
139 } while (video.state.id === VideoState.WAITING_FOR_LIVE) 147 } while (video.state.id === state)
140} 148}
141 149
142async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resolutions: number[] = []) { 150async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resolutions: number[] = []) {
@@ -168,6 +176,7 @@ async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resoluti
168 176
169export { 177export {
170 getLive, 178 getLive,
179 waitUntilLivePublished,
171 updateLive, 180 updateLive,
172 waitUntilLiveStarts, 181 waitUntilLiveStarts,
173 createLive, 182 createLive,