Init commit
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
import { VideoFileStreamType, VideoResolution } from '@peertube/peertube-models'
|
||||
import { computeOutputFPS } from '@server/helpers/ffmpeg/framerate.js'
|
||||
import { logger, loggerTagsFactory } from '@server/helpers/logger.js'
|
||||
import { CONFIG } from '@server/initializers/config.js'
|
||||
import { DEFAULT_AUDIO_MERGE_RESOLUTION, DEFAULT_AUDIO_RESOLUTION } from '@server/initializers/constants.js'
|
||||
import { Hooks } from '@server/lib/plugins/hooks.js'
|
||||
import { MUserId, MVideoFile, MVideoFullLight } from '@server/types/models/index.js'
|
||||
import { buildOriginalFileResolution, computeResolutionsToTranscode } from '../../transcoding-resolutions.js'
|
||||
|
||||
const lTags = loggerTagsFactory('transcoding')
|
||||
|
||||
export type TranscodingPriorityType = 'required' | 'optional'
|
||||
|
||||
export abstract class AbstractJobBuilder<P extends { transcodingPriority: TranscodingPriorityType }> {
|
||||
async createOptimizeOrMergeAudioJobs (options: {
|
||||
video: MVideoFullLight
|
||||
videoFile: MVideoFile
|
||||
isNewVideo: boolean
|
||||
user: MUserId
|
||||
}) {
|
||||
const { video, videoFile, isNewVideo, user } = options
|
||||
|
||||
let mergeOrOptimizePayload: P
|
||||
let children: P[][] = []
|
||||
|
||||
const inputStreams = video.getStreamTypes()
|
||||
const transcodingRequestAt = new Date().toISOString()
|
||||
|
||||
let maxFPS: number
|
||||
let maxResolution: number
|
||||
|
||||
let hlsAudioAlreadyGenerated = false
|
||||
|
||||
if (videoFile.isAudio()) {
|
||||
// The first transcoding job will transcode to this FPS value
|
||||
maxFPS = Math.min(DEFAULT_AUDIO_MERGE_RESOLUTION, CONFIG.TRANSCODING.FPS.MAX)
|
||||
maxResolution = DEFAULT_AUDIO_RESOLUTION
|
||||
|
||||
mergeOrOptimizePayload = this.buildMergeAudioPayload({
|
||||
video,
|
||||
isNewVideo,
|
||||
inputFile: videoFile,
|
||||
resolution: maxResolution,
|
||||
fps: maxFPS,
|
||||
|
||||
transcodingPriority: 'required',
|
||||
canMoveVideoState: null // Will be set below
|
||||
})
|
||||
} else {
|
||||
const inputFPS = videoFile.fps
|
||||
maxResolution = buildOriginalFileResolution(videoFile.resolution)
|
||||
maxFPS = computeOutputFPS({ inputFPS, resolution: maxResolution, isOriginResolution: true, type: 'vod' })
|
||||
|
||||
mergeOrOptimizePayload = this.buildOptimizePayload({
|
||||
video,
|
||||
isNewVideo,
|
||||
inputFile: videoFile,
|
||||
resolution: maxResolution,
|
||||
fps: maxFPS,
|
||||
|
||||
transcodingPriority: 'required',
|
||||
canMoveVideoState: null // Will be set below
|
||||
})
|
||||
}
|
||||
|
||||
// HLS version of max resolution
|
||||
if (CONFIG.TRANSCODING.HLS.ENABLED === true) {
|
||||
const hasSplitAudioTranscoding = CONFIG.TRANSCODING.HLS.SPLIT_AUDIO_AND_VIDEO && videoFile.hasAudio()
|
||||
|
||||
children.push([
|
||||
this.buildHLSJobPayload({
|
||||
deleteWebVideoFiles: !CONFIG.TRANSCODING.WEB_VIDEOS.ENABLED,
|
||||
|
||||
separatedAudio: hasSplitAudioTranscoding,
|
||||
|
||||
resolution: maxResolution,
|
||||
fps: maxFPS,
|
||||
video,
|
||||
isNewVideo,
|
||||
|
||||
inputStreams,
|
||||
transcodingRequestAt,
|
||||
|
||||
transcodingPriority: 'required',
|
||||
canMoveVideoState: true
|
||||
})
|
||||
])
|
||||
|
||||
if (hasSplitAudioTranscoding) {
|
||||
hlsAudioAlreadyGenerated = true
|
||||
|
||||
children.push([
|
||||
this.buildHLSJobPayload({
|
||||
deleteWebVideoFiles: !CONFIG.TRANSCODING.WEB_VIDEOS.ENABLED,
|
||||
separatedAudio: hasSplitAudioTranscoding,
|
||||
|
||||
resolution: 0,
|
||||
fps: 0,
|
||||
video,
|
||||
isNewVideo,
|
||||
|
||||
inputStreams,
|
||||
transcodingRequestAt,
|
||||
|
||||
transcodingPriority: 'required',
|
||||
canMoveVideoState: true
|
||||
})
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
const lowerResolutionJobPayloads = await this.buildLowerResolutionJobPayloads({
|
||||
video,
|
||||
inputStreams,
|
||||
transcodingRequestAt,
|
||||
inputVideoResolution: maxResolution,
|
||||
inputVideoFPS: maxFPS,
|
||||
hasAudio: videoFile.hasAudio(),
|
||||
isNewVideo,
|
||||
hlsAudioAlreadyGenerated
|
||||
})
|
||||
|
||||
children = children.concat(lowerResolutionJobPayloads)
|
||||
|
||||
this.reassignCanMoveVideoState(mergeOrOptimizePayload, children.length === 0)
|
||||
|
||||
await this.createJobs({
|
||||
payloads: {
|
||||
parent: mergeOrOptimizePayload,
|
||||
children
|
||||
},
|
||||
user,
|
||||
video
|
||||
})
|
||||
}
|
||||
|
||||
async createTranscodingJobs (options: {
|
||||
transcodingType: 'hls' | 'web-video'
|
||||
video: MVideoFullLight
|
||||
resolutions: number[]
|
||||
isNewVideo: boolean
|
||||
user: MUserId | null
|
||||
}) {
|
||||
const { video, transcodingType, resolutions, isNewVideo } = options
|
||||
const separatedAudio = CONFIG.TRANSCODING.HLS.SPLIT_AUDIO_AND_VIDEO
|
||||
const transcodingRequestAt = new Date().toISOString()
|
||||
|
||||
const inputStreams = video.getStreamTypes()
|
||||
const maxResolution = Math.max(...resolutions)
|
||||
|
||||
logger.info(`Manually creating transcoding jobs for ${transcodingType}`, { resolutions, maxResolution, ...lTags(video.uuid) })
|
||||
|
||||
const inputFPS = video.getMaxFPS()
|
||||
|
||||
const children = resolutions
|
||||
.map(resolution => {
|
||||
const fps = computeOutputFPS({ inputFPS, resolution, isOriginResolution: maxResolution === resolution, type: 'vod' })
|
||||
|
||||
if (transcodingType === 'hls') {
|
||||
// We'll generate audio resolution in a parent job
|
||||
if (resolution === VideoResolution.H_NOVIDEO && separatedAudio) return undefined
|
||||
|
||||
return [
|
||||
this.buildHLSJobPayload({
|
||||
video,
|
||||
resolution,
|
||||
fps,
|
||||
isNewVideo,
|
||||
separatedAudio,
|
||||
canMoveVideoState: true,
|
||||
inputStreams,
|
||||
transcodingRequestAt,
|
||||
transcodingPriority: 'optional'
|
||||
})
|
||||
]
|
||||
}
|
||||
|
||||
if (transcodingType === 'web-video') {
|
||||
return [
|
||||
this.buildWebVideoJobPayload({
|
||||
video,
|
||||
resolution,
|
||||
fps,
|
||||
isNewVideo,
|
||||
canMoveVideoState: true,
|
||||
transcodingPriority: 'optional'
|
||||
})
|
||||
]
|
||||
}
|
||||
|
||||
throw new Error('Unknown transcoding type')
|
||||
})
|
||||
.filter(r => !!r)
|
||||
|
||||
const fps = computeOutputFPS({ inputFPS, resolution: maxResolution, isOriginResolution: true, type: 'vod' })
|
||||
|
||||
// Process audio first to not override the max resolution where the audio stream will be removed
|
||||
const parent = transcodingType === 'hls' && separatedAudio
|
||||
? this.buildHLSJobPayload({
|
||||
video,
|
||||
resolution: VideoResolution.H_NOVIDEO,
|
||||
fps,
|
||||
isNewVideo,
|
||||
separatedAudio,
|
||||
canMoveVideoState: true,
|
||||
transcodingRequestAt,
|
||||
inputStreams,
|
||||
transcodingPriority: 'optional'
|
||||
})
|
||||
: undefined
|
||||
|
||||
await this.createJobs({ video, payloads: { parent, children }, user: null })
|
||||
}
|
||||
|
||||
private async buildLowerResolutionJobPayloads (options: {
|
||||
video: MVideoFullLight
|
||||
inputVideoResolution: number
|
||||
inputVideoFPS: number
|
||||
inputStreams: VideoFileStreamType[]
|
||||
hasAudio: boolean
|
||||
isNewVideo: boolean
|
||||
hlsAudioAlreadyGenerated: boolean
|
||||
transcodingRequestAt: string
|
||||
}) {
|
||||
const {
|
||||
video,
|
||||
inputVideoResolution,
|
||||
inputVideoFPS,
|
||||
inputStreams,
|
||||
isNewVideo,
|
||||
hlsAudioAlreadyGenerated,
|
||||
hasAudio,
|
||||
transcodingRequestAt
|
||||
} = options
|
||||
|
||||
// Create transcoding jobs if there are enabled resolutions
|
||||
const resolutionsEnabled = await Hooks.wrapObject(
|
||||
computeResolutionsToTranscode({ input: inputVideoResolution, type: 'vod', includeInput: false, strictLower: true, hasAudio }),
|
||||
'filter:transcoding.auto.resolutions-to-transcode.result',
|
||||
options
|
||||
)
|
||||
|
||||
logger.debug('Lower resolutions built for %s.', video.uuid, { resolutionsEnabled, ...lTags(video.uuid) })
|
||||
|
||||
const sequentialPayloads: P[][] = []
|
||||
|
||||
for (const resolution of resolutionsEnabled) {
|
||||
const fps = computeOutputFPS({
|
||||
inputFPS: inputVideoFPS,
|
||||
resolution,
|
||||
isOriginResolution: resolution === inputVideoResolution,
|
||||
type: 'vod'
|
||||
})
|
||||
|
||||
let generateHLS = CONFIG.TRANSCODING.HLS.ENABLED
|
||||
if (resolution === VideoResolution.H_NOVIDEO && hlsAudioAlreadyGenerated) generateHLS = false
|
||||
|
||||
const parallelPayloads: P[] = []
|
||||
|
||||
if (CONFIG.TRANSCODING.WEB_VIDEOS.ENABLED) {
|
||||
parallelPayloads.push(
|
||||
this.buildWebVideoJobPayload({
|
||||
video,
|
||||
resolution,
|
||||
fps,
|
||||
isNewVideo,
|
||||
canMoveVideoState: true,
|
||||
transcodingPriority: 'optional'
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// Create a subsequent job to create HLS resolution that will just copy web video codecs
|
||||
if (generateHLS) {
|
||||
parallelPayloads.push(
|
||||
this.buildHLSJobPayload({
|
||||
video,
|
||||
resolution,
|
||||
fps,
|
||||
isNewVideo,
|
||||
separatedAudio: hasAudio && CONFIG.TRANSCODING.HLS.SPLIT_AUDIO_AND_VIDEO,
|
||||
canMoveVideoState: true,
|
||||
transcodingPriority: 'optional',
|
||||
transcodingRequestAt,
|
||||
inputStreams
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (parallelPayloads.length !== 0) {
|
||||
sequentialPayloads.push(parallelPayloads)
|
||||
}
|
||||
}
|
||||
|
||||
return sequentialPayloads
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
protected abstract createJobs (options: {
|
||||
video: MVideoFullLight
|
||||
payloads: {
|
||||
parent: P
|
||||
|
||||
// Parallel of sequential jobs to execute
|
||||
// [ [ Parallel1 ], [ Parallel2 ], ... ]
|
||||
// [ [ Seq1, Seq2, ... ], [ Seq1, ... ]
|
||||
children: P[][]
|
||||
}
|
||||
user: MUserId | null
|
||||
}): Promise<void>
|
||||
|
||||
protected abstract buildMergeAudioPayload (options: {
|
||||
video: MVideoFullLight
|
||||
inputFile: MVideoFile
|
||||
isNewVideo: boolean
|
||||
resolution: number
|
||||
fps: number
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
canMoveVideoState: boolean
|
||||
}): P
|
||||
|
||||
protected abstract buildOptimizePayload (options: {
|
||||
video: MVideoFullLight
|
||||
isNewVideo: boolean
|
||||
inputFile: MVideoFile
|
||||
resolution: number
|
||||
fps: number
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
canMoveVideoState: boolean
|
||||
}): P
|
||||
|
||||
protected abstract buildHLSJobPayload (options: {
|
||||
video: MVideoFullLight
|
||||
resolution: number
|
||||
fps: number
|
||||
isNewVideo: boolean
|
||||
separatedAudio: boolean
|
||||
|
||||
deleteWebVideoFiles?: boolean // default false
|
||||
|
||||
inputStreams: VideoFileStreamType[]
|
||||
canMoveVideoState: boolean
|
||||
transcodingRequestAt: string
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
}): P
|
||||
|
||||
protected abstract buildWebVideoJobPayload (options: {
|
||||
video: MVideoFullLight
|
||||
resolution: number
|
||||
fps: number
|
||||
isNewVideo: boolean
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
canMoveVideoState: boolean
|
||||
}): P
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
protected abstract reassignCanMoveVideoState (payload: P, canMoveVideoState: boolean): void
|
||||
}
|
||||
2
server/core/lib/transcoding/shared/job-builders/index.ts
Normal file
2
server/core/lib/transcoding/shared/job-builders/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './transcoding-job-queue-builder.js'
|
||||
export * from './transcoding-runner-job-builder.js'
|
||||
@@ -0,0 +1,204 @@
|
||||
import { pick } from '@peertube/peertube-core-utils'
|
||||
import {
|
||||
HLSTranscodingPayload,
|
||||
MergeAudioTranscodingPayload,
|
||||
NewWebVideoResolutionTranscodingPayload,
|
||||
OptimizeTranscodingPayload,
|
||||
VideoFileStreamType,
|
||||
VideoTranscodingPayload
|
||||
} from '@peertube/peertube-models'
|
||||
import { CreateJobArgument, JobQueue } from '@server/lib/job-queue/index.js'
|
||||
import { VideoJobInfoModel } from '@server/models/video/video-job-info.js'
|
||||
import { MUserId, MVideo } from '@server/types/models/index.js'
|
||||
import { getTranscodingJobPriority } from '../../transcoding-priority.js'
|
||||
import { AbstractJobBuilder, TranscodingPriorityType } from './abstract-job-builder.js'
|
||||
|
||||
type BasePayload =
|
||||
| MergeAudioTranscodingPayload
|
||||
| OptimizeTranscodingPayload
|
||||
| NewWebVideoResolutionTranscodingPayload
|
||||
| HLSTranscodingPayload
|
||||
|
||||
type FullPayload = BasePayload & { transcodingPriority: TranscodingPriorityType }
|
||||
|
||||
export class TranscodingJobQueueBuilder extends AbstractJobBuilder<FullPayload> {
|
||||
protected async createJobs (options: {
|
||||
video: MVideo
|
||||
payloads: {
|
||||
parent: FullPayload | null
|
||||
children: FullPayload[][]
|
||||
}
|
||||
user: MUserId | null
|
||||
}): Promise<void> {
|
||||
const { video, payloads: { parent, children }, user } = options
|
||||
|
||||
const requiredPriority = await getTranscodingJobPriority({ user, type: 'vod-required' })
|
||||
const optionalPriority = await getTranscodingJobPriority({ user, type: 'vod-optional' })
|
||||
|
||||
const nextTranscodingSequentialJobs = children.map(p => {
|
||||
return p.map(payload => {
|
||||
return this.buildTranscodingJob({
|
||||
payload,
|
||||
|
||||
priority: payload.transcodingPriority === 'required'
|
||||
? requiredPriority
|
||||
: optionalPriority
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const transcodingJobBuilderJob: CreateJobArgument = {
|
||||
type: 'transcoding-job-builder',
|
||||
payload: {
|
||||
videoUUID: video.uuid,
|
||||
sequentialJobs: nextTranscodingSequentialJobs
|
||||
}
|
||||
}
|
||||
|
||||
const parentJob = parent
|
||||
? this.buildTranscodingJob({
|
||||
payload: parent,
|
||||
|
||||
priority: parent.transcodingPriority === 'required'
|
||||
? requiredPriority
|
||||
: optionalPriority
|
||||
})
|
||||
: undefined
|
||||
|
||||
await JobQueue.Instance.createSequentialJobFlow(parentJob, transcodingJobBuilderJob)
|
||||
|
||||
// transcoding-job-builder job will increase pendingTranscode
|
||||
if (parentJob) {
|
||||
await VideoJobInfoModel.increaseOrCreate(video.uuid, 'pendingTranscode')
|
||||
}
|
||||
}
|
||||
|
||||
private buildTranscodingJob (options: {
|
||||
payload: VideoTranscodingPayload
|
||||
priority: number
|
||||
}) {
|
||||
const { priority, payload } = options
|
||||
|
||||
return {
|
||||
type: 'video-transcoding' as 'video-transcoding',
|
||||
priority,
|
||||
payload
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
protected buildHLSJobPayload (options: {
|
||||
video: MVideo
|
||||
resolution: number
|
||||
fps: number
|
||||
isNewVideo: boolean
|
||||
separatedAudio: boolean
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
|
||||
transcodingRequestAt: string
|
||||
canMoveVideoState: boolean
|
||||
inputStreams: VideoFileStreamType[]
|
||||
|
||||
deleteWebVideoFiles?: boolean // default false
|
||||
}): HLSTranscodingPayload & { transcodingPriority: TranscodingPriorityType } {
|
||||
const { video, deleteWebVideoFiles = false } = options
|
||||
|
||||
return {
|
||||
type: 'new-resolution-to-hls',
|
||||
videoUUID: video.uuid,
|
||||
|
||||
...pick(options, [
|
||||
'resolution',
|
||||
'fps',
|
||||
'isNewVideo',
|
||||
'separatedAudio',
|
||||
'canMoveVideoState',
|
||||
'transcodingPriority',
|
||||
'transcodingRequestAt',
|
||||
'inputStreams'
|
||||
]),
|
||||
|
||||
deleteWebVideoFiles
|
||||
}
|
||||
}
|
||||
|
||||
protected buildWebVideoJobPayload (options: {
|
||||
video: MVideo
|
||||
resolution: number
|
||||
fps: number
|
||||
isNewVideo: boolean
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
canMoveVideoState: boolean
|
||||
}): NewWebVideoResolutionTranscodingPayload & { transcodingPriority: TranscodingPriorityType } {
|
||||
const { video } = options
|
||||
|
||||
return {
|
||||
type: 'new-resolution-to-web-video',
|
||||
videoUUID: video.uuid,
|
||||
|
||||
...pick(options, [
|
||||
'isNewVideo',
|
||||
'resolution',
|
||||
'fps',
|
||||
'transcodingPriority',
|
||||
'canMoveVideoState'
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
protected buildMergeAudioPayload (options: {
|
||||
video: MVideo
|
||||
isNewVideo: boolean
|
||||
fps: number
|
||||
resolution: number
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
canMoveVideoState: boolean
|
||||
}): MergeAudioTranscodingPayload & { transcodingPriority: TranscodingPriorityType } {
|
||||
const { video } = options
|
||||
|
||||
return {
|
||||
type: 'merge-audio-to-web-video',
|
||||
videoUUID: video.uuid,
|
||||
|
||||
...pick(options, [
|
||||
'resolution',
|
||||
'fps',
|
||||
'isNewVideo',
|
||||
'transcodingPriority',
|
||||
'canMoveVideoState'
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
protected buildOptimizePayload (options: {
|
||||
video: MVideo
|
||||
isNewVideo: boolean
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
canMoveVideoState: boolean
|
||||
}): OptimizeTranscodingPayload & { transcodingPriority: TranscodingPriorityType } {
|
||||
const { video } = options
|
||||
|
||||
return {
|
||||
type: 'optimize-to-web-video',
|
||||
|
||||
videoUUID: video.uuid,
|
||||
|
||||
...pick(options, [
|
||||
'isNewVideo',
|
||||
'transcodingPriority',
|
||||
'canMoveVideoState'
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
protected reassignCanMoveVideoState (payload: FullPayload, canMoveVideoState: boolean): void {
|
||||
payload.canMoveVideoState = canMoveVideoState
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
import { pick } from '@peertube/peertube-core-utils'
|
||||
import { VideoFileStreamType } from '@peertube/peertube-models'
|
||||
import {
|
||||
VODAudioMergeTranscodingJobHandler,
|
||||
VODHLSTranscodingJobHandler,
|
||||
VODWebVideoTranscodingJobHandler
|
||||
} from '@server/lib/runners/job-handlers/index.js'
|
||||
import { MUserId, MVideo, MVideoFile, MVideoFullLight } from '@server/types/models/index.js'
|
||||
import { MRunnerJob } from '@server/types/models/runners/runner-job.js'
|
||||
import { getTranscodingJobPriority } from '../../transcoding-priority.js'
|
||||
import { AbstractJobBuilder, TranscodingPriorityType } from './abstract-job-builder.js'
|
||||
|
||||
/**
|
||||
* Class to build transcoding job in the local job queue
|
||||
*/
|
||||
|
||||
type BasePayload = {
|
||||
Builder: new() => VODHLSTranscodingJobHandler
|
||||
options: Omit<Parameters<VODHLSTranscodingJobHandler['create']>[0], 'priority'>
|
||||
} | {
|
||||
Builder: new() => VODAudioMergeTranscodingJobHandler
|
||||
options: Omit<Parameters<VODAudioMergeTranscodingJobHandler['create']>[0], 'priority'>
|
||||
} | {
|
||||
Builder: new() => VODWebVideoTranscodingJobHandler
|
||||
options: Omit<Parameters<VODWebVideoTranscodingJobHandler['create']>[0], 'priority'>
|
||||
}
|
||||
|
||||
type FullPayload = BasePayload & { transcodingPriority: TranscodingPriorityType }
|
||||
|
||||
export class TranscodingRunnerJobBuilder extends AbstractJobBuilder<FullPayload> {
|
||||
protected async createJobs (options: {
|
||||
video: MVideo
|
||||
payloads: {
|
||||
parent: FullPayload | null
|
||||
children: FullPayload[][]
|
||||
}
|
||||
user: MUserId | null
|
||||
}): Promise<void> {
|
||||
const { payloads: { parent, children }, user } = options
|
||||
|
||||
const requiredPriority = await getTranscodingJobPriority({ user, type: 'vod-required' })
|
||||
const optionalPriority = await getTranscodingJobPriority({ user, type: 'vod-optional' })
|
||||
|
||||
const parentJob = parent
|
||||
? await this.createJob({
|
||||
payload: parent,
|
||||
|
||||
priority: parent.transcodingPriority === 'required'
|
||||
? requiredPriority
|
||||
: optionalPriority
|
||||
})
|
||||
: undefined
|
||||
|
||||
for (const parallelPayloads of children) {
|
||||
let lastJob = parentJob
|
||||
|
||||
for (const sequentialPayload of parallelPayloads) {
|
||||
lastJob = await this.createJob({
|
||||
payload: sequentialPayload,
|
||||
|
||||
priority: sequentialPayload.transcodingPriority === 'required'
|
||||
? requiredPriority
|
||||
: optionalPriority,
|
||||
|
||||
dependsOnRunnerJob: lastJob
|
||||
})
|
||||
}
|
||||
|
||||
lastJob = undefined
|
||||
}
|
||||
}
|
||||
|
||||
private createJob (options: {
|
||||
payload: FullPayload
|
||||
priority: number
|
||||
dependsOnRunnerJob?: MRunnerJob
|
||||
}) {
|
||||
const { dependsOnRunnerJob, payload, priority } = options
|
||||
|
||||
const builder = new payload.Builder()
|
||||
|
||||
return builder.create({
|
||||
...(payload.options as any), // FIXME: typings
|
||||
|
||||
dependsOnRunnerJob,
|
||||
priority
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
protected buildHLSJobPayload (options: {
|
||||
video: MVideoFullLight
|
||||
resolution: number
|
||||
fps: number
|
||||
isNewVideo: boolean
|
||||
separatedAudio: boolean
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
|
||||
canMoveVideoState: boolean
|
||||
inputStreams: VideoFileStreamType[]
|
||||
transcodingRequestAt: string
|
||||
|
||||
deleteWebVideoFiles?: boolean // default false
|
||||
}): FullPayload {
|
||||
const { deleteWebVideoFiles = false } = options
|
||||
|
||||
return {
|
||||
Builder: VODHLSTranscodingJobHandler,
|
||||
|
||||
options: {
|
||||
...pick(options, [
|
||||
'video',
|
||||
'resolution',
|
||||
'fps',
|
||||
'isNewVideo',
|
||||
'separatedAudio',
|
||||
'canMoveVideoState',
|
||||
'transcodingRequestAt',
|
||||
'inputStreams'
|
||||
]),
|
||||
|
||||
deleteWebVideoFiles
|
||||
},
|
||||
|
||||
...pick(options, [ 'transcodingPriority' ])
|
||||
}
|
||||
}
|
||||
|
||||
protected buildWebVideoJobPayload (options: {
|
||||
video: MVideoFullLight
|
||||
resolution: number
|
||||
fps: number
|
||||
isNewVideo: boolean
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
canMoveVideoState: boolean
|
||||
}): FullPayload {
|
||||
return {
|
||||
Builder: VODWebVideoTranscodingJobHandler,
|
||||
|
||||
options: {
|
||||
...pick(options, [
|
||||
'video',
|
||||
'resolution',
|
||||
'fps',
|
||||
'isNewVideo',
|
||||
'canMoveVideoState',
|
||||
'transcodingPriority',
|
||||
'canMoveVideoState'
|
||||
]),
|
||||
|
||||
deleteInputFileId: null
|
||||
},
|
||||
|
||||
...pick(options, [ 'transcodingPriority' ])
|
||||
}
|
||||
}
|
||||
|
||||
protected buildMergeAudioPayload (options: {
|
||||
video: MVideoFullLight
|
||||
inputFile: MVideoFile
|
||||
isNewVideo: boolean
|
||||
fps: number
|
||||
resolution: number
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
canMoveVideoState: boolean
|
||||
}): FullPayload {
|
||||
const { inputFile } = options
|
||||
|
||||
return {
|
||||
Builder: VODAudioMergeTranscodingJobHandler,
|
||||
|
||||
options: {
|
||||
...pick(options, [
|
||||
'video',
|
||||
'resolution',
|
||||
'fps',
|
||||
'isNewVideo',
|
||||
'canMoveVideoState'
|
||||
]),
|
||||
|
||||
deleteInputFileId: inputFile.id
|
||||
},
|
||||
|
||||
...pick(options, [ 'transcodingPriority' ])
|
||||
}
|
||||
}
|
||||
|
||||
protected buildOptimizePayload (options: {
|
||||
video: MVideoFullLight
|
||||
inputFile: MVideoFile
|
||||
isNewVideo: boolean
|
||||
fps: number
|
||||
resolution: number
|
||||
|
||||
transcodingPriority: TranscodingPriorityType
|
||||
canMoveVideoState: boolean
|
||||
}): FullPayload {
|
||||
const { inputFile } = options
|
||||
|
||||
return {
|
||||
Builder: VODWebVideoTranscodingJobHandler,
|
||||
|
||||
options: {
|
||||
...pick(options, [
|
||||
'video',
|
||||
'resolution',
|
||||
'fps',
|
||||
'isNewVideo',
|
||||
'canMoveVideoState'
|
||||
]),
|
||||
|
||||
deleteInputFileId: inputFile.id
|
||||
},
|
||||
|
||||
...pick(options, [ 'transcodingPriority' ])
|
||||
}
|
||||
}
|
||||
|
||||
protected reassignCanMoveVideoState (payload: FullPayload, canMoveVideoState: boolean) {
|
||||
payload.options.canMoveVideoState = canMoveVideoState
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user