]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Add transcoding module comments
authorChocobozzz <me@florianbigard.com>
Tue, 24 Nov 2020 15:29:39 +0000 (16:29 +0100)
committerChocobozzz <chocobozzz@cpy.re>
Wed, 25 Nov 2020 09:07:51 +0000 (10:07 +0100)
server/helpers/ffmpeg-utils.ts
server/helpers/ffprobe-utils.ts
server/lib/video-transcoding-profiles.ts
server/lib/video-transcoding.ts
server/tests/api/live/live.ts
shared/extra-utils/videos/live.ts

index 712ec757e552e6e2ed54e32dbebff73ddea0185a..69defccc4c6dd6b19e353fcb23e9c7a05e5a7bb4 100644 (file)
@@ -9,6 +9,13 @@ import { getAudioStream, getClosestFramerateStandard, getVideoFileFPS } from './
 import { processImage } from './image-utils'
 import { logger } from './logger'
 
+/**
+ *
+ * Functions that run transcoding/muxing ffmpeg processes
+ * Mainly called by lib/video-transcoding.ts and lib/live-manager.ts
+ *
+ */
+
 // ---------------------------------------------------------------------------
 // Encoder options
 // ---------------------------------------------------------------------------
index d03ab91ac93c23bcdcaca0b0e6c080eb8b0e150e..16b295bbdbe23df739a0c4ddc169641f48d7e645 100644 (file)
@@ -5,6 +5,12 @@ import { CONFIG } from '../initializers/config'
 import { VIDEO_TRANSCODING_FPS } from '../initializers/constants'
 import { logger } from './logger'
 
