aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers/ffmpeg
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-07-31 14:34:36 +0200
committerChocobozzz <me@florianbigard.com>2023-08-11 15:02:33 +0200
commit3a4992633ee62d5edfbb484d9c6bcb3cf158489d (patch)
treee4510b39bdac9c318fdb4b47018d08f15368b8f0 /server/helpers/ffmpeg
parent04d1da5621d25d59bd5fa1543b725c497bf5d9a8 (diff)
downloadPeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.gz
PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.zst
PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.zip
Migrate server to ESM
Sorry for the very big commit that may lead to git log issues and merge conflicts, but it's a major step forward: * Server can be faster at startup because imports() are async and we can easily lazy import big modules * Angular doesn't seem to support ES import (with .js extension), so we had to correctly organize peertube into a monorepo: * Use yarn workspace feature * Use typescript reference projects for dependencies * Shared projects have been moved into "packages", each one is now a node module (with a dedicated package.json/tsconfig.json) * server/tools have been moved into apps/ and is now a dedicated app bundled and published on NPM so users don't have to build peertube cli tools manually * server/tests have been moved into packages/ so we don't compile them every time we want to run the server * Use isolatedModule option: * Had to move from const enum to const (https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums) * Had to explictely specify "type" imports when used in decorators * Prefer tsx (that uses esbuild under the hood) instead of ts-node to load typescript files (tests with mocha or scripts): * To reduce test complexity as esbuild doesn't support decorator metadata, we only test server files that do not import server models * We still build tests files into js files for a faster CI * Remove unmaintained peertube CLI import script * Removed some barrels to speed up execution (less imports)
Diffstat (limited to 'server/helpers/ffmpeg')
-rw-r--r--server/helpers/ffmpeg/codecs.ts64
-rw-r--r--server/helpers/ffmpeg/ffmpeg-image.ts14
-rw-r--r--server/helpers/ffmpeg/ffmpeg-options.ts45
-rw-r--r--server/helpers/ffmpeg/framerate.ts44
-rw-r--r--server/helpers/ffmpeg/index.ts4
5 files changed, 0 insertions, 171 deletions
diff --git a/server/helpers/ffmpeg/codecs.ts b/server/helpers/ffmpeg/codecs.ts
deleted file mode 100644
index 3bd7db396..000000000
--- a/server/helpers/ffmpeg/codecs.ts
+++ /dev/null
@@ -1,64 +0,0 @@
1import { FfprobeData } from 'fluent-ffmpeg'
2import { getAudioStream, getVideoStream } from '@shared/ffmpeg'
3import { logger } from '../logger'
4import { forceNumber } from '@shared/core-utils'
5
6export async function getVideoStreamCodec (path: string) {
7 const videoStream = await getVideoStream(path)
8 if (!videoStream) return ''
9
10 const videoCodec = videoStream.codec_tag_string
11
12 if (videoCodec === 'vp09') return 'vp09.00.50.08'
13 if (videoCodec === 'hev1') return 'hev1.1.6.L93.B0'
14
15 const baseProfileMatrix = {
16 avc1: {
17 High: '6400',
18 Main: '4D40',
19 Baseline: '42E0'
20 },
21 av01: {
22 High: '1',
23 Main: '0',
24 Professional: '2'
25 }
26 }
27
28 let baseProfile = baseProfileMatrix[videoCodec][videoStream.profile]
29 if (!baseProfile) {
30 logger.warn('Cannot get video profile codec of %s.', path, { videoStream })
31 baseProfile = baseProfileMatrix[videoCodec]['High'] // Fallback
32 }
33
34 if (videoCodec === 'av01') {
35 let level = videoStream.level.toString()
36 if (level.length === 1) level = `0${level}`
37
38 // Guess the tier indicator and bit depth
39 return `${videoCodec}.${baseProfile}.${level}M.08`
40 }
41
42 let level = forceNumber(videoStream.level).toString(16)
43 if (level.length === 1) level = `0${level}`
44
45 // Default, h264 codec
46 return `${videoCodec}.${baseProfile}${level}`
47}
48
49export async function getAudioStreamCodec (path: string, existingProbe?: FfprobeData) {
50 const { audioStream } = await getAudioStream(path, existingProbe)
51
52 if (!audioStream) return ''
53
54 const audioCodecName = audioStream.codec_name
55
56 if (audioCodecName === 'opus') return 'opus'
57 if (audioCodecName === 'vorbis') return 'vorbis'
58 if (audioCodecName === 'aac') return 'mp4a.40.2'
59 if (audioCodecName === 'mp3') return 'mp4a.40.34'
60
61 logger.warn('Cannot get audio codec of %s.', path, { audioStream })
62
63 return 'mp4a.40.2' // Fallback
64}
diff --git a/server/helpers/ffmpeg/ffmpeg-image.ts b/server/helpers/ffmpeg/ffmpeg-image.ts
deleted file mode 100644
index 0bb0ff2c0..000000000
--- a/server/helpers/ffmpeg/ffmpeg-image.ts
+++ /dev/null
@@ -1,14 +0,0 @@
1import { FFmpegImage } from '@shared/ffmpeg'
2import { getFFmpegCommandWrapperOptions } from './ffmpeg-options'
3
4export function processGIF (options: Parameters<FFmpegImage['processGIF']>[0]) {
5 return new FFmpegImage(getFFmpegCommandWrapperOptions('thumbnail')).processGIF(options)
6}
7
8export function generateThumbnailFromVideo (options: Parameters<FFmpegImage['generateThumbnailFromVideo']>[0]) {
9 return new FFmpegImage(getFFmpegCommandWrapperOptions('thumbnail')).generateThumbnailFromVideo(options)
10}
11
12export function convertWebPToJPG (options: Parameters<FFmpegImage['convertWebPToJPG']>[0]) {
13 return new FFmpegImage(getFFmpegCommandWrapperOptions('thumbnail')).convertWebPToJPG(options)
14}
diff --git a/server/helpers/ffmpeg/ffmpeg-options.ts b/server/helpers/ffmpeg/ffmpeg-options.ts
deleted file mode 100644
index 64d7c4179..000000000
--- a/server/helpers/ffmpeg/ffmpeg-options.ts
+++ /dev/null
@@ -1,45 +0,0 @@
1import { logger } from '@server/helpers/logger'
2import { CONFIG } from '@server/initializers/config'
3import { FFMPEG_NICE } from '@server/initializers/constants'
4import { FFmpegCommandWrapperOptions } from '@shared/ffmpeg'
5import { AvailableEncoders } from '@shared/models'
6
7type CommandType = 'live' | 'vod' | 'thumbnail'
8
9export function getFFmpegCommandWrapperOptions (type: CommandType, availableEncoders?: AvailableEncoders): FFmpegCommandWrapperOptions {
10 return {
11 availableEncoders,
12 profile: getProfile(type),
13
14 niceness: FFMPEG_NICE[type.toUpperCase()],
15 tmpDirectory: CONFIG.STORAGE.TMP_DIR,
16 threads: getThreads(type),
17
18 logger: {
19 debug: logger.debug.bind(logger),
20 info: logger.info.bind(logger),
21 warn: logger.warn.bind(logger),
22 error: logger.error.bind(logger)
23 },
24 lTags: { tags: [ 'ffmpeg' ] }
25 }
26}
27
28// ---------------------------------------------------------------------------
29// Private
30// ---------------------------------------------------------------------------
31
32function getThreads (type: CommandType) {
33 if (type === 'live') return CONFIG.LIVE.TRANSCODING.THREADS
34 if (type === 'vod') return CONFIG.TRANSCODING.THREADS
35
36 // Auto
37 return 0
38}
39
40function getProfile (type: CommandType) {
41 if (type === 'live') return CONFIG.LIVE.TRANSCODING.PROFILE
42 if (type === 'vod') return CONFIG.TRANSCODING.PROFILE
43
44 return undefined
45}
diff --git a/server/helpers/ffmpeg/framerate.ts b/server/helpers/ffmpeg/framerate.ts
deleted file mode 100644
index 18cb0e0e2..000000000
--- a/server/helpers/ffmpeg/framerate.ts
+++ /dev/null
@@ -1,44 +0,0 @@
1import { VIDEO_TRANSCODING_FPS } from '@server/initializers/constants'
2import { VideoResolution } from '@shared/models'
3
4export function computeOutputFPS (options: {
5 inputFPS: number
6 resolution: VideoResolution
7}) {
8 const { resolution } = options
9
10 let fps = options.inputFPS
11
12 if (
13 // On small/medium resolutions, limit FPS
14 resolution !== undefined &&
15 resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN &&
16 fps > VIDEO_TRANSCODING_FPS.AVERAGE
17 ) {
18 // Get closest standard framerate by modulo: downsampling has to be done to a divisor of the nominal fps value
19 fps = getClosestFramerateStandard({ fps, type: 'STANDARD' })
20 }
21
22 // Hard FPS limits
23 if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = getClosestFramerateStandard({ fps, type: 'HD_STANDARD' })
24
25 if (fps < VIDEO_TRANSCODING_FPS.MIN) {
26 throw new Error(`Cannot compute FPS because ${fps} is lower than our minimum value ${VIDEO_TRANSCODING_FPS.MIN}`)
27 }
28
29 return fps
30}
31
32// ---------------------------------------------------------------------------
33// Private
34// ---------------------------------------------------------------------------
35
36function getClosestFramerateStandard (options: {
37 fps: number
38 type: 'HD_STANDARD' | 'STANDARD'
39}) {
40 const { fps, type } = options
41
42 return VIDEO_TRANSCODING_FPS[type].slice(0)
43 .sort((a, b) => fps % a - fps % b)[0]
44}
diff --git a/server/helpers/ffmpeg/index.ts b/server/helpers/ffmpeg/index.ts
deleted file mode 100644
index bf1c73fb6..000000000
--- a/server/helpers/ffmpeg/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
1export * from './codecs'
2export * from './ffmpeg-image'
3export * from './ffmpeg-options'
4export * from './framerate'