@kenzuya/mediabunny 1.26.0 → 1.28.6
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 +1 -1
- package/dist/bundles/{mediabunny.mjs → mediabunny.js} +21963 -21390
- package/dist/bundles/mediabunny.min.js +490 -0
- package/dist/modules/shared/mp3-misc.d.ts.map +1 -1
- package/dist/modules/src/adts/adts-demuxer.d.ts +6 -6
- package/dist/modules/src/adts/adts-demuxer.d.ts.map +1 -1
- package/dist/modules/src/adts/adts-muxer.d.ts +4 -4
- package/dist/modules/src/adts/adts-muxer.d.ts.map +1 -1
- package/dist/modules/src/adts/adts-reader.d.ts +1 -1
- package/dist/modules/src/adts/adts-reader.d.ts.map +1 -1
- package/dist/modules/src/avi/avi-demuxer.d.ts +44 -0
- package/dist/modules/src/avi/avi-demuxer.d.ts.map +1 -0
- package/dist/modules/src/avi/avi-misc.d.ts +88 -0
- package/dist/modules/src/avi/avi-misc.d.ts.map +1 -0
- package/dist/modules/src/avi/avi-muxer.d.ts +45 -0
- package/dist/modules/src/avi/avi-muxer.d.ts.map +1 -0
- package/dist/modules/src/avi/riff-writer.d.ts +26 -0
- package/dist/modules/src/avi/riff-writer.d.ts.map +1 -0
- package/dist/modules/src/codec-data.d.ts +8 -3
- package/dist/modules/src/codec-data.d.ts.map +1 -1
- package/dist/modules/src/codec.d.ts +10 -10
- package/dist/modules/src/codec.d.ts.map +1 -1
- package/dist/modules/src/conversion.d.ts +33 -16
- package/dist/modules/src/conversion.d.ts.map +1 -1
- package/dist/modules/src/custom-coder.d.ts +8 -8
- package/dist/modules/src/custom-coder.d.ts.map +1 -1
- package/dist/modules/src/demuxer.d.ts +3 -3
- package/dist/modules/src/demuxer.d.ts.map +1 -1
- package/dist/modules/src/encode.d.ts +8 -8
- package/dist/modules/src/encode.d.ts.map +1 -1
- package/dist/modules/src/flac/flac-demuxer.d.ts +7 -7
- package/dist/modules/src/flac/flac-demuxer.d.ts.map +1 -1
- package/dist/modules/src/flac/flac-misc.d.ts +3 -3
- package/dist/modules/src/flac/flac-misc.d.ts.map +1 -1
- package/dist/modules/src/flac/flac-muxer.d.ts +5 -5
- package/dist/modules/src/flac/flac-muxer.d.ts.map +1 -1
- package/dist/modules/src/id3.d.ts +3 -3
- package/dist/modules/src/id3.d.ts.map +1 -1
- package/dist/modules/src/index.d.ts +20 -20
- package/dist/modules/src/index.d.ts.map +1 -1
- package/dist/modules/src/input-format.d.ts +22 -0
- package/dist/modules/src/input-format.d.ts.map +1 -1
- package/dist/modules/src/input-track.d.ts +8 -8
- package/dist/modules/src/input-track.d.ts.map +1 -1
- package/dist/modules/src/input.d.ts +12 -12
- package/dist/modules/src/isobmff/isobmff-boxes.d.ts +2 -2
- package/dist/modules/src/isobmff/isobmff-boxes.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts +12 -12
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-misc.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-muxer.d.ts +11 -11
- package/dist/modules/src/isobmff/isobmff-muxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-reader.d.ts +2 -2
- package/dist/modules/src/isobmff/isobmff-reader.d.ts.map +1 -1
- package/dist/modules/src/matroska/ebml.d.ts +3 -3
- package/dist/modules/src/matroska/ebml.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-demuxer.d.ts +13 -13
- package/dist/modules/src/matroska/matroska-demuxer.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-input.d.ts +33 -0
- package/dist/modules/src/matroska/matroska-input.d.ts.map +1 -0
- package/dist/modules/src/matroska/matroska-misc.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-muxer.d.ts +5 -5
- package/dist/modules/src/matroska/matroska-muxer.d.ts.map +1 -1
- package/dist/modules/src/media-sink.d.ts +5 -5
- package/dist/modules/src/media-sink.d.ts.map +1 -1
- package/dist/modules/src/media-source.d.ts +22 -4
- package/dist/modules/src/media-source.d.ts.map +1 -1
- package/dist/modules/src/metadata.d.ts +2 -2
- package/dist/modules/src/metadata.d.ts.map +1 -1
- package/dist/modules/src/misc.d.ts +5 -4
- package/dist/modules/src/misc.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-demuxer.d.ts +7 -7
- package/dist/modules/src/mp3/mp3-demuxer.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-muxer.d.ts +4 -4
- package/dist/modules/src/mp3/mp3-muxer.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-reader.d.ts +2 -2
- package/dist/modules/src/mp3/mp3-reader.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-writer.d.ts +1 -1
- package/dist/modules/src/mp3/mp3-writer.d.ts.map +1 -1
- package/dist/modules/src/muxer.d.ts +4 -4
- package/dist/modules/src/muxer.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-demuxer.d.ts +7 -7
- package/dist/modules/src/ogg/ogg-demuxer.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-misc.d.ts +1 -1
- package/dist/modules/src/ogg/ogg-misc.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-muxer.d.ts +5 -5
- package/dist/modules/src/ogg/ogg-muxer.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-reader.d.ts +1 -1
- package/dist/modules/src/ogg/ogg-reader.d.ts.map +1 -1
- package/dist/modules/src/output-format.d.ts +51 -6
- package/dist/modules/src/output-format.d.ts.map +1 -1
- package/dist/modules/src/output.d.ts +13 -13
- package/dist/modules/src/output.d.ts.map +1 -1
- package/dist/modules/src/packet.d.ts +1 -1
- package/dist/modules/src/packet.d.ts.map +1 -1
- package/dist/modules/src/pcm.d.ts.map +1 -1
- package/dist/modules/src/reader.d.ts +2 -2
- package/dist/modules/src/reader.d.ts.map +1 -1
- package/dist/modules/src/sample.d.ts +57 -15
- package/dist/modules/src/sample.d.ts.map +1 -1
- package/dist/modules/src/source.d.ts +3 -3
- package/dist/modules/src/source.d.ts.map +1 -1
- package/dist/modules/src/subtitles.d.ts +1 -1
- package/dist/modules/src/subtitles.d.ts.map +1 -1
- package/dist/modules/src/target.d.ts +2 -2
- package/dist/modules/src/target.d.ts.map +1 -1
- package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
- package/dist/modules/src/wave/riff-writer.d.ts +1 -1
- package/dist/modules/src/wave/riff-writer.d.ts.map +1 -1
- package/dist/modules/src/wave/wave-demuxer.d.ts +6 -6
- package/dist/modules/src/wave/wave-demuxer.d.ts.map +1 -1
- package/dist/modules/src/wave/wave-muxer.d.ts +4 -4
- package/dist/modules/src/wave/wave-muxer.d.ts.map +1 -1
- package/dist/modules/src/writer.d.ts +1 -1
- package/dist/modules/src/writer.d.ts.map +1 -1
- package/dist/packages/eac3/eac3.wasm +0 -0
- package/dist/packages/eac3/mediabunny-eac3.js +1058 -0
- package/dist/packages/eac3/mediabunny-eac3.min.js +44 -0
- package/dist/packages/mp3-encoder/mediabunny-mp3-encoder.js +694 -0
- package/dist/packages/mp3-encoder/mediabunny-mp3-encoder.min.js +58 -0
- package/dist/packages/mpeg4/mediabunny-mpeg4.js +1198 -0
- package/dist/packages/mpeg4/mediabunny-mpeg4.min.js +44 -0
- package/dist/packages/mpeg4/xvid.wasm +0 -0
- package/package.json +18 -57
- package/dist/bundles/mediabunny.cjs +0 -26140
- package/dist/bundles/mediabunny.min.cjs +0 -147
- package/dist/bundles/mediabunny.min.mjs +0 -146
- package/dist/mediabunny.d.ts +0 -3319
- package/dist/modules/shared/mp3-misc.js +0 -147
- package/dist/modules/src/adts/adts-demuxer.js +0 -239
- package/dist/modules/src/adts/adts-muxer.js +0 -80
- package/dist/modules/src/adts/adts-reader.js +0 -63
- package/dist/modules/src/codec-data.js +0 -1730
- package/dist/modules/src/codec.js +0 -869
- package/dist/modules/src/conversion.js +0 -1459
- package/dist/modules/src/custom-coder.js +0 -117
- package/dist/modules/src/demuxer.js +0 -12
- package/dist/modules/src/encode.js +0 -442
- package/dist/modules/src/flac/flac-demuxer.js +0 -504
- package/dist/modules/src/flac/flac-misc.js +0 -135
- package/dist/modules/src/flac/flac-muxer.js +0 -222
- package/dist/modules/src/id3.js +0 -848
- package/dist/modules/src/index.js +0 -28
- package/dist/modules/src/input-format.js +0 -480
- package/dist/modules/src/input-track.js +0 -372
- package/dist/modules/src/input.js +0 -188
- package/dist/modules/src/isobmff/isobmff-boxes.js +0 -1480
- package/dist/modules/src/isobmff/isobmff-demuxer.js +0 -2618
- package/dist/modules/src/isobmff/isobmff-misc.js +0 -20
- package/dist/modules/src/isobmff/isobmff-muxer.js +0 -966
- package/dist/modules/src/isobmff/isobmff-reader.js +0 -72
- package/dist/modules/src/matroska/ebml.js +0 -653
- package/dist/modules/src/matroska/matroska-demuxer.js +0 -2133
- package/dist/modules/src/matroska/matroska-misc.js +0 -20
- package/dist/modules/src/matroska/matroska-muxer.js +0 -1017
- package/dist/modules/src/media-sink.js +0 -1736
- package/dist/modules/src/media-source.js +0 -1825
- package/dist/modules/src/metadata.js +0 -193
- package/dist/modules/src/misc.js +0 -623
- package/dist/modules/src/mp3/mp3-demuxer.js +0 -285
- package/dist/modules/src/mp3/mp3-muxer.js +0 -123
- package/dist/modules/src/mp3/mp3-reader.js +0 -26
- package/dist/modules/src/mp3/mp3-writer.js +0 -78
- package/dist/modules/src/muxer.js +0 -50
- package/dist/modules/src/node.d.ts +0 -9
- package/dist/modules/src/node.d.ts.map +0 -1
- package/dist/modules/src/node.js +0 -9
- package/dist/modules/src/ogg/ogg-demuxer.js +0 -763
- package/dist/modules/src/ogg/ogg-misc.js +0 -78
- package/dist/modules/src/ogg/ogg-muxer.js +0 -353
- package/dist/modules/src/ogg/ogg-reader.js +0 -65
- package/dist/modules/src/output-format.js +0 -527
- package/dist/modules/src/output.js +0 -300
- package/dist/modules/src/packet.js +0 -182
- package/dist/modules/src/pcm.js +0 -85
- package/dist/modules/src/reader.js +0 -236
- package/dist/modules/src/sample.js +0 -1056
- package/dist/modules/src/source.js +0 -1182
- package/dist/modules/src/subtitles.js +0 -575
- package/dist/modules/src/target.js +0 -140
- package/dist/modules/src/wave/riff-writer.js +0 -30
- package/dist/modules/src/wave/wave-demuxer.js +0 -447
- package/dist/modules/src/wave/wave-muxer.js +0 -318
- package/dist/modules/src/writer.js +0 -370
- package/src/adts/adts-demuxer.ts +0 -331
- package/src/adts/adts-muxer.ts +0 -111
- package/src/adts/adts-reader.ts +0 -85
- package/src/codec-data.ts +0 -2078
- package/src/codec.ts +0 -1092
- package/src/conversion.ts +0 -2112
- package/src/custom-coder.ts +0 -197
- package/src/demuxer.ts +0 -24
- package/src/encode.ts +0 -739
- package/src/flac/flac-demuxer.ts +0 -730
- package/src/flac/flac-misc.ts +0 -164
- package/src/flac/flac-muxer.ts +0 -320
- package/src/id3.ts +0 -925
- package/src/index.ts +0 -221
- package/src/input-format.ts +0 -541
- package/src/input-track.ts +0 -529
- package/src/input.ts +0 -235
- package/src/isobmff/isobmff-boxes.ts +0 -1719
- package/src/isobmff/isobmff-demuxer.ts +0 -3190
- package/src/isobmff/isobmff-misc.ts +0 -29
- package/src/isobmff/isobmff-muxer.ts +0 -1348
- package/src/isobmff/isobmff-reader.ts +0 -91
- package/src/matroska/ebml.ts +0 -730
- package/src/matroska/matroska-demuxer.ts +0 -2481
- package/src/matroska/matroska-misc.ts +0 -29
- package/src/matroska/matroska-muxer.ts +0 -1276
- package/src/media-sink.ts +0 -2179
- package/src/media-source.ts +0 -2243
- package/src/metadata.ts +0 -320
- package/src/misc.ts +0 -798
- package/src/mp3/mp3-demuxer.ts +0 -383
- package/src/mp3/mp3-muxer.ts +0 -166
- package/src/mp3/mp3-reader.ts +0 -34
- package/src/mp3/mp3-writer.ts +0 -120
- package/src/muxer.ts +0 -88
- package/src/node.ts +0 -11
- package/src/ogg/ogg-demuxer.ts +0 -1053
- package/src/ogg/ogg-misc.ts +0 -116
- package/src/ogg/ogg-muxer.ts +0 -497
- package/src/ogg/ogg-reader.ts +0 -93
- package/src/output-format.ts +0 -945
- package/src/output.ts +0 -488
- package/src/packet.ts +0 -263
- package/src/pcm.ts +0 -112
- package/src/reader.ts +0 -323
- package/src/sample.ts +0 -1461
- package/src/source.ts +0 -1688
- package/src/subtitles.ts +0 -711
- package/src/target.ts +0 -204
- package/src/tsconfig.json +0 -16
- package/src/wave/riff-writer.ts +0 -36
- package/src/wave/wave-demuxer.ts +0 -529
- package/src/wave/wave-muxer.ts +0 -371
- package/src/writer.ts +0 -490
package/src/flac/flac-misc.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
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 { assert, assertNever, Bitstream } from '../misc';
|
|
10
|
-
import { FileSlice, readBytes, readU16Be, readU8 } from '../reader';
|
|
11
|
-
|
|
12
|
-
type BlockSizeOrUncommon = number | 'uncommon-u16' | 'uncommon-u8';
|
|
13
|
-
type SampleRateOrUncommon =
|
|
14
|
-
| number
|
|
15
|
-
| 'uncommon-u8'
|
|
16
|
-
| 'uncommon-u16'
|
|
17
|
-
| 'uncommon-u16-10';
|
|
18
|
-
|
|
19
|
-
// https://www.rfc-editor.org/rfc/rfc9639.html#name-block-size-bits
|
|
20
|
-
export const getBlockSizeOrUncommon = (bits: number): BlockSizeOrUncommon | null => {
|
|
21
|
-
if (bits === 0b0000) {
|
|
22
|
-
return null;
|
|
23
|
-
} else if (bits === 0b0001) {
|
|
24
|
-
return 192;
|
|
25
|
-
} else if (bits >= 0b0010 && bits <= 0b0101) {
|
|
26
|
-
return 144 * 2 ** bits;
|
|
27
|
-
} else if (bits === 0b0110) {
|
|
28
|
-
return 'uncommon-u8';
|
|
29
|
-
} else if (bits === 0b0111) {
|
|
30
|
-
return 'uncommon-u16';
|
|
31
|
-
} else if (bits >= 0b1000 && bits <= 0b1111) {
|
|
32
|
-
return 2 ** bits;
|
|
33
|
-
} else {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// https://www.rfc-editor.org/rfc/rfc9639.html#name-sample-rate-bits
|
|
39
|
-
export const getSampleRateOrUncommon = (
|
|
40
|
-
sampleRateBits: number,
|
|
41
|
-
streamInfoSampleRate: number,
|
|
42
|
-
): SampleRateOrUncommon | null => {
|
|
43
|
-
switch (sampleRateBits) {
|
|
44
|
-
case 0b0000: return streamInfoSampleRate;
|
|
45
|
-
case 0b0001: return 88200;
|
|
46
|
-
case 0b0010: return 176400;
|
|
47
|
-
case 0b0011: return 192000;
|
|
48
|
-
case 0b0100: return 8000;
|
|
49
|
-
case 0b0101: return 16000;
|
|
50
|
-
case 0b0110: return 22050;
|
|
51
|
-
case 0b0111: return 24000;
|
|
52
|
-
case 0b1000: return 32000;
|
|
53
|
-
case 0b1001: return 44100;
|
|
54
|
-
case 0b1010: return 48000;
|
|
55
|
-
case 0b1011: return 96000;
|
|
56
|
-
case 0b1100: return 'uncommon-u8';
|
|
57
|
-
case 0b1101: return 'uncommon-u16';
|
|
58
|
-
case 0b1110: return 'uncommon-u16-10';
|
|
59
|
-
default: return null;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// https://www.rfc-editor.org/rfc/rfc9639.html#name-coded-number
|
|
64
|
-
export const readCodedNumber = (fileSlice: FileSlice): number => {
|
|
65
|
-
let ones = 0;
|
|
66
|
-
|
|
67
|
-
const bitstream1 = new Bitstream(readBytes(fileSlice, 1));
|
|
68
|
-
while (bitstream1.readBits(1) === 1) {
|
|
69
|
-
ones++;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (ones === 0) {
|
|
73
|
-
return bitstream1.readBits(7);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const bitArray: number[] = [];
|
|
77
|
-
const extraBytes = ones - 1;
|
|
78
|
-
const bitstream2 = new Bitstream(readBytes(fileSlice, extraBytes));
|
|
79
|
-
|
|
80
|
-
const firstByteBits = 8 - ones - 1;
|
|
81
|
-
for (let i = 0; i < firstByteBits; i++) {
|
|
82
|
-
bitArray.unshift(bitstream1.readBits(1));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
for (let i = 0; i < extraBytes; i++) {
|
|
86
|
-
for (let j = 0; j < 8; j++) {
|
|
87
|
-
const val = bitstream2.readBits(1);
|
|
88
|
-
if (j < 2) {
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
bitArray.unshift(val);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const encoded = bitArray.reduce((acc, bit, index) => {
|
|
97
|
-
return acc | (bit << index);
|
|
98
|
-
}, 0);
|
|
99
|
-
|
|
100
|
-
return encoded;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
export const readBlockSize = (
|
|
104
|
-
slice: FileSlice,
|
|
105
|
-
blockSizeBits: BlockSizeOrUncommon,
|
|
106
|
-
) => {
|
|
107
|
-
if (blockSizeBits === 'uncommon-u16') {
|
|
108
|
-
return readU16Be(slice) + 1;
|
|
109
|
-
} else if (blockSizeBits === 'uncommon-u8') {
|
|
110
|
-
return readU8(slice) + 1;
|
|
111
|
-
} else if (typeof blockSizeBits === 'number') {
|
|
112
|
-
return blockSizeBits;
|
|
113
|
-
} else {
|
|
114
|
-
assertNever(blockSizeBits);
|
|
115
|
-
assert(false);
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
export const readSampleRate = (
|
|
120
|
-
slice: FileSlice,
|
|
121
|
-
sampleRateOrUncommon: SampleRateOrUncommon,
|
|
122
|
-
) => {
|
|
123
|
-
if (sampleRateOrUncommon === 'uncommon-u16') {
|
|
124
|
-
return readU16Be(slice);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (sampleRateOrUncommon === 'uncommon-u16-10') {
|
|
128
|
-
return readU16Be(slice) * 10;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (sampleRateOrUncommon === 'uncommon-u8') {
|
|
132
|
-
return readU8(slice);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (typeof sampleRateOrUncommon === 'number') {
|
|
136
|
-
return sampleRateOrUncommon;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return null;
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
// https://www.rfc-editor.org/rfc/rfc9639.html#section-9.1.1
|
|
143
|
-
export const calculateCrc8 = (data: Uint8Array) => {
|
|
144
|
-
const polynomial = 0x07; // x^8 + x^2 + x^1 + x^0
|
|
145
|
-
let crc = 0x00; // Initialize CRC to 0
|
|
146
|
-
|
|
147
|
-
for (const byte of data) {
|
|
148
|
-
crc ^= byte; // XOR byte into least significant byte of crc
|
|
149
|
-
|
|
150
|
-
for (let i = 0; i < 8; i++) {
|
|
151
|
-
// For each bit in the byte
|
|
152
|
-
if ((crc & 0x80) !== 0) {
|
|
153
|
-
// If the leftmost bit (MSB) is set
|
|
154
|
-
crc = (crc << 1) ^ polynomial; // Shift left and XOR with polynomial
|
|
155
|
-
} else {
|
|
156
|
-
crc <<= 1; // Just shift left
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
crc &= 0xff; // Ensure CRC remains 8-bit
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return crc;
|
|
164
|
-
};
|
package/src/flac/flac-muxer.ts
DELETED
|
@@ -1,320 +0,0 @@
|
|
|
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 { validateAudioChunkMetadata } from '../codec';
|
|
10
|
-
import { createVorbisComments, FlacBlockType } from '../codec-data';
|
|
11
|
-
import {
|
|
12
|
-
assert,
|
|
13
|
-
Bitstream,
|
|
14
|
-
textEncoder,
|
|
15
|
-
toDataView,
|
|
16
|
-
toUint8Array,
|
|
17
|
-
} from '../misc';
|
|
18
|
-
import { Muxer } from '../muxer';
|
|
19
|
-
import { Output, OutputAudioTrack } from '../output';
|
|
20
|
-
import { FlacOutputFormat } from '../output-format';
|
|
21
|
-
import { EncodedPacket } from '../packet';
|
|
22
|
-
import { FileSlice, readBytes } from '../reader';
|
|
23
|
-
import { AttachedImage, metadataTagsAreEmpty } from '../metadata';
|
|
24
|
-
import { Writer } from '../writer';
|
|
25
|
-
import {
|
|
26
|
-
readBlockSize,
|
|
27
|
-
getBlockSizeOrUncommon,
|
|
28
|
-
readCodedNumber,
|
|
29
|
-
} from './flac-misc';
|
|
30
|
-
|
|
31
|
-
const FLAC_HEADER = /* #__PURE__ */ new Uint8Array([0x66, 0x4c, 0x61, 0x43]); // 'fLaC'
|
|
32
|
-
const STREAMINFO_SIZE = 38;
|
|
33
|
-
const STREAMINFO_BLOCK_SIZE = 34;
|
|
34
|
-
|
|
35
|
-
export class FlacMuxer extends Muxer {
|
|
36
|
-
private writer: Writer;
|
|
37
|
-
private metadataWritten = false;
|
|
38
|
-
|
|
39
|
-
private blockSizes: number[] = [];
|
|
40
|
-
private frameSizes: number[] = [];
|
|
41
|
-
|
|
42
|
-
private sampleRate: number | null = null;
|
|
43
|
-
private channels: number | null = null;
|
|
44
|
-
private bitsPerSample: number | null = null;
|
|
45
|
-
|
|
46
|
-
private format: FlacOutputFormat;
|
|
47
|
-
|
|
48
|
-
constructor(output: Output, format: FlacOutputFormat) {
|
|
49
|
-
super(output);
|
|
50
|
-
|
|
51
|
-
this.writer = output._writer;
|
|
52
|
-
this.format = format;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async start() {
|
|
56
|
-
this.writer.write(FLAC_HEADER);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
writeHeader({
|
|
60
|
-
bitsPerSample,
|
|
61
|
-
minimumBlockSize,
|
|
62
|
-
maximumBlockSize,
|
|
63
|
-
minimumFrameSize,
|
|
64
|
-
maximumFrameSize,
|
|
65
|
-
sampleRate,
|
|
66
|
-
channels,
|
|
67
|
-
totalSamples,
|
|
68
|
-
}: {
|
|
69
|
-
minimumBlockSize: number;
|
|
70
|
-
maximumBlockSize: number;
|
|
71
|
-
minimumFrameSize: number;
|
|
72
|
-
maximumFrameSize: number;
|
|
73
|
-
sampleRate: number;
|
|
74
|
-
channels: number;
|
|
75
|
-
bitsPerSample: number;
|
|
76
|
-
totalSamples: number;
|
|
77
|
-
}) {
|
|
78
|
-
assert(this.writer.getPos() === 4);
|
|
79
|
-
|
|
80
|
-
const hasMetadata = !metadataTagsAreEmpty(this.output._metadataTags);
|
|
81
|
-
const headerBitstream = new Bitstream(new Uint8Array(4));
|
|
82
|
-
headerBitstream.writeBits(1, Number(!hasMetadata)); // isLastMetadata
|
|
83
|
-
headerBitstream.writeBits(7, FlacBlockType.STREAMINFO); // metaBlockType = streaminfo
|
|
84
|
-
headerBitstream.writeBits(24, STREAMINFO_BLOCK_SIZE); // size
|
|
85
|
-
this.writer.write(headerBitstream.bytes);
|
|
86
|
-
|
|
87
|
-
const contentBitstream = new Bitstream(new Uint8Array(18));
|
|
88
|
-
|
|
89
|
-
contentBitstream.writeBits(16, minimumBlockSize);
|
|
90
|
-
contentBitstream.writeBits(16, maximumBlockSize);
|
|
91
|
-
contentBitstream.writeBits(24, minimumFrameSize);
|
|
92
|
-
contentBitstream.writeBits(24, maximumFrameSize);
|
|
93
|
-
contentBitstream.writeBits(20, sampleRate);
|
|
94
|
-
contentBitstream.writeBits(3, channels - 1);
|
|
95
|
-
contentBitstream.writeBits(5, bitsPerSample - 1);
|
|
96
|
-
|
|
97
|
-
// Bitstream operations are only safe until 32bit, breaks when using 36 bits
|
|
98
|
-
// Splitting up into writing 4 0 bits and then 32 bits is safe
|
|
99
|
-
// This is safe for audio up to (2 ** 32 / 44100 / 3600) -> 27 hours
|
|
100
|
-
// Not implementing support for more than 32 bits now
|
|
101
|
-
if (totalSamples >= 2 ** 32) {
|
|
102
|
-
throw new Error('This muxer only supports writing up to 2 ** 32 samples');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
contentBitstream.writeBits(4, 0);
|
|
106
|
-
contentBitstream.writeBits(32, totalSamples);
|
|
107
|
-
this.writer.write(contentBitstream.bytes);
|
|
108
|
-
// The MD5 hash is calculated from decoded audio data, but we do not have access
|
|
109
|
-
// to it here. We are allowed to set 0:
|
|
110
|
-
// "A value of 0 signifies that the value is not known."
|
|
111
|
-
// https://www.rfc-editor.org/rfc/rfc9639.html#name-streaminfo
|
|
112
|
-
this.writer.write(new Uint8Array(16));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
writePictureBlock(picture: AttachedImage) {
|
|
116
|
-
// Header size:
|
|
117
|
-
// 4 bytes: picture type
|
|
118
|
-
// 4 bytes: media type length
|
|
119
|
-
// x bytes: media type
|
|
120
|
-
// 4 bytes: description length
|
|
121
|
-
// y bytes: description
|
|
122
|
-
// 1 bytes: width
|
|
123
|
-
// 1 bytes: height
|
|
124
|
-
// 1 bytes: color depth
|
|
125
|
-
// 1 bytes: number of indexed colors
|
|
126
|
-
// 4 bytes: picture data length
|
|
127
|
-
// z bytes: picture data
|
|
128
|
-
// Total: 20 + x + y + z
|
|
129
|
-
const headerSize
|
|
130
|
-
= 32
|
|
131
|
-
+ picture.mimeType.length
|
|
132
|
-
+ (picture.description?.length ?? 0)
|
|
133
|
-
+ picture.data.length;
|
|
134
|
-
|
|
135
|
-
const header = new Uint8Array(headerSize);
|
|
136
|
-
|
|
137
|
-
let offset = 0;
|
|
138
|
-
const dataView = toDataView(header);
|
|
139
|
-
dataView.setUint32(
|
|
140
|
-
offset,
|
|
141
|
-
picture.kind === 'coverFront' ? 3 : picture.kind === 'coverBack' ? 4 : 0,
|
|
142
|
-
);
|
|
143
|
-
offset += 4;
|
|
144
|
-
dataView.setUint32(offset, picture.mimeType.length);
|
|
145
|
-
offset += 4;
|
|
146
|
-
header.set(textEncoder.encode(picture.mimeType), 8);
|
|
147
|
-
offset += picture.mimeType.length;
|
|
148
|
-
dataView.setUint32(offset, picture.description?.length ?? 0);
|
|
149
|
-
offset += 4;
|
|
150
|
-
header.set(textEncoder.encode(picture.description ?? ''), offset);
|
|
151
|
-
offset += picture.description?.length ?? 0;
|
|
152
|
-
offset += 4 + 4 + 4 + 4; // setting width, height, color depth, number of indexed colors to 0
|
|
153
|
-
dataView.setUint32(offset, picture.data.length);
|
|
154
|
-
offset += 4;
|
|
155
|
-
header.set(picture.data, offset);
|
|
156
|
-
offset += picture.data.length;
|
|
157
|
-
assert(offset === headerSize);
|
|
158
|
-
|
|
159
|
-
const headerBitstream = new Bitstream(new Uint8Array(4));
|
|
160
|
-
headerBitstream.writeBits(1, 0); // Last metadata block -> false, will be continued by vorbis comment
|
|
161
|
-
headerBitstream.writeBits(7, FlacBlockType.PICTURE); // Type -> Picture
|
|
162
|
-
headerBitstream.writeBits(24, headerSize);
|
|
163
|
-
this.writer.write(headerBitstream.bytes);
|
|
164
|
-
this.writer.write(header);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
writeVorbisCommentAndPictureBlock() {
|
|
168
|
-
this.writer.seek(STREAMINFO_SIZE + FLAC_HEADER.byteLength);
|
|
169
|
-
if (metadataTagsAreEmpty(this.output._metadataTags)) {
|
|
170
|
-
this.metadataWritten = true;
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const pictures = this.output._metadataTags.images ?? [];
|
|
175
|
-
for (const picture of pictures) {
|
|
176
|
-
this.writePictureBlock(picture);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const vorbisComment = createVorbisComments(
|
|
180
|
-
new Uint8Array(0),
|
|
181
|
-
this.output._metadataTags,
|
|
182
|
-
false,
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
const headerBitstream = new Bitstream(new Uint8Array(4));
|
|
186
|
-
headerBitstream.writeBits(1, 1); // Last metadata block -> true
|
|
187
|
-
headerBitstream.writeBits(7, FlacBlockType.VORBIS_COMMENT); // Type -> Vorbis comment
|
|
188
|
-
headerBitstream.writeBits(24, vorbisComment.length);
|
|
189
|
-
this.writer.write(headerBitstream.bytes);
|
|
190
|
-
this.writer.write(vorbisComment);
|
|
191
|
-
|
|
192
|
-
this.metadataWritten = true;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async getMimeType() {
|
|
196
|
-
return 'audio/flac';
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
async addEncodedVideoPacket() {
|
|
200
|
-
throw new Error('FLAC does not support video.');
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
async addEncodedAudioPacket(
|
|
204
|
-
track: OutputAudioTrack,
|
|
205
|
-
packet: EncodedPacket,
|
|
206
|
-
meta?: EncodedAudioChunkMetadata,
|
|
207
|
-
): Promise<void> {
|
|
208
|
-
const release = await this.mutex.acquire();
|
|
209
|
-
|
|
210
|
-
validateAudioChunkMetadata(meta);
|
|
211
|
-
|
|
212
|
-
assert(meta);
|
|
213
|
-
assert(meta.decoderConfig);
|
|
214
|
-
assert(meta.decoderConfig.description);
|
|
215
|
-
|
|
216
|
-
try {
|
|
217
|
-
this.validateAndNormalizeTimestamp(
|
|
218
|
-
track,
|
|
219
|
-
packet.timestamp,
|
|
220
|
-
packet.type === 'key',
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
if (this.sampleRate === null) {
|
|
224
|
-
this.sampleRate = meta.decoderConfig.sampleRate;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (this.channels === null) {
|
|
228
|
-
this.channels = meta.decoderConfig.numberOfChannels;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (this.bitsPerSample === null) {
|
|
232
|
-
const descriptionBitstream = new Bitstream(
|
|
233
|
-
toUint8Array(meta.decoderConfig.description),
|
|
234
|
-
);
|
|
235
|
-
// skip 'fLaC' + block size + frame size + sample rate + number of channels
|
|
236
|
-
// See demuxer for the exact structure
|
|
237
|
-
descriptionBitstream.skipBits(103 + 64);
|
|
238
|
-
const bitsPerSample = descriptionBitstream.readBits(5) + 1;
|
|
239
|
-
this.bitsPerSample = bitsPerSample;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (!this.metadataWritten) {
|
|
243
|
-
this.writeVorbisCommentAndPictureBlock();
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const slice = FileSlice.tempFromBytes(packet.data);
|
|
247
|
-
readBytes(slice, 2);
|
|
248
|
-
const bytes = readBytes(slice, 2);
|
|
249
|
-
const bitstream = new Bitstream(bytes);
|
|
250
|
-
const blockSizeOrUncommon = getBlockSizeOrUncommon(bitstream.readBits(4));
|
|
251
|
-
if (blockSizeOrUncommon === null) {
|
|
252
|
-
throw new Error('Invalid FLAC frame: Invalid block size.');
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
readCodedNumber(slice); // num
|
|
256
|
-
const blockSize = readBlockSize(slice, blockSizeOrUncommon);
|
|
257
|
-
|
|
258
|
-
this.blockSizes.push(blockSize);
|
|
259
|
-
this.frameSizes.push(packet.data.length);
|
|
260
|
-
|
|
261
|
-
const startPos = this.writer.getPos();
|
|
262
|
-
this.writer.write(packet.data);
|
|
263
|
-
|
|
264
|
-
if (this.format._options.onFrame) {
|
|
265
|
-
this.format._options.onFrame(packet.data, startPos);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
await this.writer.flush();
|
|
269
|
-
} finally {
|
|
270
|
-
release();
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
override addSubtitleCue(): Promise<void> {
|
|
275
|
-
throw new Error('FLAC does not support subtitles.');
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
async finalize(): Promise<void> {
|
|
279
|
-
const release = await this.mutex.acquire();
|
|
280
|
-
|
|
281
|
-
let minimumBlockSize = Infinity;
|
|
282
|
-
let maximumBlockSize = 0;
|
|
283
|
-
let minimumFrameSize = Infinity;
|
|
284
|
-
let maximumFrameSize = 0;
|
|
285
|
-
let totalSamples = 0;
|
|
286
|
-
for (let i = 0; i < this.blockSizes.length; i++) {
|
|
287
|
-
minimumFrameSize = Math.min(minimumFrameSize, this.frameSizes[i]!);
|
|
288
|
-
maximumFrameSize = Math.max(maximumFrameSize, this.frameSizes[i]!);
|
|
289
|
-
maximumBlockSize = Math.max(maximumBlockSize, this.blockSizes[i]!);
|
|
290
|
-
totalSamples += this.blockSizes[i]!;
|
|
291
|
-
|
|
292
|
-
// Excluding the last frame from block size calculation
|
|
293
|
-
// https://www.rfc-editor.org/rfc/rfc9639.html#name-streaminfo
|
|
294
|
-
// "The minimum block size (in samples) used in the stream, excluding the last block."
|
|
295
|
-
const isLastFrame = i === this.blockSizes.length - 1;
|
|
296
|
-
if (isLastFrame) {
|
|
297
|
-
continue;
|
|
298
|
-
}
|
|
299
|
-
minimumBlockSize = Math.min(minimumBlockSize, this.blockSizes[i]!);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
assert(this.sampleRate !== null);
|
|
303
|
-
assert(this.channels !== null);
|
|
304
|
-
assert(this.bitsPerSample !== null);
|
|
305
|
-
|
|
306
|
-
this.writer.seek(4);
|
|
307
|
-
this.writeHeader({
|
|
308
|
-
minimumBlockSize,
|
|
309
|
-
maximumBlockSize,
|
|
310
|
-
minimumFrameSize,
|
|
311
|
-
maximumFrameSize,
|
|
312
|
-
sampleRate: this.sampleRate,
|
|
313
|
-
channels: this.channels,
|
|
314
|
-
bitsPerSample: this.bitsPerSample,
|
|
315
|
-
totalSamples,
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
release();
|
|
319
|
-
}
|
|
320
|
-
}
|