diff --git a/CHANGELOG.md b/CHANGELOG.md index 499f07a..612152f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ _Internal changes, like typos or internal fixes to the json-schema are not liste * New **GDDType**: `color-rrggbbaa` [PR #16](https://github.com/SuperFlyTV/GraphicsDataDefinition/pull/16) * Version 1.0.0 of the [javascript npm library](https://www.npmjs.com/package/graphics-data-definition) is released. * Optional properties `authorName` and `authorEmail` added, [PR #17](https://github.com/SuperFlyTV/GraphicsDataDefinition/pull/17) +* Add `render.resolutions` property to the Schema. [PR #18](https://github.com/SuperFlyTV/GraphicsDataDefinition/pull/18) ## 2022-10-28 diff --git a/README.md b/README.md index 5a59ee3..35eddac 100644 --- a/README.md +++ b/README.md @@ -527,6 +527,39 @@ _Note: All of the properties inside of `gddPlayoutOptions` are optional._ "dataformat": "json" | "casparcg-xml" }, + /** This object contains options related to the rendering of the GFX template */ + "render": { + /** + * This property contains an array of the supported resolutions of the GFX Template. + * The array must contain at least one resolution. + * This can be used by the client to determine whether a template is compatible with the current renderer or not. + * Examples: + * * A template which only supports a fixed resolution and framerate: + * "resolutions": [{ "width": 1280, "height": 720, "framerate": 50 }] + * * A template which supports 720p50 and 1080p50: + * "resolutions": [{ "width": 1280, "height": 720, "framerate": 50 }, { "width": 1920, "height": 1080, "framerate": 50 }] + * * A template which supports any resolution above 500x500 (and any framerate): + * "resolutions": [{ "width": { min: 500 }, "height": { min: 500 } }] + * + */ + "resolutions": [ + { + "width": { + "min": number + "max": number + } | number, + "height": { + "min": number + "max": number + } | number, + "framerate": { + "min": number + "max": number + } | number, + } + ] + }, + /** This object contains specific options for the various playout server types (CasparCG, Viz, vMix etc..) */ "playout": { "**type-of-device**": { diff --git a/gdd-meta-schema/v1/lib/playout-options.json b/gdd-meta-schema/v1/lib/playout-options.json index 86445d1..5eb7f27 100644 --- a/gdd-meta-schema/v1/lib/playout-options.json +++ b/gdd-meta-schema/v1/lib/playout-options.json @@ -21,6 +21,40 @@ } } }, + "render": { + "type": "object", + "properties": { + "resolutions": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "patternProperties": { + "width|height|framerate": { + "type": ["number", "object"], + "allOf": [ + { + "if": { + "type": "object" + }, + "then": { + "properties": { + "min": { + "type": "number" + }, + "max": { + "type": "number" + } + } + } + } + ] + } + } + } + } + } + }, "playout": { "type": "object" } diff --git a/lib/javascript-library/src/lib/types.ts b/lib/javascript-library/src/lib/types.ts index cdcdb87..bed70ff 100644 --- a/lib/javascript-library/src/lib/types.ts +++ b/lib/javascript-library/src/lib/types.ts @@ -3,11 +3,69 @@ import { Schema } from 'jsonschema' export interface GDDSchema extends GDDSchemaPropertyObject { gddPlayoutOptions?: { client?: { + /** + * (Integer) + * The suggested duration of the template (in milliseconds) + * null means that it is manually taken out + * undefined should be treated as null + * (This is ignored if steps=0) + * Defaults to null + */ duration?: number | null + /** + * Number of steps in the template + * 1 means that there are no steps (ie there's only "the default step"). + * 2 or more means that it can be "stepped" (ie 2 means it can be stepped once). + * -1 means "infinite" number of steps. + * 0 means that the template is "volatile" / "fire and forget" (template really has no duration, like a bumper). + * Defaults to 1 + */ steps?: number + /** + * How the data should be formatted. + * This is mostly used for the older CasparCG flash-based xml data format. + * Defaults to "json" + */ dataformat?: 'json' | 'casparcg-xml' } + /** This object contains options related to the rendering of the GFX template */ + render?: { + /** + * This property contains an array of the supported resolutions of the GFX Template. + * The array must contain at least one resolution. + * This can be used by the client to determine whether a template is compatible with the current renderer or not. + * Examples: + * * A template which only supports a fixed resolution and framerate: + * "resolutions": [{ "width": 1280, "height": 720, "framerate": 50 }] + * * A template which supports 720p50 and 1080p50: + * "resolutions": [{ "width": 1280, "height": 720, "framerate": 50 }, { "width": 1920, "height": 1080, "framerate": 50 }] + * * A template which supports any resolution above 500x500 (and any framerate): + * "resolutions": [{ "width": { min: 500 }, "height": { min: 500 } }] + * + */ + resolutions?: { + width?: + | { + min?: number + max?: number + } + | number + height?: + | { + min?: number + max?: number + } + | number + framerate?: + | { + min?: number + max?: number + } + | number + }[] + } + /** This object contains specific options for the various playout server types (CasparCG, Viz, vMix etc..) */ playout?: { casparcg?: { diff --git a/lib/unit-tests/__tests__/playout-options.test.ts b/lib/unit-tests/__tests__/playout-options.test.ts index ad2caa5..74e2561 100644 --- a/lib/unit-tests/__tests__/playout-options.test.ts +++ b/lib/unit-tests/__tests__/playout-options.test.ts @@ -109,6 +109,116 @@ test('gddPlayoutOptions.client', async () => { }) ).toMatch(/is not.*json/) }) +test('gddPlayoutOptions.render', async () => { + const validateSchema = (await setupValidator()).validate + + // Minimal object: + expect( + validateSchema({ + type: 'object', + properties: {}, + gddPlayoutOptions: { + render: {}, + }, + }) + ).toBe(null) + expect( + validateSchema({ + type: 'object', + properties: {}, + gddPlayoutOptions: { + render: { + resolutions: [], // empty is not allowed + }, + }, + }) + ).toMatch(/min.*length/) + expect( + validateSchema({ + type: 'object', + properties: {}, + gddPlayoutOptions: { + render: { + resolutions: [{ width: 123 }], + }, + }, + }) + ).toBe(null) + expect( + validateSchema({ + type: 'object', + properties: {}, + gddPlayoutOptions: { + render: { + resolutions: [ + { + // @ts-expect-error string should be number + width: '123', // bad type + }, + ], + }, + }, + }) + ).toMatch(/is not.*number,object/) + expect( + validateSchema({ + type: 'object', + properties: {}, + gddPlayoutOptions: { + render: { + resolutions: [{ width: { min: 100, max: 9999 } }], + }, + }, + }) + ).toBe(null) + expect( + validateSchema({ + type: 'object', + properties: {}, + gddPlayoutOptions: { + render: { + resolutions: [ + { + width: { + // @ts-expect-error string should be number + max: 'two', // bad type + }, + }, + ], + }, + }, + }) + ).toMatch(/is not.*number/) + expect( + validateSchema({ + type: 'object', + properties: {}, + gddPlayoutOptions: { + render: { + resolutions: [{ width: { max: 9000 }, height: 500, framerate: 50 }], + }, + }, + }) + ).toBe(null) + expect( + validateSchema({ + type: 'object', + properties: {}, + gddPlayoutOptions: { + render: { + resolutions: [ + { + width: { max: 9000 }, + height: 500, + // @ts-expect-error string should be number + framerate: '50', // bad type + }, + ], + }, + }, + }) + ).toMatch(/is not.*number/) +}) test('gddPlayoutOptions.playout', async () => { const validateSchema = (await setupValidator()).validate