From cbe2f36d93c779ca08424336be7e3988e57be01d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 6 Jan 2022 17:55:37 +0100 Subject: [PATCH] Fix audio transcoding with video only file --- scripts/create-transcoding-job.ts | 8 ++++++ server/controllers/api/videos/transcoding.ts | 4 ++- .../job-queue/handlers/video-transcoding.ts | 25 ++++++++++++------- server/models/video/video.ts | 16 +++++++++--- shared/models/server/job.model.ts | 9 +++++-- 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 () { type: 'new-resolution-to-hls', videoUUID: video.uuid, resolution, + + // FIXME: check the file has audio and is not in portrait mode isPortraitMode: false, + hasAudio: true, + copyCodecs: false, isNewVideo: false, isMaxQuality: maxResolution === resolution, @@ -72,6 +76,10 @@ async function run () { dataInput.push({ type: 'new-resolution-to-webtorrent', videoUUID: video.uuid, + + // FIXME: check the file has audio + hasAudio: true, + isNewVideo: false, resolution: parseInt(options.resolution) }) 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) { const body: VideoTranscodingCreate = req.body - const { resolution: maxResolution, isPortraitMode } = await video.getMaxQualityResolution() + const { resolution: maxResolution, isPortraitMode, audioStream } = await video.getMaxQualityFileInfo() const resolutions = computeLowerResolutionsToTranscode(maxResolution, 'vod').concat([ maxResolution ]) video.state = VideoState.TO_TRANSCODE @@ -42,6 +42,7 @@ async function createTranscoding (req: express.Request, res: express.Response) { videoUUID: video.uuid, resolution, isPortraitMode, + hasAudio: !!audioStream, copyCodecs: false, isNewVideo: false, autoDeleteWebTorrentIfNeeded: false, @@ -53,6 +54,7 @@ async function createTranscoding (req: express.Request, res: express.Response) { videoUUID: video.uuid, isNewVideo: false, resolution: resolution, + hasAudio: !!audioStream, isPortraitMode }) } 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 import { UserModel } from '@server/models/user/user' import { VideoJobInfoModel } from '@server/models/video/video-job-info' import { MUser, MUserId, MVideo, MVideoFullLight, MVideoWithFile } from '@server/types/models' +import { pick } from '@shared/core-utils' import { HLSTranscodingPayload, MergeAudioTranscodingPayload, NewResolutionTranscodingPayload, OptimizeTranscodingPayload, + VideoResolution, VideoTranscodingPayload } from '@shared/models' import { retryTransactionWrapper } from '../../../helpers/database-utils' @@ -159,6 +161,7 @@ async function onHlsPlaylistGeneration (video: MVideoFullLight, user: MUser, pay user, videoFileResolution: payload.resolution, isPortraitMode: payload.isPortraitMode, + hasAudio: payload.hasAudio, isNewVideo: payload.isNewVideo ?? true, type: 'hls' }) @@ -174,7 +177,7 @@ async function onVideoFirstWebTorrentTranscoding ( transcodeType: TranscodeOptionsType, user: MUserId ) { - const { resolution, isPortraitMode } = await videoArg.getMaxQualityResolution() + const { resolution, isPortraitMode, audioStream } = await videoArg.getMaxQualityFileInfo() // Maybe the video changed in database, refresh it const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid) @@ -186,6 +189,7 @@ async function onVideoFirstWebTorrentTranscoding ( ...payload, isPortraitMode, + hasAudio: !!audioStream, resolution: videoDatabase.getMaxQualityFile().resolution, // If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues copyCodecs: transcodeType !== 'quick-transcode', @@ -196,6 +200,7 @@ async function onVideoFirstWebTorrentTranscoding ( video: videoDatabase, user, videoFileResolution: resolution, + hasAudio: !!audioStream, isPortraitMode, type: 'webtorrent', isNewVideo: payload.isNewVideo ?? true @@ -214,7 +219,7 @@ async function onNewWebTorrentFileResolution ( user: MUserId, payload: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload ) { - await createHlsJobIfEnabled(user, { ...payload, copyCodecs: true, isMaxQuality: false }) + await createHlsJobIfEnabled(user, { hasAudio: true, copyCodecs: true, isMaxQuality: false, ...payload }) await VideoJobInfoModel.decrease(video.uuid, 'pendingTranscode') await retryTransactionWrapper(moveToNextState, video, payload.isNewVideo) @@ -225,6 +230,7 @@ async function onNewWebTorrentFileResolution ( async function createHlsJobIfEnabled (user: MUserId, payload: { videoUUID: string resolution: number + hasAudio: boolean isPortraitMode?: boolean copyCodecs: boolean isMaxQuality: boolean @@ -238,13 +244,9 @@ async function createHlsJobIfEnabled (user: MUserId, payload: { const hlsTranscodingPayload: HLSTranscodingPayload = { type: 'new-resolution-to-hls', - videoUUID: payload.videoUUID, - resolution: payload.resolution, - isPortraitMode: payload.isPortraitMode, - copyCodecs: payload.copyCodecs, - isMaxQuality: payload.isMaxQuality, autoDeleteWebTorrentIfNeeded: true, - isNewVideo: payload.isNewVideo + + ...pick(payload, [ 'videoUUID', 'resolution', 'isPortraitMode', 'copyCodecs', 'isMaxQuality', 'isNewVideo', 'hasAudio' ]) } await addTranscodingJob(hlsTranscodingPayload, jobOptions) @@ -257,16 +259,19 @@ async function createLowerResolutionsJobs (options: { user: MUserId videoFileResolution: number isPortraitMode: boolean + hasAudio: boolean isNewVideo: boolean type: 'hls' | 'webtorrent' }) { - const { video, user, videoFileResolution, isPortraitMode, isNewVideo, type } = options + const { video, user, videoFileResolution, isPortraitMode, isNewVideo, hasAudio, type } = options // Create transcoding jobs if there are enabled resolutions const resolutionsEnabled = computeLowerResolutionsToTranscode(videoFileResolution, 'vod') const resolutionCreated: string[] = [] for (const resolution of resolutionsEnabled) { + if (resolution === VideoResolution.H_NOVIDEO && hasAudio === false) continue + let dataInput: VideoTranscodingPayload if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED && type === 'webtorrent') { @@ -276,6 +281,7 @@ async function createLowerResolutionsJobs (options: { videoUUID: video.uuid, resolution, isPortraitMode, + hasAudio, isNewVideo } @@ -288,6 +294,7 @@ async function createLowerResolutionsJobs (options: { videoUUID: video.uuid, resolution, isPortraitMode, + hasAudio, copyCodecs: false, isMaxQuality: false, 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' import { getServerActor } from '@server/models/application/application' import { ModelCache } from '@server/models/model-cache' import { buildVideoEmbedPath, buildVideoWatchPath, pick } from '@shared/core-utils' -import { uuidToShort } from '@shared/extra-utils' +import { ffprobePromise, getAudioStream, uuidToShort } from '@shared/extra-utils' import { ResultList, ThumbnailType, @@ -1678,12 +1678,20 @@ export class VideoModel extends Model>> { return peertubeTruncate(this.description, { length: maxLength }) } - getMaxQualityResolution () { + getMaxQualityFileInfo () { const file = this.getMaxQualityFile() const videoOrPlaylist = file.getVideoOrStreamingPlaylist() - return VideoPathManager.Instance.makeAvailableVideoFile(file.withVideoOrPlaylist(videoOrPlaylist), originalFilePath => { - return getVideoFileResolution(originalFilePath) + return VideoPathManager.Instance.makeAvailableVideoFile(file.withVideoOrPlaylist(videoOrPlaylist), async originalFilePath => { + const probe = await ffprobePromise(originalFilePath) + + const { audioStream } = await getAudioStream(originalFilePath, probe) + + return { + audioStream, + + ...await getVideoFileResolution(originalFilePath, probe) + } }) } 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 { export interface HLSTranscodingPayload extends BaseTranscodingPayload { type: 'new-resolution-to-hls' - isPortraitMode?: boolean resolution: VideoResolution copyCodecs: boolean + hasAudio: boolean + isPortraitMode?: boolean + autoDeleteWebTorrentIfNeeded: boolean isMaxQuality: boolean } export interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { type: 'new-resolution-to-webtorrent' - isPortraitMode?: boolean resolution: VideoResolution + + hasAudio: boolean + + isPortraitMode?: boolean } export interface MergeAudioTranscodingPayload extends BaseTranscodingPayload {