]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/live/shared/transcoding-wrapper/ffmpeg-transcoding-wrapper.ts
Fix peertube runner concurrency
[github/Chocobozzz/PeerTube.git] / server / lib / live / shared / transcoding-wrapper / ffmpeg-transcoding-wrapper.ts
CommitLineData
0c9668f7
C
1import { FfmpegCommand } from 'fluent-ffmpeg'
2import { getFFmpegCommandWrapperOptions } from '@server/helpers/ffmpeg'
3import { logger } from '@server/helpers/logger'
4import { CONFIG } from '@server/initializers/config'
5import { VIDEO_LIVE } from '@server/initializers/constants'
6import { VideoTranscodingProfilesManager } from '@server/lib/transcoding/default-transcoding-profiles'
7import { FFmpegLive } from '@shared/ffmpeg'
8import { getLiveSegmentTime } from '../../live-utils'
9import { AbstractTranscodingWrapper } from './abstract-transcoding-wrapper'
10
11export class FFmpegTranscodingWrapper extends AbstractTranscodingWrapper {
12 private ffmpegCommand: FfmpegCommand
ef2e6aab
C
13
14 private aborted = false
15 private errored = false
0c9668f7
C
16 private ended = false
17
18 async run () {
19 this.ffmpegCommand = CONFIG.LIVE.TRANSCODING.ENABLED
20 ? await this.buildFFmpegLive().getLiveTranscodingCommand({
28705705 21 inputUrl: this.inputLocalUrl,
0c9668f7
C
22
23 outPath: this.outDirectory,
24 masterPlaylistName: this.streamingPlaylist.playlistFilename,
25
26 segmentListSize: this.segmentListSize,
27 segmentDuration: this.segmentDuration,
28
29 toTranscode: this.toTranscode,
30
31 bitrate: this.bitrate,
32 ratio: this.ratio,
33
34 hasAudio: this.hasAudio
35 })
36 : this.buildFFmpegLive().getLiveMuxingCommand({
28705705 37 inputUrl: this.inputLocalUrl,
0c9668f7
C
38 outPath: this.outDirectory,
39
40 masterPlaylistName: this.streamingPlaylist.playlistFilename,
41
42 segmentListSize: VIDEO_LIVE.SEGMENTS_LIST_SIZE,
43 segmentDuration: getLiveSegmentTime(this.videoLive.latencyMode)
44 })
45
46 logger.info('Running local live muxing/transcoding for %s.', this.videoUUID, this.lTags())
47
48 this.ffmpegCommand.run()
49
50 let ffmpegShellCommand: string
51 this.ffmpegCommand.on('start', cmdline => {
52 ffmpegShellCommand = cmdline
53
54 logger.debug('Running ffmpeg command for live', { ffmpegShellCommand, ...this.lTags() })
55 })
56
57 this.ffmpegCommand.on('error', (err, stdout, stderr) => {
58 this.onFFmpegError({ err, stdout, stderr, ffmpegShellCommand })
59 })
60
61 this.ffmpegCommand.on('end', () => {
62 this.onFFmpegEnded()
63 })
64
65 this.ffmpegCommand.run()
66 }
67
68 abort () {
ef2e6aab
C
69 if (this.ended || this.errored || this.aborted) return
70
fe7019b2
C
71 logger.debug('Killing ffmpeg after live abort of ' + this.videoUUID, this.lTags())
72
ef2e6aab
C
73 this.ffmpegCommand.kill('SIGINT')
74
75 this.aborted = true
76 this.emit('end')
0c9668f7
C
77 }
78
79 private onFFmpegError (options: {
80 err: any
81 stdout: string
82 stderr: string
83 ffmpegShellCommand: string
84 }) {
85 const { err, stdout, stderr, ffmpegShellCommand } = options
86
87 // Don't care that we killed the ffmpeg process
88 if (err?.message?.includes('Exiting normally')) return
ef2e6aab 89 if (this.ended || this.errored || this.aborted) return
0c9668f7
C
90
91 logger.error('FFmpeg transcoding error.', { err, stdout, stderr, ffmpegShellCommand, ...this.lTags() })
92
ef2e6aab 93 this.errored = true
0c9668f7
C
94 this.emit('error', { err })
95 }
96
97 private onFFmpegEnded () {
ef2e6aab 98 if (this.ended || this.errored || this.aborted) return
0c9668f7 99
fe7019b2
C
100 logger.debug('Live ffmpeg transcoding ended for ' + this.videoUUID, this.lTags())
101
0c9668f7
C
102 this.ended = true
103 this.emit('end')
104 }
105
106 private buildFFmpegLive () {
107 return new FFmpegLive(getFFmpegCommandWrapperOptions('live', VideoTranscodingProfilesManager.Instance.getAvailableEncoders()))
108 }
109}