Skip to content

Commit

Permalink
yaml generation from range
Browse files Browse the repository at this point in the history
  • Loading branch information
oshinongit committed Oct 30, 2023
1 parent 595fd38 commit 3dff5bc
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 61 deletions.
9 changes: 6 additions & 3 deletions examples/encoreExample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ async function transcodeInputsAndAnalyze() {
apiAddress: "https://api-encore.stage.osaas.io",
token: "",
instanceId: "dummy",
profile: "program",
profilesUrl: "profilesUrl",
outputFolder: "/usercontent/demo",
baseName: "_demo",
inputs: ["https://testcontent.eyevinn.technology/mp4/stswe-tvplus-promo.mp4"],
Expand All @@ -21,9 +21,12 @@ async function transcodeInputsAndAnalyze() {
const bitrateResolutionPairs: BitrateResolutionPair[] = [
{resolution: { width: 1280, height: 720}, bitrate: 600000},
{resolution: { width: 640, height: 360}, bitrate: 600000},
{resolution: { width: 768, height: 432}, bitrate: 600000}
{resolution: { width: 768, height: 432, range: {
min: 500000,
max: 600000
}}, bitrate: 500000}
]

const pipeline: EncorePipeline = new EncorePipeline(configuration);
await pipeline.transcode(configuration.inputs[0], { width: 1280, height: 720}, 600000, "output", undefined, bitrateResolutionPairs);

Expand Down
6 changes: 3 additions & 3 deletions src/encoreYamlGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as fs from 'fs';
import { EncoreEncodeType, EncoreProgramProfile } from './models/encoreProfileTypes';
import { EncoreTranscodeType, EncoreProgramProfile } from './models/encoreProfileTypes';

export class EncoreYAMLGenerator {
generateYAML(profile: EncoreProgramProfile): string {
Expand Down Expand Up @@ -31,7 +31,7 @@ ${profile.encodes
twoPass: boolean,
height: number,
params: { [key: string]: string }
): EncoreEncodeType {
): EncoreTranscodeType {
return {
type,
suffix,
Expand Down Expand Up @@ -63,7 +63,7 @@ function example() {
preset: 'medium',
});

const encodeObjects: EncoreEncodeType[] = [];
const encodeObjects: EncoreTranscodeType[] = [];
encodeObjects.push(encodeObject);

const programProfile: EncoreProgramProfile = {
Expand Down
4 changes: 2 additions & 2 deletions src/models/encoreProfileTypes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type EncoreEncodeType = {
export type EncoreTranscodeType = {
type: string;
suffix: string;
twoPass: boolean;
Expand All @@ -10,5 +10,5 @@ export type EncoreProgramProfile = {
name: string;
description: string;
scaling: string;
encodes: EncoreEncodeType[];
encodes: EncoreTranscodeType[];
}
2 changes: 1 addition & 1 deletion src/pipelines/encore/encore-pipeline-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export type EncorePipelineConfiguration = {
apiAddress: string;
token: string;
instanceId: string;
profile: string;
profilesUrl: string;
outputFolder: string;
baseName: string;
inputs: Array<string>;
Expand Down
139 changes: 87 additions & 52 deletions src/pipelines/encore/encore-pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { EncoreInstance } from '../../models/encoreInstance';
import { EncoreJobs, EncoreJob } from '../../models/encoreJobs';
import { EncorePipelineConfiguration } from './encore-pipeline-configuration';
import { EncoreYAMLGenerator } from '../../encoreYamlGenerator';
import { EncoreEncodeType, EncoreProgramProfile } from '../../models/encoreProfileTypes';
import { EncoreTranscodeType, EncoreProgramProfile } from '../../models/encoreProfileTypes';
import { Pipeline } from '../pipeline';
import { Resolution } from '../../models/resolution';
import { QualityAnalysisModel } from '../../models/quality-analysis-model';
Expand All @@ -20,6 +20,74 @@ export function delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}

function createYAML(bitrateResolutions: BitrateResolutionPair[]): string {

const yamlGenerator = new EncoreYAMLGenerator();
let transcodeObjects: EncoreTranscodeType[] = [];

bitrateResolutions.forEach(bitRateResolution => {

const resolution = bitRateResolution.resolution;

if (resolution.range && resolution.range.min && resolution.range.max) {
const bitRateRange = (resolution.range.max - resolution.range.min);
if (bitRateRange < 1000) {
throw new Error(`Small bitrate range: ${bitRateRange}, use discrete values instead or increase range`);
}
let bitRateStep: number = resolution.range.min;
let bitrateSteps = [bitRateStep];
while (bitRateStep < resolution.range.max) {
bitRateStep += 1000;
bitrateSteps.push(bitRateStep);
}
if (bitrateSteps[bitrateSteps.length - 1] > resolution.range.max) {
bitrateSteps[bitrateSteps.length - 1] = resolution.range.max;
}

bitrateSteps.forEach(bitRate => {

const transcodeObject = yamlGenerator.createEncodeObject('X264Encode', `_${bitRate / 100}`, true, resolution.height, {
'b:v': `${bitRate / 100}k`,
maxrate: `${(bitRate / 100) * 1.5}k`,
bufsize: `${(bitRate / 100) * 1.5 * 1.5}k`,
r: '25',
fps_mode: 'cfr',
pix_fmt: 'yuv420p',
force_key_frames: 'expr:not(mod(n,96))',
preset: 'medium',
});
transcodeObjects.push(transcodeObject);

})

}
else if (!resolution.range) {
const encodeObject = yamlGenerator.createEncodeObject('X264Encode', `_${bitRateResolution.bitrate / 100}`, true, bitRateResolution.resolution.height, {
'b:v': `${bitRateResolution.bitrate / 100}k`,
maxrate: `${(bitRateResolution.bitrate / 100) * 1.5}k`,
bufsize: `${(bitRateResolution.bitrate / 100) * 1.5 * 1.5}k`,
r: '25',
fps_mode: 'cfr',
pix_fmt: 'yuv420p',
force_key_frames: 'expr:not(mod(n,96))',
preset: 'medium',
});
transcodeObjects.push(encodeObject);
}
})

const programProfile: EncoreProgramProfile = {
name: 'encoreProgram',
description: 'Program profile',
scaling: 'bicubic',
encodes: transcodeObjects,
};

yamlGenerator.saveToFile(programProfile, "profile.yml"); //TODO: Remove, for dev only
const transcodingProfile = yamlGenerator.generateYAML(programProfile);
return transcodingProfile
}

export class EncorePipeline implements Pipeline {

configuration: EncorePipelineConfiguration;
Expand All @@ -43,52 +111,19 @@ export class EncorePipeline implements Pipeline {
this.awsPipe = new AWSPipeline(this.awsConf);
}

async transcode(input: string, targetResolution: Resolution, targetBitrate: number, output: string, variables?: Record<string, string>, pairs?: BitrateResolutionPair[]): Promise<string> {

const yamlGenerator = new EncoreYAMLGenerator();
async transcode(input: string, targetResolution: Resolution, targetBitrate: number, output: string, variables?: Record<string, string>, bitrateResolutions?: BitrateResolutionPair[]): Promise<string> {

if(!pairs){
throw new Error('No bitrateResolutionPairs in encore transcode');
if (!bitrateResolutions) {
throw new Error('No resolutionsBitrateRange in encore transcode');
}
const bitrateResolutionPairs = pairs;
let encodeObjects: EncoreEncodeType[] = [];

bitrateResolutionPairs.forEach( pair => {
const encodeObject = yamlGenerator.createEncodeObject('X264Encode', `_${pair.bitrate / 100}`, true, pair.resolution.height, {
'b:v': `${pair.bitrate / 100}k`,
maxrate: `${(pair.bitrate / 100) * 1.5}k`,
bufsize: `${(pair.bitrate / 100) * 1.5 * 1.5}k`,
r: '25',
fps_mode: 'cfr',
pix_fmt: 'yuv420p',
force_key_frames: 'expr:not(mod(n,96))',
preset: 'medium',
});
encodeObjects.push(encodeObject);
})

const programProfile: EncoreProgramProfile = {
name: 'encoreProgram',
description: 'Program profile',
scaling: 'bicubic',
encodes: encodeObjects,
};

const profileFilename: string = 'encoreProfile.yml';
yamlGenerator.saveToFile(programProfile, profileFilename);
// this.configuration.profile = await this.awsPipe.uploadIfNeeded(
// profileFilename,
// this.awsPipe.configuration.outputBucket,
// 'encoreProfiles',
// )
// logger.info(this.configuration.profile);

const instance: EncoreInstance | undefined = await this.createEncoreInstance(this.configuration.apiAddress, this.configuration.token, this.configuration.instanceId, "addressToPublicRepoOfProfiles");
const instance: EncoreInstance | undefined = await this.createEncoreInstance(this.configuration.apiAddress, this.configuration.token, this.configuration.instanceId, this.configuration.profilesUrl);
await delay(this.configuration.encoreInstancePostCreationDelay_ms); // Delay required to allow instance to be created before calling it
if(!instance){
if (!instance) {
throw new Error('undefined instance');
}
await this.runTranscodePollUntilFinished(instance);
const transcodingProfile = createYAML(bitrateResolutions);
// await this.runTranscodePollUntilFinished(instance, transcodingProfile);
await this.deleteEncoreInstance(instance, this.configuration.apiAddress);
return output
}
Expand All @@ -105,7 +140,7 @@ export class EncorePipeline implements Pipeline {
* @param instanceId The Encore Instance that will enqueue the transcode job.
* @param profile The transcode profile.
*/
async createEncoreInstance(apiAddress: string, token: string, instanceId: string, profiles: string): Promise<EncoreInstance | undefined> {
async createEncoreInstance(apiAddress: string, token: string, instanceId: string, profilesUrl: string): Promise<EncoreInstance | undefined> {

const url = `${apiAddress}/encoreinstance`;
const headerObj = {
Expand All @@ -116,7 +151,7 @@ export class EncorePipeline implements Pipeline {
const headers = new Headers(headerObj);
const data = JSON.stringify({
"name": instanceId,
"profiles": profiles,
"profilesUrl": profilesUrl,
});

const request = new Request(url, {
Expand Down Expand Up @@ -169,9 +204,9 @@ export class EncorePipeline implements Pipeline {
/**
* Attempts to enqueue a transcode job to an Encore Instance.
* @param encoreInstance The Encore Instance were the job should be enqueued.
* @param mediaFileAddress The https address of the media file to be enqueued.
* @param input The https address of the media file to be enqueued.
*/
async createEncoreJob(encoreInstance: EncoreInstance, mediaFileAddress: string): Promise<EncoreJob> {
async createEncoreJob(encoreInstance: EncoreInstance, input: string, trancsodeProfile: string): Promise<EncoreJob> {

const url = encoreInstance.resources.enqueueJob.url;
const headerObj = {
Expand All @@ -181,12 +216,12 @@ export class EncorePipeline implements Pipeline {
};
const headers = new Headers(headerObj);
const data = JSON.stringify({
"profile": this.configuration.profile,
"inlineProfile": trancsodeProfile,
"outputFolder": this.configuration.outputFolder,
"baseName": this.configuration.baseName,
"inputs": [
{
"uri": mediaFileAddress,
"uri": input,
"type": "AudioVideo"
}
],
Expand Down Expand Up @@ -258,9 +293,9 @@ export class EncorePipeline implements Pipeline {
enqueuedJobIds.splice(jobShouldBeProcessed, 1);
}
}

//Increase poll interval if repeatedly polling, up until 20 minutes
if (pollCounter > 2){
if (pollCounter > 2) {
pollInterval_ms += Math.round(pollInterval_ms) * 2;
pollCounter = 0;
}
Expand Down Expand Up @@ -329,13 +364,13 @@ export class EncorePipeline implements Pipeline {
return filename;
}

async runTranscodePollUntilFinished(instance: EncoreInstance): Promise<void> {
async runTranscodePollUntilFinished(instance: EncoreInstance, transcodeProfile: string): Promise<void> {

let jobIds: string[] = [];
let input = this.configuration.inputs[0];

const job: EncoreJob = await this.createEncoreJob(instance, input);
if(!job) {
const job: EncoreJob = await this.createEncoreJob(instance, input, transcodeProfile);
if (!job) {
return
}
jobIds.push(job.id);
Expand Down

0 comments on commit 3dff5bc

Please sign in to comment.