aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api/videos
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2022-08-09 09:09:31 +0200
committerChocobozzz <me@florianbigard.com>2022-08-09 09:32:17 +0200
commitb42c2c7e89a64ed730d8140840fe74a13c31f2a4 (patch)
tree715e7ad31d03881e3f3530dba1fe3d172251249b /server/controllers/api/videos
parentbd911b54b555b11df7e9849cf92d358bccfecf6e (diff)
downloadPeerTube-b42c2c7e89a64ed730d8140840fe74a13c31f2a4.tar.gz
PeerTube-b42c2c7e89a64ed730d8140840fe74a13c31f2a4.tar.zst
PeerTube-b42c2c7e89a64ed730d8140840fe74a13c31f2a4.zip
Avoid concurrency issue on transcoding
Diffstat (limited to 'server/controllers/api/videos')
-rw-r--r--server/controllers/api/videos/transcoding.ts90
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 @@
1import Bluebird from 'bluebird'
1import express from 'express' 2import express from 'express'
2import { computeResolutionsToTranscode } from '@server/helpers/ffmpeg' 3import { computeResolutionsToTranscode } from '@server/helpers/ffmpeg'
3import { logger, loggerTagsFactory } from '@server/helpers/logger' 4import { logger, loggerTagsFactory } from '@server/helpers/logger'
4import { addTranscodingJob } from '@server/lib/video' 5import { JobQueue } from '@server/lib/job-queue'
6import { Hooks } from '@server/lib/plugins/hooks'
7import { buildTranscodingJob } from '@server/lib/video'
5import { HttpStatusCode, UserRight, VideoState, VideoTranscodingCreate } from '@shared/models' 8import { HttpStatusCode, UserRight, VideoState, VideoTranscodingCreate } from '@shared/models'
6import { asyncMiddleware, authenticate, createTranscodingValidator, ensureUserHasRight } from '../../../middlewares' 9import { asyncMiddleware, authenticate, createTranscodingValidator, ensureUserHasRight } from '../../../middlewares'
7import { Hooks } from '@server/lib/plugins/hooks'
8 10
9const lTags = loggerTagsFactory('api', 'video') 11const lTags = loggerTagsFactory('api', 'video')
10const transcodingRouter = express.Router() 12const 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
91function 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
111function 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}