diff options
author | Chocobozzz <me@florianbigard.com> | 2022-08-09 09:09:31 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-08-09 09:32:17 +0200 |
commit | b42c2c7e89a64ed730d8140840fe74a13c31f2a4 (patch) | |
tree | 715e7ad31d03881e3f3530dba1fe3d172251249b /server/controllers | |
parent | bd911b54b555b11df7e9849cf92d358bccfecf6e (diff) | |
download | PeerTube-b42c2c7e89a64ed730d8140840fe74a13c31f2a4.tar.gz PeerTube-b42c2c7e89a64ed730d8140840fe74a13c31f2a4.tar.zst PeerTube-b42c2c7e89a64ed730d8140840fe74a13c31f2a4.zip |
Avoid concurrency issue on transcoding
Diffstat (limited to 'server/controllers')
-rw-r--r-- | server/controllers/api/videos/transcoding.ts | 90 |
1 files changed, 72 insertions, 18 deletions
diff --git a/server/controllers/api/videos/transcoding.ts b/server/controllers/api/videos/transcoding.ts index b2b71a870..9aca761c1 100644 --- a/server/controllers/api/videos/transcoding.ts +++ b/server/controllers/api/videos/transcoding.ts | |||
@@ -1,10 +1,12 @@ | |||
1 | import Bluebird from 'bluebird' | ||
1 | import express from 'express' | 2 | import express from 'express' |
2 | import { computeResolutionsToTranscode } from '@server/helpers/ffmpeg' | 3 | import { computeResolutionsToTranscode } from '@server/helpers/ffmpeg' |
3 | import { logger, loggerTagsFactory } from '@server/helpers/logger' | 4 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
4 | import { addTranscodingJob } from '@server/lib/video' | 5 | import { JobQueue } from '@server/lib/job-queue' |
6 | import { Hooks } from '@server/lib/plugins/hooks' | ||
7 | import { buildTranscodingJob } from '@server/lib/video' | ||
5 | import { HttpStatusCode, UserRight, VideoState, VideoTranscodingCreate } from '@shared/models' | 8 | import { HttpStatusCode, UserRight, VideoState, VideoTranscodingCreate } from '@shared/models' |
6 | import { asyncMiddleware, authenticate, createTranscodingValidator, ensureUserHasRight } from '../../../middlewares' | 9 | import { asyncMiddleware, authenticate, createTranscodingValidator, ensureUserHasRight } from '../../../middlewares' |
7 | import { Hooks } from '@server/lib/plugins/hooks' | ||
8 | 10 | ||
9 | const lTags = loggerTagsFactory('api', 'video') | 11 | const lTags = loggerTagsFactory('api', 'video') |
10 | const transcodingRouter = express.Router() | 12 | const transcodingRouter = express.Router() |
@@ -44,29 +46,81 @@ async function createTranscoding (req: express.Request, res: express.Response) { | |||
44 | video.state = VideoState.TO_TRANSCODE | 46 | video.state = VideoState.TO_TRANSCODE |
45 | await video.save() | 47 | await video.save() |
46 | 48 | ||
47 | for (const resolution of resolutions) { | 49 | const hasAudio = !!audioStream |
50 | const childrenResolutions = resolutions.filter(r => r !== maxResolution) | ||
51 | |||
52 | const children = await Bluebird.mapSeries(childrenResolutions, resolution => { | ||
48 | if (body.transcodingType === 'hls') { | 53 | if (body.transcodingType === 'hls') { |
49 | await addTranscodingJob({ | 54 | return buildHLSJobOption({ |
50 | type: 'new-resolution-to-hls', | ||
51 | videoUUID: video.uuid, | 55 | videoUUID: video.uuid, |
56 | hasAudio, | ||
52 | resolution, | 57 | resolution, |
53 | hasAudio: !!audioStream, | 58 | isMaxQuality: false |
54 | copyCodecs: false, | ||
55 | isNewVideo: false, | ||
56 | autoDeleteWebTorrentIfNeeded: false, | ||
57 | isMaxQuality: maxResolution === resolution | ||
58 | }) | 59 | }) |
59 | } else if (body.transcodingType === 'webtorrent') { | 60 | } |
60 | await addTranscodingJob({ | 61 | |
61 | type: 'new-resolution-to-webtorrent', | 62 | if (body.transcodingType === 'webtorrent') { |
63 | return buildWebTorrentJobOption({ | ||
62 | videoUUID: video.uuid, | 64 | videoUUID: video.uuid, |
63 | isNewVideo: false, | 65 | hasAudio, |
64 | resolution, | 66 | resolution |
65 | hasAudio: !!audioStream, | ||
66 | createHLSIfNeeded: false | ||
67 | }) | 67 | }) |
68 | } | 68 | } |
69 | } | 69 | }) |
70 | |||
71 | const parent = body.transcodingType === 'hls' | ||
72 | ? await buildHLSJobOption({ | ||
73 | videoUUID: video.uuid, | ||
74 | hasAudio, | ||
75 | resolution: maxResolution, | ||
76 | isMaxQuality: false | ||
77 | }) | ||
78 | : await buildWebTorrentJobOption({ | ||
79 | videoUUID: video.uuid, | ||
80 | hasAudio, | ||
81 | resolution: maxResolution | ||
82 | }) | ||
83 | |||
84 | // Porcess the last resolution after the other ones to prevent concurrency issue | ||
85 | // Because low resolutions use the biggest one as ffmpeg input | ||
86 | await JobQueue.Instance.createJobWithChildren(parent, children) | ||
70 | 87 | ||
71 | return res.sendStatus(HttpStatusCode.NO_CONTENT_204) | 88 | return res.sendStatus(HttpStatusCode.NO_CONTENT_204) |
72 | } | 89 | } |
90 | |||
91 | function buildHLSJobOption (options: { | ||
92 | videoUUID: string | ||
93 | hasAudio: boolean | ||
94 | resolution: number | ||
95 | isMaxQuality: boolean | ||
96 | }) { | ||
97 | const { videoUUID, hasAudio, resolution, isMaxQuality } = options | ||
98 | |||
99 | return buildTranscodingJob({ | ||
100 | type: 'new-resolution-to-hls', | ||
101 | videoUUID, | ||
102 | resolution, | ||
103 | hasAudio, | ||
104 | copyCodecs: false, | ||
105 | isNewVideo: false, | ||
106 | autoDeleteWebTorrentIfNeeded: false, | ||
107 | isMaxQuality | ||
108 | }) | ||
109 | } | ||
110 | |||
111 | function buildWebTorrentJobOption (options: { | ||
112 | videoUUID: string | ||
113 | hasAudio: boolean | ||
114 | resolution: number | ||
115 | }) { | ||
116 | const { videoUUID, hasAudio, resolution } = options | ||
117 | |||
118 | return buildTranscodingJob({ | ||
119 | type: 'new-resolution-to-webtorrent', | ||
120 | videoUUID, | ||
121 | isNewVideo: false, | ||
122 | resolution, | ||
123 | hasAudio, | ||
124 | createHLSIfNeeded: false | ||
125 | }) | ||
126 | } | ||