From 18c72f7730c6d68cd9cd39962aec80a34e6aebbc Mon Sep 17 00:00:00 2001 From: oshinongit Date: Fri, 9 Aug 2024 14:21:27 +0200 Subject: [PATCH] feat: aws pipeline qvbr job --- README.md | 17 ++++++++++ examples/aws/aws-job-qvbr.yml | 12 +++++++ examples/aws/encoding-profile-qvbr.json | 45 +++++++++++++++++++++++++ src/analysis/brute-force.ts | 19 +++++------ src/create-job.ts | 6 ++-- src/models/bitrate-resolution-pair.ts | 2 +- src/pipelines/aws/aws-pipeline.ts | 20 ++++++++--- 7 files changed, 101 insertions(+), 20 deletions(-) create mode 100644 examples/aws/aws-job-qvbr.yml create mode 100644 examples/aws/encoding-profile-qvbr.json diff --git a/README.md b/README.md index 59a84ea..24a21b4 100644 --- a/README.md +++ b/README.md @@ -250,6 +250,23 @@ by insterting `%VARIABLENAME%`. This string will then be substituted with a valu be set to avoid injecting bitrate options to ffmpeg. Also note that the cli needs to be run with the `--probe-bitrate` option to get the correct bitrate from the transcoded files. +It is also possible to use pipelineVariables with the AWSPipeline. The following example will run transcode and vmaf analysis using the AWS MediaCOnvert QVBR levels 6, 7, 8 and 9. + +```yaml +name: job-name +pipeline: pipeline.yml +encodingProfile: encoding-profile.json +reference: reference.mp4 +models: + - HD +pipelineVariables: + QVBR: + - 6 + - 7 + - 8 + - 9 +``` + ### Generate VMAF measurements example ```bash diff --git a/examples/aws/aws-job-qvbr.yml b/examples/aws/aws-job-qvbr.yml new file mode 100644 index 0000000..b0b335a --- /dev/null +++ b/examples/aws/aws-job-qvbr.yml @@ -0,0 +1,12 @@ +name: job-name +pipeline: pipeline.yml +encodingProfile: encoding-profile.json +reference: reference.mp4 +models: + - HD +pipelineVariables: + QVBR: + - 6 + - 7 + - 8 + - 9 diff --git a/examples/aws/encoding-profile-qvbr.json b/examples/aws/encoding-profile-qvbr.json new file mode 100644 index 0000000..5f1eccb --- /dev/null +++ b/examples/aws/encoding-profile-qvbr.json @@ -0,0 +1,45 @@ +{ + "Inputs": [ + { + "TimecodeSource": "ZEROBASED", + "VideoSelector": {}, + "FileInput": "$INPUT" + } + ], + "OutputGroups": [ + { + "Name": "File Group", + "OutputGroupSettings": { + "Type": "FILE_GROUP_SETTINGS", + "FileGroupSettings": { + "Destination": "$OUTPUT" + } + }, + "Outputs": [ + { + "VideoDescription": { + "CodecSettings": { + "Codec": "H_264", + "H264Settings": { + "RateControlMode": "QVBR", + "QvbrSettings": { + "QvbrQualityLevel": "$QVBR" + }, + "CodecProfile": "HIGH" + } + }, + "Width": "$WIDTH", + "Height": "$HEIGHT" + }, + "ContainerSettings": { + "Container": "MP4", + "Mp4Settings": {} + } + } + ] + } + ], + "TimecodeConfig": { + "Source": "ZEROBASED" + } +} diff --git a/src/analysis/brute-force.ts b/src/analysis/brute-force.ts index 6e7eeea..bc67713 100644 --- a/src/analysis/brute-force.ts +++ b/src/analysis/brute-force.ts @@ -83,15 +83,14 @@ export default async function analyzeBruteForce( // Create all combinations of bitrate, resolution, and variables Object.entries(options.pipelineVariables).forEach( ([variableName, values]) => { - //console.log(`variableName: ${variableName}`); pairs = pairs.flatMap( (pair) => values.map((value) => { - const variables = pair.ffmpegOptionVariables - ? { ...pair.ffmpegOptionVariables } + const variables = pair.pipelineVariables + ? { ...pair.pipelineVariables } : {}; variables[variableName] = value; - return { ...pair, ffmpegOptionVariables: variables }; + return { ...pair, pipelineVariables: variables }; }) as BitrateResolutionPair[] ); } @@ -100,12 +99,10 @@ export default async function analyzeBruteForce( const analyzePair = async (pair: BitrateResolutionPair) => { let outFile = `${directory}/${pair.resolution.width}x${pair.resolution.height}_${pair.bitrate}`; - if (pair.ffmpegOptionVariables) { - Object.entries(pair.ffmpegOptionVariables).forEach( - ([variable, value]) => { - outFile = outFile + `_${variable}_${value}`; - } - ); + if (pair.pipelineVariables) { + Object.entries(pair.pipelineVariables).forEach(([variable, value]) => { + outFile = outFile + `_${variable}_${value}`; + }); } outFile = outFile + '.mp4'; const skip = @@ -122,7 +119,7 @@ export default async function analyzeBruteForce( pair.resolution, pair.bitrate, outFile, - pair.ffmpegOptionVariables + pair.pipelineVariables ); if (variant === '') { diff --git a/src/create-job.ts b/src/create-job.ts index ed157b2..38eedcc 100644 --- a/src/create-job.ts +++ b/src/create-job.ts @@ -41,13 +41,13 @@ export type JobDescription = { /** The method to use when analyzing the videos. Either `bruteForce` or `walkTheHull`. By default `bruteForce`. NOTE: `walkTheHull` is not implemented at the moment. */ method?: 'bruteForce' | 'walkTheHull'; - /** Values that will be substituted into the encoding options. Currently only supported for local pipeline */ + /** Values that will be substituted into the encoding options. */ pipelineVariables?: { [key: string]: string[] }; - /** Skip transcode and run analysis only, files are assumed to be already present */ + /** Skip transcode and run analysis only, files are assumed to be already present. */ skipTranscode?: boolean; - /** Skip transcode if outfile already exists */ + /** Skip transcode if outfile already exists. */ skipExisting?: boolean; }; diff --git a/src/models/bitrate-resolution-pair.ts b/src/models/bitrate-resolution-pair.ts index af94a55..b50d214 100644 --- a/src/models/bitrate-resolution-pair.ts +++ b/src/models/bitrate-resolution-pair.ts @@ -3,5 +3,5 @@ import { Resolution } from './resolution'; export type BitrateResolutionPair = { resolution: Resolution; bitrate: number; - ffmpegOptionVariables?: { [key: string]: string }; + pipelineVariables?: { [key: string]: string }; }; diff --git a/src/pipelines/aws/aws-pipeline.ts b/src/pipelines/aws/aws-pipeline.ts index a6d0445..952dded 100644 --- a/src/pipelines/aws/aws-pipeline.ts +++ b/src/pipelines/aws/aws-pipeline.ts @@ -158,11 +158,14 @@ export default class AWSPipeline implements Pipeline { '$HEIGHT', targetResolution.height.toString() ); - settingsStr = this.stringReplacement( - settingsStr, - '$BITRATE', - targetBitrate.toString() - ); + if (settingsStr.includes('$BITRATE')) { + settingsStr = this.stringReplacement( + settingsStr, + '$BITRATE', + targetBitrate.toString() + ); + } + // HEVC specific settings settingsStr = this.stringReplacement( settingsStr, @@ -170,6 +173,13 @@ export default class AWSPipeline implements Pipeline { (targetBitrate * 2).toString() ); + //Handle pipelineVariables given in the JobDescription + if (variables) { + Object.entries(variables).forEach(([key, value]) => { + settingsStr = this.stringReplacement(settingsStr, `$${key}`, value); + }); + } + const settings = JSON.parse(settingsStr); logger.debug('Settings Json: ' + JSON.stringify(settings));