+/**
+ *
+ * Helpers to run ffprobe and extract data from the JSON output
+ *
+ */
+
 function ffprobePromise (path: string) {
   return new Promise<ffmpeg.FfprobeData>((res, rej) => {
     ffmpeg.ffprobe(path, (err, data) => {
index 91a5c65f2f137b93deafacc06828ffc21303de56..03c26f236bda0654ff62959fbf822e80bb4d4551 100644 (file)
@@ -1,11 +1,22 @@
+import { logger } from '@server/helpers/logger'
 import { getTargetBitrate } from '../../shared/models/videos'
 import { AvailableEncoders, buildStreamSuffix, EncoderOptionsBuilder } from '../helpers/ffmpeg-utils'
-import { ffprobePromise, getAudioStream, getMaxAudioBitrate, getVideoFileBitrate, getVideoStreamFromFile } from '../helpers/ffprobe-utils'
+import {
+  canDoQuickAudioTranscode,
+  ffprobePromise,
+  getAudioStream,
+  getMaxAudioBitrate,
+  getVideoFileBitrate,
+  getVideoStreamFromFile
+} from '../helpers/ffprobe-utils'
 import { VIDEO_TRANSCODING_FPS } from '../initializers/constants'
 
-// ---------------------------------------------------------------------------
-// Available encoders profiles
-// ---------------------------------------------------------------------------
+/**
+ *
+ * Available encoders and profiles for the transcoding jobs
+ * These functions are used by ffmpeg-utils that will get the encoders and options depending on the chosen profile
+ *
+ */
 
 // Resources:
 //  * https://slhck.info/video/2017/03/01/rate-control.html
@@ -27,7 +38,8 @@ const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = async ({ input, reso
 
   return {
     outputOptions: [
-      `-maxrate ${targetBitrate}`, `-bufsize ${targetBitrate * 2}`
+      `-maxrate ${targetBitrate}`,
+      `-bufsize ${targetBitrate * 2}`
     ]
   }
 }
@@ -45,7 +57,14 @@ const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = async ({ resolution
 }
 
 const defaultAACOptionsBuilder: EncoderOptionsBuilder = async ({ input, streamNum }) => {
-  const parsedAudio = await getAudioStream(input)
+  const probe = await ffprobePromise(input)
+
+  if (await canDoQuickAudioTranscode(input, probe)) {
+    logger.debug('Copy audio stream %s by AAC encoder.', input)
+    return { copy: true, outputOptions: [] }
+  }
+
+  const parsedAudio = await getAudioStream(input, probe)
 
   // We try to reduce the ceiling bitrate by making rough matches of bitrates
   // 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
 
   const bitrate = getMaxAudioBitrate(audioCodecName, parsedAudio.bitrate)
 
+  logger.debug('Calculating audio bitrate of %s by AAC encoder.', input, { bitrate: parsedAudio.bitrate, audioCodecName })
+
   if (bitrate !== undefined && bitrate !== -1) {
     return { outputOptions: [ buildStreamSuffix('-b:a', streamNum), bitrate + 'k' ] }
   }
 
-  return { copy: true, outputOptions: [] }
+  return { outputOptions: [ ] }
 }
 
 const defaultLibFDKAACVODOptionsBuilder: EncoderOptionsBuilder = ({ streamNum }) => {
index aaad219ddda5692defc2187f91d55c51207a8666..e022f2a68affdcff375585d208a127e65fae4bfe 100644 (file)
@@ -16,8 +16,13 @@ import { generateVideoStreamingPlaylistName, getVideoFilename, getVideoFilePath
 import { availableEncoders } from './video-transcoding-profiles'
 
 /**
- * Optimize the original video file and replace it. The resolution is not changed.
+ *
+ * Functions that run transcoding functions, update the database, cleanup files, create torrent files...
+ * Mainly called by the job queue
+ *
  */
+
+// Optimize the original video file and replace it. The resolution is not changed.
 async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFileArg?: MVideoFile) {
   const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
   const newExtname = '.mp4'
@@ -62,9 +67,7 @@ async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFileA
   }
 }
 
-/**
- * Transcode the original video file to a lower resolution.
- */
+// Transcode the original video file to a lower resolution.
 async function transcodeNewResolution (video: MVideoWithFile, resolution: VideoResolution, isPortrait: boolean) {
   const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
   const extname = '.mp4'
@@ -110,6 +113,7 @@ async function transcodeNewResolution (video: MVideoWithFile, resolution: VideoR
   return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath)
 }
 
+// Merge an image with an audio file to create a video
 async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: VideoResolution) {
   const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
   const newExtname = '.mp4'
@@ -159,6 +163,7 @@ async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: Video
   return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath)
 }
 
+// Generate an HLS playlist from an input file, and update the master playlist
 async function generateHlsPlaylist (options: {
   video: MVideoWithFile
   videoInputPath: string
index e685be08ee1daf8d081e1c1ef89518195ed7c4d0..0786db554a3469ce074b58f57c595a43a5c7f3f1 100644 (file)
@@ -39,6 +39,7 @@ import {
   viewVideo,
   wait,
   waitJobs,
+  waitUntilLivePublished,
   waitUntilLiveStarts,
   waitUntilLog
 } from '../../../../shared/extra-utils'
@@ -396,7 +397,7 @@ describe('Test live', function () {
     })
 
     it('Should enable transcoding with some resolutions and correctly save them', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       const resolutions = [ 240, 360, 720 ]
 
@@ -410,13 +411,14 @@ describe('Test live', function () {
       await testVideoResolutions(liveVideoId, resolutions)
 
       await stopFfmpeg(command)
+      await waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoId)
 
       await waitJobs(servers)
 
       const bitrateLimits = {
-        720: 2800 * 1000,
-        360: 780 * 1000,
-        240: 320 * 1000
+        720: 3000 * 1000,
+        360: 1100 * 1000,
+        240: 600 * 1000
       }
 
       for (const server of servers) {
@@ -442,7 +444,7 @@ describe('Test live', function () {
 
           const probe = await ffprobePromise(segmentPath)
           const videoStream = await getVideoStreamFromFile(segmentPath, probe)
-          console.log(videoStream)
+
           expect(probe.format.bit_rate).to.be.below(bitrateLimits[videoStream.height])
 
           await makeRawRequest(file.torrentUrl, 200)
index 85c83c5bb5c1363cff76bc5292b594a2c0c6e16e..c8acb90daa5b5f453c410c9546a6bc2d22fef7d4 100644 (file)
@@ -128,7 +128,15 @@ async function stopFfmpeg (command: ffmpeg.FfmpegCommand) {
   await wait(500)
 }
 
-async function waitUntilLiveStarts (url: string, token: string, videoId: number | string) {
+function waitUntilLiveStarts (url: string, token: string, videoId: number | string) {
+  return waitWhileLiveState(url, token, videoId, VideoState.WAITING_FOR_LIVE)
+}
+
+function waitUntilLivePublished (url: string, token: string, videoId: number | string) {
+  return waitWhileLiveState(url, token, videoId, VideoState.PUBLISHED)
+}
+
+async function waitWhileLiveState (url: string, token: string, videoId: number | string, state: VideoState) {
   let video: VideoDetails
 
   do {
@@ -136,7 +144,7 @@ async function waitUntilLiveStarts (url: string, token: string, videoId: number
     video = res.body
 
     await wait(500)
-  } while (video.state.id === VideoState.WAITING_FOR_LIVE)
+  } while (video.state.id === state)
 }
 
 async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resolutions: number[] = []) {
@@ -168,6 +176,7 @@ async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resoluti
 
 export {
   getLive,
+  waitUntilLivePublished,
   updateLive,
   waitUntilLiveStarts,
   createLive,