@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
|
@@ -1,78 +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
|
-
import { parseOpusTocByte } from '../codec-data.js';
|
|
9
|
-
import { assert, ilog, toDataView } from '../misc.js';
|
|
10
|
-
export const OGGS = 0x5367674f; // 'OggS'
|
|
11
|
-
const OGG_CRC_POLYNOMIAL = 0x04c11db7;
|
|
12
|
-
const OGG_CRC_TABLE = new Uint32Array(256);
|
|
13
|
-
for (let n = 0; n < 256; n++) {
|
|
14
|
-
let crc = n << 24;
|
|
15
|
-
for (let k = 0; k < 8; k++) {
|
|
16
|
-
crc = (crc & 0x80000000)
|
|
17
|
-
? ((crc << 1) ^ OGG_CRC_POLYNOMIAL)
|
|
18
|
-
: (crc << 1);
|
|
19
|
-
}
|
|
20
|
-
OGG_CRC_TABLE[n] = (crc >>> 0) & 0xffffffff;
|
|
21
|
-
}
|
|
22
|
-
export const computeOggPageCrc = (bytes) => {
|
|
23
|
-
const view = toDataView(bytes);
|
|
24
|
-
const originalChecksum = view.getUint32(22, true);
|
|
25
|
-
view.setUint32(22, 0, true); // Zero out checksum field
|
|
26
|
-
let crc = 0;
|
|
27
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
28
|
-
const byte = bytes[i];
|
|
29
|
-
crc = ((crc << 8) ^ OGG_CRC_TABLE[(crc >>> 24) ^ byte]) >>> 0;
|
|
30
|
-
}
|
|
31
|
-
view.setUint32(22, originalChecksum, true); // Restore checksum field
|
|
32
|
-
return crc;
|
|
33
|
-
};
|
|
34
|
-
export const extractSampleMetadata = (data, codecInfo, vorbisLastBlocksize) => {
|
|
35
|
-
let durationInSamples = 0;
|
|
36
|
-
let currentBlocksize = null;
|
|
37
|
-
if (data.length > 0) {
|
|
38
|
-
// To know sample duration, we'll need to peak inside the packet
|
|
39
|
-
if (codecInfo.codec === 'vorbis') {
|
|
40
|
-
assert(codecInfo.vorbisInfo);
|
|
41
|
-
const vorbisModeCount = codecInfo.vorbisInfo.modeBlockflags.length;
|
|
42
|
-
const bitCount = ilog(vorbisModeCount - 1);
|
|
43
|
-
const modeMask = ((1 << bitCount) - 1) << 1;
|
|
44
|
-
const modeNumber = (data[0] & modeMask) >> 1;
|
|
45
|
-
if (modeNumber >= codecInfo.vorbisInfo.modeBlockflags.length) {
|
|
46
|
-
throw new Error('Invalid mode number.');
|
|
47
|
-
}
|
|
48
|
-
// In Vorbis, packet duration also depends on the blocksize of the previous packet
|
|
49
|
-
let prevBlocksize = vorbisLastBlocksize;
|
|
50
|
-
const blockflag = codecInfo.vorbisInfo.modeBlockflags[modeNumber];
|
|
51
|
-
currentBlocksize = codecInfo.vorbisInfo.blocksizes[blockflag];
|
|
52
|
-
if (blockflag === 1) {
|
|
53
|
-
const prevMask = (modeMask | 0x1) + 1;
|
|
54
|
-
const flag = data[0] & prevMask ? 1 : 0;
|
|
55
|
-
prevBlocksize = codecInfo.vorbisInfo.blocksizes[flag];
|
|
56
|
-
}
|
|
57
|
-
durationInSamples = prevBlocksize !== null
|
|
58
|
-
? (prevBlocksize + currentBlocksize) >> 2
|
|
59
|
-
: 0; // The first sample outputs no audio data and therefore has a duration of 0
|
|
60
|
-
}
|
|
61
|
-
else if (codecInfo.codec === 'opus') {
|
|
62
|
-
const toc = parseOpusTocByte(data);
|
|
63
|
-
durationInSamples = toc.durationInSamples;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
durationInSamples,
|
|
68
|
-
vorbisBlockSize: currentBlocksize,
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
export const buildOggMimeType = (info) => {
|
|
72
|
-
let string = 'audio/ogg';
|
|
73
|
-
if (info.codecStrings) {
|
|
74
|
-
const uniqueCodecMimeTypes = [...new Set(info.codecStrings)];
|
|
75
|
-
string += `; codecs="${uniqueCodecMimeTypes.join(', ')}"`;
|
|
76
|
-
}
|
|
77
|
-
return string;
|
|
78
|
-
};
|
|
@@ -1,353 +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
|
-
import { OPUS_SAMPLE_RATE, validateAudioChunkMetadata } from '../codec.js';
|
|
9
|
-
import { createVorbisComments, parseModesFromVorbisSetupPacket, parseOpusIdentificationHeader } from '../codec-data.js';
|
|
10
|
-
import { assert, promiseWithResolvers, setInt64, toDataView, toUint8Array, } from '../misc.js';
|
|
11
|
-
import { Muxer } from '../muxer.js';
|
|
12
|
-
import { buildOggMimeType, computeOggPageCrc, extractSampleMetadata, OGGS, } from './ogg-misc.js';
|
|
13
|
-
import { MAX_PAGE_SIZE } from './ogg-reader.js';
|
|
14
|
-
const PAGE_SIZE_TARGET = 8192;
|
|
15
|
-
export class OggMuxer extends Muxer {
|
|
16
|
-
constructor(output, format) {
|
|
17
|
-
super(output);
|
|
18
|
-
this.trackDatas = [];
|
|
19
|
-
this.bosPagesWritten = false;
|
|
20
|
-
this.allTracksKnown = promiseWithResolvers();
|
|
21
|
-
this.pageBytes = new Uint8Array(MAX_PAGE_SIZE);
|
|
22
|
-
this.pageView = new DataView(this.pageBytes.buffer);
|
|
23
|
-
this.format = format;
|
|
24
|
-
this.writer = output._writer;
|
|
25
|
-
this.writer.ensureMonotonicity = true; // Ogg is always monotonically written!
|
|
26
|
-
}
|
|
27
|
-
async start() {
|
|
28
|
-
// Nothin'
|
|
29
|
-
}
|
|
30
|
-
async getMimeType() {
|
|
31
|
-
await this.allTracksKnown.promise;
|
|
32
|
-
return buildOggMimeType({
|
|
33
|
-
codecStrings: this.trackDatas.map(x => x.codecInfo.codec),
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
addEncodedVideoPacket() {
|
|
37
|
-
throw new Error('Video tracks are not supported.');
|
|
38
|
-
}
|
|
39
|
-
getTrackData(track, meta) {
|
|
40
|
-
const existingTrackData = this.trackDatas.find(td => td.track === track);
|
|
41
|
-
if (existingTrackData) {
|
|
42
|
-
return existingTrackData;
|
|
43
|
-
}
|
|
44
|
-
// Give the track a unique random serial number
|
|
45
|
-
let serialNumber;
|
|
46
|
-
do {
|
|
47
|
-
serialNumber = Math.floor(2 ** 32 * Math.random());
|
|
48
|
-
} while (this.trackDatas.some(td => td.serialNumber === serialNumber));
|
|
49
|
-
assert(track.source._codec === 'vorbis' || track.source._codec === 'opus');
|
|
50
|
-
validateAudioChunkMetadata(meta);
|
|
51
|
-
assert(meta);
|
|
52
|
-
assert(meta.decoderConfig);
|
|
53
|
-
const newTrackData = {
|
|
54
|
-
track,
|
|
55
|
-
serialNumber,
|
|
56
|
-
internalSampleRate: track.source._codec === 'opus'
|
|
57
|
-
? OPUS_SAMPLE_RATE
|
|
58
|
-
: meta.decoderConfig.sampleRate,
|
|
59
|
-
codecInfo: {
|
|
60
|
-
codec: track.source._codec,
|
|
61
|
-
vorbisInfo: null,
|
|
62
|
-
opusInfo: null,
|
|
63
|
-
},
|
|
64
|
-
vorbisLastBlocksize: null,
|
|
65
|
-
packetQueue: [],
|
|
66
|
-
currentTimestampInSamples: 0,
|
|
67
|
-
pagesWritten: 0,
|
|
68
|
-
currentGranulePosition: 0,
|
|
69
|
-
currentLacingValues: [],
|
|
70
|
-
currentPageData: [],
|
|
71
|
-
currentPageSize: 27,
|
|
72
|
-
currentPageStartsWithFreshPacket: true,
|
|
73
|
-
};
|
|
74
|
-
this.queueHeaderPackets(newTrackData, meta);
|
|
75
|
-
this.trackDatas.push(newTrackData);
|
|
76
|
-
if (this.allTracksAreKnown()) {
|
|
77
|
-
this.allTracksKnown.resolve();
|
|
78
|
-
}
|
|
79
|
-
return newTrackData;
|
|
80
|
-
}
|
|
81
|
-
queueHeaderPackets(trackData, meta) {
|
|
82
|
-
assert(meta.decoderConfig);
|
|
83
|
-
if (trackData.track.source._codec === 'vorbis') {
|
|
84
|
-
assert(meta.decoderConfig.description);
|
|
85
|
-
const bytes = toUint8Array(meta.decoderConfig.description);
|
|
86
|
-
if (bytes[0] !== 2) {
|
|
87
|
-
throw new TypeError('First byte of Vorbis decoder description must be 2.');
|
|
88
|
-
}
|
|
89
|
-
let pos = 1;
|
|
90
|
-
const readPacketLength = () => {
|
|
91
|
-
let length = 0;
|
|
92
|
-
while (true) {
|
|
93
|
-
const value = bytes[pos++];
|
|
94
|
-
if (value === undefined) {
|
|
95
|
-
throw new TypeError('Vorbis decoder description is too short.');
|
|
96
|
-
}
|
|
97
|
-
length += value;
|
|
98
|
-
if (value < 255) {
|
|
99
|
-
return length;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
const identificationHeaderLength = readPacketLength();
|
|
104
|
-
const commentHeaderLength = readPacketLength();
|
|
105
|
-
const setupHeaderLength = bytes.length - pos; // Setup header fills the remaining bytes
|
|
106
|
-
if (setupHeaderLength <= 0) {
|
|
107
|
-
throw new TypeError('Vorbis decoder description is too short.');
|
|
108
|
-
}
|
|
109
|
-
const identificationHeader = bytes.subarray(pos, pos += identificationHeaderLength);
|
|
110
|
-
pos += commentHeaderLength; // Skip the comment header, we'll build our own
|
|
111
|
-
const setupHeader = bytes.subarray(pos);
|
|
112
|
-
const commentHeaderHeader = new Uint8Array(7);
|
|
113
|
-
commentHeaderHeader[0] = 3; // Packet type
|
|
114
|
-
commentHeaderHeader[1] = 0x76; // 'v'
|
|
115
|
-
commentHeaderHeader[2] = 0x6f; // 'o'
|
|
116
|
-
commentHeaderHeader[3] = 0x72; // 'r'
|
|
117
|
-
commentHeaderHeader[4] = 0x62; // 'b'
|
|
118
|
-
commentHeaderHeader[5] = 0x69; // 'i'
|
|
119
|
-
commentHeaderHeader[6] = 0x73; // 's'
|
|
120
|
-
const commentHeader = createVorbisComments(commentHeaderHeader, this.output._metadataTags, true);
|
|
121
|
-
trackData.packetQueue.push({
|
|
122
|
-
data: identificationHeader,
|
|
123
|
-
endGranulePosition: 0,
|
|
124
|
-
timestamp: 0,
|
|
125
|
-
forcePageFlush: true,
|
|
126
|
-
}, {
|
|
127
|
-
data: commentHeader,
|
|
128
|
-
endGranulePosition: 0,
|
|
129
|
-
timestamp: 0,
|
|
130
|
-
forcePageFlush: false,
|
|
131
|
-
}, {
|
|
132
|
-
data: setupHeader,
|
|
133
|
-
endGranulePosition: 0,
|
|
134
|
-
timestamp: 0,
|
|
135
|
-
forcePageFlush: true, // The last header packet must flush the page
|
|
136
|
-
});
|
|
137
|
-
const view = toDataView(identificationHeader);
|
|
138
|
-
const blockSizeByte = view.getUint8(28);
|
|
139
|
-
trackData.codecInfo.vorbisInfo = {
|
|
140
|
-
blocksizes: [
|
|
141
|
-
1 << (blockSizeByte & 0xf),
|
|
142
|
-
1 << (blockSizeByte >> 4),
|
|
143
|
-
],
|
|
144
|
-
modeBlockflags: parseModesFromVorbisSetupPacket(setupHeader).modeBlockflags,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
else if (trackData.track.source._codec === 'opus') {
|
|
148
|
-
if (!meta.decoderConfig.description) {
|
|
149
|
-
throw new TypeError('For Ogg, Opus decoder description is required.');
|
|
150
|
-
}
|
|
151
|
-
const identificationHeader = toUint8Array(meta.decoderConfig.description);
|
|
152
|
-
const commentHeaderHeader = new Uint8Array(8);
|
|
153
|
-
const commentHeaderHeaderView = toDataView(commentHeaderHeader);
|
|
154
|
-
commentHeaderHeaderView.setUint32(0, 0x4f707573, false); // 'Opus'
|
|
155
|
-
commentHeaderHeaderView.setUint32(4, 0x54616773, false); // 'Tags'
|
|
156
|
-
const commentHeader = createVorbisComments(commentHeaderHeader, this.output._metadataTags, true);
|
|
157
|
-
trackData.packetQueue.push({
|
|
158
|
-
data: identificationHeader,
|
|
159
|
-
endGranulePosition: 0,
|
|
160
|
-
timestamp: 0,
|
|
161
|
-
forcePageFlush: true,
|
|
162
|
-
}, {
|
|
163
|
-
data: commentHeader,
|
|
164
|
-
endGranulePosition: 0,
|
|
165
|
-
timestamp: 0,
|
|
166
|
-
forcePageFlush: true, // The last header packet must flush the page
|
|
167
|
-
});
|
|
168
|
-
trackData.codecInfo.opusInfo = {
|
|
169
|
-
preSkip: parseOpusIdentificationHeader(identificationHeader).preSkip,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
async addEncodedAudioPacket(track, packet, meta) {
|
|
174
|
-
const release = await this.mutex.acquire();
|
|
175
|
-
try {
|
|
176
|
-
const trackData = this.getTrackData(track, meta);
|
|
177
|
-
this.validateAndNormalizeTimestamp(trackData.track, packet.timestamp, packet.type === 'key');
|
|
178
|
-
const currentTimestampInSamples = trackData.currentTimestampInSamples;
|
|
179
|
-
const { durationInSamples, vorbisBlockSize } = extractSampleMetadata(packet.data, trackData.codecInfo, trackData.vorbisLastBlocksize);
|
|
180
|
-
trackData.currentTimestampInSamples += durationInSamples;
|
|
181
|
-
trackData.vorbisLastBlocksize = vorbisBlockSize;
|
|
182
|
-
trackData.packetQueue.push({
|
|
183
|
-
data: packet.data,
|
|
184
|
-
endGranulePosition: trackData.currentTimestampInSamples,
|
|
185
|
-
timestamp: currentTimestampInSamples / trackData.internalSampleRate,
|
|
186
|
-
forcePageFlush: false,
|
|
187
|
-
});
|
|
188
|
-
await this.interleavePages();
|
|
189
|
-
}
|
|
190
|
-
finally {
|
|
191
|
-
release();
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
addSubtitleCue() {
|
|
195
|
-
throw new Error('Subtitle tracks are not supported.');
|
|
196
|
-
}
|
|
197
|
-
allTracksAreKnown() {
|
|
198
|
-
for (const track of this.output._tracks) {
|
|
199
|
-
if (!track.source._closed && !this.trackDatas.some(x => x.track === track)) {
|
|
200
|
-
return false; // We haven't seen a sample from this open track yet
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
async interleavePages(isFinalCall = false) {
|
|
206
|
-
if (!this.bosPagesWritten) {
|
|
207
|
-
if (!this.allTracksAreKnown()) {
|
|
208
|
-
return; // We can't interleave yet as we don't yet know how many tracks we'll truly have
|
|
209
|
-
}
|
|
210
|
-
// Write the header page for all bitstreams
|
|
211
|
-
for (const trackData of this.trackDatas) {
|
|
212
|
-
while (trackData.packetQueue.length > 0) {
|
|
213
|
-
const packet = trackData.packetQueue.shift();
|
|
214
|
-
this.writePacket(trackData, packet, false);
|
|
215
|
-
if (packet.forcePageFlush) {
|
|
216
|
-
// We say the header page ends once the first packet is encountered that forces a page flush
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
this.bosPagesWritten = true;
|
|
222
|
-
}
|
|
223
|
-
outer: while (true) {
|
|
224
|
-
let trackWithMinTimestamp = null;
|
|
225
|
-
let minTimestamp = Infinity;
|
|
226
|
-
for (const trackData of this.trackDatas) {
|
|
227
|
-
if (!isFinalCall
|
|
228
|
-
&& trackData.packetQueue.length <= 1 // Limit is 1, not 0, for correct EOS flag logic
|
|
229
|
-
&& !trackData.track.source._closed) {
|
|
230
|
-
break outer;
|
|
231
|
-
}
|
|
232
|
-
if (trackData.packetQueue.length > 0
|
|
233
|
-
&& trackData.packetQueue[0].timestamp < minTimestamp) {
|
|
234
|
-
trackWithMinTimestamp = trackData;
|
|
235
|
-
minTimestamp = trackData.packetQueue[0].timestamp;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (!trackWithMinTimestamp) {
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
const packet = trackWithMinTimestamp.packetQueue.shift();
|
|
242
|
-
const isFinalPacket = trackWithMinTimestamp.packetQueue.length === 0;
|
|
243
|
-
this.writePacket(trackWithMinTimestamp, packet, isFinalPacket);
|
|
244
|
-
}
|
|
245
|
-
if (!isFinalCall) {
|
|
246
|
-
await this.writer.flush();
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
writePacket(trackData, packet, isFinalPacket) {
|
|
250
|
-
let remainingLength = packet.data.length;
|
|
251
|
-
let dataStartOffset = 0;
|
|
252
|
-
let dataOffset = 0;
|
|
253
|
-
while (true) {
|
|
254
|
-
if (trackData.currentLacingValues.length === 0 && dataStartOffset > 0) {
|
|
255
|
-
// This is a packet spanning multiple pages
|
|
256
|
-
trackData.currentPageStartsWithFreshPacket = false;
|
|
257
|
-
}
|
|
258
|
-
const segmentSize = Math.min(255, remainingLength);
|
|
259
|
-
trackData.currentLacingValues.push(segmentSize);
|
|
260
|
-
trackData.currentPageSize++;
|
|
261
|
-
dataOffset += segmentSize;
|
|
262
|
-
const segmentIsLastOfPacket = remainingLength < 255;
|
|
263
|
-
if (trackData.currentLacingValues.length === 255) {
|
|
264
|
-
// The page is full, we need to add part of the packet data and then flush the page
|
|
265
|
-
const slice = packet.data.subarray(dataStartOffset, dataOffset);
|
|
266
|
-
dataStartOffset = dataOffset;
|
|
267
|
-
trackData.currentPageData.push(slice);
|
|
268
|
-
trackData.currentPageSize += slice.length;
|
|
269
|
-
this.writePage(trackData, isFinalPacket && segmentIsLastOfPacket);
|
|
270
|
-
if (segmentIsLastOfPacket) {
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
if (segmentIsLastOfPacket) {
|
|
275
|
-
break;
|
|
276
|
-
}
|
|
277
|
-
remainingLength -= 255;
|
|
278
|
-
}
|
|
279
|
-
const slice = packet.data.subarray(dataStartOffset);
|
|
280
|
-
trackData.currentPageData.push(slice);
|
|
281
|
-
trackData.currentPageSize += slice.length;
|
|
282
|
-
trackData.currentGranulePosition = packet.endGranulePosition;
|
|
283
|
-
if (trackData.currentPageSize >= PAGE_SIZE_TARGET || packet.forcePageFlush) {
|
|
284
|
-
this.writePage(trackData, isFinalPacket);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
writePage(trackData, isEos) {
|
|
288
|
-
this.pageView.setUint32(0, OGGS, true); // Capture pattern
|
|
289
|
-
this.pageView.setUint8(4, 0); // Version
|
|
290
|
-
let headerType = 0;
|
|
291
|
-
if (!trackData.currentPageStartsWithFreshPacket) {
|
|
292
|
-
headerType |= 1;
|
|
293
|
-
}
|
|
294
|
-
if (trackData.pagesWritten === 0) {
|
|
295
|
-
headerType |= 2; // Beginning of stream
|
|
296
|
-
}
|
|
297
|
-
if (isEos) {
|
|
298
|
-
headerType |= 4; // End of stream
|
|
299
|
-
}
|
|
300
|
-
this.pageView.setUint8(5, headerType); // Header type
|
|
301
|
-
const granulePosition = trackData.currentLacingValues.every(x => x === 255)
|
|
302
|
-
? -1 // No packets end on this page
|
|
303
|
-
: trackData.currentGranulePosition;
|
|
304
|
-
setInt64(this.pageView, 6, granulePosition, true); // Granule position
|
|
305
|
-
this.pageView.setUint32(14, trackData.serialNumber, true); // Serial number
|
|
306
|
-
this.pageView.setUint32(18, trackData.pagesWritten, true); // Page sequence number
|
|
307
|
-
this.pageView.setUint32(22, 0, true); // Checksum placeholder
|
|
308
|
-
this.pageView.setUint8(26, trackData.currentLacingValues.length); // Number of page segments
|
|
309
|
-
this.pageBytes.set(trackData.currentLacingValues, 27);
|
|
310
|
-
let pos = 27 + trackData.currentLacingValues.length;
|
|
311
|
-
for (const data of trackData.currentPageData) {
|
|
312
|
-
this.pageBytes.set(data, pos);
|
|
313
|
-
pos += data.length;
|
|
314
|
-
}
|
|
315
|
-
const slice = this.pageBytes.subarray(0, pos);
|
|
316
|
-
const crc = computeOggPageCrc(slice);
|
|
317
|
-
this.pageView.setUint32(22, crc, true); // Checksum
|
|
318
|
-
trackData.pagesWritten++;
|
|
319
|
-
trackData.currentLacingValues.length = 0;
|
|
320
|
-
trackData.currentPageData.length = 0;
|
|
321
|
-
trackData.currentPageSize = 27;
|
|
322
|
-
trackData.currentPageStartsWithFreshPacket = true;
|
|
323
|
-
if (this.format._options.onPage) {
|
|
324
|
-
this.writer.startTrackingWrites();
|
|
325
|
-
}
|
|
326
|
-
this.writer.write(slice);
|
|
327
|
-
if (this.format._options.onPage) {
|
|
328
|
-
const { data, start } = this.writer.stopTrackingWrites();
|
|
329
|
-
this.format._options.onPage(data, start, trackData.track.source);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
333
|
-
async onTrackClose() {
|
|
334
|
-
const release = await this.mutex.acquire();
|
|
335
|
-
if (this.allTracksAreKnown()) {
|
|
336
|
-
this.allTracksKnown.resolve();
|
|
337
|
-
}
|
|
338
|
-
// Since a track is now closed, we may be able to write out chunks that were previously waiting
|
|
339
|
-
await this.interleavePages();
|
|
340
|
-
release();
|
|
341
|
-
}
|
|
342
|
-
async finalize() {
|
|
343
|
-
const release = await this.mutex.acquire();
|
|
344
|
-
this.allTracksKnown.resolve();
|
|
345
|
-
await this.interleavePages(true);
|
|
346
|
-
for (const trackData of this.trackDatas) {
|
|
347
|
-
if (trackData.currentLacingValues.length > 0) {
|
|
348
|
-
this.writePage(trackData, true);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
release();
|
|
352
|
-
}
|
|
353
|
-
}
|
|
@@ -1,65 +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
|
-
import { readI64Le, readU32Le, readU8 } from '../reader.js';
|
|
9
|
-
import { OGGS } from './ogg-misc.js';
|
|
10
|
-
export const MIN_PAGE_HEADER_SIZE = 27;
|
|
11
|
-
export const MAX_PAGE_HEADER_SIZE = 27 + 255;
|
|
12
|
-
export const MAX_PAGE_SIZE = /* #__PURE__ */ MAX_PAGE_HEADER_SIZE + 255 * 255;
|
|
13
|
-
export const readPageHeader = (slice) => {
|
|
14
|
-
const startPos = slice.filePos;
|
|
15
|
-
const capturePattern = readU32Le(slice);
|
|
16
|
-
if (capturePattern !== OGGS) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
slice.skip(1); // Version
|
|
20
|
-
const headerType = readU8(slice);
|
|
21
|
-
const granulePosition = readI64Le(slice);
|
|
22
|
-
const serialNumber = readU32Le(slice);
|
|
23
|
-
const sequenceNumber = readU32Le(slice);
|
|
24
|
-
const checksum = readU32Le(slice);
|
|
25
|
-
const numberPageSegments = readU8(slice);
|
|
26
|
-
const lacingValues = new Uint8Array(numberPageSegments);
|
|
27
|
-
for (let i = 0; i < numberPageSegments; i++) {
|
|
28
|
-
lacingValues[i] = readU8(slice);
|
|
29
|
-
}
|
|
30
|
-
const headerSize = 27 + numberPageSegments;
|
|
31
|
-
const dataSize = lacingValues.reduce((a, b) => a + b, 0);
|
|
32
|
-
const totalSize = headerSize + dataSize;
|
|
33
|
-
return {
|
|
34
|
-
headerStartPos: startPos,
|
|
35
|
-
totalSize,
|
|
36
|
-
dataStartPos: startPos + headerSize,
|
|
37
|
-
dataSize,
|
|
38
|
-
headerType,
|
|
39
|
-
granulePosition,
|
|
40
|
-
serialNumber,
|
|
41
|
-
sequenceNumber,
|
|
42
|
-
checksum,
|
|
43
|
-
lacingValues,
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
|
-
export const findNextPageHeader = (slice, until) => {
|
|
47
|
-
while (slice.filePos < until - (4 - 1)) { // Size of word minus 1
|
|
48
|
-
const word = readU32Le(slice);
|
|
49
|
-
const firstByte = word & 0xff;
|
|
50
|
-
const secondByte = (word >>> 8) & 0xff;
|
|
51
|
-
const thirdByte = (word >>> 16) & 0xff;
|
|
52
|
-
const fourthByte = (word >>> 24) & 0xff;
|
|
53
|
-
const O = 0x4f; // 'O'
|
|
54
|
-
if (firstByte !== O && secondByte !== O && thirdByte !== O && fourthByte !== O) {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
slice.skip(-4);
|
|
58
|
-
if (word === OGGS) {
|
|
59
|
-
// We have found the capture pattern
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
slice.skip(1);
|
|
63
|
-
}
|
|
64
|
-
return false;
|
|
65
|
-
};
|