mediabunny 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/mediabunny.d.ts +4 -2
- package/dist/modules/codec-data.d.ts +95 -0
- package/dist/modules/codec-data.d.ts.map +1 -0
- package/dist/modules/codec-data.js +1103 -0
- package/dist/modules/codec.d.ts +250 -0
- package/dist/modules/codec.d.ts.map +1 -0
- package/dist/modules/codec.js +1100 -0
- package/dist/modules/conversion.d.ts +158 -0
- package/dist/modules/conversion.d.ts.map +1 -0
- package/dist/modules/conversion.js +866 -0
- package/dist/modules/custom-coder.d.ts +119 -0
- package/dist/modules/custom-coder.d.ts.map +1 -0
- package/dist/modules/custom-coder.js +91 -0
- package/dist/modules/demuxer.d.ts +17 -0
- package/dist/modules/demuxer.d.ts.map +1 -0
- package/dist/modules/demuxer.js +12 -0
- package/dist/modules/index.d.ts +25 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +24 -0
- package/dist/modules/input-format.d.ts +121 -0
- package/dist/modules/input-format.d.ts.map +1 -0
- package/dist/modules/input-format.js +333 -0
- package/dist/modules/input-track.d.ts +138 -0
- package/dist/modules/input-track.d.ts.map +1 -0
- package/dist/modules/input-track.js +230 -0
- package/dist/modules/input.d.ts +55 -0
- package/dist/modules/input.d.ts.map +1 -0
- package/dist/modules/input.js +104 -0
- package/dist/modules/isobmff/isobmff-boxes.d.ts +202 -0
- package/dist/modules/isobmff/isobmff-boxes.d.ts.map +1 -0
- package/dist/modules/isobmff/isobmff-boxes.js +1111 -0
- package/dist/modules/isobmff/isobmff-demuxer.d.ts +163 -0
- package/dist/modules/isobmff/isobmff-demuxer.d.ts.map +1 -0
- package/dist/modules/isobmff/isobmff-demuxer.js +2080 -0
- package/dist/modules/isobmff/isobmff-misc.d.ts +14 -0
- package/dist/modules/isobmff/isobmff-misc.d.ts.map +1 -0
- package/dist/modules/isobmff/isobmff-misc.js +20 -0
- package/dist/modules/isobmff/isobmff-muxer.d.ts +142 -0
- package/dist/modules/isobmff/isobmff-muxer.d.ts.map +1 -0
- package/dist/modules/isobmff/isobmff-muxer.js +858 -0
- package/dist/modules/isobmff/isobmff-reader.d.ts +36 -0
- package/dist/modules/isobmff/isobmff-reader.d.ts.map +1 -0
- package/dist/modules/isobmff/isobmff-reader.js +105 -0
- package/dist/modules/matroska/ebml.d.ts +156 -0
- package/dist/modules/matroska/ebml.d.ts.map +1 -0
- package/dist/modules/matroska/ebml.js +529 -0
- package/dist/modules/matroska/matroska-demuxer.d.ts +119 -0
- package/dist/modules/matroska/matroska-demuxer.d.ts.map +1 -0
- package/dist/modules/matroska/matroska-demuxer.js +1330 -0
- package/dist/modules/matroska/matroska-misc.d.ts +14 -0
- package/dist/modules/matroska/matroska-misc.d.ts.map +1 -0
- package/dist/modules/matroska/matroska-misc.js +20 -0
- package/dist/modules/matroska/matroska-muxer.d.ts +71 -0
- package/dist/modules/matroska/matroska-muxer.d.ts.map +1 -0
- package/dist/modules/matroska/matroska-muxer.js +729 -0
- package/dist/modules/media-sink.d.ts +272 -0
- package/dist/modules/media-sink.d.ts.map +1 -0
- package/dist/modules/media-sink.js +1264 -0
- package/dist/modules/media-source.d.ts +230 -0
- package/dist/modules/media-source.d.ts.map +1 -0
- package/dist/modules/media-source.js +1095 -0
- package/dist/modules/misc.d.ts +127 -0
- package/dist/modules/misc.d.ts.map +1 -0
- package/dist/modules/misc.js +462 -0
- package/dist/modules/mp3/mp3-demuxer.d.ts +32 -0
- package/dist/modules/mp3/mp3-demuxer.d.ts.map +1 -0
- package/dist/modules/mp3/mp3-demuxer.js +160 -0
- package/dist/modules/mp3/mp3-misc.d.ts +37 -0
- package/dist/modules/mp3/mp3-misc.d.ts.map +1 -0
- package/dist/modules/mp3/mp3-misc.js +122 -0
- package/dist/modules/mp3/mp3-muxer.d.ts +27 -0
- package/dist/modules/mp3/mp3-muxer.d.ts.map +1 -0
- package/dist/modules/mp3/mp3-muxer.js +112 -0
- package/dist/modules/mp3/mp3-reader.d.ts +25 -0
- package/dist/modules/mp3/mp3-reader.d.ts.map +1 -0
- package/dist/modules/mp3/mp3-reader.js +73 -0
- package/dist/modules/mp3/mp3-writer.d.ts +30 -0
- package/dist/modules/mp3/mp3-writer.d.ts.map +1 -0
- package/dist/modules/mp3/mp3-writer.js +72 -0
- package/dist/modules/muxer.d.ts +32 -0
- package/dist/modules/muxer.d.ts.map +1 -0
- package/dist/modules/muxer.js +50 -0
- package/dist/modules/ogg/ogg-demuxer.d.ts +53 -0
- package/dist/modules/ogg/ogg-demuxer.d.ts.map +1 -0
- package/dist/modules/ogg/ogg-demuxer.js +701 -0
- package/dist/modules/ogg/ogg-misc.d.ts +27 -0
- package/dist/modules/ogg/ogg-misc.d.ts.map +1 -0
- package/dist/modules/ogg/ogg-misc.js +78 -0
- package/dist/modules/ogg/ogg-muxer.d.ts +58 -0
- package/dist/modules/ogg/ogg-muxer.d.ts.map +1 -0
- package/dist/modules/ogg/ogg-muxer.js +345 -0
- package/dist/modules/ogg/ogg-reader.d.ts +37 -0
- package/dist/modules/ogg/ogg-reader.d.ts.map +1 -0
- package/dist/modules/ogg/ogg-reader.js +104 -0
- package/dist/modules/output-format.d.ts +285 -0
- package/dist/modules/output-format.d.ts.map +1 -0
- package/dist/modules/output-format.js +385 -0
- package/dist/modules/output.d.ts +134 -0
- package/dist/modules/output.d.ts.map +1 -0
- package/dist/modules/output.js +269 -0
- package/dist/modules/packet.d.ts +86 -0
- package/dist/modules/packet.d.ts.map +1 -0
- package/dist/modules/packet.js +133 -0
- package/dist/modules/pcm.d.ts +12 -0
- package/dist/modules/pcm.d.ts.map +1 -0
- package/dist/modules/pcm.js +85 -0
- package/dist/modules/reader.d.ts +40 -0
- package/dist/modules/reader.d.ts.map +1 -0
- package/dist/modules/reader.js +153 -0
- package/dist/modules/sample.d.ts +186 -0
- package/dist/modules/sample.d.ts.map +1 -0
- package/dist/modules/sample.js +798 -0
- package/dist/modules/source.d.ts +76 -0
- package/dist/modules/source.d.ts.map +1 -0
- package/dist/modules/source.js +183 -0
- package/dist/modules/subtitles.d.ts +37 -0
- package/dist/modules/subtitles.d.ts.map +1 -0
- package/dist/modules/subtitles.js +89 -0
- package/dist/modules/target.d.ts +58 -0
- package/dist/modules/target.d.ts.map +1 -0
- package/dist/modules/target.js +63 -0
- package/dist/modules/wave/riff-reader.d.ts +19 -0
- package/dist/modules/wave/riff-reader.d.ts.map +1 -0
- package/dist/modules/wave/riff-reader.js +38 -0
- package/dist/modules/wave/riff-writer.d.ts +18 -0
- package/dist/modules/wave/riff-writer.d.ts.map +1 -0
- package/dist/modules/wave/riff-writer.js +25 -0
- package/dist/modules/wave/wave-demuxer.d.ts +42 -0
- package/dist/modules/wave/wave-demuxer.d.ts.map +1 -0
- package/dist/modules/wave/wave-demuxer.js +239 -0
- package/dist/modules/wave/wave-muxer.d.ts +27 -0
- package/dist/modules/wave/wave-muxer.d.ts.map +1 -0
- package/dist/modules/wave/wave-muxer.js +108 -0
- package/dist/modules/writer.d.ts +85 -0
- package/dist/modules/writer.d.ts.map +1 -0
- package/dist/modules/writer.js +347 -0
- package/package.json +14 -10
- package/src/codec-data.ts +1394 -0
- package/src/codec.ts +1392 -0
- package/src/conversion.ts +1199 -0
- package/src/custom-coder.ts +162 -0
- package/src/demuxer.ts +22 -0
- package/src/index.ts +148 -0
- package/src/input-format.ts +386 -0
- package/src/input-track.ts +341 -0
- package/src/input.ts +138 -0
- package/src/isobmff/isobmff-boxes.ts +1365 -0
- package/src/isobmff/isobmff-demuxer.ts +2646 -0
- package/src/isobmff/isobmff-misc.ts +29 -0
- package/src/isobmff/isobmff-muxer.ts +1210 -0
- package/src/isobmff/isobmff-reader.ts +137 -0
- package/src/matroska/ebml.ts +595 -0
- package/src/matroska/matroska-demuxer.ts +1677 -0
- package/src/matroska/matroska-misc.ts +29 -0
- package/src/matroska/matroska-muxer.ts +999 -0
- package/src/media-sink.ts +1577 -0
- package/src/media-source.ts +1406 -0
- package/src/misc.ts +584 -0
- package/src/mp3/mp3-demuxer.ts +228 -0
- package/src/mp3/mp3-misc.ts +154 -0
- package/src/mp3/mp3-muxer.ts +153 -0
- package/src/mp3/mp3-reader.ts +93 -0
- package/src/mp3/mp3-writer.ts +112 -0
- package/src/muxer.ts +88 -0
- package/src/ogg/ogg-demuxer.ts +985 -0
- package/src/ogg/ogg-misc.ts +116 -0
- package/src/ogg/ogg-muxer.ts +480 -0
- package/src/ogg/ogg-reader.ts +143 -0
- package/src/output-format.ts +689 -0
- package/src/output.ts +427 -0
- package/src/packet.ts +180 -0
- package/src/pcm.ts +112 -0
- package/src/reader.ts +205 -0
- package/src/sample.ts +1029 -0
- package/src/source.ts +279 -0
- package/src/subtitles.ts +131 -0
- package/src/target.ts +106 -0
- package/src/tsconfig.json +13 -0
- package/src/wave/riff-reader.ts +48 -0
- package/src/wave/riff-writer.ts +30 -0
- package/src/wave/wave-demuxer.ts +317 -0
- package/src/wave/wave-muxer.ts +145 -0
- package/src/writer.ts +461 -0
- /package/dist/{mediabunny.js → bundles/mediabunny.cjs} +0 -0
- /package/dist/{mediabunny.min.js → bundles/mediabunny.min.cjs} +0 -0
- /package/dist/{mediabunny.min.mjs → bundles/mediabunny.min.mjs} +0 -0
- /package/dist/{mediabunny.mjs → bundles/mediabunny.mjs} +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2025-present, Vanilagy and contributors
|
|
3
|
+
*
|
|
4
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { AudioCodec, VideoCodec } from './codec';
|
|
10
|
+
import { EncodedPacket } from './packet';
|
|
11
|
+
import { AudioSample, VideoSample } from './sample';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Base class for custom video decoders. To add your own custom video decoder, extend this class, implement the
|
|
15
|
+
* abstract methods and static `supports` method, and register the decoder using `registerDecoder`.
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export abstract class CustomVideoDecoder {
|
|
19
|
+
/** The input video's codec. */
|
|
20
|
+
readonly codec!: VideoCodec;
|
|
21
|
+
/** The input video's decoder config. */
|
|
22
|
+
readonly config!: VideoDecoderConfig;
|
|
23
|
+
/** The callback to call when a decoded VideoSample is available. */
|
|
24
|
+
readonly onSample!: (sample: VideoSample) => unknown;
|
|
25
|
+
|
|
26
|
+
/** Returns true iff the decoder can decode the given codec configuration. */
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
+
static supports(codec: VideoCodec, config: VideoDecoderConfig): boolean {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Called after decoder creation; can be used for custom initialization logic. */
|
|
33
|
+
abstract init(): Promise<void> | void;
|
|
34
|
+
/** Decodes the provided encoded packet. */
|
|
35
|
+
abstract decode(packet: EncodedPacket): Promise<void> | void;
|
|
36
|
+
/** Decodes all remaining packets and then resolves. */
|
|
37
|
+
abstract flush(): Promise<void> | void;
|
|
38
|
+
/** Called when the decoder is no longer needed and its resources can be freed. */
|
|
39
|
+
abstract close(): Promise<void> | void;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Base class for custom audio decoders. To add your own custom audio decoder, extend this class, implement the
|
|
44
|
+
* abstract methods and static `supports` method, and register the decoder using `registerDecoder`.
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export abstract class CustomAudioDecoder {
|
|
48
|
+
/** The input audio's codec. */
|
|
49
|
+
readonly codec!: AudioCodec;
|
|
50
|
+
/** The input audio's decoder config. */
|
|
51
|
+
readonly config!: AudioDecoderConfig;
|
|
52
|
+
/** The callback to call when a decoded AudioSample is available. */
|
|
53
|
+
readonly onSample!: (sample: AudioSample) => unknown;
|
|
54
|
+
|
|
55
|
+
/** Returns true iff the decoder can decode the given codec configuration. */
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
57
|
+
static supports(codec: AudioCodec, config: AudioDecoderConfig): boolean {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Called after decoder creation; can be used for custom initialization logic. */
|
|
62
|
+
abstract init(): Promise<void> | void;
|
|
63
|
+
/** Decodes the provided encoded packet. */
|
|
64
|
+
abstract decode(packet: EncodedPacket): Promise<void> | void;
|
|
65
|
+
/** Decodes all remaining packets and then resolves. */
|
|
66
|
+
abstract flush(): Promise<void> | void;
|
|
67
|
+
/** Called when the decoder is no longer needed and its resources can be freed. */
|
|
68
|
+
abstract close(): Promise<void> | void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Base class for custom video encoders. To add your own custom video encoder, extend this class, implement the
|
|
73
|
+
* abstract methods and static `supports` method, and register the encoder using `registerEncoder`.
|
|
74
|
+
* @public
|
|
75
|
+
*/
|
|
76
|
+
export abstract class CustomVideoEncoder {
|
|
77
|
+
/** The codec with which to encode the video. */
|
|
78
|
+
readonly codec!: VideoCodec;
|
|
79
|
+
/** Config for the encoder. */
|
|
80
|
+
readonly config!: VideoEncoderConfig;
|
|
81
|
+
/** The callback to call when an EncodedPacket is available. */
|
|
82
|
+
readonly onPacket!: (packet: EncodedPacket, meta?: EncodedVideoChunkMetadata) => unknown;
|
|
83
|
+
|
|
84
|
+
/** Returns true iff the encoder can encode the given codec configuration. */
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
86
|
+
static supports(codec: VideoCodec, config: VideoEncoderConfig): boolean {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Called after encoder creation; can be used for custom initialization logic. */
|
|
91
|
+
abstract init(): Promise<void> | void;
|
|
92
|
+
/** Encodes the provided video sample. */
|
|
93
|
+
abstract encode(videoSample: VideoSample, options: VideoEncoderEncodeOptions): Promise<void> | void;
|
|
94
|
+
/** Encodes all remaining video samples and then resolves. */
|
|
95
|
+
abstract flush(): Promise<void> | void;
|
|
96
|
+
/** Called when the encoder is no longer needed and its resources can be freed. */
|
|
97
|
+
abstract close(): Promise<void> | void;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Base class for custom audio encoders. To add your own custom audio encoder, extend this class, implement the
|
|
102
|
+
* abstract methods and static `supports` method, and register the encoder using `registerEncoder`.
|
|
103
|
+
* @public
|
|
104
|
+
*/
|
|
105
|
+
export abstract class CustomAudioEncoder {
|
|
106
|
+
/** The codec with which to encode the audio. */
|
|
107
|
+
readonly codec!: AudioCodec;
|
|
108
|
+
/** Config for the encoder. */
|
|
109
|
+
readonly config!: AudioEncoderConfig;
|
|
110
|
+
/** The callback to call when an EncodedPacket is available. */
|
|
111
|
+
readonly onPacket!: (packet: EncodedPacket, meta?: EncodedAudioChunkMetadata) => unknown;
|
|
112
|
+
|
|
113
|
+
/** Returns true iff the encoder can encode the given codec configuration. */
|
|
114
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
115
|
+
static supports(codec: AudioCodec, config: AudioEncoderConfig): boolean {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Called after encoder creation; can be used for custom initialization logic. */
|
|
120
|
+
abstract init(): Promise<void> | void;
|
|
121
|
+
/** Encodes the provided audio sample. */
|
|
122
|
+
abstract encode(audioSample: AudioSample): Promise<void> | void;
|
|
123
|
+
/** Encodes all remaining audio samples and then resolves. */
|
|
124
|
+
abstract flush(): Promise<void> | void;
|
|
125
|
+
/** Called when the encoder is no longer needed and its resources can be freed. */
|
|
126
|
+
abstract close(): Promise<void> | void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export const customVideoDecoders: typeof CustomVideoDecoder[] = [];
|
|
130
|
+
export const customAudioDecoders: typeof CustomAudioDecoder[] = [];
|
|
131
|
+
export const customVideoEncoders: typeof CustomVideoEncoder[] = [];
|
|
132
|
+
export const customAudioEncoders: typeof CustomAudioEncoder[] = [];
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Registers a custom video or audio decoder. Registered decoders will automatically be used for decoding whenever
|
|
136
|
+
* possible.
|
|
137
|
+
* @public
|
|
138
|
+
*/
|
|
139
|
+
export const registerDecoder = (decoder: typeof CustomVideoDecoder | typeof CustomAudioDecoder) => {
|
|
140
|
+
if (decoder.prototype instanceof CustomVideoDecoder) {
|
|
141
|
+
customVideoDecoders.push(decoder as typeof CustomVideoDecoder);
|
|
142
|
+
} else if (decoder.prototype instanceof CustomAudioDecoder) {
|
|
143
|
+
customAudioDecoders.push(decoder as typeof CustomAudioDecoder);
|
|
144
|
+
} else {
|
|
145
|
+
throw new TypeError('Decoder must be a CustomVideoDecoder or CustomAudioDecoder.');
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Registers a custom video or audio encoder. Registered encoders will automatically be used for encoding whenever
|
|
151
|
+
* possible.
|
|
152
|
+
* @public
|
|
153
|
+
*/
|
|
154
|
+
export const registerEncoder = (encoder: typeof CustomVideoEncoder | typeof CustomAudioEncoder) => {
|
|
155
|
+
if (encoder.prototype instanceof CustomVideoEncoder) {
|
|
156
|
+
customVideoEncoders.push(encoder as typeof CustomVideoEncoder);
|
|
157
|
+
} else if (encoder.prototype instanceof CustomAudioEncoder) {
|
|
158
|
+
customAudioEncoders.push(encoder as typeof CustomAudioEncoder);
|
|
159
|
+
} else {
|
|
160
|
+
throw new TypeError('Encoder must be a CustomVideoEncoder or CustomAudioEncoder.');
|
|
161
|
+
}
|
|
162
|
+
};
|
package/src/demuxer.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2025-present, Vanilagy and contributors
|
|
3
|
+
*
|
|
4
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Input } from './input';
|
|
10
|
+
import { InputTrack } from './input-track';
|
|
11
|
+
|
|
12
|
+
export abstract class Demuxer {
|
|
13
|
+
input: Input;
|
|
14
|
+
|
|
15
|
+
constructor(input: Input) {
|
|
16
|
+
this.input = input;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
abstract computeDuration(): Promise<number>;
|
|
20
|
+
abstract getTracks(): Promise<InputTrack[]>;
|
|
21
|
+
abstract getMimeType(): Promise<string>;
|
|
22
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2025-present, Vanilagy and contributors
|
|
3
|
+
*
|
|
4
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/// <reference types="dom-mediacapture-transform" preserve="true" />
|
|
10
|
+
/// <reference types="dom-webcodecs" preserve="true" />
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
Output,
|
|
14
|
+
OutputOptions,
|
|
15
|
+
BaseTrackMetadata,
|
|
16
|
+
VideoTrackMetadata,
|
|
17
|
+
AudioTrackMetadata,
|
|
18
|
+
SubtitleTrackMetadata,
|
|
19
|
+
TrackType,
|
|
20
|
+
ALL_TRACK_TYPES,
|
|
21
|
+
} from './output';
|
|
22
|
+
export {
|
|
23
|
+
OutputFormat,
|
|
24
|
+
IsobmffOutputFormat,
|
|
25
|
+
Mp4OutputFormat,
|
|
26
|
+
MovOutputFormat,
|
|
27
|
+
IsobmffOutputFormatOptions,
|
|
28
|
+
MkvOutputFormat,
|
|
29
|
+
MkvOutputFormatOptions,
|
|
30
|
+
WebMOutputFormat,
|
|
31
|
+
WebMOutputFormatOptions,
|
|
32
|
+
Mp3OutputFormat,
|
|
33
|
+
Mp3OutputFormatOptions,
|
|
34
|
+
WavOutputFormat,
|
|
35
|
+
WavOutputFormatOptions,
|
|
36
|
+
OggOutputFormat,
|
|
37
|
+
OggOutputFormatOptions,
|
|
38
|
+
TrackCountLimits,
|
|
39
|
+
InclusiveIntegerRange,
|
|
40
|
+
} from './output-format';
|
|
41
|
+
export {
|
|
42
|
+
VideoEncodingConfig,
|
|
43
|
+
AudioEncodingConfig,
|
|
44
|
+
MediaSource,
|
|
45
|
+
VideoSource,
|
|
46
|
+
EncodedVideoPacketSource,
|
|
47
|
+
VideoSampleSource,
|
|
48
|
+
CanvasSource,
|
|
49
|
+
MediaStreamVideoTrackSource,
|
|
50
|
+
AudioSource,
|
|
51
|
+
EncodedAudioPacketSource,
|
|
52
|
+
AudioSampleSource,
|
|
53
|
+
AudioBufferSource,
|
|
54
|
+
MediaStreamAudioTrackSource,
|
|
55
|
+
SubtitleSource,
|
|
56
|
+
TextSubtitleSource,
|
|
57
|
+
} from './media-source';
|
|
58
|
+
export {
|
|
59
|
+
VIDEO_CODECS,
|
|
60
|
+
VideoCodec,
|
|
61
|
+
PCM_AUDIO_CODECS,
|
|
62
|
+
NON_PCM_AUDIO_CODECS,
|
|
63
|
+
AUDIO_CODECS,
|
|
64
|
+
AudioCodec,
|
|
65
|
+
SUBTITLE_CODECS,
|
|
66
|
+
SubtitleCodec,
|
|
67
|
+
MediaCodec,
|
|
68
|
+
Quality,
|
|
69
|
+
QUALITY_VERY_LOW,
|
|
70
|
+
QUALITY_LOW,
|
|
71
|
+
QUALITY_MEDIUM,
|
|
72
|
+
QUALITY_HIGH,
|
|
73
|
+
QUALITY_VERY_HIGH,
|
|
74
|
+
canEncode,
|
|
75
|
+
canEncodeVideo,
|
|
76
|
+
canEncodeAudio,
|
|
77
|
+
canEncodeSubtitles,
|
|
78
|
+
getEncodableCodecs,
|
|
79
|
+
getEncodableVideoCodecs,
|
|
80
|
+
getEncodableAudioCodecs,
|
|
81
|
+
getEncodableSubtitleCodecs,
|
|
82
|
+
getFirstEncodableVideoCodec,
|
|
83
|
+
getFirstEncodableAudioCodec,
|
|
84
|
+
getFirstEncodableSubtitleCodec,
|
|
85
|
+
} from './codec';
|
|
86
|
+
export { Target, BufferTarget, StreamTarget, StreamTargetChunk, StreamTargetOptions } from './target';
|
|
87
|
+
export { Rotation, AnyIterable, SetRequired } from './misc';
|
|
88
|
+
export {
|
|
89
|
+
Source,
|
|
90
|
+
BufferSource,
|
|
91
|
+
StreamSource,
|
|
92
|
+
StreamSourceOptions,
|
|
93
|
+
BlobSource,
|
|
94
|
+
UrlSource,
|
|
95
|
+
UrlSourceOptions,
|
|
96
|
+
} from './source';
|
|
97
|
+
export {
|
|
98
|
+
InputFormat,
|
|
99
|
+
IsobmffInputFormat,
|
|
100
|
+
Mp4InputFormat,
|
|
101
|
+
QuickTimeInputFormat,
|
|
102
|
+
MatroskaInputFormat,
|
|
103
|
+
WebMInputFormat,
|
|
104
|
+
Mp3InputFormat,
|
|
105
|
+
WaveInputFormat,
|
|
106
|
+
OggInputFormat,
|
|
107
|
+
ALL_FORMATS,
|
|
108
|
+
MP4,
|
|
109
|
+
QTFF,
|
|
110
|
+
MATROSKA,
|
|
111
|
+
WEBM,
|
|
112
|
+
MP3,
|
|
113
|
+
WAVE,
|
|
114
|
+
OGG,
|
|
115
|
+
} from './input-format';
|
|
116
|
+
export { Input, InputOptions } from './input';
|
|
117
|
+
export { InputTrack, InputVideoTrack, InputAudioTrack, PacketStats } from './input-track';
|
|
118
|
+
export { EncodedPacket, PacketType } from './packet';
|
|
119
|
+
export {
|
|
120
|
+
VideoSample,
|
|
121
|
+
VideoSampleInit,
|
|
122
|
+
AudioSample,
|
|
123
|
+
AudioSampleInit,
|
|
124
|
+
AudioSampleCopyToOptions,
|
|
125
|
+
} from './sample';
|
|
126
|
+
export {
|
|
127
|
+
PacketRetrievalOptions,
|
|
128
|
+
EncodedPacketSink,
|
|
129
|
+
BaseMediaSampleSink,
|
|
130
|
+
VideoSampleSink,
|
|
131
|
+
CanvasSinkOptions,
|
|
132
|
+
CanvasSink,
|
|
133
|
+
WrappedCanvas,
|
|
134
|
+
AudioSampleSink,
|
|
135
|
+
AudioBufferSink,
|
|
136
|
+
WrappedAudioBuffer,
|
|
137
|
+
} from './media-sink';
|
|
138
|
+
export { ConversionOptions, Conversion } from './conversion';
|
|
139
|
+
export {
|
|
140
|
+
CustomVideoDecoder,
|
|
141
|
+
CustomAudioDecoder,
|
|
142
|
+
CustomVideoEncoder,
|
|
143
|
+
CustomAudioEncoder,
|
|
144
|
+
registerDecoder,
|
|
145
|
+
registerEncoder,
|
|
146
|
+
} from './custom-coder';
|
|
147
|
+
|
|
148
|
+
// 🐡🦔
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2025-present, Vanilagy and contributors
|
|
3
|
+
*
|
|
4
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Demuxer } from './demuxer';
|
|
10
|
+
import { Input } from './input';
|
|
11
|
+
import { IsobmffDemuxer } from './isobmff/isobmff-demuxer';
|
|
12
|
+
import { IsobmffReader } from './isobmff/isobmff-reader';
|
|
13
|
+
import { EBMLId, EBMLReader } from './matroska/ebml';
|
|
14
|
+
import { MatroskaDemuxer } from './matroska/matroska-demuxer';
|
|
15
|
+
import { Mp3Demuxer } from './mp3/mp3-demuxer';
|
|
16
|
+
import { Mp3Reader } from './mp3/mp3-reader';
|
|
17
|
+
import { OggDemuxer } from './ogg/ogg-demuxer';
|
|
18
|
+
import { OggReader } from './ogg/ogg-reader';
|
|
19
|
+
import { RiffReader } from './wave/riff-reader';
|
|
20
|
+
import { WaveDemuxer } from './wave/wave-demuxer';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Base class representing an input media file format.
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export abstract class InputFormat {
|
|
27
|
+
/** @internal */
|
|
28
|
+
abstract _canReadInput(input: Input): Promise<boolean>;
|
|
29
|
+
|
|
30
|
+
/** @internal */
|
|
31
|
+
abstract _createDemuxer(input: Input): Demuxer;
|
|
32
|
+
|
|
33
|
+
/** Returns the name of the input format. */
|
|
34
|
+
abstract get name(): string;
|
|
35
|
+
/** Returns the typical base MIME type of the input format. */
|
|
36
|
+
abstract get mimeType(): string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Format representing files compatible with the ISO base media file format (ISOBMFF), like MP4 or MOV files.
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export abstract class IsobmffInputFormat extends InputFormat {
|
|
44
|
+
/** @internal */
|
|
45
|
+
protected async _getMajorBrand(input: Input) {
|
|
46
|
+
const sourceSize = await input._mainReader.source.getSize();
|
|
47
|
+
if (sourceSize < 12) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const isobmffReader = new IsobmffReader(input._mainReader);
|
|
52
|
+
isobmffReader.pos = 4;
|
|
53
|
+
const fourCc = isobmffReader.readAscii(4);
|
|
54
|
+
|
|
55
|
+
if (fourCc !== 'ftyp') {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return isobmffReader.readAscii(4);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** @internal */
|
|
63
|
+
_createDemuxer(input: Input) {
|
|
64
|
+
return new IsobmffDemuxer(input);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* MPEG-4 Part 14 (MP4) file format.
|
|
70
|
+
* @public
|
|
71
|
+
*/
|
|
72
|
+
export class Mp4InputFormat extends IsobmffInputFormat {
|
|
73
|
+
/** @internal */
|
|
74
|
+
async _canReadInput(input: Input) {
|
|
75
|
+
const majorBrand = await this._getMajorBrand(input);
|
|
76
|
+
return !!majorBrand && majorBrand !== 'qt ';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get name() {
|
|
80
|
+
return 'MP4';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get mimeType() {
|
|
84
|
+
return 'video/mp4';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* QuickTime File Format (QTFF), often called MOV.
|
|
90
|
+
* @public
|
|
91
|
+
*/
|
|
92
|
+
export class QuickTimeInputFormat extends IsobmffInputFormat {
|
|
93
|
+
/** @internal */
|
|
94
|
+
async _canReadInput(input: Input) {
|
|
95
|
+
const majorBrand = await this._getMajorBrand(input);
|
|
96
|
+
return majorBrand === 'qt ';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get name() {
|
|
100
|
+
return 'QuickTime File Format';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get mimeType() {
|
|
104
|
+
return 'video/quicktime';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Matroska file format.
|
|
110
|
+
* @public
|
|
111
|
+
*/
|
|
112
|
+
export class MatroskaInputFormat extends InputFormat {
|
|
113
|
+
/** @internal */
|
|
114
|
+
protected async isSupportedEBMLOfDocType(input: Input, desiredDocType: string) {
|
|
115
|
+
const sourceSize = await input._mainReader.source.getSize();
|
|
116
|
+
if (sourceSize < 8) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const ebmlReader = new EBMLReader(input._mainReader);
|
|
121
|
+
const varIntSize = ebmlReader.readVarIntSize();
|
|
122
|
+
if (varIntSize < 1 || varIntSize > 8) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const id = ebmlReader.readUnsignedInt(varIntSize);
|
|
127
|
+
if (id !== EBMLId.EBML) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const dataSize = ebmlReader.readElementSize();
|
|
132
|
+
if (dataSize === null) {
|
|
133
|
+
return false; // Miss me with that shit
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const startPos = ebmlReader.pos;
|
|
137
|
+
while (ebmlReader.pos < startPos + dataSize) {
|
|
138
|
+
const { id, size } = ebmlReader.readElementHeader();
|
|
139
|
+
const dataStartPos = ebmlReader.pos;
|
|
140
|
+
if (size === null) return false;
|
|
141
|
+
|
|
142
|
+
switch (id) {
|
|
143
|
+
case EBMLId.EBMLVersion: {
|
|
144
|
+
const ebmlVersion = ebmlReader.readUnsignedInt(size);
|
|
145
|
+
if (ebmlVersion !== 1) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}; break;
|
|
149
|
+
case EBMLId.EBMLReadVersion: {
|
|
150
|
+
const ebmlReadVersion = ebmlReader.readUnsignedInt(size);
|
|
151
|
+
if (ebmlReadVersion !== 1) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}; break;
|
|
155
|
+
case EBMLId.DocType: {
|
|
156
|
+
const docType = ebmlReader.readString(size);
|
|
157
|
+
if (docType !== desiredDocType) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}; break;
|
|
161
|
+
case EBMLId.DocTypeVersion: {
|
|
162
|
+
const docTypeVersion = ebmlReader.readUnsignedInt(size);
|
|
163
|
+
if (docTypeVersion > 4) { // Support up to Matroska v4
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}; break;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
ebmlReader.pos = dataStartPos + size;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** @internal */
|
|
176
|
+
_canReadInput(input: Input) {
|
|
177
|
+
return this.isSupportedEBMLOfDocType(input, 'matroska');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** @internal */
|
|
181
|
+
_createDemuxer(input: Input) {
|
|
182
|
+
return new MatroskaDemuxer(input);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
get name() {
|
|
186
|
+
return 'Matroska';
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
get mimeType() {
|
|
190
|
+
return 'video/x-matroska';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* WebM file format, based on Matroska.
|
|
196
|
+
* @public
|
|
197
|
+
*/
|
|
198
|
+
export class WebMInputFormat extends MatroskaInputFormat {
|
|
199
|
+
/** @internal */
|
|
200
|
+
override _canReadInput(input: Input) {
|
|
201
|
+
return this.isSupportedEBMLOfDocType(input, 'webm');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
override get name() {
|
|
205
|
+
return 'WebM';
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
override get mimeType() {
|
|
209
|
+
return 'video/webm';
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* MP3 file format.
|
|
215
|
+
* @public
|
|
216
|
+
*/
|
|
217
|
+
export class Mp3InputFormat extends InputFormat {
|
|
218
|
+
/** @internal */
|
|
219
|
+
async _canReadInput(input: Input) {
|
|
220
|
+
const sourceSize = await input._mainReader.source.getSize();
|
|
221
|
+
if (sourceSize < 4) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const mp3Reader = new Mp3Reader(input._mainReader);
|
|
226
|
+
mp3Reader.fileSize = sourceSize;
|
|
227
|
+
|
|
228
|
+
const id3Tag = mp3Reader.readId3();
|
|
229
|
+
|
|
230
|
+
if (id3Tag) {
|
|
231
|
+
mp3Reader.pos += id3Tag.size;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const framesStartPos = mp3Reader.pos;
|
|
235
|
+
await mp3Reader.reader.loadRange(mp3Reader.pos, mp3Reader.pos + 4096);
|
|
236
|
+
|
|
237
|
+
const firstHeader = mp3Reader.readNextFrameHeader(Math.min(framesStartPos + 4096, sourceSize));
|
|
238
|
+
if (!firstHeader) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (id3Tag) {
|
|
243
|
+
// If there was an ID3 tag at the start, we can be pretty sure this is MP3 by now
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Fine, we found one frame header, but we're still not entirely sure this is MP3. Let's check if we can find
|
|
248
|
+
// another header nearby:
|
|
249
|
+
mp3Reader.pos = firstHeader.startPos + firstHeader.totalSize;
|
|
250
|
+
const secondHeader = mp3Reader.readNextFrameHeader(Math.min(framesStartPos + 4096, sourceSize));
|
|
251
|
+
if (!secondHeader) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// In a well-formed MP3 file, we'd expect these two frames to share some similarities:
|
|
256
|
+
if (firstHeader.channel !== secondHeader.channel || firstHeader.sampleRate !== secondHeader.sampleRate) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// We have found two matching MP3 frames, a strong indicator that this is an MP3 file
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** @internal */
|
|
265
|
+
_createDemuxer(input: Input) {
|
|
266
|
+
return new Mp3Demuxer(input);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
get name() {
|
|
270
|
+
return 'MP3';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
get mimeType() {
|
|
274
|
+
return 'audio/mpeg';
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* WAVE file format, based on RIFF.
|
|
280
|
+
* @public
|
|
281
|
+
*/
|
|
282
|
+
export class WaveInputFormat extends InputFormat {
|
|
283
|
+
/** @internal */
|
|
284
|
+
async _canReadInput(input: Input) {
|
|
285
|
+
const sourceSize = await input._mainReader.source.getSize();
|
|
286
|
+
if (sourceSize < 12) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const riffReader = new RiffReader(input._mainReader);
|
|
291
|
+
const riffType = riffReader.readAscii(4);
|
|
292
|
+
if (riffType !== 'RIFF' && riffType !== 'RIFX') {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
riffReader.pos = 8;
|
|
297
|
+
const format = riffReader.readAscii(4);
|
|
298
|
+
return format === 'WAVE';
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** @internal */
|
|
302
|
+
_createDemuxer(input: Input) {
|
|
303
|
+
return new WaveDemuxer(input);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
get name() {
|
|
307
|
+
return 'WAVE';
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
get mimeType() {
|
|
311
|
+
return 'audio/wav';
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Ogg file format.
|
|
317
|
+
* @public
|
|
318
|
+
*/
|
|
319
|
+
export class OggInputFormat extends InputFormat {
|
|
320
|
+
/** @internal */
|
|
321
|
+
async _canReadInput(input: Input) {
|
|
322
|
+
const sourceSize = await input._mainReader.source.getSize();
|
|
323
|
+
if (sourceSize < 4) {
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const oggReader = new OggReader(input._mainReader);
|
|
328
|
+
return oggReader.readAscii(4) === 'OggS';
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** @internal */
|
|
332
|
+
_createDemuxer(input: Input) {
|
|
333
|
+
return new OggDemuxer(input);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
get name() {
|
|
337
|
+
return 'Ogg';
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
get mimeType() {
|
|
341
|
+
return 'application/ogg';
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* MP4 input format singleton.
|
|
347
|
+
* @public
|
|
348
|
+
*/
|
|
349
|
+
export const MP4 = new Mp4InputFormat();
|
|
350
|
+
/**
|
|
351
|
+
* QuickTime File Format input format singleton.
|
|
352
|
+
* @public
|
|
353
|
+
*/
|
|
354
|
+
export const QTFF = new QuickTimeInputFormat();
|
|
355
|
+
/**
|
|
356
|
+
* Matroska input format singleton.
|
|
357
|
+
* @public
|
|
358
|
+
*/
|
|
359
|
+
export const MATROSKA = new MatroskaInputFormat();
|
|
360
|
+
/**
|
|
361
|
+
* WebM input format singleton.
|
|
362
|
+
* @public
|
|
363
|
+
*/
|
|
364
|
+
export const WEBM = new WebMInputFormat();
|
|
365
|
+
/**
|
|
366
|
+
* MP3 input format singleton.
|
|
367
|
+
* @public
|
|
368
|
+
*/
|
|
369
|
+
export const MP3 = new Mp3InputFormat();
|
|
370
|
+
/**
|
|
371
|
+
* WAVE input format singleton.
|
|
372
|
+
* @public
|
|
373
|
+
*/
|
|
374
|
+
export const WAVE = new WaveInputFormat();
|
|
375
|
+
/**
|
|
376
|
+
* Ogg input format singleton.
|
|
377
|
+
* @public
|
|
378
|
+
*/
|
|
379
|
+
export const OGG = new OggInputFormat();
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* List of all input format singletons. If you don't need to support all input formats, you should specify the
|
|
383
|
+
* formats individually for better tree shaking.
|
|
384
|
+
* @public
|
|
385
|
+
*/
|
|
386
|
+
export const ALL_FORMATS: InputFormat[] = [MP4, QTFF, MATROSKA, WEBM, WAVE, OGG, MP3];
|