Add MPEG-TS muxer, fix a demuxer bug, remove Infinity from output format track counts

This commit is contained in:
Vanilagy
2026-01-16 16:33:28 +01:00
parent ae37973878
commit e8b27768a9
13 changed files with 1705 additions and 64 deletions
+98 -10
View File
@@ -26,6 +26,7 @@ import { Mp3Muxer } from './mp3/mp3-muxer';
import { Muxer } from './muxer';
import { OggMuxer } from './ogg/ogg-muxer';
import { Output, TrackType } from './output';
import { MpegTsMuxer } from './mpeg-ts/mpeg-ts-muxer';
import { WaveMuxer } from './wave/wave-muxer';
/**
@@ -243,11 +244,13 @@ export abstract class IsobmffOutputFormat extends OutputFormat {
}
getSupportedTrackCounts(): TrackCountLimits {
const max = 2 ** 32 - 1; // Have fun reaching this one
return {
video: { min: 0, max: Infinity },
audio: { min: 0, max: Infinity },
subtitle: { min: 0, max: Infinity },
total: { min: 1, max: 2 ** 32 - 1 }, // Have fun reaching this one
video: { min: 0, max },
audio: { min: 0, max },
subtitle: { min: 0, max },
total: { min: 1, max },
};
}
@@ -454,11 +457,13 @@ export class MkvOutputFormat extends OutputFormat {
}
getSupportedTrackCounts(): TrackCountLimits {
const max = 127;
return {
video: { min: 0, max: Infinity },
audio: { min: 0, max: Infinity },
subtitle: { min: 0, max: Infinity },
total: { min: 1, max: 127 },
video: { min: 0, max },
audio: { min: 0, max },
subtitle: { min: 0, max },
total: { min: 1, max },
};
}
@@ -769,11 +774,13 @@ export class OggOutputFormat extends OutputFormat {
}
getSupportedTrackCounts(): TrackCountLimits {
const max = 2 ** 32; // Have fun reaching this one
return {
video: { min: 0, max: 0 },
audio: { min: 0, max: Infinity },
audio: { min: 0, max },
subtitle: { min: 0, max: 0 },
total: { min: 1, max: 2 ** 32 },
total: { min: 1, max },
};
}
@@ -940,3 +947,84 @@ export class FlacOutputFormat extends OutputFormat {
return false;
}
}
/**
* MPEG-TS-specific output options.
* @group Output formats
* @public
*/
export type MpegTsOutputFormatOptions = {
/**
* Will be called for each 188-byte Transport Stream packet that is written.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onPacket?: (data: Uint8Array, position: number) => unknown;
};
/**
* MPEG Transport Stream file format.
* @group Output formats
* @public
*/
export class MpegTsOutputFormat extends OutputFormat {
/** @internal */
_options: MpegTsOutputFormatOptions;
/** Creates a new {@link MpegTsOutputFormat} configured with the specified `options`. */
constructor(options: MpegTsOutputFormatOptions = {}) {
if (!options || typeof options !== 'object') {
throw new TypeError('options must be an object.');
}
if (options.onPacket !== undefined && typeof options.onPacket !== 'function') {
throw new TypeError('options.onPacket, when provided, must be a function.');
}
super();
this._options = options;
}
/** @internal */
_createMuxer(output: Output) {
return new MpegTsMuxer(output, this);
}
/** @internal */
get _name() {
return 'MPEG-TS';
}
getSupportedTrackCounts(): TrackCountLimits {
const maxVideo = 16; // Stream IDs 0xE0-0xEF
const maxAudio = 32;
const maxTotal = maxVideo + maxAudio;
return {
video: { min: 0, max: maxVideo },
audio: { min: 0, max: maxAudio },
subtitle: { min: 0, max: 0 },
total: { min: 1, max: maxTotal },
};
}
get fileExtension() {
return '.ts';
}
get mimeType() {
return 'video/MP2T';
}
getSupportedCodecs(): MediaCodec[] {
return [
...VIDEO_CODECS.filter(codec => ['avc', 'hevc'].includes(codec)),
...AUDIO_CODECS.filter(codec => ['aac', 'mp3'].includes(codec)),
];
}
get supportsVideoRotationMetadata() {
return false;
}
}