diff options
-rwxr-xr-x | scripts/create-transcoding-job.ts | 6 | ||||
-rw-r--r-- | server/helpers/video.ts | 4 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/video-file-import.ts | 4 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/video-live-ending.ts | 4 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/video-transcoding.ts | 199 | ||||
-rw-r--r-- | server/lib/video-transcoding.ts | 25 | ||||
-rw-r--r-- | server/models/video/video.ts | 1 | ||||
-rw-r--r-- | shared/models/server/job.model.ts | 10 |
8 files changed, 162 insertions, 91 deletions
diff --git a/scripts/create-transcoding-job.ts b/scripts/create-transcoding-job.ts index 2eed53f42..ca9e2a99a 100755 --- a/scripts/create-transcoding-job.ts +++ b/scripts/create-transcoding-job.ts | |||
@@ -47,7 +47,7 @@ async function run () { | |||
47 | 47 | ||
48 | for (const resolution of resolutionsEnabled) { | 48 | for (const resolution of resolutionsEnabled) { |
49 | dataInput.push({ | 49 | dataInput.push({ |
50 | type: 'hls', | 50 | type: 'new-resolution-to-hls', |
51 | videoUUID: video.uuid, | 51 | videoUUID: video.uuid, |
52 | resolution, | 52 | resolution, |
53 | isPortraitMode: false, | 53 | isPortraitMode: false, |
@@ -56,14 +56,14 @@ async function run () { | |||
56 | } | 56 | } |
57 | } else if (program.resolution !== undefined) { | 57 | } else if (program.resolution !== undefined) { |
58 | dataInput.push({ | 58 | dataInput.push({ |
59 | type: 'new-resolution' as 'new-resolution', | 59 | type: 'new-resolution-to-webtorrent', |
60 | videoUUID: video.uuid, | 60 | videoUUID: video.uuid, |
61 | isNewVideo: false, | 61 | isNewVideo: false, |
62 | resolution: program.resolution | 62 | resolution: program.resolution |
63 | }) | 63 | }) |
64 | } else { | 64 | } else { |
65 | dataInput.push({ | 65 | dataInput.push({ |
66 | type: 'optimize' as 'optimize', | 66 | type: 'optimize-to-webtorrent', |
67 | videoUUID: video.uuid, | 67 | videoUUID: video.uuid, |
68 | isNewVideo: false | 68 | isNewVideo: false |
69 | }) | 69 | }) |
diff --git a/server/helpers/video.ts b/server/helpers/video.ts index 5d1cd7de1..bfd5a9627 100644 --- a/server/helpers/video.ts +++ b/server/helpers/video.ts | |||
@@ -74,14 +74,14 @@ function addOptimizeOrMergeAudioJob (video: MVideo, videoFile: MVideoFile) { | |||
74 | 74 | ||
75 | if (videoFile.isAudio()) { | 75 | if (videoFile.isAudio()) { |
76 | dataInput = { | 76 | dataInput = { |
77 | type: 'merge-audio' as 'merge-audio', | 77 | type: 'merge-audio-to-webtorrent', |
78 | resolution: DEFAULT_AUDIO_RESOLUTION, | 78 | resolution: DEFAULT_AUDIO_RESOLUTION, |
79 | videoUUID: video.uuid, | 79 | videoUUID: video.uuid, |
80 | isNewVideo: true | 80 | isNewVideo: true |
81 | } | 81 | } |
82 | } else { | 82 | } else { |
83 | dataInput = { | 83 | dataInput = { |
84 | type: 'optimize' as 'optimize', | 84 | type: 'optimize-to-webtorrent', |
85 | videoUUID: video.uuid, | 85 | videoUUID: video.uuid, |
86 | isNewVideo: true | 86 | isNewVideo: true |
87 | } | 87 | } |
diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts index 18823ee9c..22e4d0cf1 100644 --- a/server/lib/job-queue/handlers/video-file-import.ts +++ b/server/lib/job-queue/handlers/video-file-import.ts | |||
@@ -9,7 +9,7 @@ import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffprob | |||
9 | import { logger } from '../../../helpers/logger' | 9 | import { logger } from '../../../helpers/logger' |
10 | import { VideoModel } from '../../../models/video/video' | 10 | import { VideoModel } from '../../../models/video/video' |
11 | import { VideoFileModel } from '../../../models/video/video-file' | 11 | import { VideoFileModel } from '../../../models/video/video-file' |
12 | import { publishNewResolutionIfNeeded } from './video-transcoding' | 12 | import { onNewWebTorrentFileResolution } from './video-transcoding' |
13 | 13 | ||
14 | async function processVideoFileImport (job: Bull.Job) { | 14 | async function processVideoFileImport (job: Bull.Job) { |
15 | const payload = job.data as VideoFileImportPayload | 15 | const payload = job.data as VideoFileImportPayload |
@@ -24,7 +24,7 @@ async function processVideoFileImport (job: Bull.Job) { | |||
24 | 24 | ||
25 | await updateVideoFile(video, payload.filePath) | 25 | await updateVideoFile(video, payload.filePath) |
26 | 26 | ||
27 | await publishNewResolutionIfNeeded(video) | 27 | await onNewWebTorrentFileResolution(video) |
28 | return video | 28 | return video |
29 | } | 29 | } |
30 | 30 | ||
diff --git a/server/lib/job-queue/handlers/video-live-ending.ts b/server/lib/job-queue/handlers/video-live-ending.ts index 8018e2277..db6cd3682 100644 --- a/server/lib/job-queue/handlers/video-live-ending.ts +++ b/server/lib/job-queue/handlers/video-live-ending.ts | |||
@@ -7,7 +7,7 @@ import { LiveManager } from '@server/lib/live-manager' | |||
7 | import { generateVideoMiniature } from '@server/lib/thumbnail' | 7 | import { generateVideoMiniature } from '@server/lib/thumbnail' |
8 | import { publishAndFederateIfNeeded } from '@server/lib/video' | 8 | import { publishAndFederateIfNeeded } from '@server/lib/video' |
9 | import { getHLSDirectory } from '@server/lib/video-paths' | 9 | import { getHLSDirectory } from '@server/lib/video-paths' |
10 | import { generateHlsPlaylistFromTS } from '@server/lib/video-transcoding' | 10 | import { generateHlsPlaylistResolutionFromTS } from '@server/lib/video-transcoding' |
11 | import { VideoModel } from '@server/models/video/video' | 11 | import { VideoModel } from '@server/models/video/video' |
12 | import { VideoFileModel } from '@server/models/video/video-file' | 12 | import { VideoFileModel } from '@server/models/video/video-file' |
13 | import { VideoLiveModel } from '@server/models/video/video-live' | 13 | import { VideoLiveModel } from '@server/models/video/video-live' |
@@ -102,7 +102,7 @@ async function saveLive (video: MVideo, live: MVideoLive) { | |||
102 | 102 | ||
103 | const { videoFileResolution, isPortraitMode } = await getVideoFileResolution(concatenatedTsFilePath, probe) | 103 | const { videoFileResolution, isPortraitMode } = await getVideoFileResolution(concatenatedTsFilePath, probe) |
104 | 104 | ||
105 | const outputPath = await generateHlsPlaylistFromTS({ | 105 | const outputPath = await generateHlsPlaylistResolutionFromTS({ |
106 | video: videoWithFiles, | 106 | video: videoWithFiles, |
107 | concatenatedTsFilePath, | 107 | concatenatedTsFilePath, |
108 | resolution: videoFileResolution, | 108 | resolution: videoFileResolution, |
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index 083cec11a..0f6b3f753 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts | |||
@@ -1,8 +1,10 @@ | |||
1 | import * as Bull from 'bull' | 1 | import * as Bull from 'bull' |
2 | import { TranscodeOptionsType } from '@server/helpers/ffmpeg-utils' | ||
2 | import { publishAndFederateIfNeeded } from '@server/lib/video' | 3 | import { publishAndFederateIfNeeded } from '@server/lib/video' |
3 | import { getVideoFilePath } from '@server/lib/video-paths' | 4 | import { getVideoFilePath } from '@server/lib/video-paths' |
4 | import { MVideoFullLight, MVideoUUID, MVideoWithFile } from '@server/types/models' | 5 | import { MVideoFullLight, MVideoUUID, MVideoWithFile } from '@server/types/models' |
5 | import { | 6 | import { |
7 | HLSTranscodingPayload, | ||
6 | MergeAudioTranscodingPayload, | 8 | MergeAudioTranscodingPayload, |
7 | NewResolutionTranscodingPayload, | 9 | NewResolutionTranscodingPayload, |
8 | OptimizeTranscodingPayload, | 10 | OptimizeTranscodingPayload, |
@@ -16,9 +18,31 @@ import { sequelizeTypescript } from '../../../initializers/database' | |||
16 | import { VideoModel } from '../../../models/video/video' | 18 | import { VideoModel } from '../../../models/video/video' |
17 | import { federateVideoIfNeeded } from '../../activitypub/videos' | 19 | import { federateVideoIfNeeded } from '../../activitypub/videos' |
18 | import { Notifier } from '../../notifier' | 20 | import { Notifier } from '../../notifier' |
19 | import { generateHlsPlaylist, mergeAudioVideofile, optimizeOriginalVideofile, transcodeNewResolution } from '../../video-transcoding' | 21 | import { |
22 | generateHlsPlaylistResolution, | ||
23 | mergeAudioVideofile, | ||
24 | optimizeOriginalVideofile, | ||
25 | transcodeNewWebTorrentResolution | ||
26 | } from '../../video-transcoding' | ||
20 | import { JobQueue } from '../job-queue' | 27 | import { JobQueue } from '../job-queue' |
21 | import { TranscodeOptionsType } from '@server/helpers/ffmpeg-utils' | 28 | |
29 | const handlers: { [ id: string ]: (job: Bull.Job, payload: VideoTranscodingPayload, video: MVideoFullLight) => Promise<any> } = { | ||
30 | // Deprecated, introduced in 3.1 | ||
31 | 'hls': handleHLSJob, | ||
32 | 'new-resolution-to-hls': handleHLSJob, | ||
33 | |||
34 | // Deprecated, introduced in 3.1 | ||
35 | 'new-resolution': handleNewWebTorrentResolutionJob, | ||
36 | 'new-resolution-to-webtorrent': handleNewWebTorrentResolutionJob, | ||
37 | |||
38 | // Deprecated, introduced in 3.1 | ||
39 | 'merge-audio': handleWebTorrentMergeAudioJob, | ||
40 | 'merge-audio-to-webtorrent': handleWebTorrentMergeAudioJob, | ||
41 | |||
42 | // Deprecated, introduced in 3.1 | ||
43 | 'optimize': handleWebTorrentOptimizeJob, | ||
44 | 'optimize-to-webtorrent': handleWebTorrentOptimizeJob | ||
45 | } | ||
22 | 46 | ||
23 | async function processVideoTranscoding (job: Bull.Job) { | 47 | async function processVideoTranscoding (job: Bull.Job) { |
24 | const payload = job.data as VideoTranscodingPayload | 48 | const payload = job.data as VideoTranscodingPayload |
@@ -31,42 +55,62 @@ async function processVideoTranscoding (job: Bull.Job) { | |||
31 | return undefined | 55 | return undefined |
32 | } | 56 | } |
33 | 57 | ||
34 | if (payload.type === 'hls') { | 58 | const handler = handlers[payload.type] |
35 | const videoFileInput = payload.copyCodecs | ||
36 | ? video.getWebTorrentFile(payload.resolution) | ||
37 | : video.getMaxQualityFile() | ||
38 | 59 | ||
39 | const videoOrStreamingPlaylist = videoFileInput.getVideoOrStreamingPlaylist() | 60 | if (!handler) { |
40 | const videoInputPath = getVideoFilePath(videoOrStreamingPlaylist, videoFileInput) | 61 | throw new Error('Cannot find transcoding handler for ' + payload.type) |
62 | } | ||
41 | 63 | ||
42 | await generateHlsPlaylist({ | 64 | await handler(job, payload, video) |
43 | video, | 65 | |
44 | videoInputPath, | 66 | return video |
45 | resolution: payload.resolution, | 67 | } |
46 | copyCodecs: payload.copyCodecs, | ||
47 | isPortraitMode: payload.isPortraitMode || false, | ||
48 | job | ||
49 | }) | ||
50 | 68 | ||
51 | await retryTransactionWrapper(onHlsPlaylistGenerationSuccess, video) | 69 | // --------------------------------------------------------------------------- |
52 | } else if (payload.type === 'new-resolution') { | 70 | // Job handlers |
53 | await transcodeNewResolution(video, payload.resolution, payload.isPortraitMode || false, job) | 71 | // --------------------------------------------------------------------------- |
54 | 72 | ||
55 | await retryTransactionWrapper(publishNewResolutionIfNeeded, video, payload) | 73 | async function handleHLSJob (job: Bull.Job, payload: HLSTranscodingPayload, video: MVideoFullLight) { |
56 | } else if (payload.type === 'merge-audio') { | 74 | const videoFileInput = payload.copyCodecs |
57 | await mergeAudioVideofile(video, payload.resolution, job) | 75 | ? video.getWebTorrentFile(payload.resolution) |
76 | : video.getMaxQualityFile() | ||
77 | |||
78 | const videoOrStreamingPlaylist = videoFileInput.getVideoOrStreamingPlaylist() | ||
79 | const videoInputPath = getVideoFilePath(videoOrStreamingPlaylist, videoFileInput) | ||
80 | |||
81 | await generateHlsPlaylistResolution({ | ||
82 | video, | ||
83 | videoInputPath, | ||
84 | resolution: payload.resolution, | ||
85 | copyCodecs: payload.copyCodecs, | ||
86 | isPortraitMode: payload.isPortraitMode || false, | ||
87 | job | ||
88 | }) | ||
58 | 89 | ||
59 | await retryTransactionWrapper(publishNewResolutionIfNeeded, video, payload) | 90 | await retryTransactionWrapper(onHlsPlaylistGeneration, video) |
60 | } else { | 91 | } |
61 | const transcodeType = await optimizeOriginalVideofile(video, video.getMaxQualityFile(), job) | ||
62 | 92 | ||
63 | await retryTransactionWrapper(onVideoFileOptimizerSuccess, video, payload, transcodeType) | 93 | async function handleNewWebTorrentResolutionJob (job: Bull.Job, payload: NewResolutionTranscodingPayload, video: MVideoFullLight) { |
64 | } | 94 | await transcodeNewWebTorrentResolution(video, payload.resolution, payload.isPortraitMode || false, job) |
65 | 95 | ||
66 | return video | 96 | await retryTransactionWrapper(onNewWebTorrentFileResolution, video, payload) |
97 | } | ||
98 | |||
99 | async function handleWebTorrentMergeAudioJob (job: Bull.Job, payload: MergeAudioTranscodingPayload, video: MVideoFullLight) { | ||
100 | await mergeAudioVideofile(video, payload.resolution, job) | ||
101 | |||
102 | await retryTransactionWrapper(onNewWebTorrentFileResolution, video, payload) | ||
67 | } | 103 | } |
68 | 104 | ||
69 | async function onHlsPlaylistGenerationSuccess (video: MVideoFullLight) { | 105 | async function handleWebTorrentOptimizeJob (job: Bull.Job, payload: OptimizeTranscodingPayload, video: MVideoFullLight) { |
106 | const transcodeType = await optimizeOriginalVideofile(video, video.getMaxQualityFile(), job) | ||
107 | |||
108 | await retryTransactionWrapper(onVideoFileOptimizer, video, payload, transcodeType) | ||
109 | } | ||
110 | |||
111 | // --------------------------------------------------------------------------- | ||
112 | |||
113 | async function onHlsPlaylistGeneration (video: MVideoFullLight) { | ||
70 | if (video === undefined) return undefined | 114 | if (video === undefined) return undefined |
71 | 115 | ||
72 | // We generated the HLS playlist, we don't need the webtorrent files anymore if the admin disabled it | 116 | // We generated the HLS playlist, we don't need the webtorrent files anymore if the admin disabled it |
@@ -82,13 +126,7 @@ async function onHlsPlaylistGenerationSuccess (video: MVideoFullLight) { | |||
82 | return publishAndFederateIfNeeded(video) | 126 | return publishAndFederateIfNeeded(video) |
83 | } | 127 | } |
84 | 128 | ||
85 | async function publishNewResolutionIfNeeded (video: MVideoUUID, payload?: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload) { | 129 | async function onVideoFileOptimizer ( |
86 | await publishAndFederateIfNeeded(video) | ||
87 | |||
88 | createHlsJobIfEnabled(Object.assign({}, payload, { copyCodecs: true })) | ||
89 | } | ||
90 | |||
91 | async function onVideoFileOptimizerSuccess ( | ||
92 | videoArg: MVideoWithFile, | 130 | videoArg: MVideoWithFile, |
93 | payload: OptimizeTranscodingPayload, | 131 | payload: OptimizeTranscodingPayload, |
94 | transcodeType: TranscodeOptionsType | 132 | transcodeType: TranscodeOptionsType |
@@ -113,7 +151,7 @@ async function onVideoFileOptimizerSuccess ( | |||
113 | 151 | ||
114 | let videoPublished = false | 152 | let videoPublished = false |
115 | 153 | ||
116 | // Generate HLS version of the max quality file | 154 | // Generate HLS version of the original file |
117 | const originalFileHLSPayload = Object.assign({}, payload, { | 155 | const originalFileHLSPayload = Object.assign({}, payload, { |
118 | isPortraitMode, | 156 | isPortraitMode, |
119 | resolution: videoDatabase.getMaxQualityFile().resolution, | 157 | resolution: videoDatabase.getMaxQualityFile().resolution, |
@@ -122,36 +160,11 @@ async function onVideoFileOptimizerSuccess ( | |||
122 | }) | 160 | }) |
123 | createHlsJobIfEnabled(originalFileHLSPayload) | 161 | createHlsJobIfEnabled(originalFileHLSPayload) |
124 | 162 | ||
125 | if (resolutionsEnabled.length !== 0) { | 163 | const hasNewResolutions = createLowerResolutionsJobs(videoDatabase, videoFileResolution, isPortraitMode) |
126 | for (const resolution of resolutionsEnabled) { | ||
127 | let dataInput: VideoTranscodingPayload | ||
128 | |||
129 | if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED) { | ||
130 | dataInput = { | ||
131 | type: 'new-resolution' as 'new-resolution', | ||
132 | videoUUID: videoDatabase.uuid, | ||
133 | resolution, | ||
134 | isPortraitMode | ||
135 | } | ||
136 | } else if (CONFIG.TRANSCODING.HLS.ENABLED) { | ||
137 | dataInput = { | ||
138 | type: 'hls', | ||
139 | videoUUID: videoDatabase.uuid, | ||
140 | resolution, | ||
141 | isPortraitMode, | ||
142 | copyCodecs: false | ||
143 | } | ||
144 | } | ||
145 | |||
146 | JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | ||
147 | } | ||
148 | 164 | ||
149 | logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) | 165 | if (!hasNewResolutions) { |
150 | } else { | ||
151 | // No transcoding to do, it's now published | 166 | // No transcoding to do, it's now published |
152 | videoPublished = await videoDatabase.publishIfNeededAndSave(t) | 167 | videoPublished = await videoDatabase.publishIfNeededAndSave(t) |
153 | |||
154 | logger.info('No transcoding jobs created for video %s (no resolutions).', videoDatabase.uuid, { privacy: videoDatabase.privacy }) | ||
155 | } | 168 | } |
156 | 169 | ||
157 | await federateVideoIfNeeded(videoDatabase, payload.isNewVideo, t) | 170 | await federateVideoIfNeeded(videoDatabase, payload.isNewVideo, t) |
@@ -163,11 +176,20 @@ async function onVideoFileOptimizerSuccess ( | |||
163 | if (videoPublished) Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(videoDatabase) | 176 | if (videoPublished) Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(videoDatabase) |
164 | } | 177 | } |
165 | 178 | ||
179 | async function onNewWebTorrentFileResolution ( | ||
180 | video: MVideoUUID, | ||
181 | payload?: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload | ||
182 | ) { | ||
183 | await publishAndFederateIfNeeded(video) | ||
184 | |||
185 | createHlsJobIfEnabled(Object.assign({}, payload, { copyCodecs: true })) | ||
186 | } | ||
187 | |||
166 | // --------------------------------------------------------------------------- | 188 | // --------------------------------------------------------------------------- |
167 | 189 | ||
168 | export { | 190 | export { |
169 | processVideoTranscoding, | 191 | processVideoTranscoding, |
170 | publishNewResolutionIfNeeded | 192 | onNewWebTorrentFileResolution |
171 | } | 193 | } |
172 | 194 | ||
173 | // --------------------------------------------------------------------------- | 195 | // --------------------------------------------------------------------------- |
@@ -175,8 +197,8 @@ export { | |||
175 | function createHlsJobIfEnabled (payload: { videoUUID: string, resolution: number, isPortraitMode?: boolean, copyCodecs: boolean }) { | 197 | function createHlsJobIfEnabled (payload: { videoUUID: string, resolution: number, isPortraitMode?: boolean, copyCodecs: boolean }) { |
176 | // Generate HLS playlist? | 198 | // Generate HLS playlist? |
177 | if (payload && CONFIG.TRANSCODING.HLS.ENABLED) { | 199 | if (payload && CONFIG.TRANSCODING.HLS.ENABLED) { |
178 | const hlsTranscodingPayload = { | 200 | const hlsTranscodingPayload: HLSTranscodingPayload = { |
179 | type: 'hls' as 'hls', | 201 | type: 'new-resolution-to-hls', |
180 | videoUUID: payload.videoUUID, | 202 | videoUUID: payload.videoUUID, |
181 | resolution: payload.resolution, | 203 | resolution: payload.resolution, |
182 | isPortraitMode: payload.isPortraitMode, | 204 | isPortraitMode: payload.isPortraitMode, |
@@ -186,3 +208,46 @@ function createHlsJobIfEnabled (payload: { videoUUID: string, resolution: number | |||
186 | return JobQueue.Instance.createJob({ type: 'video-transcoding', payload: hlsTranscodingPayload }) | 208 | return JobQueue.Instance.createJob({ type: 'video-transcoding', payload: hlsTranscodingPayload }) |
187 | } | 209 | } |
188 | } | 210 | } |
211 | |||
212 | function createLowerResolutionsJobs (video: MVideoFullLight, videoFileResolution: number, isPortraitMode: boolean) { | ||
213 | // Create transcoding jobs if there are enabled resolutions | ||
214 | const resolutionsEnabled = computeResolutionsToTranscode(videoFileResolution, 'vod') | ||
215 | logger.info( | ||
216 | 'Resolutions computed for video %s and origin file resolution of %d.', video.uuid, videoFileResolution, | ||
217 | { resolutions: resolutionsEnabled } | ||
218 | ) | ||
219 | |||
220 | if (resolutionsEnabled.length === 0) { | ||
221 | logger.info('No transcoding jobs created for video %s (no resolutions).', video.uuid) | ||
222 | |||
223 | return false | ||
224 | } | ||
225 | |||
226 | for (const resolution of resolutionsEnabled) { | ||
227 | let dataInput: VideoTranscodingPayload | ||
228 | |||
229 | if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED) { | ||
230 | // WebTorrent will create subsequent HLS job | ||
231 | dataInput = { | ||
232 | type: 'new-resolution-to-webtorrent', | ||
233 | videoUUID: video.uuid, | ||
234 | resolution, | ||
235 | isPortraitMode | ||
236 | } | ||
237 | } else if (CONFIG.TRANSCODING.HLS.ENABLED) { | ||
238 | dataInput = { | ||
239 | type: 'new-resolution-to-hls', | ||
240 | videoUUID: video.uuid, | ||
241 | resolution, | ||
242 | isPortraitMode, | ||
243 | copyCodecs: false | ||
244 | } | ||
245 | } | ||
246 | |||
247 | JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | ||
248 | } | ||
249 | |||
250 | logger.info('Transcoding jobs created for uuid %s.', video.uuid, { resolutionsEnabled }) | ||
251 | |||
252 | return true | ||
253 | } | ||
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts index beef78b44..7af7a481c 100644 --- a/server/lib/video-transcoding.ts +++ b/server/lib/video-transcoding.ts | |||
@@ -60,7 +60,7 @@ async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFile: | |||
60 | 60 | ||
61 | const videoOutputPath = getVideoFilePath(video, inputVideoFile) | 61 | const videoOutputPath = getVideoFilePath(video, inputVideoFile) |
62 | 62 | ||
63 | await onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) | 63 | await onWebTorrentVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) |
64 | 64 | ||
65 | return transcodeType | 65 | return transcodeType |
66 | } catch (err) { | 66 | } catch (err) { |
@@ -72,7 +72,7 @@ async function optimizeOriginalVideofile (video: MVideoWithFile, inputVideoFile: | |||
72 | } | 72 | } |
73 | 73 | ||
74 | // Transcode the original video file to a lower resolution. | 74 | // Transcode the original video file to a lower resolution. |
75 | async function transcodeNewResolution (video: MVideoWithFile, resolution: VideoResolution, isPortrait: boolean, job: Job) { | 75 | async function transcodeNewWebTorrentResolution (video: MVideoWithFile, resolution: VideoResolution, isPortrait: boolean, job: Job) { |
76 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR | 76 | const transcodeDirectory = CONFIG.STORAGE.TMP_DIR |
77 | const extname = '.mp4' | 77 | const extname = '.mp4' |
78 | 78 | ||
@@ -118,7 +118,7 @@ async function transcodeNewResolution (video: MVideoWithFile, resolution: VideoR | |||
118 | 118 | ||
119 | await transcode(transcodeOptions) | 119 | await transcode(transcodeOptions) |
120 | 120 | ||
121 | return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath) | 121 | return onWebTorrentVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath) |
122 | } | 122 | } |
123 | 123 | ||
124 | // Merge an image with an audio file to create a video | 124 | // Merge an image with an audio file to create a video |
@@ -170,11 +170,11 @@ async function mergeAudioVideofile (video: MVideoWithAllFiles, resolution: Video | |||
170 | video.duration = await getDurationFromVideoFile(videoTranscodedPath) | 170 | video.duration = await getDurationFromVideoFile(videoTranscodedPath) |
171 | await video.save() | 171 | await video.save() |
172 | 172 | ||
173 | return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) | 173 | return onWebTorrentVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) |
174 | } | 174 | } |
175 | 175 | ||
176 | // Concat TS segments from a live video to a fragmented mp4 HLS playlist | 176 | // Concat TS segments from a live video to a fragmented mp4 HLS playlist |
177 | async function generateHlsPlaylistFromTS (options: { | 177 | async function generateHlsPlaylistResolutionFromTS (options: { |
178 | video: MVideoWithFile | 178 | video: MVideoWithFile |
179 | concatenatedTsFilePath: string | 179 | concatenatedTsFilePath: string |
180 | resolution: VideoResolution | 180 | resolution: VideoResolution |
@@ -192,7 +192,7 @@ async function generateHlsPlaylistFromTS (options: { | |||
192 | } | 192 | } |
193 | 193 | ||
194 | // Generate an HLS playlist from an input file, and update the master playlist | 194 | // Generate an HLS playlist from an input file, and update the master playlist |
195 | function generateHlsPlaylist (options: { | 195 | function generateHlsPlaylistResolution (options: { |
196 | video: MVideoWithFile | 196 | video: MVideoWithFile |
197 | videoInputPath: string | 197 | videoInputPath: string |
198 | resolution: VideoResolution | 198 | resolution: VideoResolution |
@@ -224,17 +224,22 @@ function getEnabledResolutions (type: 'vod' | 'live') { | |||
224 | // --------------------------------------------------------------------------- | 224 | // --------------------------------------------------------------------------- |
225 | 225 | ||
226 | export { | 226 | export { |
227 | generateHlsPlaylist, | 227 | generateHlsPlaylistResolution, |
228 | generateHlsPlaylistFromTS, | 228 | generateHlsPlaylistResolutionFromTS, |
229 | optimizeOriginalVideofile, | 229 | optimizeOriginalVideofile, |
230 | transcodeNewResolution, | 230 | transcodeNewWebTorrentResolution, |
231 | mergeAudioVideofile, | 231 | mergeAudioVideofile, |
232 | getEnabledResolutions | 232 | getEnabledResolutions |
233 | } | 233 | } |
234 | 234 | ||
235 | // --------------------------------------------------------------------------- | 235 | // --------------------------------------------------------------------------- |
236 | 236 | ||
237 | async function onVideoFileTranscoding (video: MVideoWithFile, videoFile: MVideoFile, transcodingPath: string, outputPath: string) { | 237 | async function onWebTorrentVideoFileTranscoding ( |
238 | video: MVideoWithFile, | ||
239 | videoFile: MVideoFile, | ||
240 | transcodingPath: string, | ||
241 | outputPath: string | ||
242 | ) { | ||
238 | const stats = await stat(transcodingPath) | 243 | const stats = await stat(transcodingPath) |
239 | const fps = await getVideoFileFPS(transcodingPath) | 244 | const fps = await getVideoFileFPS(transcodingPath) |
240 | const metadata = await getMetadataFromFile(transcodingPath) | 245 | const metadata = await getMetadataFromFile(transcodingPath) |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 3db6549ae..2bfa704ec 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1735,6 +1735,7 @@ export class VideoModel extends Model { | |||
1735 | } | 1735 | } |
1736 | 1736 | ||
1737 | getQualityFileBy<T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) { | 1737 | getQualityFileBy<T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) { |
1738 | // We first transcode to WebTorrent format, so try this array first | ||
1738 | if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) { | 1739 | if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) { |
1739 | const file = fun(this.VideoFiles, file => file.resolution) | 1740 | const file = fun(this.VideoFiles, file => file.resolution) |
1740 | 1741 | ||
diff --git a/shared/models/server/job.model.ts b/shared/models/server/job.model.ts index 11d90c32f..d16ac1032 100644 --- a/shared/models/server/job.model.ts +++ b/shared/models/server/job.model.ts | |||
@@ -100,26 +100,26 @@ interface BaseTranscodingPayload { | |||
100 | isNewVideo?: boolean | 100 | isNewVideo?: boolean |
101 | } | 101 | } |
102 | 102 | ||
103 | interface HLSTranscodingPayload extends BaseTranscodingPayload { | 103 | export interface HLSTranscodingPayload extends BaseTranscodingPayload { |
104 | type: 'hls' | 104 | type: 'new-resolution-to-hls' |
105 | isPortraitMode?: boolean | 105 | isPortraitMode?: boolean |
106 | resolution: VideoResolution | 106 | resolution: VideoResolution |
107 | copyCodecs: boolean | 107 | copyCodecs: boolean |
108 | } | 108 | } |
109 | 109 | ||
110 | export interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { | 110 | export interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { |
111 | type: 'new-resolution' | 111 | type: 'new-resolution-to-webtorrent' |
112 | isPortraitMode?: boolean | 112 | isPortraitMode?: boolean |
113 | resolution: VideoResolution | 113 | resolution: VideoResolution |
114 | } | 114 | } |
115 | 115 | ||
116 | export interface MergeAudioTranscodingPayload extends BaseTranscodingPayload { | 116 | export interface MergeAudioTranscodingPayload extends BaseTranscodingPayload { |
117 | type: 'merge-audio' | 117 | type: 'merge-audio-to-webtorrent' |
118 | resolution: VideoResolution | 118 | resolution: VideoResolution |
119 | } | 119 | } |
120 | 120 | ||
121 | export interface OptimizeTranscodingPayload extends BaseTranscodingPayload { | 121 | export interface OptimizeTranscodingPayload extends BaseTranscodingPayload { |
122 | type: 'optimize' | 122 | type: 'optimize-to-webtorrent' |
123 | } | 123 | } |
124 | 124 | ||
125 | export type VideoTranscodingPayload = | 125 | export type VideoTranscodingPayload = |