Address a bunch of TODOs and add parameter validation everywhere

This commit is contained in:
Vanilagy
2024-11-24 21:17:00 +01:00
parent 29749451bb
commit b51b2b1b45
14 changed files with 1846 additions and 1059 deletions
+48 -5
View File
@@ -32,7 +32,7 @@ export type OutputAudioTrack = OutputTrack & { type: 'audio' };
export type OutputSubtitleTrack = OutputTrack & { type: 'subtitle' };
type VideoTrackMetadata = {
rotation?: 0 | 90 | 180 | 270 | TransformationMatrix,
rotation?: 0 | 90 | 180 | 270 | TransformationMatrix, // TODO respect this field for Matroska
frameRate?: number
};
type AudioTrackMetadata = {};
@@ -46,6 +46,16 @@ export class Output {
finalizing = false;
constructor(options: OutputOptions) {
if (!options || typeof options !== 'object') {
throw new TypeError('options must be an object.');
}
if (!(options.format instanceof OutputFormat)) {
throw new TypeError('options.format must be an OutputFormat.');
}
if (!(options.target instanceof Target)) {
throw new TypeError('options.target must be a Target.');
}
if (options.target.output) {
throw new Error('Target is already used for another output.');
}
@@ -56,14 +66,51 @@ export class Output {
}
addVideoTrack(source: VideoSource, metadata: VideoTrackMetadata = {}) {
if (!(source instanceof VideoSource)) {
throw new TypeError('source must be a VideoSource.');
}
if (!metadata || typeof metadata !== 'object') {
throw new TypeError('metadata must be an object.');
}
if (typeof metadata.rotation === 'number' && ![0, 90, 180, 270].includes(metadata.rotation)) {
throw new TypeError(`Invalid video rotation: ${metadata.rotation}. Has to be 0, 90, 180 or 270.`);
} else if (
Array.isArray(metadata.rotation) &&
(metadata.rotation.length !== 9 || metadata.rotation.some(value => !Number.isFinite(value)))
) {
throw new TypeError(`Invalid video transformation matrix: ${metadata.rotation.join()}`);
}
if (
metadata.frameRate !== undefined &&
(!Number.isInteger(metadata.frameRate) || metadata.frameRate <= 0)
) {
throw new TypeError(
`Invalid video frame rate: ${metadata.frameRate}. Must be a positive integer.`
);
}
this.addTrack('video', source, metadata);
}
addAudioTrack(source: AudioSource, metadata: AudioTrackMetadata = {}) {
if (!(source instanceof AudioSource)) {
throw new TypeError('source must be an AudioSource.');
}
if (!metadata || typeof metadata !== 'object') {
throw new TypeError('metadata must be an object.');
}
this.addTrack('audio', source, metadata);
}
addSubtitleTrack(source: SubtitleSource, metadata: SubtitleTrackMetadata = {}) {
if (!(source instanceof SubtitleSource)) {
throw new TypeError('source must be a SubtitleSource.');
}
if (!metadata || typeof metadata !== 'object') {
throw new TypeError('metadata must be an object.');
}
this.addTrack('subtitle', source, metadata);
}
@@ -90,8 +137,6 @@ export class Output {
}
start() {
// TODO: Warn / throw if there are no sources
if (this.started) {
throw new Error('Output already started.');
}
@@ -105,8 +150,6 @@ export class Output {
}
async finalize() {
// TODO: Test what happens when finalizing without a single chunk of media
if (this.finalizing) {
throw new Error('Cannot call finalize twice.');
}