Add Matroska muxer

This commit is contained in:
Vanilagy
2024-11-10 17:08:04 +01:00
parent dd6526a070
commit d01d32f08c
14 changed files with 2655 additions and 36 deletions
+8 -4
View File
@@ -1,4 +1,4 @@
import { assert, isU32, last, TransformationMatrix } from '../misc';
import { toUint8Array, assert, isU32, last, TransformationMatrix } from '../misc';
import { AudioCodec, AudioSource, VideoCodec, VideoSource } from '../source';
import { GLOBAL_TIMESCALE, intoTimescale, IsobmffAudioTrackData, IsobmffTrackData, IsobmffVideoTrackData, Sample } from './isobmff_muxer';
@@ -295,6 +295,7 @@ export const hdlr = (componentSubtype: string) => fullBox('hdlr', 0, 0, [
u32(0), // Component manufacturer
u32(0), // Component flags
u32(0), // Component flags mask
// TODO:
ascii('mp4-muxer-hdlr', true) // Component name
]);
@@ -401,16 +402,19 @@ export const videoSampleDescription = (
VIDEO_CODEC_TO_CONFIGURATION_BOX[trackData.track.source.codec](trackData)
]);
// TODO: All muxers should ensure that the decoder config description is provided for the codecs that require it. This
// is relevant when the user skips WebCodecs and uses their own encoder.
/** AVC Configuration Box: Provides additional information to the decoder. */
export const avcC = (trackData: IsobmffVideoTrackData) => trackData.info.decoderConfig && box('avcC', [
// For AVC, description is an AVCDecoderConfigurationRecord, so nothing else to do here
...new Uint8Array(trackData.info.decoderConfig.description as ArrayBuffer)
...toUint8Array(trackData.info.decoderConfig.description!)
]);
/** HEVC Configuration Box: Provides additional information to the decoder. */
export const hvcC = (trackData: IsobmffVideoTrackData) => trackData.info.decoderConfig && box('hvcC', [
// For HEVC, description is a HEVCDecoderConfigurationRecord, so nothing else to do here
...new Uint8Array(trackData.info.decoderConfig.description as ArrayBuffer)
...toUint8Array(trackData.info.decoderConfig.description!)
]);
/** VP Configuration Box: Provides additional information to the decoder. */
@@ -489,7 +493,7 @@ export const soundSampleDescription = (
/** MPEG-4 Elementary Stream Descriptor Box. */
export const esds = (trackData: IsobmffAudioTrackData) => {
let description = new Uint8Array(trackData.info.decoderConfig.description as ArrayBuffer);
let description = toUint8Array(trackData.info.decoderConfig.description ?? new ArrayBuffer(0));
// TODO Compact the 808080 stuff, it's superfluous
+8 -7
View File
@@ -177,12 +177,9 @@ export class IsobmffMuxer extends Muxer {
}
start() {
this.#writeHeader();
}
#writeHeader() {
const holdsAvc = this.output.tracks.some(x => x.type === 'video' && x.source.codec === 'avc');
// Write the header
this.writeBox(ftyp({
holdsAvc: holdsAvc,
fragmented: this.#format.options.fastStart === 'fragmented'
@@ -248,8 +245,8 @@ export class IsobmffMuxer extends Muxer {
// TODO Make proper errors for these
assert(meta);
assert(meta.decoderConfig);
assert(meta.decoderConfig.codedWidth);
assert(meta.decoderConfig.codedHeight);
assert(meta.decoderConfig.codedWidth !== undefined);
assert(meta.decoderConfig.codedHeight !== undefined);
const newTrackData: IsobmffTrackData = {
track,
@@ -509,6 +506,10 @@ export class IsobmffMuxer extends Muxer {
}
#validateTimestamp(trackData: IsobmffTrackData, presentationTimestamp: number, decodeTimestamp: number) {
if (decodeTimestamp < 0) {
throw new Error(`Timestamps must be non-negative (got ${decodeTimestamp}s).`);
}
if (trackData.firstDecodeTimestamp === null) {
trackData.firstDecodeTimestamp = decodeTimestamp;
}