aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rwxr-xr-xscripts/create-transcoding-job.ts8
-rw-r--r--server/controllers/api/videos/transcoding.ts4
-rw-r--r--server/lib/job-queue/handlers/video-transcoding.ts25
-rw-r--r--server/models/video/video.ts16
-rw-r--r--shared/models/server/job.model.ts9
5 files changed, 46 insertions, 16 deletions
diff --git a/scripts/create-transcoding-job.ts b/scripts/create-transcoding-job.ts
index d462fbf33..95e1e66cf 100755
--- a/scripts/create-transcoding-job.ts
+++ b/scripts/create-transcoding-job.ts
@@ -60,7 +60,11 @@ async function run () {
60 type: 'new-resolution-to-hls', 60 type: 'new-resolution-to-hls',
61 videoUUID: video.uuid, 61 videoUUID: video.uuid,
62 resolution, 62 resolution,
63
64 // FIXME: check the file has audio and is not in portrait mode
63 isPortraitMode: false, 65 isPortraitMode: false,
66 hasAudio: true,
67
64 copyCodecs: false, 68 copyCodecs: false,
65 isNewVideo: false, 69 isNewVideo: false,
66 isMaxQuality: maxResolution === resolution, 70 isMaxQuality: maxResolution === resolution,
@@ -72,6 +76,10 @@ async function run () {
72 dataInput.push({ 76 dataInput.push({
73 type: 'new-resolution-to-webtorrent', 77 type: 'new-resolution-to-webtorrent',
74 videoUUID: video.uuid, 78 videoUUID: video.uuid,
79
80 // FIXME: check the file has audio
81 hasAudio: true,
82
75 isNewVideo: false, 83 isNewVideo: false,
76 resolution: parseInt(options.resolution) 84 resolution: parseInt(options.resolution)
77 }) 85 })
diff --git a/server/controllers/api/videos/transcoding.ts b/server/controllers/api/videos/transcoding.ts
index dd6fbd3de..388689c8a 100644
--- a/server/controllers/api/videos/transcoding.ts
+++ b/server/controllers/api/videos/transcoding.ts
@@ -29,7 +29,7 @@ async function createTranscoding (req: express.Request, res: express.Response) {
29 29
30 const body: VideoTranscodingCreate = req.body 30 const body: VideoTranscodingCreate = req.body
31 31
32 const { resolution: maxResolution, isPortraitMode } = await video.getMaxQualityResolution() 32 const { resolution: maxResolution, isPortraitMode, audioStream } = await video.getMaxQualityFileInfo()
33 const resolutions = computeLowerResolutionsToTranscode(maxResolution, 'vod').concat([ maxResolution ]) 33 const resolutions = computeLowerResolutionsToTranscode(maxResolution, 'vod').concat([ maxResolution ])
34 34
35 video.state = VideoState.TO_TRANSCODE 35 video.state = VideoState.TO_TRANSCODE
@@ -42,6 +42,7 @@ async function createTranscoding (req: express.Request, res: express.Response) {
42 videoUUID: video.uuid, 42 videoUUID: video.uuid,
43 resolution, 43 resolution,
44 isPortraitMode, 44 isPortraitMode,
45 hasAudio: !!audioStream,
45 copyCodecs: false, 46 copyCodecs: false,
46 isNewVideo: false, 47 isNewVideo: false,
47 autoDeleteWebTorrentIfNeeded: false, 48 autoDeleteWebTorrentIfNeeded: false,
@@ -53,6 +54,7 @@ async function createTranscoding (req: express.Request, res: express.Response) {
53 videoUUID: video.uuid, 54 videoUUID: video.uuid,
54 isNewVideo: false, 55 isNewVideo: false,
55 resolution: resolution, 56 resolution: resolution,
57 hasAudio: !!audioStream,
56 isPortraitMode 58 isPortraitMode
57 }) 59 })
58 } 60 }
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts
index ef3abcbcd..02902b0b8 100644
--- a/server/lib/job-queue/handlers/video-transcoding.ts
+++ b/server/lib/job-queue/handlers/video-transcoding.ts
@@ -6,11 +6,13 @@ import { moveToFailedTranscodingState, moveToNextState } from '@server/lib/video
6import { UserModel } from '@server/models/user/user' 6import { UserModel } from '@server/models/user/user'
7import { VideoJobInfoModel } from '@server/models/video/video-job-info' 7import { VideoJobInfoModel } from '@server/models/video/video-job-info'
8import { MUser, MUserId, MVideo, MVideoFullLight, MVideoWithFile } from '@server/types/models' 8import { MUser, MUserId, MVideo, MVideoFullLight, MVideoWithFile } from '@server/types/models'
9import { pick } from '@shared/core-utils'
9import { 10import {
10 HLSTranscodingPayload, 11 HLSTranscodingPayload,
11 MergeAudioTranscodingPayload, 12 MergeAudioTranscodingPayload,
12 NewResolutionTranscodingPayload, 13 NewResolutionTranscodingPayload,
13 OptimizeTranscodingPayload, 14 OptimizeTranscodingPayload,
15 VideoResolution,
14 VideoTranscodingPayload 16 VideoTranscodingPayload
15} from '@shared/models' 17} from '@shared/models'
16import { retryTransactionWrapper } from '../../../helpers/database-utils' 18import { retryTransactionWrapper } from '../../../helpers/database-utils'
@@ -159,6 +161,7 @@ async function onHlsPlaylistGeneration (video: MVideoFullLight, user: MUser, pay
159 user, 161 user,
160 videoFileResolution: payload.resolution, 162 videoFileResolution: payload.resolution,
161 isPortraitMode: payload.isPortraitMode, 163 isPortraitMode: payload.isPortraitMode,
164 hasAudio: payload.hasAudio,
162 isNewVideo: payload.isNewVideo ?? true, 165 isNewVideo: payload.isNewVideo ?? true,
163 type: 'hls' 166 type: 'hls'
164 }) 167 })
@@ -174,7 +177,7 @@ async function onVideoFirstWebTorrentTranscoding (
174 transcodeType: TranscodeOptionsType, 177 transcodeType: TranscodeOptionsType,
175 user: MUserId 178 user: MUserId
176) { 179) {
177 const { resolution, isPortraitMode } = await videoArg.getMaxQualityResolution() 180 const { resolution, isPortraitMode, audioStream } = await videoArg.getMaxQualityFileInfo()
178 181
179 // Maybe the video changed in database, refresh it 182 // Maybe the video changed in database, refresh it
180 const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid) 183 const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid)
@@ -186,6 +189,7 @@ async function onVideoFirstWebTorrentTranscoding (
186 ...payload, 189 ...payload,
187 190
188 isPortraitMode, 191 isPortraitMode,
192 hasAudio: !!audioStream,
189 resolution: videoDatabase.getMaxQualityFile().resolution, 193 resolution: videoDatabase.getMaxQualityFile().resolution,
190 // If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues 194 // If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues
191 copyCodecs: transcodeType !== 'quick-transcode', 195 copyCodecs: transcodeType !== 'quick-transcode',
@@ -196,6 +200,7 @@ async function onVideoFirstWebTorrentTranscoding (
196 video: videoDatabase, 200 video: videoDatabase,
197 user, 201 user,
198 videoFileResolution: resolution, 202 videoFileResolution: resolution,
203 hasAudio: !!audioStream,
199 isPortraitMode, 204 isPortraitMode,
200 type: 'webtorrent', 205 type: 'webtorrent',
201 isNewVideo: payload.isNewVideo ?? true 206 isNewVideo: payload.isNewVideo ?? true
@@ -214,7 +219,7 @@ async function onNewWebTorrentFileResolution (
214 user: MUserId, 219 user: MUserId,
215 payload: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload 220 payload: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload
216) { 221) {
217 await createHlsJobIfEnabled(user, { ...payload, copyCodecs: true, isMaxQuality: false }) 222 await createHlsJobIfEnabled(user, { hasAudio: true, copyCodecs: true, isMaxQuality: false, ...payload })
218 await VideoJobInfoModel.decrease(video.uuid, 'pendingTranscode') 223 await VideoJobInfoModel.decrease(video.uuid, 'pendingTranscode')
219 224
220 await retryTransactionWrapper(moveToNextState, video, payload.isNewVideo) 225 await retryTransactionWrapper(moveToNextState, video, payload.isNewVideo)
@@ -225,6 +230,7 @@ async function onNewWebTorrentFileResolution (
225async function createHlsJobIfEnabled (user: MUserId, payload: { 230async function createHlsJobIfEnabled (user: MUserId, payload: {
226 videoUUID: string 231 videoUUID: string
227 resolution: number 232 resolution: number
233 hasAudio: boolean
228 isPortraitMode?: boolean 234 isPortraitMode?: boolean
229 copyCodecs: boolean 235 copyCodecs: boolean
230 isMaxQuality: boolean 236 isMaxQuality: boolean
@@ -238,13 +244,9 @@ async function createHlsJobIfEnabled (user: MUserId, payload: {
238 244
239 const hlsTranscodingPayload: HLSTranscodingPayload = { 245 const hlsTranscodingPayload: HLSTranscodingPayload = {
240 type: 'new-resolution-to-hls', 246 type: 'new-resolution-to-hls',
241 videoUUID: payload.videoUUID,
242 resolution: payload.resolution,
243 isPortraitMode: payload.isPortraitMode,
244 copyCodecs: payload.copyCodecs,
245 isMaxQuality: payload.isMaxQuality,
246 autoDeleteWebTorrentIfNeeded: true, 247 autoDeleteWebTorrentIfNeeded: true,
247 isNewVideo: payload.isNewVideo 248
249 ...pick(payload, [ 'videoUUID', 'resolution', 'isPortraitMode', 'copyCodecs', 'isMaxQuality', 'isNewVideo', 'hasAudio' ])
248 } 250 }
249 251
250 await addTranscodingJob(hlsTranscodingPayload, jobOptions) 252 await addTranscodingJob(hlsTranscodingPayload, jobOptions)
@@ -257,16 +259,19 @@ async function createLowerResolutionsJobs (options: {
257 user: MUserId 259 user: MUserId
258 videoFileResolution: number 260 videoFileResolution: number
259 isPortraitMode: boolean 261 isPortraitMode: boolean
262 hasAudio: boolean
260 isNewVideo: boolean 263 isNewVideo: boolean
261 type: 'hls' | 'webtorrent' 264 type: 'hls' | 'webtorrent'
262}) { 265}) {
263 const { video, user, videoFileResolution, isPortraitMode, isNewVideo, type } = options 266 const { video, user, videoFileResolution, isPortraitMode, isNewVideo, hasAudio, type } = options
264 267
265 // Create transcoding jobs if there are enabled resolutions 268 // Create transcoding jobs if there are enabled resolutions
266 const resolutionsEnabled = computeLowerResolutionsToTranscode(videoFileResolution, 'vod') 269 const resolutionsEnabled = computeLowerResolutionsToTranscode(videoFileResolution, 'vod')
267 const resolutionCreated: string[] = [] 270 const resolutionCreated: string[] = []
268 271
269 for (const resolution of resolutionsEnabled) { 272 for (const resolution of resolutionsEnabled) {
273 if (resolution === VideoResolution.H_NOVIDEO && hasAudio === false) continue
274
270 let dataInput: VideoTranscodingPayload 275 let dataInput: VideoTranscodingPayload
271 276
272 if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED && type === 'webtorrent') { 277 if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED && type === 'webtorrent') {
@@ -276,6 +281,7 @@ async function createLowerResolutionsJobs (options: {
276 videoUUID: video.uuid, 281 videoUUID: video.uuid,
277 resolution, 282 resolution,
278 isPortraitMode, 283 isPortraitMode,
284 hasAudio,
279 isNewVideo 285 isNewVideo
280 } 286 }
281 287
@@ -288,6 +294,7 @@ async function createLowerResolutionsJobs (options: {
288 videoUUID: video.uuid, 294 videoUUID: video.uuid,
289 resolution, 295 resolution,
290 isPortraitMode, 296 isPortraitMode,
297 hasAudio,
291 copyCodecs: false, 298 copyCodecs: false,
292 isMaxQuality: false, 299 isMaxQuality: false,
293 autoDeleteWebTorrentIfNeeded: true, 300 autoDeleteWebTorrentIfNeeded: true,
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index e5077487a..12b937574 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -33,7 +33,7 @@ import { VideoPathManager } from '@server/lib/video-path-manager'
33import { getServerActor } from '@server/models/application/application' 33import { getServerActor } from '@server/models/application/application'
34import { ModelCache } from '@server/models/model-cache' 34import { ModelCache } from '@server/models/model-cache'
35import { buildVideoEmbedPath, buildVideoWatchPath, pick } from '@shared/core-utils' 35import { buildVideoEmbedPath, buildVideoWatchPath, pick } from '@shared/core-utils'
36import { uuidToShort } from '@shared/extra-utils' 36import { ffprobePromise, getAudioStream, uuidToShort } from '@shared/extra-utils'
37import { 37import {
38 ResultList, 38 ResultList,
39 ThumbnailType, 39 ThumbnailType,
@@ -1678,12 +1678,20 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
1678 return peertubeTruncate(this.description, { length: maxLength }) 1678 return peertubeTruncate(this.description, { length: maxLength })
1679 } 1679 }
1680 1680
1681 getMaxQualityResolution () { 1681 getMaxQualityFileInfo () {
1682 const file = this.getMaxQualityFile() 1682 const file = this.getMaxQualityFile()
1683 const videoOrPlaylist = file.getVideoOrStreamingPlaylist() 1683 const videoOrPlaylist = file.getVideoOrStreamingPlaylist()
1684 1684
1685 return VideoPathManager.Instance.makeAvailableVideoFile(file.withVideoOrPlaylist(videoOrPlaylist), originalFilePath => { 1685 return VideoPathManager.Instance.makeAvailableVideoFile(file.withVideoOrPlaylist(videoOrPlaylist), async originalFilePath => {
1686 return getVideoFileResolution(originalFilePath) 1686 const probe = await ffprobePromise(originalFilePath)
1687
1688 const { audioStream } = await getAudioStream(originalFilePath, probe)
1689
1690 return {
1691 audioStream,
1692
1693 ...await getVideoFileResolution(originalFilePath, probe)
1694 }
1687 }) 1695 })
1688 } 1696 }
1689 1697
diff --git a/shared/models/server/job.model.ts b/shared/models/server/job.model.ts
index ecc960da5..8a69d11fa 100644
--- a/shared/models/server/job.model.ts
+++ b/shared/models/server/job.model.ts
@@ -103,18 +103,23 @@ interface BaseTranscodingPayload {
103 103
104export interface HLSTranscodingPayload extends BaseTranscodingPayload { 104export interface HLSTranscodingPayload extends BaseTranscodingPayload {
105 type: 'new-resolution-to-hls' 105 type: 'new-resolution-to-hls'
106 isPortraitMode?: boolean
107 resolution: VideoResolution 106 resolution: VideoResolution
108 copyCodecs: boolean 107 copyCodecs: boolean
109 108
109 hasAudio: boolean
110 isPortraitMode?: boolean
111
110 autoDeleteWebTorrentIfNeeded: boolean 112 autoDeleteWebTorrentIfNeeded: boolean
111 isMaxQuality: boolean 113 isMaxQuality: boolean
112} 114}
113 115
114export interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { 116export interface NewResolutionTranscodingPayload extends BaseTranscodingPayload {
115 type: 'new-resolution-to-webtorrent' 117 type: 'new-resolution-to-webtorrent'
116 isPortraitMode?: boolean
117 resolution: VideoResolution 118 resolution: VideoResolution
119
120 hasAudio: boolean
121
122 isPortraitMode?: boolean
118} 123}
119 124
120export interface MergeAudioTranscodingPayload extends BaseTranscodingPayload { 125export interface MergeAudioTranscodingPayload extends BaseTranscodingPayload {