mediabunny 1.13.3 → 1.14.0
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/dist/bundles/mediabunny.cjs +3423 -293
- package/dist/bundles/mediabunny.min.cjs +4 -4
- package/dist/bundles/mediabunny.min.mjs +4 -4
- package/dist/bundles/mediabunny.mjs +3423 -293
- package/dist/mediabunny.d.ts +126 -2
- package/dist/modules/shared/mp3-misc.d.ts +2 -0
- package/dist/modules/shared/mp3-misc.d.ts.map +1 -1
- package/dist/modules/shared/mp3-misc.js +23 -0
- package/dist/modules/src/adts/adts-demuxer.d.ts +1 -0
- package/dist/modules/src/adts/adts-demuxer.d.ts.map +1 -1
- package/dist/modules/src/adts/adts-demuxer.js +3 -0
- package/dist/modules/src/conversion.d.ts +9 -0
- package/dist/modules/src/conversion.d.ts.map +1 -1
- package/dist/modules/src/conversion.js +24 -0
- package/dist/modules/src/demuxer.d.ts +2 -0
- package/dist/modules/src/demuxer.d.ts.map +1 -1
- package/dist/modules/src/index.d.ts +1 -0
- package/dist/modules/src/index.d.ts.map +1 -1
- package/dist/modules/src/index.js +1 -0
- package/dist/modules/src/input-format.d.ts.map +1 -1
- package/dist/modules/src/input-format.js +16 -6
- package/dist/modules/src/input-track.d.ts +4 -2
- package/dist/modules/src/input-track.d.ts.map +1 -1
- package/dist/modules/src/input-track.js +4 -2
- package/dist/modules/src/input.d.ts +2 -0
- package/dist/modules/src/input.d.ts.map +1 -1
- package/dist/modules/src/input.js +5 -0
- package/dist/modules/src/isobmff/isobmff-boxes.d.ts +3 -3
- package/dist/modules/src/isobmff/isobmff-boxes.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-boxes.js +315 -64
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts +13 -0
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-demuxer.js +434 -32
- package/dist/modules/src/isobmff/isobmff-muxer.d.ts +2 -2
- package/dist/modules/src/isobmff/isobmff-muxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-muxer.js +4 -4
- package/dist/modules/src/isobmff/isobmff-reader.d.ts +3 -0
- package/dist/modules/src/isobmff/isobmff-reader.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-reader.js +25 -1
- package/dist/modules/src/matroska/ebml.d.ts +20 -1
- package/dist/modules/src/matroska/ebml.d.ts.map +1 -1
- package/dist/modules/src/matroska/ebml.js +19 -0
- package/dist/modules/src/matroska/matroska-demuxer.d.ts +16 -0
- package/dist/modules/src/matroska/matroska-demuxer.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-demuxer.js +317 -2
- package/dist/modules/src/matroska/matroska-muxer.d.ts +5 -1
- package/dist/modules/src/matroska/matroska-muxer.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-muxer.js +239 -18
- package/dist/modules/src/misc.d.ts +14 -0
- package/dist/modules/src/misc.d.ts.map +1 -1
- package/dist/modules/src/misc.js +63 -0
- package/dist/modules/src/mp3/mp3-demuxer.d.ts +3 -0
- package/dist/modules/src/mp3/mp3-demuxer.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-demuxer.js +66 -15
- package/dist/modules/src/mp3/mp3-muxer.d.ts +3 -0
- package/dist/modules/src/mp3/mp3-muxer.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-muxer.js +162 -4
- package/dist/modules/src/mp3/mp3-reader.d.ts +50 -3
- package/dist/modules/src/mp3/mp3-reader.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-reader.js +561 -21
- package/dist/modules/src/mp3/mp3-writer.d.ts +10 -0
- package/dist/modules/src/mp3/mp3-writer.d.ts.map +1 -1
- package/dist/modules/src/mp3/mp3-writer.js +110 -1
- package/dist/modules/src/ogg/ogg-demuxer.d.ts +4 -0
- package/dist/modules/src/ogg/ogg-demuxer.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-demuxer.js +167 -2
- package/dist/modules/src/ogg/ogg-muxer.d.ts +1 -0
- package/dist/modules/src/ogg/ogg-muxer.d.ts.map +1 -1
- package/dist/modules/src/ogg/ogg-muxer.js +189 -8
- package/dist/modules/src/output.d.ts +8 -0
- package/dist/modules/src/output.d.ts.map +1 -1
- package/dist/modules/src/output.js +16 -0
- package/dist/modules/src/source.d.ts.map +1 -1
- package/dist/modules/src/source.js +24 -0
- package/dist/modules/src/tags.d.ts +112 -0
- package/dist/modules/src/tags.d.ts.map +1 -0
- package/dist/modules/src/tags.js +119 -0
- package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
- package/dist/modules/src/wave/wave-demuxer.d.ts +4 -0
- package/dist/modules/src/wave/wave-demuxer.d.ts.map +1 -1
- package/dist/modules/src/wave/wave-demuxer.js +117 -0
- package/dist/modules/src/wave/wave-muxer.d.ts +6 -0
- package/dist/modules/src/wave/wave-muxer.d.ts.map +1 -1
- package/dist/modules/src/wave/wave-muxer.js +148 -6
- package/package.json +1 -1
- package/src/adts/adts-demuxer.ts +4 -0
- package/src/conversion.ts +39 -0
- package/src/demuxer.ts +2 -0
- package/src/index.ts +5 -0
- package/src/input-format.ts +15 -6
- package/src/input-track.ts +4 -2
- package/src/input.ts +6 -0
- package/src/isobmff/isobmff-boxes.ts +290 -66
- package/src/isobmff/isobmff-demuxer.ts +408 -31
- package/src/isobmff/isobmff-muxer.ts +6 -6
- package/src/isobmff/isobmff-reader.ts +30 -1
- package/src/matroska/ebml.ts +19 -0
- package/src/matroska/matroska-demuxer.ts +298 -3
- package/src/matroska/matroska-muxer.ts +236 -37
- package/src/misc.ts +82 -0
- package/src/mp3/mp3-demuxer.ts +81 -14
- package/src/mp3/mp3-muxer.ts +142 -4
- package/src/mp3/mp3-reader.ts +618 -20
- package/src/mp3/mp3-writer.ts +129 -0
- package/src/ogg/ogg-demuxer.ts +169 -2
- package/src/ogg/ogg-muxer.ts +201 -9
- package/src/output.ts +19 -0
- package/src/source.ts +32 -0
- package/src/tags.ts +215 -0
- package/src/wave/wave-demuxer.ts +109 -0
- package/src/wave/wave-muxer.ts +152 -6
|
@@ -93,6 +93,7 @@ var Mediabunny = (() => {
|
|
|
93
93
|
Quality: () => Quality,
|
|
94
94
|
QuickTimeInputFormat: () => QuickTimeInputFormat,
|
|
95
95
|
ReadableStreamSource: () => ReadableStreamSource,
|
|
96
|
+
RichImageData: () => RichImageData,
|
|
96
97
|
SUBTITLE_CODECS: () => SUBTITLE_CODECS,
|
|
97
98
|
Source: () => Source,
|
|
98
99
|
StreamSource: () => StreamSource,
|
|
@@ -253,6 +254,15 @@ var Mediabunny = (() => {
|
|
|
253
254
|
};
|
|
254
255
|
var textDecoder = new TextDecoder();
|
|
255
256
|
var textEncoder = new TextEncoder();
|
|
257
|
+
var isIso88591Compatible = (text) => {
|
|
258
|
+
for (let i = 0; i < text.length; i++) {
|
|
259
|
+
const code = text.charCodeAt(i);
|
|
260
|
+
if (code > 255) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return true;
|
|
265
|
+
};
|
|
256
266
|
var invertObject = (object) => {
|
|
257
267
|
return Object.fromEntries(Object.entries(object).map(([key, value]) => [value, key]));
|
|
258
268
|
};
|
|
@@ -576,9 +586,149 @@ var Mediabunny = (() => {
|
|
|
576
586
|
isSafariCache = result;
|
|
577
587
|
return result;
|
|
578
588
|
};
|
|
589
|
+
var coalesceIndex = (a, b) => {
|
|
590
|
+
return a !== -1 ? a : b;
|
|
591
|
+
};
|
|
579
592
|
var closedIntervalsOverlap = (startA, endA, startB, endB) => {
|
|
580
593
|
return startA <= endB && startB <= endA;
|
|
581
594
|
};
|
|
595
|
+
var keyValueIterator = function* (object) {
|
|
596
|
+
for (const key in object) {
|
|
597
|
+
const value = object[key];
|
|
598
|
+
if (value === void 0) {
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
yield { key, value };
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
var imageMimeTypeToExtension = (mimeType) => {
|
|
605
|
+
switch (mimeType.toLowerCase()) {
|
|
606
|
+
case "image/jpeg":
|
|
607
|
+
case "image/jpg":
|
|
608
|
+
return ".jpg";
|
|
609
|
+
case "image/png":
|
|
610
|
+
return ".png";
|
|
611
|
+
case "image/gif":
|
|
612
|
+
return ".gif";
|
|
613
|
+
case "image/webp":
|
|
614
|
+
return ".webp";
|
|
615
|
+
case "image/bmp":
|
|
616
|
+
return ".bmp";
|
|
617
|
+
case "image/svg+xml":
|
|
618
|
+
return ".svg";
|
|
619
|
+
case "image/tiff":
|
|
620
|
+
return ".tiff";
|
|
621
|
+
case "image/avif":
|
|
622
|
+
return ".avif";
|
|
623
|
+
case "image/x-icon":
|
|
624
|
+
case "image/vnd.microsoft.icon":
|
|
625
|
+
return ".ico";
|
|
626
|
+
default:
|
|
627
|
+
return null;
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
var base64ToBytes = (base64) => {
|
|
631
|
+
const decoded = atob(base64);
|
|
632
|
+
const bytes2 = new Uint8Array(decoded.length);
|
|
633
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
634
|
+
bytes2[i] = decoded.charCodeAt(i);
|
|
635
|
+
}
|
|
636
|
+
return bytes2;
|
|
637
|
+
};
|
|
638
|
+
var bytesToBase64 = (bytes2) => {
|
|
639
|
+
let string = "";
|
|
640
|
+
for (let i = 0; i < bytes2.length; i++) {
|
|
641
|
+
string += String.fromCharCode(bytes2[i]);
|
|
642
|
+
}
|
|
643
|
+
return btoa(string);
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
// src/tags.ts
|
|
647
|
+
var RichImageData = class {
|
|
648
|
+
/** Creates a new {@link RichImageData}. */
|
|
649
|
+
constructor(data, mimeType) {
|
|
650
|
+
this.data = data;
|
|
651
|
+
this.mimeType = mimeType;
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
var validateMetadataTags = (tags) => {
|
|
655
|
+
if (!tags || typeof tags !== "object") {
|
|
656
|
+
throw new TypeError("tags must be an object.");
|
|
657
|
+
}
|
|
658
|
+
if (tags.title !== void 0 && typeof tags.title !== "string") {
|
|
659
|
+
throw new TypeError("tags.title, when provided, must be a string.");
|
|
660
|
+
}
|
|
661
|
+
if (tags.description !== void 0 && typeof tags.description !== "string") {
|
|
662
|
+
throw new TypeError("tags.description, when provided, must be a string.");
|
|
663
|
+
}
|
|
664
|
+
if (tags.artist !== void 0 && typeof tags.artist !== "string") {
|
|
665
|
+
throw new TypeError("tags.artist, when provided, must be a string.");
|
|
666
|
+
}
|
|
667
|
+
if (tags.album !== void 0 && typeof tags.album !== "string") {
|
|
668
|
+
throw new TypeError("tags.album, when provided, must be a string.");
|
|
669
|
+
}
|
|
670
|
+
if (tags.albumArtist !== void 0 && typeof tags.albumArtist !== "string") {
|
|
671
|
+
throw new TypeError("tags.albumArtist, when provided, must be a string.");
|
|
672
|
+
}
|
|
673
|
+
if (tags.trackNumber !== void 0 && (!Number.isInteger(tags.trackNumber) || tags.trackNumber <= 0)) {
|
|
674
|
+
throw new TypeError("tags.trackNumber, when provided, must be a positive integer.");
|
|
675
|
+
}
|
|
676
|
+
if (tags.tracksTotal !== void 0 && (!Number.isInteger(tags.tracksTotal) || tags.tracksTotal <= 0)) {
|
|
677
|
+
throw new TypeError("tags.tracksTotal, when provided, must be a positive integer.");
|
|
678
|
+
}
|
|
679
|
+
if (tags.discNumber !== void 0 && (!Number.isInteger(tags.discNumber) || tags.discNumber <= 0)) {
|
|
680
|
+
throw new TypeError("tags.discNumber, when provided, must be a positive integer.");
|
|
681
|
+
}
|
|
682
|
+
if (tags.discsTotal !== void 0 && (!Number.isInteger(tags.discsTotal) || tags.discsTotal <= 0)) {
|
|
683
|
+
throw new TypeError("tags.discsTotal, when provided, must be a positive integer.");
|
|
684
|
+
}
|
|
685
|
+
if (tags.genre !== void 0 && typeof tags.genre !== "string") {
|
|
686
|
+
throw new TypeError("tags.genre, when provided, must be a string.");
|
|
687
|
+
}
|
|
688
|
+
if (tags.date !== void 0 && (!(tags.date instanceof Date) || Number.isNaN(tags.date.getTime()))) {
|
|
689
|
+
throw new TypeError("tags.date, when provided, must be a valid Date.");
|
|
690
|
+
}
|
|
691
|
+
if (tags.lyrics !== void 0 && typeof tags.lyrics !== "string") {
|
|
692
|
+
throw new TypeError("tags.lyrics, when provided, must be a string.");
|
|
693
|
+
}
|
|
694
|
+
if (tags.images !== void 0) {
|
|
695
|
+
if (!Array.isArray(tags.images)) {
|
|
696
|
+
throw new TypeError("tags.images, when provided, must be an array.");
|
|
697
|
+
}
|
|
698
|
+
for (const image of tags.images) {
|
|
699
|
+
if (!image || typeof image !== "object") {
|
|
700
|
+
throw new TypeError("Each image in tags.images must be an object.");
|
|
701
|
+
}
|
|
702
|
+
if (!(image.data instanceof Uint8Array)) {
|
|
703
|
+
throw new TypeError("Each image.data must be a Uint8Array.");
|
|
704
|
+
}
|
|
705
|
+
if (typeof image.mimeType !== "string") {
|
|
706
|
+
throw new TypeError("Each image.mimeType must be a string.");
|
|
707
|
+
}
|
|
708
|
+
if (!["coverFront", "coverBack", "unknown"].includes(image.kind)) {
|
|
709
|
+
throw new TypeError("Each image.kind must be 'coverFront', 'coverBack', or 'unknown'.");
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
if (tags.comment !== void 0 && typeof tags.comment !== "string") {
|
|
714
|
+
throw new TypeError("tags.comment, when provided, must be a string.");
|
|
715
|
+
}
|
|
716
|
+
if (tags.raw !== void 0) {
|
|
717
|
+
if (!tags.raw || typeof tags.raw !== "object") {
|
|
718
|
+
throw new TypeError("tags.raw, when provided, must be an object.");
|
|
719
|
+
}
|
|
720
|
+
for (const value of Object.values(tags.raw)) {
|
|
721
|
+
if (value !== null && typeof value !== "string" && !(value instanceof Uint8Array) && !(value instanceof RichImageData)) {
|
|
722
|
+
throw new TypeError(
|
|
723
|
+
"Each value in tags.raw must be a string, Uint8Array, RichImageData, or null."
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
var metadataTagsAreEmpty = (tags) => {
|
|
730
|
+
return tags.title === void 0 && tags.description === void 0 && tags.artist === void 0 && tags.album === void 0 && tags.albumArtist === void 0 && tags.trackNumber === void 0 && tags.tracksTotal === void 0 && tags.discNumber === void 0 && tags.discsTotal === void 0 && tags.genre === void 0 && tags.date === void 0 && tags.lyrics === void 0 && (!tags.images || tags.images.length === 0) && tags.comment === void 0 && (tags.raw === void 0 || Object.keys(tags.raw).length === 0);
|
|
731
|
+
};
|
|
582
732
|
|
|
583
733
|
// src/codec.ts
|
|
584
734
|
var VIDEO_CODECS = [
|
|
@@ -1460,13 +1610,13 @@ var Mediabunny = (() => {
|
|
|
1460
1610
|
async addEncodedVideoPacket() {
|
|
1461
1611
|
throw new Error("ADTS does not support video.");
|
|
1462
1612
|
}
|
|
1463
|
-
async addEncodedAudioPacket(track, packet,
|
|
1613
|
+
async addEncodedAudioPacket(track, packet, meta2) {
|
|
1464
1614
|
const release = await this.mutex.acquire();
|
|
1465
1615
|
try {
|
|
1466
1616
|
this.validateAndNormalizeTimestamp(track, packet.timestamp, packet.type === "key");
|
|
1467
1617
|
if (!this.audioSpecificConfig) {
|
|
1468
|
-
validateAudioChunkMetadata(
|
|
1469
|
-
const description =
|
|
1618
|
+
validateAudioChunkMetadata(meta2);
|
|
1619
|
+
const description = meta2?.decoderConfig?.description;
|
|
1470
1620
|
assert(description);
|
|
1471
1621
|
this.audioSpecificConfig = parseAacAudioSpecificConfig(toUint8Array(description));
|
|
1472
1622
|
const { objectType, frequencyIndex, channelConfiguration } = this.audioSpecificConfig;
|
|
@@ -1562,14 +1712,14 @@ var Mediabunny = (() => {
|
|
|
1562
1712
|
settings: cueSettings,
|
|
1563
1713
|
notes
|
|
1564
1714
|
};
|
|
1565
|
-
const
|
|
1715
|
+
const meta2 = {};
|
|
1566
1716
|
if (!this.preambleEmitted) {
|
|
1567
|
-
|
|
1717
|
+
meta2.config = {
|
|
1568
1718
|
description: this.preambleText
|
|
1569
1719
|
};
|
|
1570
1720
|
this.preambleEmitted = true;
|
|
1571
1721
|
}
|
|
1572
|
-
this.options.output(cue,
|
|
1722
|
+
this.options.output(cue, meta2);
|
|
1573
1723
|
}
|
|
1574
1724
|
}
|
|
1575
1725
|
};
|
|
@@ -2902,10 +3052,11 @@ var Mediabunny = (() => {
|
|
|
2902
3052
|
]);
|
|
2903
3053
|
};
|
|
2904
3054
|
var mdat = (reserveLargeSize) => ({ type: "mdat", largeSize: reserveLargeSize });
|
|
2905
|
-
var moov = (
|
|
2906
|
-
mvhd(creationTime, trackDatas),
|
|
2907
|
-
...trackDatas.map((x) => trak(x, creationTime)),
|
|
2908
|
-
fragmented ? mvex(trackDatas) : null
|
|
3055
|
+
var moov = (muxer, fragmented = false) => box("moov", void 0, [
|
|
3056
|
+
mvhd(muxer.creationTime, muxer.trackDatas),
|
|
3057
|
+
...muxer.trackDatas.map((x) => trak(x, muxer.creationTime)),
|
|
3058
|
+
fragmented ? mvex(muxer.trackDatas) : null,
|
|
3059
|
+
udta(muxer)
|
|
2909
3060
|
]);
|
|
2910
3061
|
var mvhd = (creationTime, trackDatas) => {
|
|
2911
3062
|
const duration = intoTimescale(Math.max(
|
|
@@ -2947,7 +3098,8 @@ var Mediabunny = (() => {
|
|
|
2947
3098
|
tkhd(trackData, creationTime),
|
|
2948
3099
|
mdia(trackData, creationTime),
|
|
2949
3100
|
trackMetadata.name !== void 0 ? box("udta", void 0, [
|
|
2950
|
-
box("
|
|
3101
|
+
box("name", [
|
|
3102
|
+
// VLC (and Mediabunny) also recognize ©nam
|
|
2951
3103
|
...textEncoder.encode(trackMetadata.name)
|
|
2952
3104
|
])
|
|
2953
3105
|
]) : null
|
|
@@ -3010,11 +3162,6 @@ var Mediabunny = (() => {
|
|
|
3010
3162
|
);
|
|
3011
3163
|
const needsU64 = !isU32(creationTime) || !isU32(localDuration);
|
|
3012
3164
|
const u32OrU64 = needsU64 ? u64 : u32;
|
|
3013
|
-
let language = 0;
|
|
3014
|
-
for (const character of trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE) {
|
|
3015
|
-
language <<= 5;
|
|
3016
|
-
language += character.charCodeAt(0) - 96;
|
|
3017
|
-
}
|
|
3018
3165
|
return fullBox("mdhd", +needsU64, 0, [
|
|
3019
3166
|
u32OrU64(creationTime),
|
|
3020
3167
|
// Creation time
|
|
@@ -3024,7 +3171,7 @@ var Mediabunny = (() => {
|
|
|
3024
3171
|
// Timescale
|
|
3025
3172
|
u32OrU64(localDuration),
|
|
3026
3173
|
// Duration
|
|
3027
|
-
u16(
|
|
3174
|
+
u16(getLanguageCodeInt(trackData.track.metadata.languageCode ?? UNDETERMINED_LANGUAGE)),
|
|
3028
3175
|
// Language
|
|
3029
3176
|
u16(0)
|
|
3030
3177
|
// Quality
|
|
@@ -3040,12 +3187,12 @@ var Mediabunny = (() => {
|
|
|
3040
3187
|
audio: "MediabunnySoundHandler",
|
|
3041
3188
|
subtitle: "MediabunnyTextHandler"
|
|
3042
3189
|
};
|
|
3043
|
-
var hdlr = (hasComponentType, handlerType, name) => fullBox("hdlr", 0, 0, [
|
|
3190
|
+
var hdlr = (hasComponentType, handlerType, name, manufacturer = "\0\0\0\0") => fullBox("hdlr", 0, 0, [
|
|
3044
3191
|
hasComponentType ? ascii("mhlr") : u32(0),
|
|
3045
3192
|
// Component type
|
|
3046
3193
|
ascii(handlerType),
|
|
3047
3194
|
// Component subtype
|
|
3048
|
-
|
|
3195
|
+
ascii(manufacturer),
|
|
3049
3196
|
// Component manufacturer
|
|
3050
3197
|
u32(0),
|
|
3051
3198
|
// Component flags
|
|
@@ -3740,6 +3887,303 @@ var Mediabunny = (() => {
|
|
|
3740
3887
|
box("payl", [...textEncoder.encode(payload)])
|
|
3741
3888
|
]);
|
|
3742
3889
|
var vtta = (notes) => box("vtta", [...textEncoder.encode(notes)]);
|
|
3890
|
+
var udta = (muxer) => {
|
|
3891
|
+
const boxes = [];
|
|
3892
|
+
if (muxer.isQuickTime) {
|
|
3893
|
+
addQuickTimeMetadataTagBoxes(boxes, muxer.output._metadataTags);
|
|
3894
|
+
} else {
|
|
3895
|
+
const metaBox = meta(muxer.output._metadataTags);
|
|
3896
|
+
if (metaBox) {
|
|
3897
|
+
boxes.push(metaBox);
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3900
|
+
if (boxes.length === 0) {
|
|
3901
|
+
return null;
|
|
3902
|
+
}
|
|
3903
|
+
return box("udta", void 0, boxes);
|
|
3904
|
+
};
|
|
3905
|
+
var addQuickTimeMetadataTagBoxes = (boxes, tags) => {
|
|
3906
|
+
for (const { key, value } of keyValueIterator(tags)) {
|
|
3907
|
+
switch (key) {
|
|
3908
|
+
case "title":
|
|
3909
|
+
{
|
|
3910
|
+
boxes.push(metadataTagStringBoxShort("\xA9nam", value));
|
|
3911
|
+
}
|
|
3912
|
+
;
|
|
3913
|
+
break;
|
|
3914
|
+
case "description":
|
|
3915
|
+
{
|
|
3916
|
+
boxes.push(metadataTagStringBoxShort("\xA9des", value));
|
|
3917
|
+
}
|
|
3918
|
+
;
|
|
3919
|
+
break;
|
|
3920
|
+
case "artist":
|
|
3921
|
+
{
|
|
3922
|
+
boxes.push(metadataTagStringBoxShort("\xA9ART", value));
|
|
3923
|
+
}
|
|
3924
|
+
;
|
|
3925
|
+
break;
|
|
3926
|
+
case "album":
|
|
3927
|
+
{
|
|
3928
|
+
boxes.push(metadataTagStringBoxShort("\xA9alb", value));
|
|
3929
|
+
}
|
|
3930
|
+
;
|
|
3931
|
+
break;
|
|
3932
|
+
case "albumArtist":
|
|
3933
|
+
{
|
|
3934
|
+
boxes.push(metadataTagStringBoxShort("albr", value));
|
|
3935
|
+
}
|
|
3936
|
+
;
|
|
3937
|
+
break;
|
|
3938
|
+
case "genre":
|
|
3939
|
+
{
|
|
3940
|
+
boxes.push(metadataTagStringBoxShort("\xA9gen", value));
|
|
3941
|
+
}
|
|
3942
|
+
;
|
|
3943
|
+
break;
|
|
3944
|
+
case "date":
|
|
3945
|
+
{
|
|
3946
|
+
boxes.push(metadataTagStringBoxShort("\xA9day", value.toISOString().slice(0, 10)));
|
|
3947
|
+
}
|
|
3948
|
+
;
|
|
3949
|
+
break;
|
|
3950
|
+
case "comment":
|
|
3951
|
+
{
|
|
3952
|
+
boxes.push(metadataTagStringBoxShort("\xA9cmt", value));
|
|
3953
|
+
}
|
|
3954
|
+
;
|
|
3955
|
+
break;
|
|
3956
|
+
case "lyrics":
|
|
3957
|
+
{
|
|
3958
|
+
boxes.push(metadataTagStringBoxShort("\xA9lyr", value));
|
|
3959
|
+
}
|
|
3960
|
+
;
|
|
3961
|
+
break;
|
|
3962
|
+
case "raw":
|
|
3963
|
+
{
|
|
3964
|
+
}
|
|
3965
|
+
;
|
|
3966
|
+
break;
|
|
3967
|
+
case "discNumber":
|
|
3968
|
+
case "discsTotal":
|
|
3969
|
+
case "trackNumber":
|
|
3970
|
+
case "tracksTotal":
|
|
3971
|
+
case "images":
|
|
3972
|
+
{
|
|
3973
|
+
}
|
|
3974
|
+
;
|
|
3975
|
+
break;
|
|
3976
|
+
default:
|
|
3977
|
+
assertNever(key);
|
|
3978
|
+
}
|
|
3979
|
+
}
|
|
3980
|
+
if (tags.raw) {
|
|
3981
|
+
for (const key in tags.raw) {
|
|
3982
|
+
const value = tags.raw[key];
|
|
3983
|
+
if (value == null || key.length !== 4 || boxes.some((x) => x.type === key)) {
|
|
3984
|
+
continue;
|
|
3985
|
+
}
|
|
3986
|
+
if (typeof value === "string") {
|
|
3987
|
+
boxes.push(metadataTagStringBoxShort(key, value));
|
|
3988
|
+
} else if (value instanceof Uint8Array) {
|
|
3989
|
+
boxes.push(box(key, Array.from(value)));
|
|
3990
|
+
}
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
};
|
|
3994
|
+
var metadataTagStringBoxShort = (name, value) => {
|
|
3995
|
+
const encoded = textEncoder.encode(value);
|
|
3996
|
+
return box(name, [
|
|
3997
|
+
u16(encoded.length),
|
|
3998
|
+
u16(getLanguageCodeInt("und")),
|
|
3999
|
+
Array.from(encoded)
|
|
4000
|
+
]);
|
|
4001
|
+
};
|
|
4002
|
+
var DATA_BOX_MIME_TYPE_MAP = {
|
|
4003
|
+
"image/jpeg": 13,
|
|
4004
|
+
"image/png": 14,
|
|
4005
|
+
"image/bmp": 27
|
|
4006
|
+
};
|
|
4007
|
+
var meta = (tags) => {
|
|
4008
|
+
const boxes = [];
|
|
4009
|
+
for (const { key, value } of keyValueIterator(tags)) {
|
|
4010
|
+
switch (key) {
|
|
4011
|
+
case "title":
|
|
4012
|
+
{
|
|
4013
|
+
boxes.push(metadataTagStringBoxLong("\xA9nam", value));
|
|
4014
|
+
}
|
|
4015
|
+
;
|
|
4016
|
+
break;
|
|
4017
|
+
case "description":
|
|
4018
|
+
{
|
|
4019
|
+
boxes.push(metadataTagStringBoxLong("\xA9des", value));
|
|
4020
|
+
}
|
|
4021
|
+
;
|
|
4022
|
+
break;
|
|
4023
|
+
case "artist":
|
|
4024
|
+
{
|
|
4025
|
+
boxes.push(metadataTagStringBoxLong("\xA9ART", value));
|
|
4026
|
+
}
|
|
4027
|
+
;
|
|
4028
|
+
break;
|
|
4029
|
+
case "album":
|
|
4030
|
+
{
|
|
4031
|
+
boxes.push(metadataTagStringBoxLong("\xA9alb", value));
|
|
4032
|
+
}
|
|
4033
|
+
;
|
|
4034
|
+
break;
|
|
4035
|
+
case "albumArtist":
|
|
4036
|
+
{
|
|
4037
|
+
boxes.push(metadataTagStringBoxLong("aART", value));
|
|
4038
|
+
}
|
|
4039
|
+
;
|
|
4040
|
+
break;
|
|
4041
|
+
case "comment":
|
|
4042
|
+
{
|
|
4043
|
+
boxes.push(metadataTagStringBoxLong("\xA9cmt", value));
|
|
4044
|
+
}
|
|
4045
|
+
;
|
|
4046
|
+
break;
|
|
4047
|
+
case "genre":
|
|
4048
|
+
{
|
|
4049
|
+
boxes.push(metadataTagStringBoxLong("\xA9gen", value));
|
|
4050
|
+
}
|
|
4051
|
+
;
|
|
4052
|
+
break;
|
|
4053
|
+
case "lyrics":
|
|
4054
|
+
{
|
|
4055
|
+
boxes.push(metadataTagStringBoxLong("\xA9lyr", value));
|
|
4056
|
+
}
|
|
4057
|
+
;
|
|
4058
|
+
break;
|
|
4059
|
+
case "date":
|
|
4060
|
+
{
|
|
4061
|
+
boxes.push(metadataTagStringBoxLong("\xA9day", value.toISOString().slice(0, 10)));
|
|
4062
|
+
}
|
|
4063
|
+
;
|
|
4064
|
+
break;
|
|
4065
|
+
case "images":
|
|
4066
|
+
{
|
|
4067
|
+
for (const image of value) {
|
|
4068
|
+
if (image.kind !== "coverFront") {
|
|
4069
|
+
continue;
|
|
4070
|
+
}
|
|
4071
|
+
boxes.push(box("covr", void 0, [
|
|
4072
|
+
box("data", [
|
|
4073
|
+
u32(DATA_BOX_MIME_TYPE_MAP[image.mimeType] ?? 0),
|
|
4074
|
+
// Type indicator
|
|
4075
|
+
u32(0),
|
|
4076
|
+
// Locale indicator
|
|
4077
|
+
Array.from(image.data)
|
|
4078
|
+
// Kinda slow, hopefully temp
|
|
4079
|
+
])
|
|
4080
|
+
]));
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
;
|
|
4084
|
+
break;
|
|
4085
|
+
case "trackNumber":
|
|
4086
|
+
{
|
|
4087
|
+
boxes.push(box("trkn", void 0, [
|
|
4088
|
+
box("data", [
|
|
4089
|
+
u32(0),
|
|
4090
|
+
// 8 bytes empty
|
|
4091
|
+
u32(0),
|
|
4092
|
+
u16(0),
|
|
4093
|
+
// Empty
|
|
4094
|
+
u16(value),
|
|
4095
|
+
u16(tags.tracksTotal ?? 0),
|
|
4096
|
+
u16(0)
|
|
4097
|
+
// Empty
|
|
4098
|
+
])
|
|
4099
|
+
]));
|
|
4100
|
+
}
|
|
4101
|
+
;
|
|
4102
|
+
break;
|
|
4103
|
+
case "discNumber":
|
|
4104
|
+
{
|
|
4105
|
+
boxes.push(box("disc", void 0, [
|
|
4106
|
+
box("data", [
|
|
4107
|
+
u32(0),
|
|
4108
|
+
// 8 bytes empty
|
|
4109
|
+
u32(0),
|
|
4110
|
+
u16(0),
|
|
4111
|
+
// Empty
|
|
4112
|
+
u16(value),
|
|
4113
|
+
u16(tags.discsTotal ?? 0),
|
|
4114
|
+
u16(0)
|
|
4115
|
+
// Empty
|
|
4116
|
+
])
|
|
4117
|
+
]));
|
|
4118
|
+
}
|
|
4119
|
+
;
|
|
4120
|
+
break;
|
|
4121
|
+
case "tracksTotal":
|
|
4122
|
+
case "discsTotal":
|
|
4123
|
+
{
|
|
4124
|
+
}
|
|
4125
|
+
;
|
|
4126
|
+
break;
|
|
4127
|
+
case "raw":
|
|
4128
|
+
{
|
|
4129
|
+
}
|
|
4130
|
+
;
|
|
4131
|
+
break;
|
|
4132
|
+
default:
|
|
4133
|
+
assertNever(key);
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
if (tags.raw) {
|
|
4137
|
+
for (const key in tags.raw) {
|
|
4138
|
+
const value = tags.raw[key];
|
|
4139
|
+
if (value == null || key.length !== 4 || boxes.some((x) => x.type === key)) {
|
|
4140
|
+
continue;
|
|
4141
|
+
}
|
|
4142
|
+
if (typeof value === "string") {
|
|
4143
|
+
boxes.push(metadataTagStringBoxLong(key, value));
|
|
4144
|
+
} else if (value instanceof Uint8Array) {
|
|
4145
|
+
boxes.push(box(key, void 0, [
|
|
4146
|
+
box("data", [
|
|
4147
|
+
u32(0),
|
|
4148
|
+
// Type indicator
|
|
4149
|
+
u32(0),
|
|
4150
|
+
// Locale indicator
|
|
4151
|
+
Array.from(value)
|
|
4152
|
+
])
|
|
4153
|
+
]));
|
|
4154
|
+
} else if (value instanceof RichImageData) {
|
|
4155
|
+
boxes.push(box(key, void 0, [
|
|
4156
|
+
box("data", [
|
|
4157
|
+
u32(DATA_BOX_MIME_TYPE_MAP[value.mimeType] ?? 0),
|
|
4158
|
+
// Type indicator
|
|
4159
|
+
u32(0),
|
|
4160
|
+
// Locale indicator
|
|
4161
|
+
Array.from(value.data)
|
|
4162
|
+
// Kinda slow, hopefully temp
|
|
4163
|
+
])
|
|
4164
|
+
]));
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
}
|
|
4168
|
+
if (boxes.length === 0) {
|
|
4169
|
+
return null;
|
|
4170
|
+
}
|
|
4171
|
+
return fullBox("meta", 0, 0, void 0, [
|
|
4172
|
+
hdlr(false, "mdir", "", "appl"),
|
|
4173
|
+
box("ilst", void 0, boxes)
|
|
4174
|
+
]);
|
|
4175
|
+
};
|
|
4176
|
+
var metadataTagStringBoxLong = (name, value) => {
|
|
4177
|
+
return box(name, void 0, [
|
|
4178
|
+
box("data", [
|
|
4179
|
+
u32(1),
|
|
4180
|
+
// Type indicator (UTF-8)
|
|
4181
|
+
u32(0),
|
|
4182
|
+
// Locale indicator
|
|
4183
|
+
...textEncoder.encode(value)
|
|
4184
|
+
])
|
|
4185
|
+
]);
|
|
4186
|
+
};
|
|
3743
4187
|
var VIDEO_CODEC_TO_BOX_NAME = {
|
|
3744
4188
|
avc: "avc1",
|
|
3745
4189
|
hevc: "hvc1",
|
|
@@ -3887,6 +4331,16 @@ var Mediabunny = (() => {
|
|
|
3887
4331
|
var SUBTITLE_CODEC_TO_CONFIGURATION_BOX = {
|
|
3888
4332
|
webvtt: vttC
|
|
3889
4333
|
};
|
|
4334
|
+
var getLanguageCodeInt = (code) => {
|
|
4335
|
+
assert(code.length === 3);
|
|
4336
|
+
;
|
|
4337
|
+
let language = 0;
|
|
4338
|
+
for (let i = 0; i < 3; i++) {
|
|
4339
|
+
language <<= 5;
|
|
4340
|
+
language += code.charCodeAt(i) - 96;
|
|
4341
|
+
}
|
|
4342
|
+
return language;
|
|
4343
|
+
};
|
|
3890
4344
|
|
|
3891
4345
|
// src/writer.ts
|
|
3892
4346
|
var Writer = class {
|
|
@@ -4522,6 +4976,36 @@ var Mediabunny = (() => {
|
|
|
4522
4976
|
}
|
|
4523
4977
|
return result;
|
|
4524
4978
|
};
|
|
4979
|
+
var readMetadataStringShort = (slice) => {
|
|
4980
|
+
const stringLength = readU16Be(slice);
|
|
4981
|
+
slice.skip(2);
|
|
4982
|
+
return textDecoder.decode(readBytes(slice, stringLength));
|
|
4983
|
+
};
|
|
4984
|
+
var readDataBox = (slice) => {
|
|
4985
|
+
const header = readBoxHeader(slice);
|
|
4986
|
+
if (!header || header.name !== "data") {
|
|
4987
|
+
return null;
|
|
4988
|
+
}
|
|
4989
|
+
const typeIndicator = readU32Be(slice);
|
|
4990
|
+
slice.skip(4);
|
|
4991
|
+
const data = readBytes(slice, header.contentSize - 8);
|
|
4992
|
+
switch (typeIndicator) {
|
|
4993
|
+
case 1:
|
|
4994
|
+
return textDecoder.decode(data);
|
|
4995
|
+
// UTF-8
|
|
4996
|
+
case 2:
|
|
4997
|
+
return new TextDecoder("utf-16be").decode(data);
|
|
4998
|
+
// UTF-16-BE
|
|
4999
|
+
case 13:
|
|
5000
|
+
return new RichImageData(data, "image/jpeg");
|
|
5001
|
+
case 14:
|
|
5002
|
+
return new RichImageData(data, "image/png");
|
|
5003
|
+
case 27:
|
|
5004
|
+
return new RichImageData(data, "image/bmp");
|
|
5005
|
+
default:
|
|
5006
|
+
return data;
|
|
5007
|
+
}
|
|
5008
|
+
};
|
|
4525
5009
|
|
|
4526
5010
|
// src/isobmff/isobmff-muxer.ts
|
|
4527
5011
|
var GLOBAL_TIMESCALE = 1e3;
|
|
@@ -4538,7 +5022,7 @@ var Mediabunny = (() => {
|
|
|
4538
5022
|
const value = timeInSeconds * timescale;
|
|
4539
5023
|
return round ? Math.round(value) : value;
|
|
4540
5024
|
};
|
|
4541
|
-
var
|
|
5025
|
+
var IsobmffMuxer2 = class extends Muxer {
|
|
4542
5026
|
constructor(output, format) {
|
|
4543
5027
|
super(output);
|
|
4544
5028
|
this.auxTarget = new BufferTarget();
|
|
@@ -4623,15 +5107,15 @@ var Mediabunny = (() => {
|
|
|
4623
5107
|
codecStrings
|
|
4624
5108
|
});
|
|
4625
5109
|
}
|
|
4626
|
-
getVideoTrackData(track, packet,
|
|
5110
|
+
getVideoTrackData(track, packet, meta2) {
|
|
4627
5111
|
const existingTrackData = this.trackDatas.find((x) => x.track === track);
|
|
4628
5112
|
if (existingTrackData) {
|
|
4629
5113
|
return existingTrackData;
|
|
4630
5114
|
}
|
|
4631
|
-
validateVideoChunkMetadata(
|
|
4632
|
-
assert(
|
|
4633
|
-
assert(
|
|
4634
|
-
const decoderConfig = { ...
|
|
5115
|
+
validateVideoChunkMetadata(meta2);
|
|
5116
|
+
assert(meta2);
|
|
5117
|
+
assert(meta2.decoderConfig);
|
|
5118
|
+
const decoderConfig = { ...meta2.decoderConfig };
|
|
4635
5119
|
assert(decoderConfig.codedWidth !== void 0);
|
|
4636
5120
|
assert(decoderConfig.codedHeight !== void 0);
|
|
4637
5121
|
let requiresAnnexBTransformation = false;
|
|
@@ -4684,25 +5168,25 @@ var Mediabunny = (() => {
|
|
|
4684
5168
|
}
|
|
4685
5169
|
return newTrackData;
|
|
4686
5170
|
}
|
|
4687
|
-
getAudioTrackData(track,
|
|
5171
|
+
getAudioTrackData(track, meta2) {
|
|
4688
5172
|
const existingTrackData = this.trackDatas.find((x) => x.track === track);
|
|
4689
5173
|
if (existingTrackData) {
|
|
4690
5174
|
return existingTrackData;
|
|
4691
5175
|
}
|
|
4692
|
-
validateAudioChunkMetadata(
|
|
4693
|
-
assert(
|
|
4694
|
-
assert(
|
|
5176
|
+
validateAudioChunkMetadata(meta2);
|
|
5177
|
+
assert(meta2);
|
|
5178
|
+
assert(meta2.decoderConfig);
|
|
4695
5179
|
const newTrackData = {
|
|
4696
5180
|
muxer: this,
|
|
4697
5181
|
track,
|
|
4698
5182
|
type: "audio",
|
|
4699
5183
|
info: {
|
|
4700
|
-
numberOfChannels:
|
|
4701
|
-
sampleRate:
|
|
4702
|
-
decoderConfig:
|
|
5184
|
+
numberOfChannels: meta2.decoderConfig.numberOfChannels,
|
|
5185
|
+
sampleRate: meta2.decoderConfig.sampleRate,
|
|
5186
|
+
decoderConfig: meta2.decoderConfig,
|
|
4703
5187
|
requiresPcmTransformation: !this.isFragmented && PCM_AUDIO_CODECS.includes(track.source._codec)
|
|
4704
5188
|
},
|
|
4705
|
-
timescale:
|
|
5189
|
+
timescale: meta2.decoderConfig.sampleRate,
|
|
4706
5190
|
samples: [],
|
|
4707
5191
|
sampleQueue: [],
|
|
4708
5192
|
timestampProcessingQueue: [],
|
|
@@ -4721,20 +5205,20 @@ var Mediabunny = (() => {
|
|
|
4721
5205
|
}
|
|
4722
5206
|
return newTrackData;
|
|
4723
5207
|
}
|
|
4724
|
-
getSubtitleTrackData(track,
|
|
5208
|
+
getSubtitleTrackData(track, meta2) {
|
|
4725
5209
|
const existingTrackData = this.trackDatas.find((x) => x.track === track);
|
|
4726
5210
|
if (existingTrackData) {
|
|
4727
5211
|
return existingTrackData;
|
|
4728
5212
|
}
|
|
4729
|
-
validateSubtitleMetadata(
|
|
4730
|
-
assert(
|
|
4731
|
-
assert(
|
|
5213
|
+
validateSubtitleMetadata(meta2);
|
|
5214
|
+
assert(meta2);
|
|
5215
|
+
assert(meta2.config);
|
|
4732
5216
|
const newTrackData = {
|
|
4733
5217
|
muxer: this,
|
|
4734
5218
|
track,
|
|
4735
5219
|
type: "subtitle",
|
|
4736
5220
|
info: {
|
|
4737
|
-
config:
|
|
5221
|
+
config: meta2.config
|
|
4738
5222
|
},
|
|
4739
5223
|
timescale: 1e3,
|
|
4740
5224
|
// Reasonable
|
|
@@ -4760,10 +5244,10 @@ var Mediabunny = (() => {
|
|
|
4760
5244
|
}
|
|
4761
5245
|
return newTrackData;
|
|
4762
5246
|
}
|
|
4763
|
-
async addEncodedVideoPacket(track, packet,
|
|
5247
|
+
async addEncodedVideoPacket(track, packet, meta2) {
|
|
4764
5248
|
const release = await this.mutex.acquire();
|
|
4765
5249
|
try {
|
|
4766
|
-
const trackData = this.getVideoTrackData(track, packet,
|
|
5250
|
+
const trackData = this.getVideoTrackData(track, packet, meta2);
|
|
4767
5251
|
let packetData = packet.data;
|
|
4768
5252
|
if (trackData.info.requiresAnnexBTransformation) {
|
|
4769
5253
|
const transformedData = transformAnnexBToLengthPrefixed(packetData);
|
|
@@ -4791,10 +5275,10 @@ var Mediabunny = (() => {
|
|
|
4791
5275
|
release();
|
|
4792
5276
|
}
|
|
4793
5277
|
}
|
|
4794
|
-
async addEncodedAudioPacket(track, packet,
|
|
5278
|
+
async addEncodedAudioPacket(track, packet, meta2) {
|
|
4795
5279
|
const release = await this.mutex.acquire();
|
|
4796
5280
|
try {
|
|
4797
|
-
const trackData = this.getAudioTrackData(track,
|
|
5281
|
+
const trackData = this.getAudioTrackData(track, meta2);
|
|
4798
5282
|
const timestamp = this.validateAndNormalizeTimestamp(
|
|
4799
5283
|
trackData.track,
|
|
4800
5284
|
packet.timestamp,
|
|
@@ -4836,10 +5320,10 @@ var Mediabunny = (() => {
|
|
|
4836
5320
|
await this.registerSample(trackData, paddingSample);
|
|
4837
5321
|
}
|
|
4838
5322
|
}
|
|
4839
|
-
async addSubtitleCue(track, cue,
|
|
5323
|
+
async addSubtitleCue(track, cue, meta2) {
|
|
4840
5324
|
const release = await this.mutex.acquire();
|
|
4841
5325
|
try {
|
|
4842
|
-
const trackData = this.getSubtitleTrackData(track,
|
|
5326
|
+
const trackData = this.getSubtitleTrackData(track, meta2);
|
|
4843
5327
|
this.validateAndNormalizeTimestamp(trackData.track, cue.timestamp, true);
|
|
4844
5328
|
if (track.source._codec === "webvtt") {
|
|
4845
5329
|
trackData.cueQueue.push(cue);
|
|
@@ -5154,7 +5638,7 @@ var Mediabunny = (() => {
|
|
|
5154
5638
|
if (this.format._options.onMoov) {
|
|
5155
5639
|
this.writer.startTrackingWrites();
|
|
5156
5640
|
}
|
|
5157
|
-
const movieBox = moov(this
|
|
5641
|
+
const movieBox = moov(this, true);
|
|
5158
5642
|
this.boxWriter.writeBox(movieBox);
|
|
5159
5643
|
if (this.format._options.onMoov) {
|
|
5160
5644
|
const { data, start } = this.writer.stopTrackingWrites();
|
|
@@ -5260,7 +5744,7 @@ var Mediabunny = (() => {
|
|
|
5260
5744
|
assert(this.mdat);
|
|
5261
5745
|
let mdatSize;
|
|
5262
5746
|
for (let i = 0; i < 2; i++) {
|
|
5263
|
-
const movieBox2 = moov(this
|
|
5747
|
+
const movieBox2 = moov(this);
|
|
5264
5748
|
const movieBoxSize = this.boxWriter.measureBox(movieBox2);
|
|
5265
5749
|
mdatSize = this.boxWriter.measureBox(this.mdat);
|
|
5266
5750
|
let currentChunkPos = this.writer.getPos() + movieBoxSize + mdatSize;
|
|
@@ -5278,7 +5762,7 @@ var Mediabunny = (() => {
|
|
|
5278
5762
|
if (this.format._options.onMoov) {
|
|
5279
5763
|
this.writer.startTrackingWrites();
|
|
5280
5764
|
}
|
|
5281
|
-
const movieBox = moov(this
|
|
5765
|
+
const movieBox = moov(this);
|
|
5282
5766
|
this.boxWriter.writeBox(movieBox);
|
|
5283
5767
|
if (this.format._options.onMoov) {
|
|
5284
5768
|
const { data, start } = this.writer.stopTrackingWrites();
|
|
@@ -5322,7 +5806,7 @@ var Mediabunny = (() => {
|
|
|
5322
5806
|
if (this.format._options.onMoov) {
|
|
5323
5807
|
this.writer.startTrackingWrites();
|
|
5324
5808
|
}
|
|
5325
|
-
const movieBox = moov(this
|
|
5809
|
+
const movieBox = moov(this);
|
|
5326
5810
|
this.boxWriter.writeBox(movieBox);
|
|
5327
5811
|
if (this.format._options.onMoov) {
|
|
5328
5812
|
const { data, start } = this.writer.stopTrackingWrites();
|
|
@@ -5767,7 +6251,7 @@ var Mediabunny = (() => {
|
|
|
5767
6251
|
// src/matroska/matroska-muxer.ts
|
|
5768
6252
|
var MIN_CLUSTER_TIMESTAMP_MS = -(2 ** 15);
|
|
5769
6253
|
var MAX_CLUSTER_TIMESTAMP_MS = 2 ** 15 - 1;
|
|
5770
|
-
var APP_NAME = "
|
|
6254
|
+
var APP_NAME = "Mediabunny";
|
|
5771
6255
|
var SEGMENT_SIZE_BYTES = 6;
|
|
5772
6256
|
var CLUSTER_SIZE_BYTES = 5;
|
|
5773
6257
|
var TRACK_TYPE_MAP = {
|
|
@@ -5784,6 +6268,8 @@ var Mediabunny = (() => {
|
|
|
5784
6268
|
this.segmentInfo = null;
|
|
5785
6269
|
this.seekHead = null;
|
|
5786
6270
|
this.tracksElement = null;
|
|
6271
|
+
this.tagsElement = null;
|
|
6272
|
+
this.attachmentsElement = null;
|
|
5787
6273
|
this.segmentDuration = null;
|
|
5788
6274
|
this.cues = null;
|
|
5789
6275
|
this.currentCluster = null;
|
|
@@ -5801,9 +6287,6 @@ var Mediabunny = (() => {
|
|
|
5801
6287
|
async start() {
|
|
5802
6288
|
const release = await this.mutex.acquire();
|
|
5803
6289
|
this.writeEBMLHeader();
|
|
5804
|
-
if (!this.format._options.appendOnly) {
|
|
5805
|
-
this.createSeekHead();
|
|
5806
|
-
}
|
|
5807
6290
|
this.createSegmentInfo();
|
|
5808
6291
|
this.createCues();
|
|
5809
6292
|
await this.writer.flush();
|
|
@@ -5832,23 +6315,56 @@ var Mediabunny = (() => {
|
|
|
5832
6315
|
* Creates a SeekHead element which is positioned near the start of the file and allows the media player to seek to
|
|
5833
6316
|
* relevant sections more easily. Since we don't know the positions of those sections yet, we'll set them later.
|
|
5834
6317
|
*/
|
|
5835
|
-
|
|
6318
|
+
maybeCreateSeekHead(writeOffsets) {
|
|
6319
|
+
if (this.format._options.appendOnly) {
|
|
6320
|
+
return;
|
|
6321
|
+
}
|
|
5836
6322
|
const kaxCues = new Uint8Array([28, 83, 187, 107]);
|
|
5837
6323
|
const kaxInfo = new Uint8Array([21, 73, 169, 102]);
|
|
5838
6324
|
const kaxTracks = new Uint8Array([22, 84, 174, 107]);
|
|
6325
|
+
const kaxAttachments = new Uint8Array([25, 65, 164, 105]);
|
|
6326
|
+
const kaxTags = new Uint8Array([18, 84, 195, 103]);
|
|
5839
6327
|
const seekHead = { id: 290298740 /* SeekHead */, data: [
|
|
5840
6328
|
{ id: 19899 /* Seek */, data: [
|
|
5841
6329
|
{ id: 21419 /* SeekID */, data: kaxCues },
|
|
5842
|
-
{
|
|
6330
|
+
{
|
|
6331
|
+
id: 21420 /* SeekPosition */,
|
|
6332
|
+
size: 5,
|
|
6333
|
+
data: writeOffsets ? this.ebmlWriter.offsets.get(this.cues) - this.segmentDataOffset : 0
|
|
6334
|
+
}
|
|
5843
6335
|
] },
|
|
5844
6336
|
{ id: 19899 /* Seek */, data: [
|
|
5845
6337
|
{ id: 21419 /* SeekID */, data: kaxInfo },
|
|
5846
|
-
{
|
|
6338
|
+
{
|
|
6339
|
+
id: 21420 /* SeekPosition */,
|
|
6340
|
+
size: 5,
|
|
6341
|
+
data: writeOffsets ? this.ebmlWriter.offsets.get(this.segmentInfo) - this.segmentDataOffset : 0
|
|
6342
|
+
}
|
|
5847
6343
|
] },
|
|
5848
6344
|
{ id: 19899 /* Seek */, data: [
|
|
5849
6345
|
{ id: 21419 /* SeekID */, data: kaxTracks },
|
|
5850
|
-
{
|
|
5851
|
-
|
|
6346
|
+
{
|
|
6347
|
+
id: 21420 /* SeekPosition */,
|
|
6348
|
+
size: 5,
|
|
6349
|
+
data: writeOffsets ? this.ebmlWriter.offsets.get(this.tracksElement) - this.segmentDataOffset : 0
|
|
6350
|
+
}
|
|
6351
|
+
] },
|
|
6352
|
+
this.attachmentsElement ? { id: 19899 /* Seek */, data: [
|
|
6353
|
+
{ id: 21419 /* SeekID */, data: kaxAttachments },
|
|
6354
|
+
{
|
|
6355
|
+
id: 21420 /* SeekPosition */,
|
|
6356
|
+
size: 5,
|
|
6357
|
+
data: writeOffsets ? this.ebmlWriter.offsets.get(this.attachmentsElement) - this.segmentDataOffset : 0
|
|
6358
|
+
}
|
|
6359
|
+
] } : null,
|
|
6360
|
+
this.tagsElement ? { id: 19899 /* Seek */, data: [
|
|
6361
|
+
{ id: 21419 /* SeekID */, data: kaxTags },
|
|
6362
|
+
{
|
|
6363
|
+
id: 21420 /* SeekPosition */,
|
|
6364
|
+
size: 5,
|
|
6365
|
+
data: writeOffsets ? this.ebmlWriter.offsets.get(this.tagsElement) - this.segmentDataOffset : 0
|
|
6366
|
+
}
|
|
6367
|
+
] } : null
|
|
5852
6368
|
] };
|
|
5853
6369
|
this.seekHead = seekHead;
|
|
5854
6370
|
}
|
|
@@ -5971,48 +6487,221 @@ var Mediabunny = (() => {
|
|
|
5971
6487
|
{ id: 25506 /* CodecPrivate */, data: textEncoder.encode(trackData.info.config.description) }
|
|
5972
6488
|
];
|
|
5973
6489
|
}
|
|
5974
|
-
|
|
5975
|
-
const
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
this.tracksElement
|
|
5982
|
-
]
|
|
6490
|
+
maybeCreateTags() {
|
|
6491
|
+
const simpleTags = [];
|
|
6492
|
+
const addSimpleTag = (key, value) => {
|
|
6493
|
+
simpleTags.push({ id: 26568 /* SimpleTag */, data: [
|
|
6494
|
+
{ id: 17827 /* TagName */, data: new EBMLUnicodeString(key) },
|
|
6495
|
+
typeof value === "string" ? { id: 17543 /* TagString */, data: new EBMLUnicodeString(value) } : { id: 17541 /* TagBinary */, data: value }
|
|
6496
|
+
] });
|
|
5983
6497
|
};
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6498
|
+
const metadataTags = this.output._metadataTags;
|
|
6499
|
+
const writtenTags = /* @__PURE__ */ new Set();
|
|
6500
|
+
for (const { key, value } of keyValueIterator(metadataTags)) {
|
|
6501
|
+
switch (key) {
|
|
6502
|
+
case "title":
|
|
6503
|
+
{
|
|
6504
|
+
addSimpleTag("TITLE", value);
|
|
6505
|
+
writtenTags.add("TITLE");
|
|
6506
|
+
}
|
|
6507
|
+
;
|
|
6508
|
+
break;
|
|
6509
|
+
case "description":
|
|
6510
|
+
{
|
|
6511
|
+
addSimpleTag("DESCRIPTION", value);
|
|
6512
|
+
writtenTags.add("DESCRIPTION");
|
|
6513
|
+
}
|
|
6514
|
+
;
|
|
6515
|
+
break;
|
|
6516
|
+
case "artist":
|
|
6517
|
+
{
|
|
6518
|
+
addSimpleTag("ARTIST", value);
|
|
6519
|
+
writtenTags.add("ARTIST");
|
|
6520
|
+
}
|
|
6521
|
+
;
|
|
6522
|
+
break;
|
|
6523
|
+
case "album":
|
|
6524
|
+
{
|
|
6525
|
+
addSimpleTag("ALBUM", value);
|
|
6526
|
+
writtenTags.add("ALBUM");
|
|
6527
|
+
}
|
|
6528
|
+
;
|
|
6529
|
+
break;
|
|
6530
|
+
case "albumArtist":
|
|
6531
|
+
{
|
|
6532
|
+
addSimpleTag("ALBUM_ARTIST", value);
|
|
6533
|
+
writtenTags.add("ALBUM_ARTIST");
|
|
6534
|
+
}
|
|
6535
|
+
;
|
|
6536
|
+
break;
|
|
6537
|
+
case "genre":
|
|
6538
|
+
{
|
|
6539
|
+
addSimpleTag("GENRE", value);
|
|
6540
|
+
writtenTags.add("GENRE");
|
|
6541
|
+
}
|
|
6542
|
+
;
|
|
6543
|
+
break;
|
|
6544
|
+
case "comment":
|
|
6545
|
+
{
|
|
6546
|
+
addSimpleTag("COMMENT", value);
|
|
6547
|
+
writtenTags.add("COMMENT");
|
|
6548
|
+
}
|
|
6549
|
+
;
|
|
6550
|
+
break;
|
|
6551
|
+
case "lyrics":
|
|
6552
|
+
{
|
|
6553
|
+
addSimpleTag("LYRICS", value);
|
|
6554
|
+
writtenTags.add("LYRICS");
|
|
6555
|
+
}
|
|
6556
|
+
;
|
|
6557
|
+
break;
|
|
6558
|
+
case "date":
|
|
6559
|
+
{
|
|
6560
|
+
addSimpleTag("DATE", value.toISOString().slice(0, 10));
|
|
6561
|
+
writtenTags.add("DATE");
|
|
6562
|
+
}
|
|
6563
|
+
;
|
|
6564
|
+
break;
|
|
6565
|
+
case "trackNumber":
|
|
6566
|
+
{
|
|
6567
|
+
const string = metadataTags.tracksTotal !== void 0 ? `${value}/${metadataTags.tracksTotal}` : value.toString();
|
|
6568
|
+
addSimpleTag("PART_NUMBER", string);
|
|
6569
|
+
writtenTags.add("PART_NUMBER");
|
|
6570
|
+
}
|
|
6571
|
+
;
|
|
6572
|
+
break;
|
|
6573
|
+
case "discNumber":
|
|
6574
|
+
{
|
|
6575
|
+
const string = metadataTags.discsTotal !== void 0 ? `${value}/${metadataTags.discsTotal}` : value.toString();
|
|
6576
|
+
addSimpleTag("DISC", string);
|
|
6577
|
+
writtenTags.add("DISC");
|
|
6578
|
+
}
|
|
6579
|
+
;
|
|
6580
|
+
break;
|
|
6581
|
+
case "tracksTotal":
|
|
6582
|
+
case "discsTotal":
|
|
6583
|
+
{
|
|
6584
|
+
}
|
|
6585
|
+
;
|
|
6586
|
+
break;
|
|
6587
|
+
case "images":
|
|
6588
|
+
case "raw":
|
|
6589
|
+
{
|
|
6590
|
+
}
|
|
6591
|
+
;
|
|
6592
|
+
break;
|
|
6593
|
+
default:
|
|
6594
|
+
assertNever(key);
|
|
6595
|
+
}
|
|
6596
|
+
}
|
|
6597
|
+
if (metadataTags.raw) {
|
|
6598
|
+
for (const key in metadataTags.raw) {
|
|
6599
|
+
const value = metadataTags.raw[key];
|
|
6600
|
+
if (value == null || writtenTags.has(key)) {
|
|
6601
|
+
continue;
|
|
6602
|
+
}
|
|
6603
|
+
if (typeof value === "string" || value instanceof Uint8Array) {
|
|
6604
|
+
addSimpleTag(key, value);
|
|
6605
|
+
}
|
|
6606
|
+
}
|
|
6607
|
+
}
|
|
6608
|
+
if (simpleTags.length === 0) {
|
|
6609
|
+
return;
|
|
6610
|
+
}
|
|
6611
|
+
this.tagsElement = {
|
|
6612
|
+
id: 307544935 /* Tags */,
|
|
6613
|
+
data: [{ id: 29555 /* Tag */, data: [
|
|
6614
|
+
{ id: 25536 /* Targets */, data: [
|
|
6615
|
+
{ id: 26826 /* TargetTypeValue */, data: 50 },
|
|
6616
|
+
{ id: 25546 /* TargetType */, data: "MOVIE" }
|
|
6617
|
+
] },
|
|
6618
|
+
...simpleTags
|
|
6619
|
+
] }]
|
|
6620
|
+
};
|
|
6621
|
+
}
|
|
6622
|
+
maybeCreateAttachments() {
|
|
6623
|
+
const metadataTags = this.output._metadataTags;
|
|
6624
|
+
if (!metadataTags.images || metadataTags.images.length === 0) {
|
|
6625
|
+
return;
|
|
6626
|
+
}
|
|
6627
|
+
const existingFileUids = /* @__PURE__ */ new Set();
|
|
6628
|
+
this.attachmentsElement = { id: 423732329 /* Attachments */, data: metadataTags.images.map((image) => {
|
|
6629
|
+
let imageName = image.name;
|
|
6630
|
+
if (imageName === void 0) {
|
|
6631
|
+
const baseName = image.kind === "coverFront" ? "cover" : image.kind === "coverBack" ? "back" : "image";
|
|
6632
|
+
imageName = baseName + (imageMimeTypeToExtension(image.mimeType) ?? "");
|
|
6633
|
+
}
|
|
6634
|
+
let fileUid;
|
|
6635
|
+
while (true) {
|
|
6636
|
+
fileUid = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
|
6637
|
+
if (fileUid !== 0 && !existingFileUids.has(fileUid)) {
|
|
6638
|
+
break;
|
|
6639
|
+
}
|
|
6640
|
+
}
|
|
6641
|
+
existingFileUids.add(fileUid);
|
|
6642
|
+
return {
|
|
6643
|
+
id: 24999 /* AttachedFile */,
|
|
6644
|
+
data: [
|
|
6645
|
+
image.description !== void 0 ? { id: 18046 /* FileDescription */, data: new EBMLUnicodeString(image.description) } : null,
|
|
6646
|
+
{ id: 18030 /* FileName */, data: new EBMLUnicodeString(imageName) },
|
|
6647
|
+
{ id: 18016 /* FileMediaType */, data: image.mimeType },
|
|
6648
|
+
{ id: 18012 /* FileData */, data: image.data },
|
|
6649
|
+
{ id: 18094 /* FileUID */, data: fileUid }
|
|
6650
|
+
]
|
|
6651
|
+
};
|
|
6652
|
+
}) };
|
|
6653
|
+
}
|
|
6654
|
+
createSegment() {
|
|
6655
|
+
this.createTracks();
|
|
6656
|
+
this.maybeCreateTags();
|
|
6657
|
+
this.maybeCreateAttachments();
|
|
6658
|
+
this.maybeCreateSeekHead(false);
|
|
6659
|
+
const segment = {
|
|
6660
|
+
id: 408125543 /* Segment */,
|
|
6661
|
+
size: this.format._options.appendOnly ? -1 : SEGMENT_SIZE_BYTES,
|
|
6662
|
+
data: [
|
|
6663
|
+
this.seekHead,
|
|
6664
|
+
// null if append-only
|
|
6665
|
+
this.segmentInfo,
|
|
6666
|
+
this.tracksElement,
|
|
6667
|
+
// Matroska spec says put this at the end of the file, but I think placing it before the first cluster
|
|
6668
|
+
// makes more sense, and FFmpeg agrees (argumentum ad ffmpegum fallacy)
|
|
6669
|
+
this.attachmentsElement,
|
|
6670
|
+
this.tagsElement
|
|
6671
|
+
]
|
|
6672
|
+
};
|
|
6673
|
+
this.segment = segment;
|
|
6674
|
+
if (this.format._options.onSegmentHeader) {
|
|
6675
|
+
this.writer.startTrackingWrites();
|
|
6676
|
+
}
|
|
6677
|
+
this.ebmlWriter.writeEBML(segment);
|
|
6678
|
+
if (this.format._options.onSegmentHeader) {
|
|
6679
|
+
const { data, start } = this.writer.stopTrackingWrites();
|
|
6680
|
+
this.format._options.onSegmentHeader(data, start);
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6683
|
+
createCues() {
|
|
6684
|
+
this.cues = { id: 475249515 /* Cues */, data: [] };
|
|
6685
|
+
}
|
|
6686
|
+
get segmentDataOffset() {
|
|
6687
|
+
assert(this.segment);
|
|
6688
|
+
return this.ebmlWriter.dataOffsets.get(this.segment);
|
|
6689
|
+
}
|
|
6690
|
+
allTracksAreKnown() {
|
|
6691
|
+
for (const track of this.output._tracks) {
|
|
6692
|
+
if (!track.source._closed && !this.trackDatas.some((x) => x.track === track)) {
|
|
6693
|
+
return false;
|
|
6694
|
+
}
|
|
6695
|
+
}
|
|
6696
|
+
return true;
|
|
6697
|
+
}
|
|
6698
|
+
async getMimeType() {
|
|
6699
|
+
await this.allTracksKnown.promise;
|
|
6700
|
+
const codecStrings = this.trackDatas.map((trackData) => {
|
|
6701
|
+
if (trackData.type === "video") {
|
|
6702
|
+
return trackData.info.decoderConfig.codec;
|
|
6703
|
+
} else if (trackData.type === "audio") {
|
|
6704
|
+
return trackData.info.decoderConfig.codec;
|
|
6016
6705
|
} else {
|
|
6017
6706
|
const map = {
|
|
6018
6707
|
webvtt: "wvtt"
|
|
@@ -6027,23 +6716,23 @@ var Mediabunny = (() => {
|
|
|
6027
6716
|
codecStrings
|
|
6028
6717
|
});
|
|
6029
6718
|
}
|
|
6030
|
-
getVideoTrackData(track,
|
|
6719
|
+
getVideoTrackData(track, meta2) {
|
|
6031
6720
|
const existingTrackData = this.trackDatas.find((x) => x.track === track);
|
|
6032
6721
|
if (existingTrackData) {
|
|
6033
6722
|
return existingTrackData;
|
|
6034
6723
|
}
|
|
6035
|
-
validateVideoChunkMetadata(
|
|
6036
|
-
assert(
|
|
6037
|
-
assert(
|
|
6038
|
-
assert(
|
|
6039
|
-
assert(
|
|
6724
|
+
validateVideoChunkMetadata(meta2);
|
|
6725
|
+
assert(meta2);
|
|
6726
|
+
assert(meta2.decoderConfig);
|
|
6727
|
+
assert(meta2.decoderConfig.codedWidth !== void 0);
|
|
6728
|
+
assert(meta2.decoderConfig.codedHeight !== void 0);
|
|
6040
6729
|
const newTrackData = {
|
|
6041
6730
|
track,
|
|
6042
6731
|
type: "video",
|
|
6043
6732
|
info: {
|
|
6044
|
-
width:
|
|
6045
|
-
height:
|
|
6046
|
-
decoderConfig:
|
|
6733
|
+
width: meta2.decoderConfig.codedWidth,
|
|
6734
|
+
height: meta2.decoderConfig.codedHeight,
|
|
6735
|
+
decoderConfig: meta2.decoderConfig
|
|
6047
6736
|
},
|
|
6048
6737
|
chunkQueue: [],
|
|
6049
6738
|
lastWrittenMsTimestamp: null
|
|
@@ -6070,21 +6759,21 @@ var Mediabunny = (() => {
|
|
|
6070
6759
|
}
|
|
6071
6760
|
return newTrackData;
|
|
6072
6761
|
}
|
|
6073
|
-
getAudioTrackData(track,
|
|
6762
|
+
getAudioTrackData(track, meta2) {
|
|
6074
6763
|
const existingTrackData = this.trackDatas.find((x) => x.track === track);
|
|
6075
6764
|
if (existingTrackData) {
|
|
6076
6765
|
return existingTrackData;
|
|
6077
6766
|
}
|
|
6078
|
-
validateAudioChunkMetadata(
|
|
6079
|
-
assert(
|
|
6080
|
-
assert(
|
|
6767
|
+
validateAudioChunkMetadata(meta2);
|
|
6768
|
+
assert(meta2);
|
|
6769
|
+
assert(meta2.decoderConfig);
|
|
6081
6770
|
const newTrackData = {
|
|
6082
6771
|
track,
|
|
6083
6772
|
type: "audio",
|
|
6084
6773
|
info: {
|
|
6085
|
-
numberOfChannels:
|
|
6086
|
-
sampleRate:
|
|
6087
|
-
decoderConfig:
|
|
6774
|
+
numberOfChannels: meta2.decoderConfig.numberOfChannels,
|
|
6775
|
+
sampleRate: meta2.decoderConfig.sampleRate,
|
|
6776
|
+
decoderConfig: meta2.decoderConfig
|
|
6088
6777
|
},
|
|
6089
6778
|
chunkQueue: [],
|
|
6090
6779
|
lastWrittenMsTimestamp: null
|
|
@@ -6096,19 +6785,19 @@ var Mediabunny = (() => {
|
|
|
6096
6785
|
}
|
|
6097
6786
|
return newTrackData;
|
|
6098
6787
|
}
|
|
6099
|
-
getSubtitleTrackData(track,
|
|
6788
|
+
getSubtitleTrackData(track, meta2) {
|
|
6100
6789
|
const existingTrackData = this.trackDatas.find((x) => x.track === track);
|
|
6101
6790
|
if (existingTrackData) {
|
|
6102
6791
|
return existingTrackData;
|
|
6103
6792
|
}
|
|
6104
|
-
validateSubtitleMetadata(
|
|
6105
|
-
assert(
|
|
6106
|
-
assert(
|
|
6793
|
+
validateSubtitleMetadata(meta2);
|
|
6794
|
+
assert(meta2);
|
|
6795
|
+
assert(meta2.config);
|
|
6107
6796
|
const newTrackData = {
|
|
6108
6797
|
track,
|
|
6109
6798
|
type: "subtitle",
|
|
6110
6799
|
info: {
|
|
6111
|
-
config:
|
|
6800
|
+
config: meta2.config
|
|
6112
6801
|
},
|
|
6113
6802
|
chunkQueue: [],
|
|
6114
6803
|
lastWrittenMsTimestamp: null
|
|
@@ -6120,10 +6809,10 @@ var Mediabunny = (() => {
|
|
|
6120
6809
|
}
|
|
6121
6810
|
return newTrackData;
|
|
6122
6811
|
}
|
|
6123
|
-
async addEncodedVideoPacket(track, packet,
|
|
6812
|
+
async addEncodedVideoPacket(track, packet, meta2) {
|
|
6124
6813
|
const release = await this.mutex.acquire();
|
|
6125
6814
|
try {
|
|
6126
|
-
const trackData = this.getVideoTrackData(track,
|
|
6815
|
+
const trackData = this.getVideoTrackData(track, meta2);
|
|
6127
6816
|
const isKeyFrame = packet.type === "key";
|
|
6128
6817
|
let timestamp = this.validateAndNormalizeTimestamp(trackData.track, packet.timestamp, isKeyFrame);
|
|
6129
6818
|
let duration = packet.duration;
|
|
@@ -6139,10 +6828,10 @@ var Mediabunny = (() => {
|
|
|
6139
6828
|
release();
|
|
6140
6829
|
}
|
|
6141
6830
|
}
|
|
6142
|
-
async addEncodedAudioPacket(track, packet,
|
|
6831
|
+
async addEncodedAudioPacket(track, packet, meta2) {
|
|
6143
6832
|
const release = await this.mutex.acquire();
|
|
6144
6833
|
try {
|
|
6145
|
-
const trackData = this.getAudioTrackData(track,
|
|
6834
|
+
const trackData = this.getAudioTrackData(track, meta2);
|
|
6146
6835
|
const isKeyFrame = packet.type === "key";
|
|
6147
6836
|
const timestamp = this.validateAndNormalizeTimestamp(trackData.track, packet.timestamp, isKeyFrame);
|
|
6148
6837
|
const audioChunk = this.createInternalChunk(packet.data, timestamp, packet.duration, packet.type);
|
|
@@ -6152,10 +6841,10 @@ var Mediabunny = (() => {
|
|
|
6152
6841
|
release();
|
|
6153
6842
|
}
|
|
6154
6843
|
}
|
|
6155
|
-
async addSubtitleCue(track, cue,
|
|
6844
|
+
async addSubtitleCue(track, cue, meta2) {
|
|
6156
6845
|
const release = await this.mutex.acquire();
|
|
6157
6846
|
try {
|
|
6158
|
-
const trackData = this.getSubtitleTrackData(track,
|
|
6847
|
+
const trackData = this.getSubtitleTrackData(track, meta2);
|
|
6159
6848
|
const timestamp = this.validateAndNormalizeTimestamp(trackData.track, cue.timestamp, true);
|
|
6160
6849
|
let bodyText = cue.text;
|
|
6161
6850
|
const timestampMs = Math.round(timestamp * 1e3);
|
|
@@ -6254,7 +6943,6 @@ ${cue.notes ?? ""}`;
|
|
|
6254
6943
|
/** Writes a block containing media data to the file. */
|
|
6255
6944
|
writeBlock(trackData, chunk) {
|
|
6256
6945
|
if (!this.segment) {
|
|
6257
|
-
this.createTracks();
|
|
6258
6946
|
this.createSegment();
|
|
6259
6947
|
}
|
|
6260
6948
|
const msTimestamp = Math.round(1e3 * chunk.timestamp);
|
|
@@ -6396,7 +7084,6 @@ ${cue.notes ?? ""}`;
|
|
|
6396
7084
|
const release = await this.mutex.acquire();
|
|
6397
7085
|
this.allTracksKnown.resolve();
|
|
6398
7086
|
if (!this.segment) {
|
|
6399
|
-
this.createTracks();
|
|
6400
7087
|
this.createSegment();
|
|
6401
7088
|
}
|
|
6402
7089
|
await this.interleaveChunks(true);
|
|
@@ -6413,10 +7100,9 @@ ${cue.notes ?? ""}`;
|
|
|
6413
7100
|
this.segmentDuration.data = new EBMLFloat64(this.duration);
|
|
6414
7101
|
this.writer.seek(this.ebmlWriter.offsets.get(this.segmentDuration));
|
|
6415
7102
|
this.ebmlWriter.writeEBML(this.segmentDuration);
|
|
6416
|
-
this.seekHead
|
|
6417
|
-
this.seekHead.data[1].data[1].data = this.ebmlWriter.offsets.get(this.segmentInfo) - this.segmentDataOffset;
|
|
6418
|
-
this.seekHead.data[2].data[1].data = this.ebmlWriter.offsets.get(this.tracksElement) - this.segmentDataOffset;
|
|
7103
|
+
assert(this.seekHead);
|
|
6419
7104
|
this.writer.seek(this.ebmlWriter.offsets.get(this.seekHead));
|
|
7105
|
+
this.maybeCreateSeekHead(true);
|
|
6420
7106
|
this.ebmlWriter.writeEBML(this.seekHead);
|
|
6421
7107
|
this.writer.seek(endPos);
|
|
6422
7108
|
}
|
|
@@ -6532,6 +7218,726 @@ ${cue.notes ?? ""}`;
|
|
|
6532
7218
|
bytesAdvanced: 1
|
|
6533
7219
|
};
|
|
6534
7220
|
};
|
|
7221
|
+
var encodeSynchsafe = (unsynchsafed) => {
|
|
7222
|
+
let mask = 127;
|
|
7223
|
+
let synchsafed = 0;
|
|
7224
|
+
let unsynchsafedRest = unsynchsafed;
|
|
7225
|
+
while ((mask ^ 2147483647) !== 0) {
|
|
7226
|
+
synchsafed = unsynchsafedRest & ~mask;
|
|
7227
|
+
synchsafed <<= 1;
|
|
7228
|
+
synchsafed |= unsynchsafedRest & mask;
|
|
7229
|
+
mask = (mask + 1 << 8) - 1;
|
|
7230
|
+
unsynchsafedRest = synchsafed;
|
|
7231
|
+
}
|
|
7232
|
+
return synchsafed;
|
|
7233
|
+
};
|
|
7234
|
+
var decodeSynchsafe = (synchsafed) => {
|
|
7235
|
+
let mask = 2130706432;
|
|
7236
|
+
let unsynchsafed = 0;
|
|
7237
|
+
while (mask !== 0) {
|
|
7238
|
+
unsynchsafed >>= 1;
|
|
7239
|
+
unsynchsafed |= synchsafed & mask;
|
|
7240
|
+
mask >>= 8;
|
|
7241
|
+
}
|
|
7242
|
+
return unsynchsafed;
|
|
7243
|
+
};
|
|
7244
|
+
|
|
7245
|
+
// src/mp3/mp3-reader.ts
|
|
7246
|
+
var ID3_V1_TAG_SIZE = 128;
|
|
7247
|
+
var ID3_V2_HEADER_SIZE = 10;
|
|
7248
|
+
var ID3_V1_GENRES = [
|
|
7249
|
+
"Blues",
|
|
7250
|
+
"Classic rock",
|
|
7251
|
+
"Country",
|
|
7252
|
+
"Dance",
|
|
7253
|
+
"Disco",
|
|
7254
|
+
"Funk",
|
|
7255
|
+
"Grunge",
|
|
7256
|
+
"Hip-hop",
|
|
7257
|
+
"Jazz",
|
|
7258
|
+
"Metal",
|
|
7259
|
+
"New age",
|
|
7260
|
+
"Oldies",
|
|
7261
|
+
"Other",
|
|
7262
|
+
"Pop",
|
|
7263
|
+
"Rhythm and blues",
|
|
7264
|
+
"Rap",
|
|
7265
|
+
"Reggae",
|
|
7266
|
+
"Rock",
|
|
7267
|
+
"Techno",
|
|
7268
|
+
"Industrial",
|
|
7269
|
+
"Alternative",
|
|
7270
|
+
"Ska",
|
|
7271
|
+
"Death metal",
|
|
7272
|
+
"Pranks",
|
|
7273
|
+
"Soundtrack",
|
|
7274
|
+
"Euro-techno",
|
|
7275
|
+
"Ambient",
|
|
7276
|
+
"Trip-hop",
|
|
7277
|
+
"Vocal",
|
|
7278
|
+
"Jazz & funk",
|
|
7279
|
+
"Fusion",
|
|
7280
|
+
"Trance",
|
|
7281
|
+
"Classical",
|
|
7282
|
+
"Instrumental",
|
|
7283
|
+
"Acid",
|
|
7284
|
+
"House",
|
|
7285
|
+
"Game",
|
|
7286
|
+
"Sound clip",
|
|
7287
|
+
"Gospel",
|
|
7288
|
+
"Noise",
|
|
7289
|
+
"Alternative rock",
|
|
7290
|
+
"Bass",
|
|
7291
|
+
"Soul",
|
|
7292
|
+
"Punk",
|
|
7293
|
+
"Space",
|
|
7294
|
+
"Meditative",
|
|
7295
|
+
"Instrumental pop",
|
|
7296
|
+
"Instrumental rock",
|
|
7297
|
+
"Ethnic",
|
|
7298
|
+
"Gothic",
|
|
7299
|
+
"Darkwave",
|
|
7300
|
+
"Techno-industrial",
|
|
7301
|
+
"Electronic",
|
|
7302
|
+
"Pop-folk",
|
|
7303
|
+
"Eurodance",
|
|
7304
|
+
"Dream",
|
|
7305
|
+
"Southern rock",
|
|
7306
|
+
"Comedy",
|
|
7307
|
+
"Cult",
|
|
7308
|
+
"Gangsta",
|
|
7309
|
+
"Top 40",
|
|
7310
|
+
"Christian rap",
|
|
7311
|
+
"Pop/funk",
|
|
7312
|
+
"Jungle music",
|
|
7313
|
+
"Native US",
|
|
7314
|
+
"Cabaret",
|
|
7315
|
+
"New wave",
|
|
7316
|
+
"Psychedelic",
|
|
7317
|
+
"Rave",
|
|
7318
|
+
"Showtunes",
|
|
7319
|
+
"Trailer",
|
|
7320
|
+
"Lo-fi",
|
|
7321
|
+
"Tribal",
|
|
7322
|
+
"Acid punk",
|
|
7323
|
+
"Acid jazz",
|
|
7324
|
+
"Polka",
|
|
7325
|
+
"Retro",
|
|
7326
|
+
"Musical",
|
|
7327
|
+
"Rock 'n' roll",
|
|
7328
|
+
"Hard rock",
|
|
7329
|
+
"Folk",
|
|
7330
|
+
"Folk rock",
|
|
7331
|
+
"National folk",
|
|
7332
|
+
"Swing",
|
|
7333
|
+
"Fast fusion",
|
|
7334
|
+
"Bebop",
|
|
7335
|
+
"Latin",
|
|
7336
|
+
"Revival",
|
|
7337
|
+
"Celtic",
|
|
7338
|
+
"Bluegrass",
|
|
7339
|
+
"Avantgarde",
|
|
7340
|
+
"Gothic rock",
|
|
7341
|
+
"Progressive rock",
|
|
7342
|
+
"Psychedelic rock",
|
|
7343
|
+
"Symphonic rock",
|
|
7344
|
+
"Slow rock",
|
|
7345
|
+
"Big band",
|
|
7346
|
+
"Chorus",
|
|
7347
|
+
"Easy listening",
|
|
7348
|
+
"Acoustic",
|
|
7349
|
+
"Humour",
|
|
7350
|
+
"Speech",
|
|
7351
|
+
"Chanson",
|
|
7352
|
+
"Opera",
|
|
7353
|
+
"Chamber music",
|
|
7354
|
+
"Sonata",
|
|
7355
|
+
"Symphony",
|
|
7356
|
+
"Booty bass",
|
|
7357
|
+
"Primus",
|
|
7358
|
+
"Porn groove",
|
|
7359
|
+
"Satire",
|
|
7360
|
+
"Slow jam",
|
|
7361
|
+
"Club",
|
|
7362
|
+
"Tango",
|
|
7363
|
+
"Samba",
|
|
7364
|
+
"Folklore",
|
|
7365
|
+
"Ballad",
|
|
7366
|
+
"Power ballad",
|
|
7367
|
+
"Rhythmic Soul",
|
|
7368
|
+
"Freestyle",
|
|
7369
|
+
"Duet",
|
|
7370
|
+
"Punk rock",
|
|
7371
|
+
"Drum solo",
|
|
7372
|
+
"A cappella",
|
|
7373
|
+
"Euro-house",
|
|
7374
|
+
"Dance hall",
|
|
7375
|
+
"Goa music",
|
|
7376
|
+
"Drum & bass",
|
|
7377
|
+
"Club-house",
|
|
7378
|
+
"Hardcore techno",
|
|
7379
|
+
"Terror",
|
|
7380
|
+
"Indie",
|
|
7381
|
+
"Britpop",
|
|
7382
|
+
"Negerpunk",
|
|
7383
|
+
"Polsk punk",
|
|
7384
|
+
"Beat",
|
|
7385
|
+
"Christian gangsta rap",
|
|
7386
|
+
"Heavy metal",
|
|
7387
|
+
"Black metal",
|
|
7388
|
+
"Crossover",
|
|
7389
|
+
"Contemporary Christian",
|
|
7390
|
+
"Christian rock",
|
|
7391
|
+
"Merengue",
|
|
7392
|
+
"Salsa",
|
|
7393
|
+
"Thrash metal",
|
|
7394
|
+
"Anime",
|
|
7395
|
+
"Jpop",
|
|
7396
|
+
"Synthpop",
|
|
7397
|
+
"Christmas",
|
|
7398
|
+
"Art rock",
|
|
7399
|
+
"Baroque",
|
|
7400
|
+
"Bhangra",
|
|
7401
|
+
"Big beat",
|
|
7402
|
+
"Breakbeat",
|
|
7403
|
+
"Chillout",
|
|
7404
|
+
"Downtempo",
|
|
7405
|
+
"Dub",
|
|
7406
|
+
"EBM",
|
|
7407
|
+
"Eclectic",
|
|
7408
|
+
"Electro",
|
|
7409
|
+
"Electroclash",
|
|
7410
|
+
"Emo",
|
|
7411
|
+
"Experimental",
|
|
7412
|
+
"Garage",
|
|
7413
|
+
"Global",
|
|
7414
|
+
"IDM",
|
|
7415
|
+
"Illbient",
|
|
7416
|
+
"Industro-Goth",
|
|
7417
|
+
"Jam Band",
|
|
7418
|
+
"Krautrock",
|
|
7419
|
+
"Leftfield",
|
|
7420
|
+
"Lounge",
|
|
7421
|
+
"Math rock",
|
|
7422
|
+
"New romantic",
|
|
7423
|
+
"Nu-breakz",
|
|
7424
|
+
"Post-punk",
|
|
7425
|
+
"Post-rock",
|
|
7426
|
+
"Psytrance",
|
|
7427
|
+
"Shoegaze",
|
|
7428
|
+
"Space rock",
|
|
7429
|
+
"Trop rock",
|
|
7430
|
+
"World music",
|
|
7431
|
+
"Neoclassical",
|
|
7432
|
+
"Audiobook",
|
|
7433
|
+
"Audio theatre",
|
|
7434
|
+
"Neue Deutsche Welle",
|
|
7435
|
+
"Podcast",
|
|
7436
|
+
"Indie rock",
|
|
7437
|
+
"G-Funk",
|
|
7438
|
+
"Dubstep",
|
|
7439
|
+
"Garage rock",
|
|
7440
|
+
"Psybient"
|
|
7441
|
+
];
|
|
7442
|
+
var readNextFrameHeader = async (reader, startPos, until) => {
|
|
7443
|
+
let currentPos = startPos;
|
|
7444
|
+
while (until === null || currentPos < until) {
|
|
7445
|
+
let slice = reader.requestSlice(currentPos, FRAME_HEADER_SIZE);
|
|
7446
|
+
if (slice instanceof Promise) slice = await slice;
|
|
7447
|
+
if (!slice) break;
|
|
7448
|
+
const word = readU32Be(slice);
|
|
7449
|
+
const result = readFrameHeader(word, reader.fileSize !== null ? reader.fileSize - currentPos : null);
|
|
7450
|
+
if (result.header) {
|
|
7451
|
+
return { header: result.header, startPos: currentPos };
|
|
7452
|
+
}
|
|
7453
|
+
currentPos += result.bytesAdvanced;
|
|
7454
|
+
}
|
|
7455
|
+
return null;
|
|
7456
|
+
};
|
|
7457
|
+
var parseId3V1Tag = (slice, tags) => {
|
|
7458
|
+
const startPos = slice.filePos;
|
|
7459
|
+
tags.raw ??= {};
|
|
7460
|
+
tags.raw["TAG"] ??= readBytes(slice, ID3_V1_TAG_SIZE - 3);
|
|
7461
|
+
slice.filePos = startPos;
|
|
7462
|
+
const title = readId3V1String(slice, 30);
|
|
7463
|
+
if (title) tags.title ??= title;
|
|
7464
|
+
const artist = readId3V1String(slice, 30);
|
|
7465
|
+
if (artist) tags.artist ??= artist;
|
|
7466
|
+
const album = readId3V1String(slice, 30);
|
|
7467
|
+
if (album) tags.album ??= album;
|
|
7468
|
+
const yearText = readId3V1String(slice, 4);
|
|
7469
|
+
const year = Number.parseInt(yearText, 10);
|
|
7470
|
+
if (Number.isInteger(year) && year > 0) {
|
|
7471
|
+
tags.date ??= new Date(year, 0, 1);
|
|
7472
|
+
}
|
|
7473
|
+
const commentBytes = readBytes(slice, 30);
|
|
7474
|
+
let comment;
|
|
7475
|
+
if (commentBytes[28] === 0 && commentBytes[29] !== 0) {
|
|
7476
|
+
const trackNum = commentBytes[29];
|
|
7477
|
+
if (trackNum > 0) {
|
|
7478
|
+
tags.trackNumber ??= trackNum;
|
|
7479
|
+
}
|
|
7480
|
+
slice.skip(-30);
|
|
7481
|
+
comment = readId3V1String(slice, 28);
|
|
7482
|
+
slice.skip(2);
|
|
7483
|
+
} else {
|
|
7484
|
+
slice.skip(-30);
|
|
7485
|
+
comment = readId3V1String(slice, 30);
|
|
7486
|
+
}
|
|
7487
|
+
if (comment) tags.comment ??= comment;
|
|
7488
|
+
const genreIndex = readU8(slice);
|
|
7489
|
+
if (genreIndex < ID3_V1_GENRES.length) {
|
|
7490
|
+
tags.genre ??= ID3_V1_GENRES[genreIndex];
|
|
7491
|
+
}
|
|
7492
|
+
};
|
|
7493
|
+
var readId3V1String = (slice, length) => {
|
|
7494
|
+
const bytes2 = readBytes(slice, length);
|
|
7495
|
+
const endIndex = coalesceIndex(bytes2.indexOf(0), bytes2.length);
|
|
7496
|
+
const relevantBytes = bytes2.subarray(0, endIndex);
|
|
7497
|
+
let str = "";
|
|
7498
|
+
for (let i = 0; i < relevantBytes.length; i++) {
|
|
7499
|
+
str += String.fromCharCode(relevantBytes[i]);
|
|
7500
|
+
}
|
|
7501
|
+
return str.trimEnd();
|
|
7502
|
+
};
|
|
7503
|
+
var readId3V2Header = (slice) => {
|
|
7504
|
+
const startPos = slice.filePos;
|
|
7505
|
+
const tag = readAscii(slice, 3);
|
|
7506
|
+
const majorVersion = readU8(slice);
|
|
7507
|
+
const revision = readU8(slice);
|
|
7508
|
+
const flags = readU8(slice);
|
|
7509
|
+
const sizeRaw = readU32Be(slice);
|
|
7510
|
+
if (tag !== "ID3" || majorVersion === 255 || revision === 255 || (sizeRaw & 2155905152) !== 0) {
|
|
7511
|
+
slice.filePos = startPos;
|
|
7512
|
+
return null;
|
|
7513
|
+
}
|
|
7514
|
+
const size = decodeSynchsafe(sizeRaw);
|
|
7515
|
+
return { majorVersion, revision, flags, size };
|
|
7516
|
+
};
|
|
7517
|
+
var parseId3V2Tag = (slice, header, tags) => {
|
|
7518
|
+
if (![2, 3, 4].includes(header.majorVersion)) {
|
|
7519
|
+
console.warn(`Unsupported ID3v2 major version: ${header.majorVersion}`);
|
|
7520
|
+
return;
|
|
7521
|
+
}
|
|
7522
|
+
const bytes2 = readBytes(slice, header.size);
|
|
7523
|
+
const reader = new Id3V2Reader(header, bytes2);
|
|
7524
|
+
if (header.flags & 16 /* Footer */) {
|
|
7525
|
+
reader.removeFooter();
|
|
7526
|
+
}
|
|
7527
|
+
if (header.flags & 128 /* Unsynchronisation */ && header.majorVersion === 3) {
|
|
7528
|
+
reader.ununsynchronizeAll();
|
|
7529
|
+
}
|
|
7530
|
+
if (header.flags & 64 /* ExtendedHeader */) {
|
|
7531
|
+
const extendedHeaderSize = reader.readU32();
|
|
7532
|
+
if (header.majorVersion === 3) {
|
|
7533
|
+
reader.pos += extendedHeaderSize;
|
|
7534
|
+
} else {
|
|
7535
|
+
reader.pos += extendedHeaderSize - 4;
|
|
7536
|
+
}
|
|
7537
|
+
}
|
|
7538
|
+
while (reader.pos <= reader.bytes.length - reader.frameHeaderSize()) {
|
|
7539
|
+
const frame = reader.readId3V2Frame();
|
|
7540
|
+
if (!frame) {
|
|
7541
|
+
break;
|
|
7542
|
+
}
|
|
7543
|
+
const frameStartPos = reader.pos;
|
|
7544
|
+
const frameEndPos = reader.pos + frame.size;
|
|
7545
|
+
let frameEncrypted = false;
|
|
7546
|
+
let frameCompressed = false;
|
|
7547
|
+
let frameUnsynchronized = false;
|
|
7548
|
+
if (header.majorVersion === 3) {
|
|
7549
|
+
frameEncrypted = !!(frame.flags & 1 << 6);
|
|
7550
|
+
frameCompressed = !!(frame.flags & 1 << 7);
|
|
7551
|
+
} else if (header.majorVersion === 4) {
|
|
7552
|
+
frameEncrypted = !!(frame.flags & 1 << 2);
|
|
7553
|
+
frameCompressed = !!(frame.flags & 1 << 3);
|
|
7554
|
+
frameUnsynchronized = !!(frame.flags & 1 << 1) || !!(header.flags & 128 /* Unsynchronisation */);
|
|
7555
|
+
}
|
|
7556
|
+
if (frameEncrypted) {
|
|
7557
|
+
console.warn(`Skipping encrypted ID3v2 frame ${frame.id}`);
|
|
7558
|
+
reader.pos = frameEndPos;
|
|
7559
|
+
continue;
|
|
7560
|
+
}
|
|
7561
|
+
if (frameCompressed) {
|
|
7562
|
+
console.warn(`Skipping compressed ID3v2 frame ${frame.id}`);
|
|
7563
|
+
reader.pos = frameEndPos;
|
|
7564
|
+
continue;
|
|
7565
|
+
}
|
|
7566
|
+
if (frameUnsynchronized) {
|
|
7567
|
+
reader.ununsynchronizeRegion(reader.pos, frameEndPos);
|
|
7568
|
+
}
|
|
7569
|
+
tags.raw ??= {};
|
|
7570
|
+
if (frame.id[0] === "T") {
|
|
7571
|
+
tags.raw[frame.id] ??= reader.readId3V2EncodingAndText(frameEndPos);
|
|
7572
|
+
} else {
|
|
7573
|
+
tags.raw[frame.id] ??= reader.readBytes(frame.size);
|
|
7574
|
+
}
|
|
7575
|
+
reader.pos = frameStartPos;
|
|
7576
|
+
switch (frame.id) {
|
|
7577
|
+
case "TIT2":
|
|
7578
|
+
case "TT2":
|
|
7579
|
+
{
|
|
7580
|
+
tags.title ??= reader.readId3V2EncodingAndText(frameEndPos);
|
|
7581
|
+
}
|
|
7582
|
+
;
|
|
7583
|
+
break;
|
|
7584
|
+
case "TIT3":
|
|
7585
|
+
case "TT3":
|
|
7586
|
+
{
|
|
7587
|
+
tags.description ??= reader.readId3V2EncodingAndText(frameEndPos);
|
|
7588
|
+
}
|
|
7589
|
+
;
|
|
7590
|
+
break;
|
|
7591
|
+
case "TPE1":
|
|
7592
|
+
case "TP1":
|
|
7593
|
+
{
|
|
7594
|
+
tags.artist ??= reader.readId3V2EncodingAndText(frameEndPos);
|
|
7595
|
+
}
|
|
7596
|
+
;
|
|
7597
|
+
break;
|
|
7598
|
+
case "TALB":
|
|
7599
|
+
case "TAL":
|
|
7600
|
+
{
|
|
7601
|
+
tags.album ??= reader.readId3V2EncodingAndText(frameEndPos);
|
|
7602
|
+
}
|
|
7603
|
+
;
|
|
7604
|
+
break;
|
|
7605
|
+
case "TPE2":
|
|
7606
|
+
case "TP2":
|
|
7607
|
+
{
|
|
7608
|
+
tags.albumArtist ??= reader.readId3V2EncodingAndText(frameEndPos);
|
|
7609
|
+
}
|
|
7610
|
+
;
|
|
7611
|
+
break;
|
|
7612
|
+
case "TRCK":
|
|
7613
|
+
case "TRK":
|
|
7614
|
+
{
|
|
7615
|
+
const trackText = reader.readId3V2EncodingAndText(frameEndPos);
|
|
7616
|
+
const parts = trackText.split("/");
|
|
7617
|
+
const trackNum = Number.parseInt(parts[0], 10);
|
|
7618
|
+
const tracksTotal = parts[1] && Number.parseInt(parts[1], 10);
|
|
7619
|
+
if (Number.isInteger(trackNum) && trackNum > 0) {
|
|
7620
|
+
tags.trackNumber ??= trackNum;
|
|
7621
|
+
}
|
|
7622
|
+
if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) {
|
|
7623
|
+
tags.tracksTotal ??= tracksTotal;
|
|
7624
|
+
}
|
|
7625
|
+
}
|
|
7626
|
+
;
|
|
7627
|
+
break;
|
|
7628
|
+
case "TPOS":
|
|
7629
|
+
case "TPA":
|
|
7630
|
+
{
|
|
7631
|
+
const discText = reader.readId3V2EncodingAndText(frameEndPos);
|
|
7632
|
+
const parts = discText.split("/");
|
|
7633
|
+
const discNum = Number.parseInt(parts[0], 10);
|
|
7634
|
+
const discsTotal = parts[1] && Number.parseInt(parts[1], 10);
|
|
7635
|
+
if (Number.isInteger(discNum) && discNum > 0) {
|
|
7636
|
+
tags.discNumber ??= discNum;
|
|
7637
|
+
}
|
|
7638
|
+
if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) {
|
|
7639
|
+
tags.discsTotal ??= discsTotal;
|
|
7640
|
+
}
|
|
7641
|
+
}
|
|
7642
|
+
;
|
|
7643
|
+
break;
|
|
7644
|
+
case "TCON":
|
|
7645
|
+
case "TCO":
|
|
7646
|
+
{
|
|
7647
|
+
const genreText = reader.readId3V2EncodingAndText(frameEndPos);
|
|
7648
|
+
let match = /^\((\d+)\)/.exec(genreText);
|
|
7649
|
+
if (match) {
|
|
7650
|
+
const genreNumber = Number.parseInt(match[1]);
|
|
7651
|
+
if (ID3_V1_GENRES[genreNumber] !== void 0) {
|
|
7652
|
+
tags.genre ??= ID3_V1_GENRES[genreNumber];
|
|
7653
|
+
break;
|
|
7654
|
+
}
|
|
7655
|
+
}
|
|
7656
|
+
match = /^\d+$/.exec(genreText);
|
|
7657
|
+
if (match) {
|
|
7658
|
+
const genreNumber = Number.parseInt(match[0]);
|
|
7659
|
+
if (ID3_V1_GENRES[genreNumber] !== void 0) {
|
|
7660
|
+
tags.genre ??= ID3_V1_GENRES[genreNumber];
|
|
7661
|
+
break;
|
|
7662
|
+
}
|
|
7663
|
+
}
|
|
7664
|
+
tags.genre ??= genreText;
|
|
7665
|
+
}
|
|
7666
|
+
;
|
|
7667
|
+
break;
|
|
7668
|
+
case "TDRC":
|
|
7669
|
+
case "TDAT":
|
|
7670
|
+
{
|
|
7671
|
+
const dateText = reader.readId3V2EncodingAndText(frameEndPos);
|
|
7672
|
+
const date = new Date(dateText);
|
|
7673
|
+
if (!Number.isNaN(date.getTime())) {
|
|
7674
|
+
tags.date ??= date;
|
|
7675
|
+
}
|
|
7676
|
+
}
|
|
7677
|
+
;
|
|
7678
|
+
break;
|
|
7679
|
+
case "TYER":
|
|
7680
|
+
case "TYE":
|
|
7681
|
+
{
|
|
7682
|
+
const yearText = reader.readId3V2EncodingAndText(frameEndPos);
|
|
7683
|
+
const year = Number.parseInt(yearText, 10);
|
|
7684
|
+
if (Number.isInteger(year)) {
|
|
7685
|
+
tags.date ??= new Date(year, 0, 1);
|
|
7686
|
+
}
|
|
7687
|
+
}
|
|
7688
|
+
;
|
|
7689
|
+
break;
|
|
7690
|
+
case "USLT":
|
|
7691
|
+
case "ULT":
|
|
7692
|
+
{
|
|
7693
|
+
const encoding = reader.readU8();
|
|
7694
|
+
reader.pos += 3;
|
|
7695
|
+
reader.readId3V2Text(encoding, frameEndPos);
|
|
7696
|
+
tags.lyrics ??= reader.readId3V2Text(encoding, frameEndPos);
|
|
7697
|
+
}
|
|
7698
|
+
;
|
|
7699
|
+
break;
|
|
7700
|
+
case "COMM":
|
|
7701
|
+
case "COM":
|
|
7702
|
+
{
|
|
7703
|
+
const encoding = reader.readU8();
|
|
7704
|
+
reader.pos += 3;
|
|
7705
|
+
reader.readId3V2Text(encoding, frameEndPos);
|
|
7706
|
+
tags.comment ??= reader.readId3V2Text(encoding, frameEndPos);
|
|
7707
|
+
}
|
|
7708
|
+
;
|
|
7709
|
+
break;
|
|
7710
|
+
case "APIC":
|
|
7711
|
+
case "PIC":
|
|
7712
|
+
{
|
|
7713
|
+
const encoding = reader.readId3V2TextEncoding();
|
|
7714
|
+
let mimeType;
|
|
7715
|
+
if (header.majorVersion === 2) {
|
|
7716
|
+
const imageFormat = reader.readAscii(3);
|
|
7717
|
+
mimeType = imageFormat === "PNG" ? "image/png" : imageFormat === "JPG" ? "image/jpeg" : "image/*";
|
|
7718
|
+
} else {
|
|
7719
|
+
mimeType = reader.readId3V2Text(encoding, frameEndPos);
|
|
7720
|
+
}
|
|
7721
|
+
const pictureType = reader.readU8();
|
|
7722
|
+
const description = reader.readId3V2Text(encoding, frameEndPos).trimEnd();
|
|
7723
|
+
const imageDataSize = frameEndPos - reader.pos;
|
|
7724
|
+
if (imageDataSize >= 0) {
|
|
7725
|
+
const imageData = reader.readBytes(imageDataSize);
|
|
7726
|
+
if (!tags.images) tags.images = [];
|
|
7727
|
+
tags.images.push({
|
|
7728
|
+
data: imageData,
|
|
7729
|
+
mimeType,
|
|
7730
|
+
kind: pictureType === 3 ? "coverFront" : pictureType === 4 ? "coverBack" : "unknown",
|
|
7731
|
+
description
|
|
7732
|
+
});
|
|
7733
|
+
}
|
|
7734
|
+
}
|
|
7735
|
+
;
|
|
7736
|
+
break;
|
|
7737
|
+
default:
|
|
7738
|
+
{
|
|
7739
|
+
reader.pos += frame.size;
|
|
7740
|
+
}
|
|
7741
|
+
;
|
|
7742
|
+
break;
|
|
7743
|
+
}
|
|
7744
|
+
reader.pos = frameEndPos;
|
|
7745
|
+
}
|
|
7746
|
+
};
|
|
7747
|
+
var Id3V2Reader = class {
|
|
7748
|
+
constructor(header, bytes2) {
|
|
7749
|
+
this.header = header;
|
|
7750
|
+
this.bytes = bytes2;
|
|
7751
|
+
this.pos = 0;
|
|
7752
|
+
this.view = new DataView(bytes2.buffer, bytes2.byteOffset, bytes2.byteLength);
|
|
7753
|
+
}
|
|
7754
|
+
frameHeaderSize() {
|
|
7755
|
+
return this.header.majorVersion === 2 ? 6 : 10;
|
|
7756
|
+
}
|
|
7757
|
+
ununsynchronizeAll() {
|
|
7758
|
+
const newBytes = [];
|
|
7759
|
+
for (let i = 0; i < this.bytes.length; i++) {
|
|
7760
|
+
const value1 = this.bytes[i];
|
|
7761
|
+
newBytes.push(value1);
|
|
7762
|
+
if (value1 === 255 && i !== this.bytes.length - 1) {
|
|
7763
|
+
const value2 = this.bytes[i];
|
|
7764
|
+
if (value2 === 0) {
|
|
7765
|
+
i++;
|
|
7766
|
+
}
|
|
7767
|
+
}
|
|
7768
|
+
}
|
|
7769
|
+
this.bytes = new Uint8Array(newBytes);
|
|
7770
|
+
this.view = new DataView(this.bytes.buffer);
|
|
7771
|
+
}
|
|
7772
|
+
ununsynchronizeRegion(start, end) {
|
|
7773
|
+
const newBytes = [];
|
|
7774
|
+
for (let i = start; i < end; i++) {
|
|
7775
|
+
const value1 = this.bytes[i];
|
|
7776
|
+
newBytes.push(value1);
|
|
7777
|
+
if (value1 === 255 && i !== end - 1) {
|
|
7778
|
+
const value2 = this.bytes[i + 1];
|
|
7779
|
+
if (value2 === 0) {
|
|
7780
|
+
i++;
|
|
7781
|
+
}
|
|
7782
|
+
}
|
|
7783
|
+
}
|
|
7784
|
+
const before = this.bytes.subarray(0, start);
|
|
7785
|
+
const after = this.bytes.subarray(end);
|
|
7786
|
+
this.bytes = new Uint8Array(before.length + newBytes.length + after.length);
|
|
7787
|
+
this.bytes.set(before, 0);
|
|
7788
|
+
this.bytes.set(newBytes, before.length);
|
|
7789
|
+
this.bytes.set(after, before.length + newBytes.length);
|
|
7790
|
+
this.view = new DataView(this.bytes.buffer);
|
|
7791
|
+
}
|
|
7792
|
+
removeFooter() {
|
|
7793
|
+
this.bytes = this.bytes.subarray(0, this.bytes.length - ID3_V2_HEADER_SIZE);
|
|
7794
|
+
this.view = new DataView(this.bytes.buffer);
|
|
7795
|
+
}
|
|
7796
|
+
readBytes(length) {
|
|
7797
|
+
const slice = this.bytes.subarray(this.pos, this.pos + length);
|
|
7798
|
+
this.pos += length;
|
|
7799
|
+
return slice;
|
|
7800
|
+
}
|
|
7801
|
+
readU8() {
|
|
7802
|
+
const value = this.view.getUint8(this.pos);
|
|
7803
|
+
this.pos += 1;
|
|
7804
|
+
return value;
|
|
7805
|
+
}
|
|
7806
|
+
readU16() {
|
|
7807
|
+
const value = this.view.getUint16(this.pos, false);
|
|
7808
|
+
this.pos += 2;
|
|
7809
|
+
return value;
|
|
7810
|
+
}
|
|
7811
|
+
readU24() {
|
|
7812
|
+
const high = this.view.getUint16(this.pos, false);
|
|
7813
|
+
const low = this.view.getUint8(this.pos + 1);
|
|
7814
|
+
this.pos += 3;
|
|
7815
|
+
return high * 256 + low;
|
|
7816
|
+
}
|
|
7817
|
+
readU32() {
|
|
7818
|
+
const value = this.view.getUint32(this.pos, false);
|
|
7819
|
+
this.pos += 4;
|
|
7820
|
+
return value;
|
|
7821
|
+
}
|
|
7822
|
+
readAscii(length) {
|
|
7823
|
+
let str = "";
|
|
7824
|
+
for (let i = 0; i < length; i++) {
|
|
7825
|
+
str += String.fromCharCode(this.view.getUint8(this.pos + i));
|
|
7826
|
+
}
|
|
7827
|
+
this.pos += length;
|
|
7828
|
+
return str;
|
|
7829
|
+
}
|
|
7830
|
+
readId3V2Frame() {
|
|
7831
|
+
if (this.header.majorVersion === 2) {
|
|
7832
|
+
const id = this.readAscii(3);
|
|
7833
|
+
if (id === "\0\0\0") {
|
|
7834
|
+
return null;
|
|
7835
|
+
}
|
|
7836
|
+
const size = this.readU24();
|
|
7837
|
+
return { id, size, flags: 0 };
|
|
7838
|
+
} else {
|
|
7839
|
+
const id = this.readAscii(4);
|
|
7840
|
+
if (id === "\0\0\0\0") {
|
|
7841
|
+
return null;
|
|
7842
|
+
}
|
|
7843
|
+
const sizeRaw = this.readU32();
|
|
7844
|
+
let size = this.header.majorVersion === 4 ? decodeSynchsafe(sizeRaw) : sizeRaw;
|
|
7845
|
+
const flags = this.readU16();
|
|
7846
|
+
const headerEndPos = this.pos;
|
|
7847
|
+
const isSizeValid = (size2) => {
|
|
7848
|
+
const nextPos = this.pos + size2;
|
|
7849
|
+
if (nextPos > this.bytes.length) {
|
|
7850
|
+
return false;
|
|
7851
|
+
}
|
|
7852
|
+
if (nextPos <= this.bytes.length - this.frameHeaderSize()) {
|
|
7853
|
+
this.pos += size2;
|
|
7854
|
+
const nextId = this.readAscii(4);
|
|
7855
|
+
if (nextId !== "\0\0\0\0" && !/[0-9A-Z]{4}/.test(nextId)) {
|
|
7856
|
+
return false;
|
|
7857
|
+
}
|
|
7858
|
+
}
|
|
7859
|
+
return true;
|
|
7860
|
+
};
|
|
7861
|
+
if (!isSizeValid(size)) {
|
|
7862
|
+
const otherSize = this.header.majorVersion === 4 ? sizeRaw : decodeSynchsafe(sizeRaw);
|
|
7863
|
+
if (isSizeValid(otherSize)) {
|
|
7864
|
+
size = otherSize;
|
|
7865
|
+
}
|
|
7866
|
+
}
|
|
7867
|
+
this.pos = headerEndPos;
|
|
7868
|
+
return { id, size, flags };
|
|
7869
|
+
}
|
|
7870
|
+
}
|
|
7871
|
+
readId3V2TextEncoding() {
|
|
7872
|
+
const number = this.readU8();
|
|
7873
|
+
if (number > 3) {
|
|
7874
|
+
throw new Error(`Unsupported text encoding: ${number}`);
|
|
7875
|
+
}
|
|
7876
|
+
return number;
|
|
7877
|
+
}
|
|
7878
|
+
readId3V2Text(encoding, until) {
|
|
7879
|
+
const startPos = this.pos;
|
|
7880
|
+
const data = this.readBytes(until);
|
|
7881
|
+
switch (encoding) {
|
|
7882
|
+
case 0 /* ISO_8859_1 */: {
|
|
7883
|
+
let str = "";
|
|
7884
|
+
for (let i = 0; i < data.length; i++) {
|
|
7885
|
+
const value = data[i];
|
|
7886
|
+
if (value === 0) {
|
|
7887
|
+
this.pos = startPos + i + 1;
|
|
7888
|
+
break;
|
|
7889
|
+
}
|
|
7890
|
+
str += String.fromCharCode(value);
|
|
7891
|
+
}
|
|
7892
|
+
return str;
|
|
7893
|
+
}
|
|
7894
|
+
case 1 /* UTF_16_WITH_BOM */: {
|
|
7895
|
+
if (data[0] === 255 && data[1] === 254) {
|
|
7896
|
+
const decoder = new TextDecoder("utf-16le");
|
|
7897
|
+
const endIndex = coalesceIndex(
|
|
7898
|
+
data.findIndex((x, i) => x === 0 && data[i + 1] === 0 && i % 2 === 0),
|
|
7899
|
+
data.length
|
|
7900
|
+
);
|
|
7901
|
+
this.pos = startPos + Math.min(endIndex + 2, data.length);
|
|
7902
|
+
return decoder.decode(data.subarray(2, endIndex));
|
|
7903
|
+
} else if (data[0] === 254 && data[1] === 255) {
|
|
7904
|
+
const decoder = new TextDecoder("utf-16be");
|
|
7905
|
+
const endIndex = coalesceIndex(
|
|
7906
|
+
data.findIndex((x, i) => x === 0 && data[i + 1] === 0 && i % 2 === 0),
|
|
7907
|
+
data.length
|
|
7908
|
+
);
|
|
7909
|
+
this.pos = startPos + Math.min(endIndex + 2, data.length);
|
|
7910
|
+
return decoder.decode(data.subarray(2, endIndex));
|
|
7911
|
+
} else {
|
|
7912
|
+
const endIndex = coalesceIndex(data.findIndex((x) => x === 0), data.length);
|
|
7913
|
+
this.pos = startPos + Math.min(endIndex + 1, data.length);
|
|
7914
|
+
return textDecoder.decode(data.subarray(0, endIndex));
|
|
7915
|
+
}
|
|
7916
|
+
}
|
|
7917
|
+
case 2 /* UTF_16_BE_NO_BOM */: {
|
|
7918
|
+
const decoder = new TextDecoder("utf-16be");
|
|
7919
|
+
const endIndex = coalesceIndex(
|
|
7920
|
+
data.findIndex((x, i) => x === 0 && data[i + 1] === 0 && i % 2 === 0),
|
|
7921
|
+
data.length
|
|
7922
|
+
);
|
|
7923
|
+
this.pos = startPos + Math.min(endIndex + 2, data.length);
|
|
7924
|
+
return decoder.decode(data.subarray(0, endIndex));
|
|
7925
|
+
}
|
|
7926
|
+
case 3 /* UTF_8 */: {
|
|
7927
|
+
const endIndex = coalesceIndex(data.findIndex((x) => x === 0), data.length);
|
|
7928
|
+
this.pos = startPos + Math.min(endIndex + 1, data.length);
|
|
7929
|
+
return textDecoder.decode(data.subarray(0, endIndex));
|
|
7930
|
+
}
|
|
7931
|
+
}
|
|
7932
|
+
}
|
|
7933
|
+
readId3V2EncodingAndText(until) {
|
|
7934
|
+
if (this.pos >= until) {
|
|
7935
|
+
return "";
|
|
7936
|
+
}
|
|
7937
|
+
const encoding = this.readId3V2TextEncoding();
|
|
7938
|
+
return this.readId3V2Text(encoding, until);
|
|
7939
|
+
}
|
|
7940
|
+
};
|
|
6535
7941
|
|
|
6536
7942
|
// src/mp3/mp3-writer.ts
|
|
6537
7943
|
var Mp3Writer = class {
|
|
@@ -6540,10 +7946,112 @@ ${cue.notes ?? ""}`;
|
|
|
6540
7946
|
this.helper = new Uint8Array(8);
|
|
6541
7947
|
this.helperView = new DataView(this.helper.buffer);
|
|
6542
7948
|
}
|
|
7949
|
+
writeU8(value) {
|
|
7950
|
+
this.helper[0] = value;
|
|
7951
|
+
this.writer.write(this.helper.subarray(0, 1));
|
|
7952
|
+
}
|
|
7953
|
+
writeU16(value) {
|
|
7954
|
+
this.helperView.setUint16(0, value, false);
|
|
7955
|
+
this.writer.write(this.helper.subarray(0, 2));
|
|
7956
|
+
}
|
|
6543
7957
|
writeU32(value) {
|
|
6544
7958
|
this.helperView.setUint32(0, value, false);
|
|
6545
7959
|
this.writer.write(this.helper.subarray(0, 4));
|
|
6546
7960
|
}
|
|
7961
|
+
writeAscii(text) {
|
|
7962
|
+
for (let i = 0; i < text.length; i++) {
|
|
7963
|
+
this.helper[i] = text.charCodeAt(i);
|
|
7964
|
+
}
|
|
7965
|
+
this.writer.write(this.helper.subarray(0, text.length));
|
|
7966
|
+
}
|
|
7967
|
+
writeSynchsafeU32(value) {
|
|
7968
|
+
this.writeU32(encodeSynchsafe(value));
|
|
7969
|
+
}
|
|
7970
|
+
writeIsoString(text) {
|
|
7971
|
+
const bytes2 = new Uint8Array(text.length + 1);
|
|
7972
|
+
for (let i = 0; i < text.length; i++) {
|
|
7973
|
+
bytes2[i] = text.charCodeAt(i);
|
|
7974
|
+
}
|
|
7975
|
+
bytes2[text.length] = 0;
|
|
7976
|
+
this.writer.write(bytes2);
|
|
7977
|
+
}
|
|
7978
|
+
writeUtf8String(text) {
|
|
7979
|
+
const utf8Data = textEncoder.encode(text);
|
|
7980
|
+
this.writer.write(utf8Data);
|
|
7981
|
+
this.writeU8(0);
|
|
7982
|
+
}
|
|
7983
|
+
writeId3V2TextFrame(frameId, text) {
|
|
7984
|
+
const useIso88591 = isIso88591Compatible(text);
|
|
7985
|
+
const textDataLength = useIso88591 ? text.length : textEncoder.encode(text).byteLength;
|
|
7986
|
+
const frameSize = 1 + textDataLength + 1;
|
|
7987
|
+
this.writeAscii(frameId);
|
|
7988
|
+
this.writeSynchsafeU32(frameSize);
|
|
7989
|
+
this.writeU16(0);
|
|
7990
|
+
this.writeU8(useIso88591 ? 0 /* ISO_8859_1 */ : 3 /* UTF_8 */);
|
|
7991
|
+
if (useIso88591) {
|
|
7992
|
+
this.writeIsoString(text);
|
|
7993
|
+
} else {
|
|
7994
|
+
this.writeUtf8String(text);
|
|
7995
|
+
}
|
|
7996
|
+
}
|
|
7997
|
+
writeId3V2LyricsFrame(lyrics) {
|
|
7998
|
+
const useIso88591 = isIso88591Compatible(lyrics);
|
|
7999
|
+
const shortDescription = "";
|
|
8000
|
+
const frameSize = 1 + 3 + shortDescription.length + 1 + lyrics.length + 1;
|
|
8001
|
+
this.writeAscii("USLT");
|
|
8002
|
+
this.writeSynchsafeU32(frameSize);
|
|
8003
|
+
this.writeU16(0);
|
|
8004
|
+
this.writeU8(useIso88591 ? 0 /* ISO_8859_1 */ : 3 /* UTF_8 */);
|
|
8005
|
+
this.writeAscii("und");
|
|
8006
|
+
if (useIso88591) {
|
|
8007
|
+
this.writeIsoString(shortDescription);
|
|
8008
|
+
this.writeIsoString(lyrics);
|
|
8009
|
+
} else {
|
|
8010
|
+
this.writeUtf8String(shortDescription);
|
|
8011
|
+
this.writeUtf8String(lyrics);
|
|
8012
|
+
}
|
|
8013
|
+
}
|
|
8014
|
+
writeId3V2CommentFrame(comment) {
|
|
8015
|
+
const useIso88591 = isIso88591Compatible(comment);
|
|
8016
|
+
const textDataLength = useIso88591 ? comment.length : textEncoder.encode(comment).byteLength;
|
|
8017
|
+
const shortDescription = "";
|
|
8018
|
+
const frameSize = 1 + 3 + shortDescription.length + 1 + textDataLength + 1;
|
|
8019
|
+
this.writeAscii("COMM");
|
|
8020
|
+
this.writeSynchsafeU32(frameSize);
|
|
8021
|
+
this.writeU16(0);
|
|
8022
|
+
this.writeU8(useIso88591 ? 0 /* ISO_8859_1 */ : 3 /* UTF_8 */);
|
|
8023
|
+
this.writeU8(117);
|
|
8024
|
+
this.writeU8(110);
|
|
8025
|
+
this.writeU8(100);
|
|
8026
|
+
if (useIso88591) {
|
|
8027
|
+
this.writeIsoString(shortDescription);
|
|
8028
|
+
this.writeIsoString(comment);
|
|
8029
|
+
} else {
|
|
8030
|
+
this.writeUtf8String(shortDescription);
|
|
8031
|
+
this.writeUtf8String(comment);
|
|
8032
|
+
}
|
|
8033
|
+
}
|
|
8034
|
+
writeId3V2ApicFrame(mimeType, pictureType, description, imageData) {
|
|
8035
|
+
const useIso88591 = isIso88591Compatible(mimeType) && isIso88591Compatible(description);
|
|
8036
|
+
const descriptionDataLength = useIso88591 ? description.length : textEncoder.encode(description).byteLength;
|
|
8037
|
+
const frameSize = 1 + mimeType.length + 1 + 1 + descriptionDataLength + 1 + imageData.byteLength;
|
|
8038
|
+
this.writeAscii("APIC");
|
|
8039
|
+
this.writeSynchsafeU32(frameSize);
|
|
8040
|
+
this.writeU16(0);
|
|
8041
|
+
this.writeU8(useIso88591 ? 0 /* ISO_8859_1 */ : 3 /* UTF_8 */);
|
|
8042
|
+
if (useIso88591) {
|
|
8043
|
+
this.writeIsoString(mimeType);
|
|
8044
|
+
} else {
|
|
8045
|
+
this.writeUtf8String(mimeType);
|
|
8046
|
+
}
|
|
8047
|
+
this.writeU8(pictureType);
|
|
8048
|
+
if (useIso88591) {
|
|
8049
|
+
this.writeIsoString(description);
|
|
8050
|
+
} else {
|
|
8051
|
+
this.writeUtf8String(description);
|
|
8052
|
+
}
|
|
8053
|
+
this.writer.write(imageData);
|
|
8054
|
+
}
|
|
6547
8055
|
writeXingFrame(data) {
|
|
6548
8056
|
const startPos = this.writer.getPos();
|
|
6549
8057
|
const firstByte = 255;
|
|
@@ -6601,11 +8109,15 @@ ${cue.notes ?? ""}`;
|
|
|
6601
8109
|
this.xingFrameData = null;
|
|
6602
8110
|
this.frameCount = 0;
|
|
6603
8111
|
this.framePositions = [];
|
|
8112
|
+
this.xingFramePos = null;
|
|
6604
8113
|
this.format = format;
|
|
6605
8114
|
this.writer = output._writer;
|
|
6606
8115
|
this.mp3Writer = new Mp3Writer(output._writer);
|
|
6607
8116
|
}
|
|
6608
8117
|
async start() {
|
|
8118
|
+
if (!metadataTagsAreEmpty(this.output._metadataTags)) {
|
|
8119
|
+
this.writeId3v2Tag(this.output._metadataTags);
|
|
8120
|
+
}
|
|
6609
8121
|
}
|
|
6610
8122
|
async getMimeType() {
|
|
6611
8123
|
return "audio/mpeg";
|
|
@@ -6648,6 +8160,7 @@ ${cue.notes ?? ""}`;
|
|
|
6648
8160
|
fileSize: null,
|
|
6649
8161
|
toc: null
|
|
6650
8162
|
};
|
|
8163
|
+
this.xingFramePos = this.writer.getPos();
|
|
6651
8164
|
this.mp3Writer.writeXingFrame(this.xingFrameData);
|
|
6652
8165
|
this.frameCount++;
|
|
6653
8166
|
}
|
|
@@ -6665,13 +8178,157 @@ ${cue.notes ?? ""}`;
|
|
|
6665
8178
|
async addSubtitleCue() {
|
|
6666
8179
|
throw new Error("MP3 does not support subtitles.");
|
|
6667
8180
|
}
|
|
8181
|
+
writeId3v2Tag(tags) {
|
|
8182
|
+
this.mp3Writer.writeAscii("ID3");
|
|
8183
|
+
this.mp3Writer.writeU8(4);
|
|
8184
|
+
this.mp3Writer.writeU8(0);
|
|
8185
|
+
this.mp3Writer.writeU8(0);
|
|
8186
|
+
this.mp3Writer.writeSynchsafeU32(0);
|
|
8187
|
+
const startPos = this.writer.getPos();
|
|
8188
|
+
const writtenTags = /* @__PURE__ */ new Set();
|
|
8189
|
+
for (const { key, value } of keyValueIterator(tags)) {
|
|
8190
|
+
switch (key) {
|
|
8191
|
+
case "title":
|
|
8192
|
+
{
|
|
8193
|
+
this.mp3Writer.writeId3V2TextFrame("TIT2", value);
|
|
8194
|
+
writtenTags.add("TIT2");
|
|
8195
|
+
}
|
|
8196
|
+
;
|
|
8197
|
+
break;
|
|
8198
|
+
case "description":
|
|
8199
|
+
{
|
|
8200
|
+
this.mp3Writer.writeId3V2TextFrame("TIT3", value);
|
|
8201
|
+
writtenTags.add("TIT3");
|
|
8202
|
+
}
|
|
8203
|
+
;
|
|
8204
|
+
break;
|
|
8205
|
+
case "artist":
|
|
8206
|
+
{
|
|
8207
|
+
this.mp3Writer.writeId3V2TextFrame("TPE1", value);
|
|
8208
|
+
writtenTags.add("TPE1");
|
|
8209
|
+
}
|
|
8210
|
+
;
|
|
8211
|
+
break;
|
|
8212
|
+
case "album":
|
|
8213
|
+
{
|
|
8214
|
+
this.mp3Writer.writeId3V2TextFrame("TALB", value);
|
|
8215
|
+
writtenTags.add("TALB");
|
|
8216
|
+
}
|
|
8217
|
+
;
|
|
8218
|
+
break;
|
|
8219
|
+
case "albumArtist":
|
|
8220
|
+
{
|
|
8221
|
+
this.mp3Writer.writeId3V2TextFrame("TPE2", value);
|
|
8222
|
+
writtenTags.add("TPE2");
|
|
8223
|
+
}
|
|
8224
|
+
;
|
|
8225
|
+
break;
|
|
8226
|
+
case "trackNumber":
|
|
8227
|
+
{
|
|
8228
|
+
const string = tags.tracksTotal !== void 0 ? `${value}/${tags.tracksTotal}` : value.toString();
|
|
8229
|
+
this.mp3Writer.writeId3V2TextFrame("TRCK", string);
|
|
8230
|
+
writtenTags.add("TRCK");
|
|
8231
|
+
}
|
|
8232
|
+
;
|
|
8233
|
+
break;
|
|
8234
|
+
case "discNumber":
|
|
8235
|
+
{
|
|
8236
|
+
const string = tags.discsTotal !== void 0 ? `${value}/${tags.discsTotal}` : value.toString();
|
|
8237
|
+
this.mp3Writer.writeId3V2TextFrame("TPOS", string);
|
|
8238
|
+
writtenTags.add("TPOS");
|
|
8239
|
+
}
|
|
8240
|
+
;
|
|
8241
|
+
break;
|
|
8242
|
+
case "genre":
|
|
8243
|
+
{
|
|
8244
|
+
this.mp3Writer.writeId3V2TextFrame("TCON", value);
|
|
8245
|
+
writtenTags.add("TCON");
|
|
8246
|
+
}
|
|
8247
|
+
;
|
|
8248
|
+
break;
|
|
8249
|
+
case "date":
|
|
8250
|
+
{
|
|
8251
|
+
this.mp3Writer.writeId3V2TextFrame("TDRC", value.toISOString().slice(0, 10));
|
|
8252
|
+
writtenTags.add("TDRC");
|
|
8253
|
+
}
|
|
8254
|
+
;
|
|
8255
|
+
break;
|
|
8256
|
+
case "lyrics":
|
|
8257
|
+
{
|
|
8258
|
+
this.mp3Writer.writeId3V2LyricsFrame(value);
|
|
8259
|
+
writtenTags.add("USLT");
|
|
8260
|
+
}
|
|
8261
|
+
;
|
|
8262
|
+
break;
|
|
8263
|
+
case "comment":
|
|
8264
|
+
{
|
|
8265
|
+
this.mp3Writer.writeId3V2CommentFrame(value);
|
|
8266
|
+
writtenTags.add("COMM");
|
|
8267
|
+
}
|
|
8268
|
+
;
|
|
8269
|
+
break;
|
|
8270
|
+
case "images":
|
|
8271
|
+
{
|
|
8272
|
+
const pictureTypeMap = { coverFront: 3, coverBack: 4, unknown: 0 };
|
|
8273
|
+
for (const image of value) {
|
|
8274
|
+
const pictureType = pictureTypeMap[image.kind];
|
|
8275
|
+
const description = image.description ?? "";
|
|
8276
|
+
this.mp3Writer.writeId3V2ApicFrame(image.mimeType, pictureType, description, image.data);
|
|
8277
|
+
}
|
|
8278
|
+
}
|
|
8279
|
+
;
|
|
8280
|
+
break;
|
|
8281
|
+
case "tracksTotal":
|
|
8282
|
+
case "discsTotal":
|
|
8283
|
+
{
|
|
8284
|
+
}
|
|
8285
|
+
;
|
|
8286
|
+
break;
|
|
8287
|
+
case "raw":
|
|
8288
|
+
{
|
|
8289
|
+
}
|
|
8290
|
+
;
|
|
8291
|
+
break;
|
|
8292
|
+
default:
|
|
8293
|
+
assertNever(key);
|
|
8294
|
+
}
|
|
8295
|
+
}
|
|
8296
|
+
if (tags.raw) {
|
|
8297
|
+
for (const key in tags.raw) {
|
|
8298
|
+
const value = tags.raw[key];
|
|
8299
|
+
if (value == null || key.length !== 4 || writtenTags.has(key)) {
|
|
8300
|
+
continue;
|
|
8301
|
+
}
|
|
8302
|
+
let bytes2;
|
|
8303
|
+
if (typeof value === "string") {
|
|
8304
|
+
const encoded = textEncoder.encode(value);
|
|
8305
|
+
bytes2 = new Uint8Array(encoded.byteLength + 2);
|
|
8306
|
+
bytes2[0] = 3 /* UTF_8 */;
|
|
8307
|
+
bytes2.set(encoded, 1);
|
|
8308
|
+
} else if (value instanceof Uint8Array) {
|
|
8309
|
+
bytes2 = value;
|
|
8310
|
+
} else {
|
|
8311
|
+
continue;
|
|
8312
|
+
}
|
|
8313
|
+
this.mp3Writer.writeAscii(key);
|
|
8314
|
+
this.mp3Writer.writeSynchsafeU32(bytes2.byteLength);
|
|
8315
|
+
this.mp3Writer.writeU16(0);
|
|
8316
|
+
this.writer.write(bytes2);
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
const endPos = this.writer.getPos();
|
|
8320
|
+
const framesSize = endPos - startPos;
|
|
8321
|
+
this.writer.seek(6);
|
|
8322
|
+
this.mp3Writer.writeSynchsafeU32(framesSize);
|
|
8323
|
+
this.writer.seek(endPos);
|
|
8324
|
+
}
|
|
6668
8325
|
async finalize() {
|
|
6669
|
-
if (!this.xingFrameData) {
|
|
8326
|
+
if (!this.xingFrameData || this.xingFramePos === null) {
|
|
6670
8327
|
return;
|
|
6671
8328
|
}
|
|
6672
8329
|
const release = await this.mutex.acquire();
|
|
6673
8330
|
const endPos = this.writer.getPos();
|
|
6674
|
-
this.writer.seek(
|
|
8331
|
+
this.writer.seek(this.xingFramePos);
|
|
6675
8332
|
const toc = new Uint8Array(100);
|
|
6676
8333
|
for (let i = 0; i < 100; i++) {
|
|
6677
8334
|
const index = Math.floor(this.framePositions.length * (i / 100));
|
|
@@ -6841,7 +8498,7 @@ ${cue.notes ?? ""}`;
|
|
|
6841
8498
|
addEncodedVideoPacket() {
|
|
6842
8499
|
throw new Error("Video tracks are not supported.");
|
|
6843
8500
|
}
|
|
6844
|
-
getTrackData(track,
|
|
8501
|
+
getTrackData(track, meta2) {
|
|
6845
8502
|
const existingTrackData = this.trackDatas.find((td) => td.track === track);
|
|
6846
8503
|
if (existingTrackData) {
|
|
6847
8504
|
return existingTrackData;
|
|
@@ -6851,13 +8508,13 @@ ${cue.notes ?? ""}`;
|
|
|
6851
8508
|
serialNumber = Math.floor(2 ** 32 * Math.random());
|
|
6852
8509
|
} while (this.trackDatas.some((td) => td.serialNumber === serialNumber));
|
|
6853
8510
|
assert(track.source._codec === "vorbis" || track.source._codec === "opus");
|
|
6854
|
-
validateAudioChunkMetadata(
|
|
6855
|
-
assert(
|
|
6856
|
-
assert(
|
|
8511
|
+
validateAudioChunkMetadata(meta2);
|
|
8512
|
+
assert(meta2);
|
|
8513
|
+
assert(meta2.decoderConfig);
|
|
6857
8514
|
const newTrackData = {
|
|
6858
8515
|
track,
|
|
6859
8516
|
serialNumber,
|
|
6860
|
-
internalSampleRate: track.source._codec === "opus" ? OPUS_INTERNAL_SAMPLE_RATE :
|
|
8517
|
+
internalSampleRate: track.source._codec === "opus" ? OPUS_INTERNAL_SAMPLE_RATE : meta2.decoderConfig.sampleRate,
|
|
6861
8518
|
codecInfo: {
|
|
6862
8519
|
codec: track.source._codec,
|
|
6863
8520
|
vorbisInfo: null,
|
|
@@ -6873,18 +8530,18 @@ ${cue.notes ?? ""}`;
|
|
|
6873
8530
|
currentPageSize: 27,
|
|
6874
8531
|
currentPageStartsWithFreshPacket: true
|
|
6875
8532
|
};
|
|
6876
|
-
this.queueHeaderPackets(newTrackData,
|
|
8533
|
+
this.queueHeaderPackets(newTrackData, meta2);
|
|
6877
8534
|
this.trackDatas.push(newTrackData);
|
|
6878
8535
|
if (this.allTracksAreKnown()) {
|
|
6879
8536
|
this.allTracksKnown.resolve();
|
|
6880
8537
|
}
|
|
6881
8538
|
return newTrackData;
|
|
6882
8539
|
}
|
|
6883
|
-
queueHeaderPackets(trackData,
|
|
6884
|
-
assert(
|
|
8540
|
+
queueHeaderPackets(trackData, meta2) {
|
|
8541
|
+
assert(meta2.decoderConfig);
|
|
6885
8542
|
if (trackData.track.source._codec === "vorbis") {
|
|
6886
|
-
assert(
|
|
6887
|
-
const bytes2 = toUint8Array(
|
|
8543
|
+
assert(meta2.decoderConfig.description);
|
|
8544
|
+
const bytes2 = toUint8Array(meta2.decoderConfig.description);
|
|
6888
8545
|
if (bytes2[0] !== 2) {
|
|
6889
8546
|
throw new TypeError("First byte of Vorbis decoder description must be 2.");
|
|
6890
8547
|
}
|
|
@@ -6909,8 +8566,17 @@ ${cue.notes ?? ""}`;
|
|
|
6909
8566
|
throw new TypeError("Vorbis decoder description is too short.");
|
|
6910
8567
|
}
|
|
6911
8568
|
const identificationHeader = bytes2.subarray(pos, pos += identificationHeaderLength);
|
|
6912
|
-
|
|
8569
|
+
pos += commentHeaderLength;
|
|
6913
8570
|
const setupHeader = bytes2.subarray(pos);
|
|
8571
|
+
const commentHeaderHeader = new Uint8Array(7);
|
|
8572
|
+
commentHeaderHeader[0] = 3;
|
|
8573
|
+
commentHeaderHeader[1] = 118;
|
|
8574
|
+
commentHeaderHeader[2] = 111;
|
|
8575
|
+
commentHeaderHeader[3] = 114;
|
|
8576
|
+
commentHeaderHeader[4] = 98;
|
|
8577
|
+
commentHeaderHeader[5] = 105;
|
|
8578
|
+
commentHeaderHeader[6] = 115;
|
|
8579
|
+
const commentHeader = this.createVorbisComments(commentHeaderHeader);
|
|
6914
8580
|
trackData.packetQueue.push({
|
|
6915
8581
|
data: identificationHeader,
|
|
6916
8582
|
endGranulePosition: 0,
|
|
@@ -6938,16 +8604,15 @@ ${cue.notes ?? ""}`;
|
|
|
6938
8604
|
modeBlockflags: parseModesFromVorbisSetupPacket(setupHeader).modeBlockflags
|
|
6939
8605
|
};
|
|
6940
8606
|
} else if (trackData.track.source._codec === "opus") {
|
|
6941
|
-
if (!
|
|
8607
|
+
if (!meta2.decoderConfig.description) {
|
|
6942
8608
|
throw new TypeError("For Ogg, Opus decoder description is required.");
|
|
6943
8609
|
}
|
|
6944
|
-
const identificationHeader = toUint8Array(
|
|
6945
|
-
const
|
|
6946
|
-
const
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
view2.setUint32(12, 0, true);
|
|
8610
|
+
const identificationHeader = toUint8Array(meta2.decoderConfig.description);
|
|
8611
|
+
const commentHeaderHeader = new Uint8Array(8);
|
|
8612
|
+
const commentHeaderHeaderView = toDataView(commentHeaderHeader);
|
|
8613
|
+
commentHeaderHeaderView.setUint32(0, 1332770163, false);
|
|
8614
|
+
commentHeaderHeaderView.setUint32(4, 1415669619, false);
|
|
8615
|
+
const commentHeader = this.createVorbisComments(commentHeaderHeader);
|
|
6951
8616
|
trackData.packetQueue.push({
|
|
6952
8617
|
data: identificationHeader,
|
|
6953
8618
|
endGranulePosition: 0,
|
|
@@ -6965,10 +8630,182 @@ ${cue.notes ?? ""}`;
|
|
|
6965
8630
|
};
|
|
6966
8631
|
}
|
|
6967
8632
|
}
|
|
6968
|
-
|
|
8633
|
+
createVorbisComments(headerBytes) {
|
|
8634
|
+
const tags = this.output._metadataTags;
|
|
8635
|
+
const commentHeaderParts = [
|
|
8636
|
+
headerBytes
|
|
8637
|
+
];
|
|
8638
|
+
let vendorString = "";
|
|
8639
|
+
if (typeof tags.raw?.["vendor"] === "string") {
|
|
8640
|
+
vendorString = tags.raw?.["vendor"];
|
|
8641
|
+
}
|
|
8642
|
+
const encodedVendorString = textEncoder.encode(vendorString);
|
|
8643
|
+
let currentBuffer = new Uint8Array(4 + encodedVendorString.length);
|
|
8644
|
+
let currentView = new DataView(currentBuffer.buffer);
|
|
8645
|
+
currentView.setUint32(0, encodedVendorString.length, true);
|
|
8646
|
+
currentBuffer.set(encodedVendorString, 4);
|
|
8647
|
+
commentHeaderParts.push(currentBuffer);
|
|
8648
|
+
const writtenTags = /* @__PURE__ */ new Set();
|
|
8649
|
+
const addCommentTag = (key, value) => {
|
|
8650
|
+
const joined = `${key}=${value}`;
|
|
8651
|
+
const encoded = textEncoder.encode(joined);
|
|
8652
|
+
currentBuffer = new Uint8Array(4 + encoded.length);
|
|
8653
|
+
currentView = new DataView(currentBuffer.buffer);
|
|
8654
|
+
currentView.setUint32(0, encoded.length, true);
|
|
8655
|
+
currentBuffer.set(encoded, 4);
|
|
8656
|
+
commentHeaderParts.push(currentBuffer);
|
|
8657
|
+
writtenTags.add(key);
|
|
8658
|
+
};
|
|
8659
|
+
for (const { key, value } of keyValueIterator(tags)) {
|
|
8660
|
+
switch (key) {
|
|
8661
|
+
case "title":
|
|
8662
|
+
{
|
|
8663
|
+
addCommentTag("TITLE", value);
|
|
8664
|
+
}
|
|
8665
|
+
;
|
|
8666
|
+
break;
|
|
8667
|
+
case "description":
|
|
8668
|
+
{
|
|
8669
|
+
addCommentTag("DESCRIPTION", value);
|
|
8670
|
+
}
|
|
8671
|
+
;
|
|
8672
|
+
break;
|
|
8673
|
+
case "artist":
|
|
8674
|
+
{
|
|
8675
|
+
addCommentTag("ARTIST", value);
|
|
8676
|
+
}
|
|
8677
|
+
;
|
|
8678
|
+
break;
|
|
8679
|
+
case "album":
|
|
8680
|
+
{
|
|
8681
|
+
addCommentTag("ALBUM", value);
|
|
8682
|
+
}
|
|
8683
|
+
;
|
|
8684
|
+
break;
|
|
8685
|
+
case "albumArtist":
|
|
8686
|
+
{
|
|
8687
|
+
addCommentTag("ALBUMARTIST", value);
|
|
8688
|
+
}
|
|
8689
|
+
;
|
|
8690
|
+
break;
|
|
8691
|
+
case "genre":
|
|
8692
|
+
{
|
|
8693
|
+
addCommentTag("GENRE", value);
|
|
8694
|
+
}
|
|
8695
|
+
;
|
|
8696
|
+
break;
|
|
8697
|
+
case "date":
|
|
8698
|
+
{
|
|
8699
|
+
addCommentTag("DATE", value.toISOString().slice(0, 10));
|
|
8700
|
+
}
|
|
8701
|
+
;
|
|
8702
|
+
break;
|
|
8703
|
+
case "comment":
|
|
8704
|
+
{
|
|
8705
|
+
addCommentTag("COMMENT", value);
|
|
8706
|
+
}
|
|
8707
|
+
;
|
|
8708
|
+
break;
|
|
8709
|
+
case "lyrics":
|
|
8710
|
+
{
|
|
8711
|
+
addCommentTag("LYRICS", value);
|
|
8712
|
+
}
|
|
8713
|
+
;
|
|
8714
|
+
break;
|
|
8715
|
+
case "trackNumber":
|
|
8716
|
+
{
|
|
8717
|
+
addCommentTag("TRACKNUMBER", value.toString());
|
|
8718
|
+
}
|
|
8719
|
+
;
|
|
8720
|
+
break;
|
|
8721
|
+
case "tracksTotal":
|
|
8722
|
+
{
|
|
8723
|
+
addCommentTag("TRACKTOTAL", value.toString());
|
|
8724
|
+
}
|
|
8725
|
+
;
|
|
8726
|
+
break;
|
|
8727
|
+
case "discNumber":
|
|
8728
|
+
{
|
|
8729
|
+
addCommentTag("DISCNUMBER", value.toString());
|
|
8730
|
+
}
|
|
8731
|
+
;
|
|
8732
|
+
break;
|
|
8733
|
+
case "discsTotal":
|
|
8734
|
+
{
|
|
8735
|
+
addCommentTag("DISCTOTAL", value.toString());
|
|
8736
|
+
}
|
|
8737
|
+
;
|
|
8738
|
+
break;
|
|
8739
|
+
case "images":
|
|
8740
|
+
{
|
|
8741
|
+
for (const image of value) {
|
|
8742
|
+
const pictureType = image.kind === "coverFront" ? 3 : image.kind === "coverBack" ? 4 : 0;
|
|
8743
|
+
const encodedMediaType = new Uint8Array(image.mimeType.length);
|
|
8744
|
+
for (let i = 0; i < image.mimeType.length; i++) {
|
|
8745
|
+
encodedMediaType[i] = image.mimeType.charCodeAt(i);
|
|
8746
|
+
}
|
|
8747
|
+
const encodedDescription = textEncoder.encode(image.description ?? "");
|
|
8748
|
+
const buffer = new Uint8Array(
|
|
8749
|
+
4 + 4 + encodedMediaType.length + 4 + encodedDescription.length + 16 + 4 + image.data.length
|
|
8750
|
+
// Picture data
|
|
8751
|
+
);
|
|
8752
|
+
const view2 = toDataView(buffer);
|
|
8753
|
+
view2.setUint32(0, pictureType, false);
|
|
8754
|
+
view2.setUint32(4, encodedMediaType.length, false);
|
|
8755
|
+
buffer.set(encodedMediaType, 8);
|
|
8756
|
+
view2.setUint32(8 + encodedMediaType.length, encodedDescription.length, false);
|
|
8757
|
+
buffer.set(encodedDescription, 12 + encodedMediaType.length);
|
|
8758
|
+
view2.setUint32(
|
|
8759
|
+
28 + encodedMediaType.length + encodedDescription.length,
|
|
8760
|
+
image.data.length,
|
|
8761
|
+
false
|
|
8762
|
+
);
|
|
8763
|
+
buffer.set(
|
|
8764
|
+
image.data,
|
|
8765
|
+
32 + encodedMediaType.length + encodedDescription.length
|
|
8766
|
+
);
|
|
8767
|
+
const encoded = bytesToBase64(buffer);
|
|
8768
|
+
addCommentTag("METADATA_BLOCK_PICTURE", encoded);
|
|
8769
|
+
}
|
|
8770
|
+
}
|
|
8771
|
+
;
|
|
8772
|
+
break;
|
|
8773
|
+
case "raw":
|
|
8774
|
+
{
|
|
8775
|
+
}
|
|
8776
|
+
;
|
|
8777
|
+
break;
|
|
8778
|
+
default:
|
|
8779
|
+
assertNever(key);
|
|
8780
|
+
}
|
|
8781
|
+
}
|
|
8782
|
+
if (tags.raw) {
|
|
8783
|
+
for (const key in tags.raw) {
|
|
8784
|
+
const value = tags.raw[key];
|
|
8785
|
+
if (key === "vendor" || value == null || writtenTags.has(key)) {
|
|
8786
|
+
continue;
|
|
8787
|
+
}
|
|
8788
|
+
if (typeof value === "string") {
|
|
8789
|
+
addCommentTag(key, value);
|
|
8790
|
+
}
|
|
8791
|
+
}
|
|
8792
|
+
}
|
|
8793
|
+
const listLengthBuffer = new Uint8Array(4);
|
|
8794
|
+
toDataView(listLengthBuffer).setUint32(0, writtenTags.size, true);
|
|
8795
|
+
commentHeaderParts.splice(2, 0, listLengthBuffer);
|
|
8796
|
+
const commentHeaderLength = commentHeaderParts.reduce((a, b) => a + b.length, 0);
|
|
8797
|
+
const commentHeader = new Uint8Array(commentHeaderLength);
|
|
8798
|
+
let pos = 0;
|
|
8799
|
+
for (const part of commentHeaderParts) {
|
|
8800
|
+
commentHeader.set(part, pos);
|
|
8801
|
+
pos += part.length;
|
|
8802
|
+
}
|
|
8803
|
+
return commentHeader;
|
|
8804
|
+
}
|
|
8805
|
+
async addEncodedAudioPacket(track, packet, meta2) {
|
|
6969
8806
|
const release = await this.mutex.acquire();
|
|
6970
8807
|
try {
|
|
6971
|
-
const trackData = this.getTrackData(track,
|
|
8808
|
+
const trackData = this.getTrackData(track, meta2);
|
|
6972
8809
|
this.validateAndNormalizeTimestamp(trackData.track, packet.timestamp, packet.type === "key");
|
|
6973
8810
|
const currentTimestampInSamples = trackData.currentTimestampInSamples;
|
|
6974
8811
|
const { durationInSamples, vorbisBlockSize } = extractSampleMetadata(
|
|
@@ -9643,7 +11480,8 @@ ${cue.notes ?? ""}`;
|
|
|
9643
11480
|
}
|
|
9644
11481
|
/**
|
|
9645
11482
|
* Returns the [decoder configuration](https://www.w3.org/TR/webcodecs/#video-decoder-config) for decoding the
|
|
9646
|
-
* track's packets using a VideoDecoder. Returns
|
|
11483
|
+
* track's packets using a [`VideoDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder). Returns
|
|
11484
|
+
* null if the track's codec is unknown.
|
|
9647
11485
|
*/
|
|
9648
11486
|
getDecoderConfig() {
|
|
9649
11487
|
return this._backing.getDecoderConfig();
|
|
@@ -9708,7 +11546,8 @@ ${cue.notes ?? ""}`;
|
|
|
9708
11546
|
}
|
|
9709
11547
|
/**
|
|
9710
11548
|
* Returns the [decoder configuration](https://www.w3.org/TR/webcodecs/#audio-decoder-config) for decoding the
|
|
9711
|
-
* track's packets using an AudioDecoder. Returns
|
|
11549
|
+
* track's packets using an [`AudioDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/AudioDecoder). Returns
|
|
11550
|
+
* null if the track's codec is unknown.
|
|
9712
11551
|
*/
|
|
9713
11552
|
getDecoderConfig() {
|
|
9714
11553
|
return this._backing.getDecoderConfig();
|
|
@@ -9763,6 +11602,7 @@ ${cue.notes ?? ""}`;
|
|
|
9763
11602
|
this.audioInfo = null;
|
|
9764
11603
|
this.tracks = [];
|
|
9765
11604
|
this.lastKnownPacketIndex = 0;
|
|
11605
|
+
this.metadataTags = {};
|
|
9766
11606
|
this.reader = input._reader;
|
|
9767
11607
|
}
|
|
9768
11608
|
async readMetadata() {
|
|
@@ -9798,10 +11638,15 @@ ${cue.notes ?? ""}`;
|
|
|
9798
11638
|
dataChunkSize ??= chunkSize;
|
|
9799
11639
|
this.dataStart = slice2.filePos;
|
|
9800
11640
|
this.dataSize = Math.min(dataChunkSize, (totalFileSize ?? Infinity) - this.dataStart);
|
|
11641
|
+
if (this.reader.fileSize === null) {
|
|
11642
|
+
break;
|
|
11643
|
+
}
|
|
9801
11644
|
} else if (chunkId === "ds64") {
|
|
9802
11645
|
const riffChunkSize = readU64(slice2, littleEndian);
|
|
9803
11646
|
dataChunkSize = readU64(slice2, littleEndian);
|
|
9804
11647
|
totalFileSize = Math.min(riffChunkSize + 8, this.reader.fileSize ?? Infinity);
|
|
11648
|
+
} else if (chunkId === "LIST") {
|
|
11649
|
+
await this.parseListChunk(startPos, chunkSize, littleEndian);
|
|
9805
11650
|
}
|
|
9806
11651
|
currentPos = startPos + chunkSize + (chunkSize & 1);
|
|
9807
11652
|
chunksRead++;
|
|
@@ -9853,6 +11698,110 @@ ${cue.notes ?? ""}`;
|
|
|
9853
11698
|
blockSizeInBytes: blockAlign
|
|
9854
11699
|
};
|
|
9855
11700
|
}
|
|
11701
|
+
async parseListChunk(startPos, size, littleEndian) {
|
|
11702
|
+
let slice = this.reader.requestSlice(startPos, size);
|
|
11703
|
+
if (slice instanceof Promise) slice = await slice;
|
|
11704
|
+
if (!slice) return;
|
|
11705
|
+
const infoType = readAscii(slice, 4);
|
|
11706
|
+
if (infoType !== "INFO" && infoType !== "INF0") {
|
|
11707
|
+
return;
|
|
11708
|
+
}
|
|
11709
|
+
let currentPos = slice.filePos;
|
|
11710
|
+
while (currentPos <= startPos + size - 8) {
|
|
11711
|
+
slice.filePos = currentPos;
|
|
11712
|
+
const chunkName = readAscii(slice, 4);
|
|
11713
|
+
const chunkSize = readU32(slice, littleEndian);
|
|
11714
|
+
const bytes2 = readBytes(slice, chunkSize);
|
|
11715
|
+
let stringLength = 0;
|
|
11716
|
+
for (let i = 0; i < bytes2.length; i++) {
|
|
11717
|
+
if (bytes2[i] === 0) {
|
|
11718
|
+
break;
|
|
11719
|
+
}
|
|
11720
|
+
stringLength++;
|
|
11721
|
+
}
|
|
11722
|
+
const value = String.fromCharCode(...bytes2.subarray(0, stringLength));
|
|
11723
|
+
this.metadataTags.raw ??= {};
|
|
11724
|
+
this.metadataTags.raw[chunkName] = value;
|
|
11725
|
+
switch (chunkName) {
|
|
11726
|
+
case "INAM":
|
|
11727
|
+
case "TITL":
|
|
11728
|
+
{
|
|
11729
|
+
this.metadataTags.title ??= value;
|
|
11730
|
+
}
|
|
11731
|
+
;
|
|
11732
|
+
break;
|
|
11733
|
+
case "TIT3":
|
|
11734
|
+
{
|
|
11735
|
+
this.metadataTags.description ??= value;
|
|
11736
|
+
}
|
|
11737
|
+
;
|
|
11738
|
+
break;
|
|
11739
|
+
case "IART":
|
|
11740
|
+
{
|
|
11741
|
+
this.metadataTags.artist ??= value;
|
|
11742
|
+
}
|
|
11743
|
+
;
|
|
11744
|
+
break;
|
|
11745
|
+
case "IPRD":
|
|
11746
|
+
{
|
|
11747
|
+
this.metadataTags.album ??= value;
|
|
11748
|
+
}
|
|
11749
|
+
;
|
|
11750
|
+
break;
|
|
11751
|
+
case "IPRT":
|
|
11752
|
+
case "ITRK":
|
|
11753
|
+
case "TRCK":
|
|
11754
|
+
{
|
|
11755
|
+
const parts = value.split("/");
|
|
11756
|
+
const trackNum = Number.parseInt(parts[0], 10);
|
|
11757
|
+
const tracksTotal = parts[1] && Number.parseInt(parts[1], 10);
|
|
11758
|
+
if (Number.isInteger(trackNum) && trackNum > 0) {
|
|
11759
|
+
this.metadataTags.trackNumber ??= trackNum;
|
|
11760
|
+
}
|
|
11761
|
+
if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) {
|
|
11762
|
+
this.metadataTags.tracksTotal ??= tracksTotal;
|
|
11763
|
+
}
|
|
11764
|
+
}
|
|
11765
|
+
;
|
|
11766
|
+
break;
|
|
11767
|
+
case "ICRD":
|
|
11768
|
+
case "IDIT":
|
|
11769
|
+
{
|
|
11770
|
+
const date = new Date(value);
|
|
11771
|
+
if (!Number.isNaN(date.getTime())) {
|
|
11772
|
+
this.metadataTags.date ??= date;
|
|
11773
|
+
}
|
|
11774
|
+
}
|
|
11775
|
+
;
|
|
11776
|
+
break;
|
|
11777
|
+
case "YEAR":
|
|
11778
|
+
{
|
|
11779
|
+
const year = Number.parseInt(value, 10);
|
|
11780
|
+
if (Number.isInteger(year) && year > 0) {
|
|
11781
|
+
this.metadataTags.date ??= new Date(year, 0, 1);
|
|
11782
|
+
}
|
|
11783
|
+
}
|
|
11784
|
+
;
|
|
11785
|
+
break;
|
|
11786
|
+
case "IGNR":
|
|
11787
|
+
case "GENR":
|
|
11788
|
+
{
|
|
11789
|
+
this.metadataTags.genre ??= value;
|
|
11790
|
+
}
|
|
11791
|
+
;
|
|
11792
|
+
break;
|
|
11793
|
+
case "ICMT":
|
|
11794
|
+
case "CMNT":
|
|
11795
|
+
case "COMM":
|
|
11796
|
+
{
|
|
11797
|
+
this.metadataTags.comment ??= value;
|
|
11798
|
+
}
|
|
11799
|
+
;
|
|
11800
|
+
break;
|
|
11801
|
+
}
|
|
11802
|
+
currentPos += 8 + chunkSize + (chunkSize & 1);
|
|
11803
|
+
}
|
|
11804
|
+
}
|
|
9856
11805
|
getCodec() {
|
|
9857
11806
|
assert(this.audioInfo);
|
|
9858
11807
|
if (this.audioInfo.format === 7 /* MULAW */) {
|
|
@@ -9892,6 +11841,10 @@ ${cue.notes ?? ""}`;
|
|
|
9892
11841
|
await this.readMetadata();
|
|
9893
11842
|
return this.tracks;
|
|
9894
11843
|
}
|
|
11844
|
+
async getMetadataTags() {
|
|
11845
|
+
await this.readMetadata();
|
|
11846
|
+
return this.metadataTags;
|
|
11847
|
+
}
|
|
9895
11848
|
};
|
|
9896
11849
|
var PACKET_SIZE_IN_FRAMES = 2048;
|
|
9897
11850
|
var WaveAudioTrackBacking = class {
|
|
@@ -10059,6 +12012,11 @@ ${cue.notes ?? ""}`;
|
|
|
10059
12012
|
this.dataSize = 0;
|
|
10060
12013
|
this.sampleRate = null;
|
|
10061
12014
|
this.sampleCount = 0;
|
|
12015
|
+
this.riffSizePos = null;
|
|
12016
|
+
this.dataSizePos = null;
|
|
12017
|
+
this.ds64RiffSizePos = null;
|
|
12018
|
+
this.ds64DataSizePos = null;
|
|
12019
|
+
this.ds64SampleCountPos = null;
|
|
10062
12020
|
this.format = format;
|
|
10063
12021
|
this.writer = output._writer;
|
|
10064
12022
|
this.riffWriter = new RiffWriter(output._writer);
|
|
@@ -10072,15 +12030,15 @@ ${cue.notes ?? ""}`;
|
|
|
10072
12030
|
async addEncodedVideoPacket() {
|
|
10073
12031
|
throw new Error("WAVE does not support video.");
|
|
10074
12032
|
}
|
|
10075
|
-
async addEncodedAudioPacket(track, packet,
|
|
12033
|
+
async addEncodedAudioPacket(track, packet, meta2) {
|
|
10076
12034
|
const release = await this.mutex.acquire();
|
|
10077
12035
|
try {
|
|
10078
12036
|
if (!this.headerWritten) {
|
|
10079
|
-
validateAudioChunkMetadata(
|
|
10080
|
-
assert(
|
|
10081
|
-
assert(
|
|
10082
|
-
this.writeHeader(track,
|
|
10083
|
-
this.sampleRate =
|
|
12037
|
+
validateAudioChunkMetadata(meta2);
|
|
12038
|
+
assert(meta2);
|
|
12039
|
+
assert(meta2.decoderConfig);
|
|
12040
|
+
this.writeHeader(track, meta2.decoderConfig);
|
|
12041
|
+
this.sampleRate = meta2.decoderConfig.sampleRate;
|
|
10084
12042
|
this.headerWritten = true;
|
|
10085
12043
|
}
|
|
10086
12044
|
this.validateAndNormalizeTimestamp(track, packet.timestamp, packet.type === "key");
|
|
@@ -10123,50 +12081,179 @@ ${cue.notes ?? ""}`;
|
|
|
10123
12081
|
if (this.isRf64) {
|
|
10124
12082
|
this.riffWriter.writeU32(4294967295);
|
|
10125
12083
|
} else {
|
|
12084
|
+
this.riffSizePos = this.writer.getPos();
|
|
10126
12085
|
this.riffWriter.writeU32(0);
|
|
10127
12086
|
}
|
|
10128
12087
|
this.riffWriter.writeAscii("WAVE");
|
|
10129
12088
|
if (this.isRf64) {
|
|
10130
12089
|
this.riffWriter.writeAscii("ds64");
|
|
10131
12090
|
this.riffWriter.writeU32(28);
|
|
12091
|
+
this.ds64RiffSizePos = this.writer.getPos();
|
|
10132
12092
|
this.riffWriter.writeU64(0);
|
|
12093
|
+
this.ds64DataSizePos = this.writer.getPos();
|
|
10133
12094
|
this.riffWriter.writeU64(0);
|
|
12095
|
+
this.ds64SampleCountPos = this.writer.getPos();
|
|
10134
12096
|
this.riffWriter.writeU64(0);
|
|
10135
12097
|
this.riffWriter.writeU32(0);
|
|
10136
12098
|
}
|
|
10137
|
-
this.riffWriter.writeAscii("fmt ");
|
|
10138
|
-
this.riffWriter.writeU32(16);
|
|
10139
|
-
this.riffWriter.writeU16(format);
|
|
10140
|
-
this.riffWriter.writeU16(channels);
|
|
10141
|
-
this.riffWriter.writeU32(sampleRate);
|
|
10142
|
-
this.riffWriter.writeU32(sampleRate * blockSize);
|
|
10143
|
-
this.riffWriter.writeU16(blockSize);
|
|
10144
|
-
this.riffWriter.writeU16(8 * pcmInfo.sampleSize);
|
|
10145
|
-
this.
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
12099
|
+
this.riffWriter.writeAscii("fmt ");
|
|
12100
|
+
this.riffWriter.writeU32(16);
|
|
12101
|
+
this.riffWriter.writeU16(format);
|
|
12102
|
+
this.riffWriter.writeU16(channels);
|
|
12103
|
+
this.riffWriter.writeU32(sampleRate);
|
|
12104
|
+
this.riffWriter.writeU32(sampleRate * blockSize);
|
|
12105
|
+
this.riffWriter.writeU16(blockSize);
|
|
12106
|
+
this.riffWriter.writeU16(8 * pcmInfo.sampleSize);
|
|
12107
|
+
if (!metadataTagsAreEmpty(this.output._metadataTags)) {
|
|
12108
|
+
this.writeInfoChunk(this.output._metadataTags);
|
|
12109
|
+
}
|
|
12110
|
+
this.riffWriter.writeAscii("data");
|
|
12111
|
+
if (this.isRf64) {
|
|
12112
|
+
this.riffWriter.writeU32(4294967295);
|
|
12113
|
+
} else {
|
|
12114
|
+
this.dataSizePos = this.writer.getPos();
|
|
12115
|
+
this.riffWriter.writeU32(0);
|
|
12116
|
+
}
|
|
12117
|
+
if (this.format._options.onHeader) {
|
|
12118
|
+
const { data, start } = this.writer.stopTrackingWrites();
|
|
12119
|
+
this.format._options.onHeader(data, start);
|
|
12120
|
+
}
|
|
12121
|
+
}
|
|
12122
|
+
writeInfoChunk(metadata) {
|
|
12123
|
+
const startPos = this.writer.getPos();
|
|
12124
|
+
this.riffWriter.writeAscii("LIST");
|
|
12125
|
+
this.riffWriter.writeU32(0);
|
|
12126
|
+
this.riffWriter.writeAscii("INFO");
|
|
12127
|
+
const writtenTags = /* @__PURE__ */ new Set();
|
|
12128
|
+
const writeInfoTag = (tag, value) => {
|
|
12129
|
+
if (!isIso88591Compatible(value)) {
|
|
12130
|
+
console.warn(`Didn't write tag '${tag}' because '${value}' is not ISO 8859-1-compatible.`);
|
|
12131
|
+
return;
|
|
12132
|
+
}
|
|
12133
|
+
const size = value.length + 1;
|
|
12134
|
+
const bytes2 = new Uint8Array(size);
|
|
12135
|
+
for (let i = 0; i < value.length; i++) {
|
|
12136
|
+
bytes2[i] = value.charCodeAt(i);
|
|
12137
|
+
}
|
|
12138
|
+
this.riffWriter.writeAscii(tag);
|
|
12139
|
+
this.riffWriter.writeU32(size);
|
|
12140
|
+
this.writer.write(bytes2);
|
|
12141
|
+
if (size & 1) {
|
|
12142
|
+
this.writer.write(new Uint8Array(1));
|
|
12143
|
+
}
|
|
12144
|
+
writtenTags.add(tag);
|
|
12145
|
+
};
|
|
12146
|
+
for (const { key, value } of keyValueIterator(metadata)) {
|
|
12147
|
+
switch (key) {
|
|
12148
|
+
case "title":
|
|
12149
|
+
{
|
|
12150
|
+
writeInfoTag("INAM", value);
|
|
12151
|
+
writtenTags.add("INAM");
|
|
12152
|
+
}
|
|
12153
|
+
;
|
|
12154
|
+
break;
|
|
12155
|
+
case "artist":
|
|
12156
|
+
{
|
|
12157
|
+
writeInfoTag("IART", value);
|
|
12158
|
+
writtenTags.add("IART");
|
|
12159
|
+
}
|
|
12160
|
+
;
|
|
12161
|
+
break;
|
|
12162
|
+
case "album":
|
|
12163
|
+
{
|
|
12164
|
+
writeInfoTag("IPRD", value);
|
|
12165
|
+
writtenTags.add("IPRD");
|
|
12166
|
+
}
|
|
12167
|
+
;
|
|
12168
|
+
break;
|
|
12169
|
+
case "trackNumber":
|
|
12170
|
+
{
|
|
12171
|
+
const string = metadata.tracksTotal !== void 0 ? `${value}/${metadata.tracksTotal}` : value.toString();
|
|
12172
|
+
writeInfoTag("ITRK", string);
|
|
12173
|
+
writtenTags.add("ITRK");
|
|
12174
|
+
}
|
|
12175
|
+
;
|
|
12176
|
+
break;
|
|
12177
|
+
case "genre":
|
|
12178
|
+
{
|
|
12179
|
+
writeInfoTag("IGNR", value);
|
|
12180
|
+
writtenTags.add("IGNR");
|
|
12181
|
+
}
|
|
12182
|
+
;
|
|
12183
|
+
break;
|
|
12184
|
+
case "date":
|
|
12185
|
+
{
|
|
12186
|
+
writeInfoTag("ICRD", value.toISOString().slice(0, 10));
|
|
12187
|
+
writtenTags.add("ICRD");
|
|
12188
|
+
}
|
|
12189
|
+
;
|
|
12190
|
+
break;
|
|
12191
|
+
case "comment":
|
|
12192
|
+
{
|
|
12193
|
+
writeInfoTag("ICMT", value);
|
|
12194
|
+
writtenTags.add("ICMT");
|
|
12195
|
+
}
|
|
12196
|
+
;
|
|
12197
|
+
break;
|
|
12198
|
+
case "albumArtist":
|
|
12199
|
+
case "discNumber":
|
|
12200
|
+
case "tracksTotal":
|
|
12201
|
+
case "discsTotal":
|
|
12202
|
+
case "description":
|
|
12203
|
+
case "lyrics":
|
|
12204
|
+
case "images":
|
|
12205
|
+
{
|
|
12206
|
+
}
|
|
12207
|
+
;
|
|
12208
|
+
break;
|
|
12209
|
+
case "raw":
|
|
12210
|
+
{
|
|
12211
|
+
}
|
|
12212
|
+
;
|
|
12213
|
+
break;
|
|
12214
|
+
default:
|
|
12215
|
+
assertNever(key);
|
|
12216
|
+
}
|
|
12217
|
+
}
|
|
12218
|
+
if (metadata.raw) {
|
|
12219
|
+
for (const key in metadata.raw) {
|
|
12220
|
+
const value = metadata.raw[key];
|
|
12221
|
+
if (value == null || key.length !== 4 || writtenTags.has(key)) {
|
|
12222
|
+
continue;
|
|
12223
|
+
}
|
|
12224
|
+
if (typeof value === "string") {
|
|
12225
|
+
writeInfoTag(key, value);
|
|
12226
|
+
}
|
|
12227
|
+
}
|
|
10150
12228
|
}
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
12229
|
+
const endPos = this.writer.getPos();
|
|
12230
|
+
const chunkSize = endPos - startPos - 8;
|
|
12231
|
+
this.writer.seek(startPos + 4);
|
|
12232
|
+
this.riffWriter.writeU32(chunkSize);
|
|
12233
|
+
this.writer.seek(endPos);
|
|
12234
|
+
if (chunkSize & 1) {
|
|
12235
|
+
this.writer.write(new Uint8Array(1));
|
|
10154
12236
|
}
|
|
10155
12237
|
}
|
|
10156
12238
|
async finalize() {
|
|
10157
12239
|
const release = await this.mutex.acquire();
|
|
10158
12240
|
const endPos = this.writer.getPos();
|
|
10159
12241
|
if (this.isRf64) {
|
|
10160
|
-
this.
|
|
12242
|
+
assert(this.ds64RiffSizePos !== null);
|
|
12243
|
+
this.writer.seek(this.ds64RiffSizePos);
|
|
10161
12244
|
this.riffWriter.writeU64(endPos - 8);
|
|
10162
|
-
this.
|
|
12245
|
+
assert(this.ds64DataSizePos !== null);
|
|
12246
|
+
this.writer.seek(this.ds64DataSizePos);
|
|
10163
12247
|
this.riffWriter.writeU64(this.dataSize);
|
|
10164
|
-
this.
|
|
12248
|
+
assert(this.ds64SampleCountPos !== null);
|
|
12249
|
+
this.writer.seek(this.ds64SampleCountPos);
|
|
10165
12250
|
this.riffWriter.writeU64(this.sampleCount);
|
|
10166
12251
|
} else {
|
|
10167
|
-
this.
|
|
12252
|
+
assert(this.riffSizePos !== null);
|
|
12253
|
+
this.writer.seek(this.riffSizePos);
|
|
10168
12254
|
this.riffWriter.writeU32(endPos - 8);
|
|
10169
|
-
this.
|
|
12255
|
+
assert(this.dataSizePos !== null);
|
|
12256
|
+
this.writer.seek(this.dataSizePos);
|
|
10170
12257
|
this.riffWriter.writeU32(this.dataSize);
|
|
10171
12258
|
}
|
|
10172
12259
|
this.writer.seek(endPos);
|
|
@@ -10235,7 +12322,7 @@ ${cue.notes ?? ""}`;
|
|
|
10235
12322
|
}
|
|
10236
12323
|
/** @internal */
|
|
10237
12324
|
_createMuxer(output) {
|
|
10238
|
-
return new
|
|
12325
|
+
return new IsobmffMuxer2(output, this);
|
|
10239
12326
|
}
|
|
10240
12327
|
};
|
|
10241
12328
|
var Mp4OutputFormat = class extends IsobmffOutputFormat2 {
|
|
@@ -11049,18 +13136,18 @@ ${cue.notes ?? ""}`;
|
|
|
11049
13136
|
* @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise
|
|
11050
13137
|
* to respect writer and encoder backpressure.
|
|
11051
13138
|
*/
|
|
11052
|
-
add(packet,
|
|
13139
|
+
add(packet, meta2) {
|
|
11053
13140
|
if (!(packet instanceof EncodedPacket)) {
|
|
11054
13141
|
throw new TypeError("packet must be an EncodedPacket.");
|
|
11055
13142
|
}
|
|
11056
13143
|
if (packet.isMetadataOnly) {
|
|
11057
13144
|
throw new TypeError("Metadata-only packets cannot be added.");
|
|
11058
13145
|
}
|
|
11059
|
-
if (
|
|
13146
|
+
if (meta2 !== void 0 && (!meta2 || typeof meta2 !== "object")) {
|
|
11060
13147
|
throw new TypeError("meta, when provided, must be an object.");
|
|
11061
13148
|
}
|
|
11062
13149
|
this._ensureValidAdd();
|
|
11063
|
-
return this._connectedTrack.output._muxer.addEncodedVideoPacket(this._connectedTrack, packet,
|
|
13150
|
+
return this._connectedTrack.output._muxer.addEncodedVideoPacket(this._connectedTrack, packet, meta2);
|
|
11064
13151
|
}
|
|
11065
13152
|
};
|
|
11066
13153
|
var VideoEncoderWrapper = class {
|
|
@@ -11195,15 +13282,15 @@ ${cue.notes ?? ""}`;
|
|
|
11195
13282
|
this.customEncoder = new MatchingCustomEncoder();
|
|
11196
13283
|
this.customEncoder.codec = this.encodingConfig.codec;
|
|
11197
13284
|
this.customEncoder.config = encoderConfig;
|
|
11198
|
-
this.customEncoder.onPacket = (packet,
|
|
13285
|
+
this.customEncoder.onPacket = (packet, meta2) => {
|
|
11199
13286
|
if (!(packet instanceof EncodedPacket)) {
|
|
11200
13287
|
throw new TypeError("The first argument passed to onPacket must be an EncodedPacket.");
|
|
11201
13288
|
}
|
|
11202
|
-
if (
|
|
13289
|
+
if (meta2 !== void 0 && (!meta2 || typeof meta2 !== "object")) {
|
|
11203
13290
|
throw new TypeError("The second argument passed to onPacket must be an object or undefined.");
|
|
11204
13291
|
}
|
|
11205
|
-
this.encodingConfig.onEncodedPacket?.(packet,
|
|
11206
|
-
void this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet,
|
|
13292
|
+
this.encodingConfig.onEncodedPacket?.(packet, meta2);
|
|
13293
|
+
void this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta2);
|
|
11207
13294
|
};
|
|
11208
13295
|
await this.customEncoder.init();
|
|
11209
13296
|
} else {
|
|
@@ -11217,10 +13304,10 @@ ${cue.notes ?? ""}`;
|
|
|
11217
13304
|
);
|
|
11218
13305
|
}
|
|
11219
13306
|
this.encoder = new VideoEncoder({
|
|
11220
|
-
output: (chunk,
|
|
13307
|
+
output: (chunk, meta2) => {
|
|
11221
13308
|
const packet = EncodedPacket.fromEncodedChunk(chunk);
|
|
11222
|
-
this.encodingConfig.onEncodedPacket?.(packet,
|
|
11223
|
-
void this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet,
|
|
13309
|
+
this.encodingConfig.onEncodedPacket?.(packet, meta2);
|
|
13310
|
+
void this.muxer.addEncodedVideoPacket(this.source._connectedTrack, packet, meta2);
|
|
11224
13311
|
},
|
|
11225
13312
|
error: (error) => {
|
|
11226
13313
|
error.stack = encoderError.stack;
|
|
@@ -11491,18 +13578,18 @@ ${cue.notes ?? ""}`;
|
|
|
11491
13578
|
* @returns A Promise that resolves once the output is ready to receive more samples. You should await this Promise
|
|
11492
13579
|
* to respect writer and encoder backpressure.
|
|
11493
13580
|
*/
|
|
11494
|
-
add(packet,
|
|
13581
|
+
add(packet, meta2) {
|
|
11495
13582
|
if (!(packet instanceof EncodedPacket)) {
|
|
11496
13583
|
throw new TypeError("packet must be an EncodedPacket.");
|
|
11497
13584
|
}
|
|
11498
13585
|
if (packet.isMetadataOnly) {
|
|
11499
13586
|
throw new TypeError("Metadata-only packets cannot be added.");
|
|
11500
13587
|
}
|
|
11501
|
-
if (
|
|
13588
|
+
if (meta2 !== void 0 && (!meta2 || typeof meta2 !== "object")) {
|
|
11502
13589
|
throw new TypeError("meta, when provided, must be an object.");
|
|
11503
13590
|
}
|
|
11504
13591
|
this._ensureValidAdd();
|
|
11505
|
-
return this._connectedTrack.output._muxer.addEncodedAudioPacket(this._connectedTrack, packet,
|
|
13592
|
+
return this._connectedTrack.output._muxer.addEncodedAudioPacket(this._connectedTrack, packet, meta2);
|
|
11506
13593
|
}
|
|
11507
13594
|
};
|
|
11508
13595
|
var AudioEncoderWrapper = class {
|
|
@@ -11613,7 +13700,7 @@ ${cue.notes ?? ""}`;
|
|
|
11613
13700
|
if (shouldClose) {
|
|
11614
13701
|
audioSample.close();
|
|
11615
13702
|
}
|
|
11616
|
-
const
|
|
13703
|
+
const meta2 = {
|
|
11617
13704
|
decoderConfig: {
|
|
11618
13705
|
codec: this.encodingConfig.codec,
|
|
11619
13706
|
numberOfChannels,
|
|
@@ -11630,8 +13717,8 @@ ${cue.notes ?? ""}`;
|
|
|
11630
13717
|
timestamp + startFrame / sampleRate,
|
|
11631
13718
|
frameCount / sampleRate
|
|
11632
13719
|
);
|
|
11633
|
-
this.encodingConfig.onEncodedPacket?.(packet,
|
|
11634
|
-
await this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet,
|
|
13720
|
+
this.encodingConfig.onEncodedPacket?.(packet, meta2);
|
|
13721
|
+
await this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta2);
|
|
11635
13722
|
}
|
|
11636
13723
|
}
|
|
11637
13724
|
ensureEncoder(audioSample) {
|
|
@@ -11655,15 +13742,15 @@ ${cue.notes ?? ""}`;
|
|
|
11655
13742
|
this.customEncoder = new MatchingCustomEncoder();
|
|
11656
13743
|
this.customEncoder.codec = this.encodingConfig.codec;
|
|
11657
13744
|
this.customEncoder.config = encoderConfig;
|
|
11658
|
-
this.customEncoder.onPacket = (packet,
|
|
13745
|
+
this.customEncoder.onPacket = (packet, meta2) => {
|
|
11659
13746
|
if (!(packet instanceof EncodedPacket)) {
|
|
11660
13747
|
throw new TypeError("The first argument passed to onPacket must be an EncodedPacket.");
|
|
11661
13748
|
}
|
|
11662
|
-
if (
|
|
13749
|
+
if (meta2 !== void 0 && (!meta2 || typeof meta2 !== "object")) {
|
|
11663
13750
|
throw new TypeError("The second argument passed to onPacket must be an object or undefined.");
|
|
11664
13751
|
}
|
|
11665
|
-
this.encodingConfig.onEncodedPacket?.(packet,
|
|
11666
|
-
void this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet,
|
|
13752
|
+
this.encodingConfig.onEncodedPacket?.(packet, meta2);
|
|
13753
|
+
void this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta2);
|
|
11667
13754
|
};
|
|
11668
13755
|
await this.customEncoder.init();
|
|
11669
13756
|
} else if (PCM_AUDIO_CODECS.includes(this.encodingConfig.codec)) {
|
|
@@ -11679,10 +13766,10 @@ ${cue.notes ?? ""}`;
|
|
|
11679
13766
|
);
|
|
11680
13767
|
}
|
|
11681
13768
|
this.encoder = new AudioEncoder({
|
|
11682
|
-
output: (chunk,
|
|
13769
|
+
output: (chunk, meta2) => {
|
|
11683
13770
|
const packet = EncodedPacket.fromEncodedChunk(chunk);
|
|
11684
|
-
this.encodingConfig.onEncodedPacket?.(packet,
|
|
11685
|
-
void this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet,
|
|
13771
|
+
this.encodingConfig.onEncodedPacket?.(packet, meta2);
|
|
13772
|
+
void this.muxer.addEncodedAudioPacket(this.source._connectedTrack, packet, meta2);
|
|
11686
13773
|
},
|
|
11687
13774
|
error: (error) => {
|
|
11688
13775
|
error.stack = encoderError.stack;
|
|
@@ -12182,6 +14269,8 @@ ${cue.notes ?? ""}`;
|
|
|
12182
14269
|
this._finalizePromise = null;
|
|
12183
14270
|
/** @internal */
|
|
12184
14271
|
this._mutex = new AsyncMutex();
|
|
14272
|
+
/** @internal */
|
|
14273
|
+
this._metadataTags = {};
|
|
12185
14274
|
if (!options || typeof options !== "object") {
|
|
12186
14275
|
throw new TypeError("options must be an object.");
|
|
12187
14276
|
}
|
|
@@ -12235,6 +14324,19 @@ ${cue.notes ?? ""}`;
|
|
|
12235
14324
|
validateBaseTrackMetadata(metadata);
|
|
12236
14325
|
this._addTrack("subtitle", source, metadata);
|
|
12237
14326
|
}
|
|
14327
|
+
/**
|
|
14328
|
+
* Sets descriptive metadata tags about the media file, such as title, author, date, or cover art. When called
|
|
14329
|
+
* multiple times, only the metadata from the last call will be used.
|
|
14330
|
+
*
|
|
14331
|
+
* Must be called before output is started.
|
|
14332
|
+
*/
|
|
14333
|
+
setMetadataTags(tags) {
|
|
14334
|
+
validateMetadataTags(tags);
|
|
14335
|
+
if (this.state !== "pending") {
|
|
14336
|
+
throw new Error("Cannot set metadata tags after output has been started or canceled.");
|
|
14337
|
+
}
|
|
14338
|
+
this._metadataTags = tags;
|
|
14339
|
+
}
|
|
12238
14340
|
/** @internal */
|
|
12239
14341
|
_addTrack(type, source, metadata) {
|
|
12240
14342
|
if (this.state !== "pending") {
|
|
@@ -12466,6 +14568,10 @@ ${cue.notes ?? ""}`;
|
|
|
12466
14568
|
offset: 0
|
|
12467
14569
|
};
|
|
12468
14570
|
}
|
|
14571
|
+
/** @internal */
|
|
14572
|
+
get _supportsRandomAccess() {
|
|
14573
|
+
return true;
|
|
14574
|
+
}
|
|
12469
14575
|
};
|
|
12470
14576
|
var BlobSource = class extends Source {
|
|
12471
14577
|
/**
|
|
@@ -12524,6 +14630,10 @@ ${cue.notes ?? ""}`;
|
|
|
12524
14630
|
}
|
|
12525
14631
|
worker.running = false;
|
|
12526
14632
|
}
|
|
14633
|
+
/** @internal */
|
|
14634
|
+
get _supportsRandomAccess() {
|
|
14635
|
+
return true;
|
|
14636
|
+
}
|
|
12527
14637
|
};
|
|
12528
14638
|
var URL_SOURCE_MIN_LOAD_AMOUNT = 0.5 * 2 ** 20;
|
|
12529
14639
|
var UrlSource = class extends Source {
|
|
@@ -12701,6 +14811,10 @@ ${cue.notes ?? ""}`;
|
|
|
12701
14811
|
}
|
|
12702
14812
|
}
|
|
12703
14813
|
}
|
|
14814
|
+
/** @internal */
|
|
14815
|
+
get _supportsRandomAccess() {
|
|
14816
|
+
return true;
|
|
14817
|
+
}
|
|
12704
14818
|
};
|
|
12705
14819
|
var FilePathSource = class extends Source {
|
|
12706
14820
|
/** Creates a new {@link FilePathSource} backed by the file at the specified file path. */
|
|
@@ -12745,6 +14859,10 @@ ${cue.notes ?? ""}`;
|
|
|
12745
14859
|
_retrieveSize() {
|
|
12746
14860
|
return this._streamSource._retrieveSize();
|
|
12747
14861
|
}
|
|
14862
|
+
/** @internal */
|
|
14863
|
+
get _supportsRandomAccess() {
|
|
14864
|
+
return true;
|
|
14865
|
+
}
|
|
12748
14866
|
};
|
|
12749
14867
|
var StreamSource = class extends Source {
|
|
12750
14868
|
/** Creates a new {@link StreamSource} whose behavior is specified by `options`. */
|
|
@@ -12841,6 +14959,10 @@ ${cue.notes ?? ""}`;
|
|
|
12841
14959
|
}
|
|
12842
14960
|
worker.running = false;
|
|
12843
14961
|
}
|
|
14962
|
+
/** @internal */
|
|
14963
|
+
get _supportsRandomAccess() {
|
|
14964
|
+
return true;
|
|
14965
|
+
}
|
|
12844
14966
|
};
|
|
12845
14967
|
var ReadableStreamSource = class extends Source {
|
|
12846
14968
|
/** Creates a new {@link ReadableStreamSource} backed by the specified `ReadableStream<Uint8Array>`. */
|
|
@@ -13009,6 +15131,10 @@ ${cue.notes ?? ""}`;
|
|
|
13009
15131
|
}
|
|
13010
15132
|
this._pulling = false;
|
|
13011
15133
|
}
|
|
15134
|
+
/** @internal */
|
|
15135
|
+
get _supportsRandomAccess() {
|
|
15136
|
+
return false;
|
|
15137
|
+
}
|
|
13012
15138
|
};
|
|
13013
15139
|
var PREFETCH_PROFILES = {
|
|
13014
15140
|
none: (start, end) => ({ start, end }),
|
|
@@ -13360,6 +15486,129 @@ ${cue.notes ?? ""}`;
|
|
|
13360
15486
|
};
|
|
13361
15487
|
|
|
13362
15488
|
// src/isobmff/isobmff-demuxer.ts
|
|
15489
|
+
var UDTA_STRING_KEYS = /* @__PURE__ */ new Set([
|
|
15490
|
+
"@day",
|
|
15491
|
+
"@mak",
|
|
15492
|
+
"@mod",
|
|
15493
|
+
"@swr",
|
|
15494
|
+
"@xyz",
|
|
15495
|
+
"CAME",
|
|
15496
|
+
"CNCV",
|
|
15497
|
+
"CNFV",
|
|
15498
|
+
"CNMN",
|
|
15499
|
+
"FIRM",
|
|
15500
|
+
"FOV\0",
|
|
15501
|
+
"GoPr",
|
|
15502
|
+
"LENS",
|
|
15503
|
+
"PXMN",
|
|
15504
|
+
"SIGM",
|
|
15505
|
+
"SNum",
|
|
15506
|
+
"TAGS",
|
|
15507
|
+
"albm",
|
|
15508
|
+
"albr",
|
|
15509
|
+
"angl",
|
|
15510
|
+
"auth",
|
|
15511
|
+
"ccid",
|
|
15512
|
+
"cdis",
|
|
15513
|
+
"clfn",
|
|
15514
|
+
"clid",
|
|
15515
|
+
"clsf",
|
|
15516
|
+
"cmid",
|
|
15517
|
+
"cmnm",
|
|
15518
|
+
"coll",
|
|
15519
|
+
"cprt",
|
|
15520
|
+
"cver",
|
|
15521
|
+
"cvru",
|
|
15522
|
+
"date",
|
|
15523
|
+
"dscp",
|
|
15524
|
+
"fsid",
|
|
15525
|
+
"gnre",
|
|
15526
|
+
"hinv",
|
|
15527
|
+
"icnu",
|
|
15528
|
+
"info",
|
|
15529
|
+
"infu",
|
|
15530
|
+
"kgtt",
|
|
15531
|
+
"loci",
|
|
15532
|
+
"lrcu",
|
|
15533
|
+
"mcvr",
|
|
15534
|
+
"name",
|
|
15535
|
+
"perf",
|
|
15536
|
+
"pmcc",
|
|
15537
|
+
"reel",
|
|
15538
|
+
"rtng",
|
|
15539
|
+
"scen",
|
|
15540
|
+
"shot",
|
|
15541
|
+
"slno",
|
|
15542
|
+
"thmb",
|
|
15543
|
+
"titl",
|
|
15544
|
+
"tnam",
|
|
15545
|
+
"urat",
|
|
15546
|
+
"uuid",
|
|
15547
|
+
"vndr",
|
|
15548
|
+
"yrrc",
|
|
15549
|
+
"\xA9ART",
|
|
15550
|
+
"\xA9TIM",
|
|
15551
|
+
"\xA9TSC",
|
|
15552
|
+
"\xA9TSZ",
|
|
15553
|
+
"\xA9alb",
|
|
15554
|
+
"\xA9arg",
|
|
15555
|
+
"\xA9ark",
|
|
15556
|
+
"\xA9cmt",
|
|
15557
|
+
"\xA9cok",
|
|
15558
|
+
"\xA9com",
|
|
15559
|
+
"\xA9cpy",
|
|
15560
|
+
"\xA9day",
|
|
15561
|
+
"\xA9dir",
|
|
15562
|
+
"\xA9ed1",
|
|
15563
|
+
"\xA9ed2",
|
|
15564
|
+
"\xA9ed3",
|
|
15565
|
+
"\xA9ed4",
|
|
15566
|
+
"\xA9ed5",
|
|
15567
|
+
"\xA9ed6",
|
|
15568
|
+
"\xA9ed7",
|
|
15569
|
+
"\xA9ed8",
|
|
15570
|
+
"\xA9ed9",
|
|
15571
|
+
"\xA9enc",
|
|
15572
|
+
"\xA9fmt",
|
|
15573
|
+
"\xA9fpt",
|
|
15574
|
+
"\xA9frl",
|
|
15575
|
+
"\xA9fyw",
|
|
15576
|
+
"\xA9gen",
|
|
15577
|
+
"\xA9gpt",
|
|
15578
|
+
"\xA9grl",
|
|
15579
|
+
"\xA9grp",
|
|
15580
|
+
"\xA9gyw",
|
|
15581
|
+
"\xA9inf",
|
|
15582
|
+
"\xA9isr",
|
|
15583
|
+
"\xA9lab",
|
|
15584
|
+
"\xA9lal",
|
|
15585
|
+
"\xA9lyr",
|
|
15586
|
+
"\xA9mak",
|
|
15587
|
+
"\xA9mal",
|
|
15588
|
+
"\xA9mdl",
|
|
15589
|
+
"\xA9mod",
|
|
15590
|
+
"\xA9nam",
|
|
15591
|
+
"\xA9pdk",
|
|
15592
|
+
"\xA9phg",
|
|
15593
|
+
"\xA9prd",
|
|
15594
|
+
"\xA9prf",
|
|
15595
|
+
"\xA9prk",
|
|
15596
|
+
"\xA9prl",
|
|
15597
|
+
"\xA9req",
|
|
15598
|
+
"\xA9snk",
|
|
15599
|
+
"\xA9snm",
|
|
15600
|
+
"\xA9src",
|
|
15601
|
+
"\xA9swf",
|
|
15602
|
+
"\xA9swk",
|
|
15603
|
+
"\xA9swr",
|
|
15604
|
+
"\xA9too",
|
|
15605
|
+
"\xA9trk",
|
|
15606
|
+
"\xA9wrt",
|
|
15607
|
+
"\xA9xsp",
|
|
15608
|
+
"\xA9xyz",
|
|
15609
|
+
"\xA9ysp",
|
|
15610
|
+
"\xA9zsp"
|
|
15611
|
+
]);
|
|
13363
15612
|
var IsobmffDemuxer = class extends Demuxer {
|
|
13364
15613
|
constructor(input) {
|
|
13365
15614
|
super(input);
|
|
@@ -13370,6 +15619,8 @@ ${cue.notes ?? ""}`;
|
|
|
13370
15619
|
this.movieTimescale = -1;
|
|
13371
15620
|
this.movieDurationInTimescale = -1;
|
|
13372
15621
|
this.isQuickTime = false;
|
|
15622
|
+
this.metadataTags = {};
|
|
15623
|
+
this.currentMetadataKeys = null;
|
|
13373
15624
|
this.isFragmented = false;
|
|
13374
15625
|
this.fragmentTrackDefaults = [];
|
|
13375
15626
|
this.fragments = [];
|
|
@@ -13396,6 +15647,10 @@ ${cue.notes ?? ""}`;
|
|
|
13396
15647
|
codecStrings: codecStrings.filter(Boolean)
|
|
13397
15648
|
});
|
|
13398
15649
|
}
|
|
15650
|
+
async getMetadataTags() {
|
|
15651
|
+
await this.readMetadata();
|
|
15652
|
+
return this.metadataTags;
|
|
15653
|
+
}
|
|
13399
15654
|
readMetadata() {
|
|
13400
15655
|
return this.metadataPromise ??= (async () => {
|
|
13401
15656
|
let currentPos = 0;
|
|
@@ -13634,6 +15889,19 @@ ${cue.notes ?? ""}`;
|
|
|
13634
15889
|
}
|
|
13635
15890
|
}
|
|
13636
15891
|
}
|
|
15892
|
+
// eslint-disable-next-line @stylistic/generator-star-spacing
|
|
15893
|
+
*iterateContiguousBoxes(slice) {
|
|
15894
|
+
const startIndex = slice.filePos;
|
|
15895
|
+
while (slice.filePos - startIndex <= slice.length - MIN_BOX_HEADER_SIZE) {
|
|
15896
|
+
const startPos = slice.filePos;
|
|
15897
|
+
const boxInfo = readBoxHeader(slice);
|
|
15898
|
+
if (!boxInfo) {
|
|
15899
|
+
break;
|
|
15900
|
+
}
|
|
15901
|
+
yield { boxInfo, slice };
|
|
15902
|
+
slice.filePos = startPos + boxInfo.totalSize;
|
|
15903
|
+
}
|
|
15904
|
+
}
|
|
13637
15905
|
traverseBox(slice) {
|
|
13638
15906
|
const startPos = slice.filePos;
|
|
13639
15907
|
const boxInfo = readBoxHeader(slice);
|
|
@@ -13648,7 +15916,6 @@ ${cue.notes ?? ""}`;
|
|
|
13648
15916
|
case "dinf":
|
|
13649
15917
|
case "mfra":
|
|
13650
15918
|
case "edts":
|
|
13651
|
-
case "udta":
|
|
13652
15919
|
{
|
|
13653
15920
|
this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize));
|
|
13654
15921
|
}
|
|
@@ -13713,7 +15980,9 @@ ${cue.notes ?? ""}`;
|
|
|
13713
15980
|
case "tkhd":
|
|
13714
15981
|
{
|
|
13715
15982
|
const track = this.currentTrack;
|
|
13716
|
-
|
|
15983
|
+
if (!track) {
|
|
15984
|
+
break;
|
|
15985
|
+
}
|
|
13717
15986
|
const version = readU8(slice);
|
|
13718
15987
|
const flags = readU24Be(slice);
|
|
13719
15988
|
const trackEnabled = (flags & 1) !== 0;
|
|
@@ -13754,7 +16023,9 @@ ${cue.notes ?? ""}`;
|
|
|
13754
16023
|
case "elst":
|
|
13755
16024
|
{
|
|
13756
16025
|
const track = this.currentTrack;
|
|
13757
|
-
|
|
16026
|
+
if (!track) {
|
|
16027
|
+
break;
|
|
16028
|
+
}
|
|
13758
16029
|
const version = readU8(slice);
|
|
13759
16030
|
slice.skip(3);
|
|
13760
16031
|
let relevantEntryFound = false;
|
|
@@ -13791,7 +16062,9 @@ ${cue.notes ?? ""}`;
|
|
|
13791
16062
|
case "mdhd":
|
|
13792
16063
|
{
|
|
13793
16064
|
const track = this.currentTrack;
|
|
13794
|
-
|
|
16065
|
+
if (!track) {
|
|
16066
|
+
break;
|
|
16067
|
+
}
|
|
13795
16068
|
const version = readU8(slice);
|
|
13796
16069
|
slice.skip(3);
|
|
13797
16070
|
if (version === 0) {
|
|
@@ -13820,7 +16093,9 @@ ${cue.notes ?? ""}`;
|
|
|
13820
16093
|
case "hdlr":
|
|
13821
16094
|
{
|
|
13822
16095
|
const track = this.currentTrack;
|
|
13823
|
-
|
|
16096
|
+
if (!track) {
|
|
16097
|
+
break;
|
|
16098
|
+
}
|
|
13824
16099
|
slice.skip(8);
|
|
13825
16100
|
const handlerType = readAscii(slice, 4);
|
|
13826
16101
|
if (handlerType === "vide") {
|
|
@@ -13852,7 +16127,9 @@ ${cue.notes ?? ""}`;
|
|
|
13852
16127
|
case "stbl":
|
|
13853
16128
|
{
|
|
13854
16129
|
const track = this.currentTrack;
|
|
13855
|
-
|
|
16130
|
+
if (!track) {
|
|
16131
|
+
break;
|
|
16132
|
+
}
|
|
13856
16133
|
track.sampleTableByteOffset = startPos;
|
|
13857
16134
|
this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize));
|
|
13858
16135
|
}
|
|
@@ -13861,7 +16138,9 @@ ${cue.notes ?? ""}`;
|
|
|
13861
16138
|
case "stsd":
|
|
13862
16139
|
{
|
|
13863
16140
|
const track = this.currentTrack;
|
|
13864
|
-
|
|
16141
|
+
if (!track) {
|
|
16142
|
+
break;
|
|
16143
|
+
}
|
|
13865
16144
|
if (track.info === null || track.sampleTable) {
|
|
13866
16145
|
break;
|
|
13867
16146
|
}
|
|
@@ -14017,7 +16296,10 @@ ${cue.notes ?? ""}`;
|
|
|
14017
16296
|
case "avcC":
|
|
14018
16297
|
{
|
|
14019
16298
|
const track = this.currentTrack;
|
|
14020
|
-
|
|
16299
|
+
if (!track) {
|
|
16300
|
+
break;
|
|
16301
|
+
}
|
|
16302
|
+
assert(track.info);
|
|
14021
16303
|
track.info.codecDescription = readBytes(slice, boxInfo.contentSize);
|
|
14022
16304
|
}
|
|
14023
16305
|
;
|
|
@@ -14025,7 +16307,10 @@ ${cue.notes ?? ""}`;
|
|
|
14025
16307
|
case "hvcC":
|
|
14026
16308
|
{
|
|
14027
16309
|
const track = this.currentTrack;
|
|
14028
|
-
|
|
16310
|
+
if (!track) {
|
|
16311
|
+
break;
|
|
16312
|
+
}
|
|
16313
|
+
assert(track.info);
|
|
14029
16314
|
track.info.codecDescription = readBytes(slice, boxInfo.contentSize);
|
|
14030
16315
|
}
|
|
14031
16316
|
;
|
|
@@ -14033,7 +16318,10 @@ ${cue.notes ?? ""}`;
|
|
|
14033
16318
|
case "vpcC":
|
|
14034
16319
|
{
|
|
14035
16320
|
const track = this.currentTrack;
|
|
14036
|
-
|
|
16321
|
+
if (!track) {
|
|
16322
|
+
break;
|
|
16323
|
+
}
|
|
16324
|
+
assert(track.info?.type === "video");
|
|
14037
16325
|
slice.skip(4);
|
|
14038
16326
|
const profile = readU8(slice);
|
|
14039
16327
|
const level = readU8(slice);
|
|
@@ -14060,7 +16348,10 @@ ${cue.notes ?? ""}`;
|
|
|
14060
16348
|
case "av1C":
|
|
14061
16349
|
{
|
|
14062
16350
|
const track = this.currentTrack;
|
|
14063
|
-
|
|
16351
|
+
if (!track) {
|
|
16352
|
+
break;
|
|
16353
|
+
}
|
|
16354
|
+
assert(track.info?.type === "video");
|
|
14064
16355
|
slice.skip(1);
|
|
14065
16356
|
const secondByte = readU8(slice);
|
|
14066
16357
|
const profile = secondByte >> 5;
|
|
@@ -14090,7 +16381,10 @@ ${cue.notes ?? ""}`;
|
|
|
14090
16381
|
case "colr":
|
|
14091
16382
|
{
|
|
14092
16383
|
const track = this.currentTrack;
|
|
14093
|
-
|
|
16384
|
+
if (!track) {
|
|
16385
|
+
break;
|
|
16386
|
+
}
|
|
16387
|
+
assert(track.info?.type === "video");
|
|
14094
16388
|
const colourType = readAscii(slice, 4);
|
|
14095
16389
|
if (colourType !== "nclx") {
|
|
14096
16390
|
break;
|
|
@@ -14117,7 +16411,10 @@ ${cue.notes ?? ""}`;
|
|
|
14117
16411
|
case "esds":
|
|
14118
16412
|
{
|
|
14119
16413
|
const track = this.currentTrack;
|
|
14120
|
-
|
|
16414
|
+
if (!track) {
|
|
16415
|
+
break;
|
|
16416
|
+
}
|
|
16417
|
+
assert(track.info?.type === "audio");
|
|
14121
16418
|
slice.skip(4);
|
|
14122
16419
|
const tag = readU8(slice);
|
|
14123
16420
|
assert(tag === 3);
|
|
@@ -14176,7 +16473,10 @@ ${cue.notes ?? ""}`;
|
|
|
14176
16473
|
case "enda":
|
|
14177
16474
|
{
|
|
14178
16475
|
const track = this.currentTrack;
|
|
14179
|
-
|
|
16476
|
+
if (!track) {
|
|
16477
|
+
break;
|
|
16478
|
+
}
|
|
16479
|
+
assert(track.info?.type === "audio");
|
|
14180
16480
|
const littleEndian = readU16Be(slice) & 255;
|
|
14181
16481
|
if (littleEndian) {
|
|
14182
16482
|
if (track.info.codec === "pcm-s16be") {
|
|
@@ -14197,7 +16497,10 @@ ${cue.notes ?? ""}`;
|
|
|
14197
16497
|
case "pcmC":
|
|
14198
16498
|
{
|
|
14199
16499
|
const track = this.currentTrack;
|
|
14200
|
-
|
|
16500
|
+
if (!track) {
|
|
16501
|
+
break;
|
|
16502
|
+
}
|
|
16503
|
+
assert(track.info?.type === "audio");
|
|
14201
16504
|
slice.skip(1 + 3);
|
|
14202
16505
|
const formatFlags = readU8(slice);
|
|
14203
16506
|
const isLittleEndian = Boolean(formatFlags & 1);
|
|
@@ -14253,7 +16556,10 @@ ${cue.notes ?? ""}`;
|
|
|
14253
16556
|
case "dOps":
|
|
14254
16557
|
{
|
|
14255
16558
|
const track = this.currentTrack;
|
|
14256
|
-
|
|
16559
|
+
if (!track) {
|
|
16560
|
+
break;
|
|
16561
|
+
}
|
|
16562
|
+
assert(track.info?.type === "audio");
|
|
14257
16563
|
slice.skip(1);
|
|
14258
16564
|
const outputChannelCount = readU8(slice);
|
|
14259
16565
|
const preSkip = readU16Be(slice);
|
|
@@ -14286,7 +16592,10 @@ ${cue.notes ?? ""}`;
|
|
|
14286
16592
|
case "dfLa":
|
|
14287
16593
|
{
|
|
14288
16594
|
const track = this.currentTrack;
|
|
14289
|
-
|
|
16595
|
+
if (!track) {
|
|
16596
|
+
break;
|
|
16597
|
+
}
|
|
16598
|
+
assert(track.info?.type === "audio");
|
|
14290
16599
|
slice.skip(4);
|
|
14291
16600
|
const BLOCK_TYPE_MASK = 127;
|
|
14292
16601
|
const LAST_METADATA_BLOCK_FLAG_MASK = 128;
|
|
@@ -14324,7 +16633,9 @@ ${cue.notes ?? ""}`;
|
|
|
14324
16633
|
case "stts":
|
|
14325
16634
|
{
|
|
14326
16635
|
const track = this.currentTrack;
|
|
14327
|
-
|
|
16636
|
+
if (!track) {
|
|
16637
|
+
break;
|
|
16638
|
+
}
|
|
14328
16639
|
if (!track.sampleTable) {
|
|
14329
16640
|
break;
|
|
14330
16641
|
}
|
|
@@ -14350,7 +16661,9 @@ ${cue.notes ?? ""}`;
|
|
|
14350
16661
|
case "ctts":
|
|
14351
16662
|
{
|
|
14352
16663
|
const track = this.currentTrack;
|
|
14353
|
-
|
|
16664
|
+
if (!track) {
|
|
16665
|
+
break;
|
|
16666
|
+
}
|
|
14354
16667
|
if (!track.sampleTable) {
|
|
14355
16668
|
break;
|
|
14356
16669
|
}
|
|
@@ -14373,7 +16686,9 @@ ${cue.notes ?? ""}`;
|
|
|
14373
16686
|
case "stsz":
|
|
14374
16687
|
{
|
|
14375
16688
|
const track = this.currentTrack;
|
|
14376
|
-
|
|
16689
|
+
if (!track) {
|
|
16690
|
+
break;
|
|
16691
|
+
}
|
|
14377
16692
|
if (!track.sampleTable) {
|
|
14378
16693
|
break;
|
|
14379
16694
|
}
|
|
@@ -14394,7 +16709,9 @@ ${cue.notes ?? ""}`;
|
|
|
14394
16709
|
case "stz2":
|
|
14395
16710
|
{
|
|
14396
16711
|
const track = this.currentTrack;
|
|
14397
|
-
|
|
16712
|
+
if (!track) {
|
|
16713
|
+
break;
|
|
16714
|
+
}
|
|
14398
16715
|
if (!track.sampleTable) {
|
|
14399
16716
|
break;
|
|
14400
16717
|
}
|
|
@@ -14414,7 +16731,9 @@ ${cue.notes ?? ""}`;
|
|
|
14414
16731
|
case "stss":
|
|
14415
16732
|
{
|
|
14416
16733
|
const track = this.currentTrack;
|
|
14417
|
-
|
|
16734
|
+
if (!track) {
|
|
16735
|
+
break;
|
|
16736
|
+
}
|
|
14418
16737
|
if (!track.sampleTable) {
|
|
14419
16738
|
break;
|
|
14420
16739
|
}
|
|
@@ -14434,7 +16753,9 @@ ${cue.notes ?? ""}`;
|
|
|
14434
16753
|
case "stsc":
|
|
14435
16754
|
{
|
|
14436
16755
|
const track = this.currentTrack;
|
|
14437
|
-
|
|
16756
|
+
if (!track) {
|
|
16757
|
+
break;
|
|
16758
|
+
}
|
|
14438
16759
|
if (!track.sampleTable) {
|
|
14439
16760
|
break;
|
|
14440
16761
|
}
|
|
@@ -14466,7 +16787,9 @@ ${cue.notes ?? ""}`;
|
|
|
14466
16787
|
case "stco":
|
|
14467
16788
|
{
|
|
14468
16789
|
const track = this.currentTrack;
|
|
14469
|
-
|
|
16790
|
+
if (!track) {
|
|
16791
|
+
break;
|
|
16792
|
+
}
|
|
14470
16793
|
if (!track.sampleTable) {
|
|
14471
16794
|
break;
|
|
14472
16795
|
}
|
|
@@ -14482,7 +16805,9 @@ ${cue.notes ?? ""}`;
|
|
|
14482
16805
|
case "co64":
|
|
14483
16806
|
{
|
|
14484
16807
|
const track = this.currentTrack;
|
|
14485
|
-
|
|
16808
|
+
if (!track) {
|
|
16809
|
+
break;
|
|
16810
|
+
}
|
|
14486
16811
|
if (!track.sampleTable) {
|
|
14487
16812
|
break;
|
|
14488
16813
|
}
|
|
@@ -14793,14 +17118,316 @@ ${cue.notes ?? ""}`;
|
|
|
14793
17118
|
}
|
|
14794
17119
|
;
|
|
14795
17120
|
break;
|
|
14796
|
-
//
|
|
14797
|
-
|
|
14798
|
-
|
|
17121
|
+
// Metadata section
|
|
17122
|
+
// https://exiftool.org/TagNames/QuickTime.html
|
|
17123
|
+
// https://mp4workshop.com/about
|
|
17124
|
+
case "udta":
|
|
17125
|
+
{
|
|
17126
|
+
const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize));
|
|
17127
|
+
for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) {
|
|
17128
|
+
if (boxInfo2.name !== "meta" && !this.currentTrack) {
|
|
17129
|
+
const startPos2 = slice2.filePos;
|
|
17130
|
+
this.metadataTags.raw ??= {};
|
|
17131
|
+
if (UDTA_STRING_KEYS.has(boxInfo2.name)) {
|
|
17132
|
+
this.metadataTags.raw[boxInfo2.name] ??= readMetadataStringShort(slice2);
|
|
17133
|
+
} else {
|
|
17134
|
+
this.metadataTags.raw[boxInfo2.name] ??= readBytes(slice2, boxInfo2.contentSize);
|
|
17135
|
+
}
|
|
17136
|
+
slice2.filePos = startPos2;
|
|
17137
|
+
}
|
|
17138
|
+
switch (boxInfo2.name) {
|
|
17139
|
+
case "meta":
|
|
17140
|
+
{
|
|
17141
|
+
slice2.skip(-boxInfo2.headerSize);
|
|
17142
|
+
this.traverseBox(slice2);
|
|
17143
|
+
}
|
|
17144
|
+
;
|
|
17145
|
+
break;
|
|
17146
|
+
case "\xA9nam":
|
|
17147
|
+
case "name":
|
|
17148
|
+
{
|
|
17149
|
+
if (this.currentTrack) {
|
|
17150
|
+
this.currentTrack.name = textDecoder.decode(readBytes(slice2, boxInfo2.contentSize));
|
|
17151
|
+
} else {
|
|
17152
|
+
this.metadataTags.title ??= readMetadataStringShort(slice2);
|
|
17153
|
+
}
|
|
17154
|
+
}
|
|
17155
|
+
;
|
|
17156
|
+
break;
|
|
17157
|
+
case "\xA9des":
|
|
17158
|
+
{
|
|
17159
|
+
if (!this.currentTrack) {
|
|
17160
|
+
this.metadataTags.description ??= readMetadataStringShort(slice2);
|
|
17161
|
+
}
|
|
17162
|
+
}
|
|
17163
|
+
;
|
|
17164
|
+
break;
|
|
17165
|
+
case "\xA9ART":
|
|
17166
|
+
{
|
|
17167
|
+
if (!this.currentTrack) {
|
|
17168
|
+
this.metadataTags.artist ??= readMetadataStringShort(slice2);
|
|
17169
|
+
}
|
|
17170
|
+
}
|
|
17171
|
+
;
|
|
17172
|
+
break;
|
|
17173
|
+
case "\xA9alb":
|
|
17174
|
+
{
|
|
17175
|
+
if (!this.currentTrack) {
|
|
17176
|
+
this.metadataTags.album ??= readMetadataStringShort(slice2);
|
|
17177
|
+
}
|
|
17178
|
+
}
|
|
17179
|
+
;
|
|
17180
|
+
break;
|
|
17181
|
+
case "albr":
|
|
17182
|
+
{
|
|
17183
|
+
if (!this.currentTrack) {
|
|
17184
|
+
this.metadataTags.albumArtist ??= readMetadataStringShort(slice2);
|
|
17185
|
+
}
|
|
17186
|
+
}
|
|
17187
|
+
;
|
|
17188
|
+
break;
|
|
17189
|
+
case "\xA9gen":
|
|
17190
|
+
{
|
|
17191
|
+
if (!this.currentTrack) {
|
|
17192
|
+
this.metadataTags.genre ??= readMetadataStringShort(slice2);
|
|
17193
|
+
}
|
|
17194
|
+
}
|
|
17195
|
+
;
|
|
17196
|
+
break;
|
|
17197
|
+
case "\xA9day":
|
|
17198
|
+
{
|
|
17199
|
+
if (!this.currentTrack) {
|
|
17200
|
+
const date = new Date(readMetadataStringShort(slice2));
|
|
17201
|
+
if (!Number.isNaN(date.getTime())) {
|
|
17202
|
+
this.metadataTags.date ??= date;
|
|
17203
|
+
}
|
|
17204
|
+
}
|
|
17205
|
+
}
|
|
17206
|
+
;
|
|
17207
|
+
break;
|
|
17208
|
+
case "\xA9cmt":
|
|
17209
|
+
{
|
|
17210
|
+
if (!this.currentTrack) {
|
|
17211
|
+
this.metadataTags.comment ??= readMetadataStringShort(slice2);
|
|
17212
|
+
}
|
|
17213
|
+
}
|
|
17214
|
+
;
|
|
17215
|
+
break;
|
|
17216
|
+
case "\xA9lyr":
|
|
17217
|
+
{
|
|
17218
|
+
if (!this.currentTrack) {
|
|
17219
|
+
this.metadataTags.lyrics ??= readMetadataStringShort(slice2);
|
|
17220
|
+
}
|
|
17221
|
+
}
|
|
17222
|
+
;
|
|
17223
|
+
break;
|
|
17224
|
+
}
|
|
17225
|
+
}
|
|
17226
|
+
}
|
|
17227
|
+
;
|
|
17228
|
+
break;
|
|
17229
|
+
case "meta":
|
|
17230
|
+
{
|
|
17231
|
+
if (this.currentTrack) {
|
|
17232
|
+
break;
|
|
17233
|
+
}
|
|
17234
|
+
const word = readU32Be(slice);
|
|
17235
|
+
const isQuickTime = word !== 0;
|
|
17236
|
+
this.currentMetadataKeys = /* @__PURE__ */ new Map();
|
|
17237
|
+
if (isQuickTime) {
|
|
17238
|
+
this.readContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize));
|
|
17239
|
+
} else {
|
|
17240
|
+
this.readContiguousBoxes(slice.slice(contentStartPos + 4, boxInfo.contentSize - 4));
|
|
17241
|
+
}
|
|
17242
|
+
this.currentMetadataKeys = null;
|
|
17243
|
+
}
|
|
17244
|
+
;
|
|
17245
|
+
break;
|
|
17246
|
+
case "keys":
|
|
17247
|
+
{
|
|
17248
|
+
if (!this.currentMetadataKeys) {
|
|
17249
|
+
break;
|
|
17250
|
+
}
|
|
17251
|
+
slice.skip(4);
|
|
17252
|
+
const entryCount = readU32Be(slice);
|
|
17253
|
+
for (let i = 0; i < entryCount; i++) {
|
|
17254
|
+
const keySize = readU32Be(slice);
|
|
17255
|
+
slice.skip(4);
|
|
17256
|
+
const keyName = textDecoder.decode(readBytes(slice, keySize - 8));
|
|
17257
|
+
this.currentMetadataKeys.set(i + 1, keyName);
|
|
17258
|
+
}
|
|
17259
|
+
}
|
|
17260
|
+
;
|
|
17261
|
+
break;
|
|
17262
|
+
case "ilst":
|
|
14799
17263
|
{
|
|
14800
|
-
if (!this.
|
|
17264
|
+
if (!this.currentMetadataKeys) {
|
|
14801
17265
|
break;
|
|
14802
17266
|
}
|
|
14803
|
-
|
|
17267
|
+
const iterator = this.iterateContiguousBoxes(slice.slice(contentStartPos, boxInfo.contentSize));
|
|
17268
|
+
for (const { boxInfo: boxInfo2, slice: slice2 } of iterator) {
|
|
17269
|
+
let metadataKey = boxInfo2.name;
|
|
17270
|
+
const nameAsNumber = (metadataKey.charCodeAt(0) << 24) + (metadataKey.charCodeAt(1) << 16) + (metadataKey.charCodeAt(2) << 8) + metadataKey.charCodeAt(3);
|
|
17271
|
+
if (this.currentMetadataKeys.has(nameAsNumber)) {
|
|
17272
|
+
metadataKey = this.currentMetadataKeys.get(nameAsNumber);
|
|
17273
|
+
}
|
|
17274
|
+
const data = readDataBox(slice2);
|
|
17275
|
+
this.metadataTags.raw ??= {};
|
|
17276
|
+
this.metadataTags.raw[metadataKey] ??= data;
|
|
17277
|
+
switch (metadataKey) {
|
|
17278
|
+
case "\xA9nam":
|
|
17279
|
+
case "titl":
|
|
17280
|
+
case "com.apple.quicktime.title":
|
|
17281
|
+
case "title":
|
|
17282
|
+
{
|
|
17283
|
+
if (typeof data === "string") {
|
|
17284
|
+
this.metadataTags.title ??= data;
|
|
17285
|
+
}
|
|
17286
|
+
}
|
|
17287
|
+
;
|
|
17288
|
+
break;
|
|
17289
|
+
case "\xA9des":
|
|
17290
|
+
case "desc":
|
|
17291
|
+
case "dscp":
|
|
17292
|
+
case "com.apple.quicktime.description":
|
|
17293
|
+
case "description":
|
|
17294
|
+
{
|
|
17295
|
+
if (typeof data === "string") {
|
|
17296
|
+
this.metadataTags.description ??= data;
|
|
17297
|
+
}
|
|
17298
|
+
}
|
|
17299
|
+
;
|
|
17300
|
+
break;
|
|
17301
|
+
case "\xA9ART":
|
|
17302
|
+
case "com.apple.quicktime.artist":
|
|
17303
|
+
case "artist":
|
|
17304
|
+
{
|
|
17305
|
+
if (typeof data === "string") {
|
|
17306
|
+
this.metadataTags.artist ??= data;
|
|
17307
|
+
}
|
|
17308
|
+
}
|
|
17309
|
+
;
|
|
17310
|
+
break;
|
|
17311
|
+
case "\xA9alb":
|
|
17312
|
+
case "albm":
|
|
17313
|
+
case "com.apple.quicktime.album":
|
|
17314
|
+
case "album":
|
|
17315
|
+
{
|
|
17316
|
+
if (typeof data === "string") {
|
|
17317
|
+
this.metadataTags.album ??= data;
|
|
17318
|
+
}
|
|
17319
|
+
}
|
|
17320
|
+
;
|
|
17321
|
+
break;
|
|
17322
|
+
case "aART":
|
|
17323
|
+
case "album_artist":
|
|
17324
|
+
{
|
|
17325
|
+
if (typeof data === "string") {
|
|
17326
|
+
this.metadataTags.albumArtist ??= data;
|
|
17327
|
+
}
|
|
17328
|
+
}
|
|
17329
|
+
;
|
|
17330
|
+
break;
|
|
17331
|
+
case "\xA9cmt":
|
|
17332
|
+
case "com.apple.quicktime.comment":
|
|
17333
|
+
case "comment":
|
|
17334
|
+
{
|
|
17335
|
+
if (typeof data === "string") {
|
|
17336
|
+
this.metadataTags.comment ??= data;
|
|
17337
|
+
}
|
|
17338
|
+
}
|
|
17339
|
+
;
|
|
17340
|
+
break;
|
|
17341
|
+
case "\xA9gen":
|
|
17342
|
+
case "gnre":
|
|
17343
|
+
case "com.apple.quicktime.genre":
|
|
17344
|
+
case "genre":
|
|
17345
|
+
{
|
|
17346
|
+
if (typeof data === "string") {
|
|
17347
|
+
this.metadataTags.genre ??= data;
|
|
17348
|
+
}
|
|
17349
|
+
}
|
|
17350
|
+
;
|
|
17351
|
+
break;
|
|
17352
|
+
case "\xA9lyr":
|
|
17353
|
+
case "lyrics":
|
|
17354
|
+
{
|
|
17355
|
+
if (typeof data === "string") {
|
|
17356
|
+
this.metadataTags.lyrics ??= data;
|
|
17357
|
+
}
|
|
17358
|
+
}
|
|
17359
|
+
;
|
|
17360
|
+
break;
|
|
17361
|
+
case "\xA9day":
|
|
17362
|
+
case "rldt":
|
|
17363
|
+
case "com.apple.quicktime.creationdate":
|
|
17364
|
+
case "date":
|
|
17365
|
+
{
|
|
17366
|
+
if (typeof data === "string") {
|
|
17367
|
+
const date = new Date(data);
|
|
17368
|
+
if (!Number.isNaN(date.getTime())) {
|
|
17369
|
+
this.metadataTags.date ??= date;
|
|
17370
|
+
}
|
|
17371
|
+
}
|
|
17372
|
+
}
|
|
17373
|
+
;
|
|
17374
|
+
break;
|
|
17375
|
+
case "covr":
|
|
17376
|
+
case "com.apple.quicktime.artwork":
|
|
17377
|
+
{
|
|
17378
|
+
if (data instanceof RichImageData) {
|
|
17379
|
+
this.metadataTags.images ??= [];
|
|
17380
|
+
this.metadataTags.images.push({
|
|
17381
|
+
data: data.data,
|
|
17382
|
+
kind: "coverFront",
|
|
17383
|
+
mimeType: data.mimeType
|
|
17384
|
+
});
|
|
17385
|
+
} else if (data instanceof Uint8Array) {
|
|
17386
|
+
this.metadataTags.images ??= [];
|
|
17387
|
+
this.metadataTags.images.push({
|
|
17388
|
+
data,
|
|
17389
|
+
kind: "coverFront",
|
|
17390
|
+
mimeType: "image/*"
|
|
17391
|
+
});
|
|
17392
|
+
}
|
|
17393
|
+
}
|
|
17394
|
+
;
|
|
17395
|
+
break;
|
|
17396
|
+
case "trkn":
|
|
17397
|
+
{
|
|
17398
|
+
if (data instanceof Uint8Array) {
|
|
17399
|
+
const view2 = toDataView(data);
|
|
17400
|
+
const trackNumber = view2.getUint16(2, false);
|
|
17401
|
+
const tracksTotal = view2.getUint16(4, false);
|
|
17402
|
+
if (trackNumber > 0) {
|
|
17403
|
+
this.metadataTags.trackNumber ??= trackNumber;
|
|
17404
|
+
}
|
|
17405
|
+
if (tracksTotal > 0) {
|
|
17406
|
+
this.metadataTags.tracksTotal ??= tracksTotal;
|
|
17407
|
+
}
|
|
17408
|
+
}
|
|
17409
|
+
}
|
|
17410
|
+
;
|
|
17411
|
+
break;
|
|
17412
|
+
case "disc":
|
|
17413
|
+
case "disk":
|
|
17414
|
+
{
|
|
17415
|
+
if (data instanceof Uint8Array) {
|
|
17416
|
+
const view2 = toDataView(data);
|
|
17417
|
+
const discNumber = view2.getUint16(2, false);
|
|
17418
|
+
const discNumberMax = view2.getUint16(4, false);
|
|
17419
|
+
if (discNumber > 0) {
|
|
17420
|
+
this.metadataTags.discNumber ??= discNumber;
|
|
17421
|
+
}
|
|
17422
|
+
if (discNumberMax > 0) {
|
|
17423
|
+
this.metadataTags.discsTotal ??= discNumberMax;
|
|
17424
|
+
}
|
|
17425
|
+
}
|
|
17426
|
+
}
|
|
17427
|
+
;
|
|
17428
|
+
break;
|
|
17429
|
+
}
|
|
17430
|
+
}
|
|
14804
17431
|
}
|
|
14805
17432
|
;
|
|
14806
17433
|
break;
|
|
@@ -15459,6 +18086,9 @@ ${cue.notes ?? ""}`;
|
|
|
15459
18086
|
this.currentCluster = null;
|
|
15460
18087
|
this.currentBlock = null;
|
|
15461
18088
|
this.currentCueTime = null;
|
|
18089
|
+
this.currentTagTargetIsMovie = true;
|
|
18090
|
+
this.currentSimpleTagName = null;
|
|
18091
|
+
this.currentAttachedFile = null;
|
|
15462
18092
|
this.isWebM = false;
|
|
15463
18093
|
this.reader = input._reader;
|
|
15464
18094
|
}
|
|
@@ -15482,6 +18112,23 @@ ${cue.notes ?? ""}`;
|
|
|
15482
18112
|
codecStrings: codecStrings.filter(Boolean)
|
|
15483
18113
|
});
|
|
15484
18114
|
}
|
|
18115
|
+
async getMetadataTags() {
|
|
18116
|
+
await this.readMetadata();
|
|
18117
|
+
for (const segment of this.segments) {
|
|
18118
|
+
if (!segment.metadataTagsCollected) {
|
|
18119
|
+
if (this.reader.fileSize !== null) {
|
|
18120
|
+
await this.loadSegmentMetadata(segment);
|
|
18121
|
+
} else {
|
|
18122
|
+
}
|
|
18123
|
+
segment.metadataTagsCollected = true;
|
|
18124
|
+
}
|
|
18125
|
+
}
|
|
18126
|
+
let metadataTags = {};
|
|
18127
|
+
for (const segment of this.segments) {
|
|
18128
|
+
metadataTags = { ...metadataTags, ...segment.metadataTags };
|
|
18129
|
+
}
|
|
18130
|
+
return metadataTags;
|
|
18131
|
+
}
|
|
15485
18132
|
readMetadata() {
|
|
15486
18133
|
return this.readMetadataPromise ??= (async () => {
|
|
15487
18134
|
let currentPos = 0;
|
|
@@ -15539,6 +18186,8 @@ ${cue.notes ?? ""}`;
|
|
|
15539
18186
|
infoSeen: false,
|
|
15540
18187
|
tracksSeen: false,
|
|
15541
18188
|
cuesSeen: false,
|
|
18189
|
+
tagsSeen: false,
|
|
18190
|
+
attachmentsSeen: false,
|
|
15542
18191
|
timestampScale: -1,
|
|
15543
18192
|
timestampFactor: -1,
|
|
15544
18193
|
duration: -1,
|
|
@@ -15549,7 +18198,9 @@ ${cue.notes ?? ""}`;
|
|
|
15549
18198
|
elementEndPos: dataSize === null ? null : segmentDataStart + dataSize,
|
|
15550
18199
|
clusterSeekStartPos: segmentDataStart,
|
|
15551
18200
|
clusters: [],
|
|
15552
|
-
clusterLookupMutex: new AsyncMutex()
|
|
18201
|
+
clusterLookupMutex: new AsyncMutex(),
|
|
18202
|
+
metadataTags: {},
|
|
18203
|
+
metadataTagsCollected: false
|
|
15553
18204
|
};
|
|
15554
18205
|
this.segments.push(this.currentSegment);
|
|
15555
18206
|
let currentPos = segmentDataStart;
|
|
@@ -15585,6 +18236,18 @@ ${cue.notes ?? ""}`;
|
|
|
15585
18236
|
if (slice2) {
|
|
15586
18237
|
this.readContiguousElements(slice2);
|
|
15587
18238
|
}
|
|
18239
|
+
} else if (id === 307544935 /* Tags */ || id === 423732329 /* Attachments */) {
|
|
18240
|
+
if (id === 307544935 /* Tags */) {
|
|
18241
|
+
this.currentSegment.tagsSeen = true;
|
|
18242
|
+
} else {
|
|
18243
|
+
this.currentSegment.attachmentsSeen = true;
|
|
18244
|
+
}
|
|
18245
|
+
assertDefinedSize(size);
|
|
18246
|
+
let slice2 = this.reader.requestSlice(dataStartPos, size);
|
|
18247
|
+
if (slice2 instanceof Promise) slice2 = await slice2;
|
|
18248
|
+
if (slice2) {
|
|
18249
|
+
this.readContiguousElements(slice2);
|
|
18250
|
+
}
|
|
15588
18251
|
} else if (id === 524531317 /* Cluster */) {
|
|
15589
18252
|
this.currentSegment.clusterSeekStartPos = elementStartPos;
|
|
15590
18253
|
break;
|
|
@@ -15595,8 +18258,8 @@ ${cue.notes ?? ""}`;
|
|
|
15595
18258
|
currentPos = dataStartPos + size;
|
|
15596
18259
|
}
|
|
15597
18260
|
}
|
|
18261
|
+
this.currentSegment.seekEntries.sort((a, b) => a.segmentPosition - b.segmentPosition);
|
|
15598
18262
|
if (this.reader.fileSize !== null) {
|
|
15599
|
-
this.currentSegment.seekEntries.sort((a, b) => a.segmentPosition - b.segmentPosition);
|
|
15600
18263
|
for (const seekEntry of this.currentSegment.seekEntries) {
|
|
15601
18264
|
const target = METADATA_ELEMENTS.find((x) => x.id === seekEntry.id);
|
|
15602
18265
|
if (!target) {
|
|
@@ -15850,6 +18513,39 @@ ${cue.notes ?? ""}`;
|
|
|
15850
18513
|
blockIndex--;
|
|
15851
18514
|
}
|
|
15852
18515
|
}
|
|
18516
|
+
async loadSegmentMetadata(segment) {
|
|
18517
|
+
for (const seekEntry of segment.seekEntries) {
|
|
18518
|
+
if (seekEntry.id === 307544935 /* Tags */ && !segment.tagsSeen) {
|
|
18519
|
+
} else if (seekEntry.id === 423732329 /* Attachments */ && !segment.attachmentsSeen) {
|
|
18520
|
+
} else {
|
|
18521
|
+
continue;
|
|
18522
|
+
}
|
|
18523
|
+
let slice = this.reader.requestSliceRange(
|
|
18524
|
+
segment.dataStartPos + seekEntry.segmentPosition,
|
|
18525
|
+
MIN_HEADER_SIZE,
|
|
18526
|
+
MAX_HEADER_SIZE
|
|
18527
|
+
);
|
|
18528
|
+
if (slice instanceof Promise) slice = await slice;
|
|
18529
|
+
if (!slice) continue;
|
|
18530
|
+
const header = readElementHeader(slice);
|
|
18531
|
+
if (!header || header.id !== seekEntry.id) continue;
|
|
18532
|
+
const { size } = header;
|
|
18533
|
+
assertDefinedSize(size);
|
|
18534
|
+
assert(!this.currentSegment);
|
|
18535
|
+
this.currentSegment = segment;
|
|
18536
|
+
let dataSlice = this.reader.requestSlice(slice.filePos, size);
|
|
18537
|
+
if (dataSlice instanceof Promise) dataSlice = await dataSlice;
|
|
18538
|
+
if (dataSlice) {
|
|
18539
|
+
this.readContiguousElements(dataSlice);
|
|
18540
|
+
}
|
|
18541
|
+
this.currentSegment = null;
|
|
18542
|
+
if (seekEntry.id === 307544935 /* Tags */) {
|
|
18543
|
+
segment.tagsSeen = true;
|
|
18544
|
+
} else if (seekEntry.id === 423732329 /* Attachments */) {
|
|
18545
|
+
segment.attachmentsSeen = true;
|
|
18546
|
+
}
|
|
18547
|
+
}
|
|
18548
|
+
}
|
|
15853
18549
|
readContiguousElements(slice) {
|
|
15854
18550
|
const startIndex = slice.filePos;
|
|
15855
18551
|
while (slice.filePos - startIndex <= slice.length - MIN_HEADER_SIZE) {
|
|
@@ -16356,10 +19052,230 @@ ${cue.notes ?? ""}`;
|
|
|
16356
19052
|
}
|
|
16357
19053
|
;
|
|
16358
19054
|
break;
|
|
19055
|
+
case 29555 /* Tag */:
|
|
19056
|
+
{
|
|
19057
|
+
this.currentTagTargetIsMovie = true;
|
|
19058
|
+
this.readContiguousElements(slice.slice(dataStartPos, size));
|
|
19059
|
+
}
|
|
19060
|
+
;
|
|
19061
|
+
break;
|
|
19062
|
+
case 25536 /* Targets */:
|
|
19063
|
+
{
|
|
19064
|
+
this.readContiguousElements(slice.slice(dataStartPos, size));
|
|
19065
|
+
}
|
|
19066
|
+
;
|
|
19067
|
+
break;
|
|
19068
|
+
case 26826 /* TargetTypeValue */:
|
|
19069
|
+
{
|
|
19070
|
+
const targetTypeValue = readUnsignedInt(slice, size);
|
|
19071
|
+
if (targetTypeValue !== 50) {
|
|
19072
|
+
this.currentTagTargetIsMovie = false;
|
|
19073
|
+
}
|
|
19074
|
+
}
|
|
19075
|
+
;
|
|
19076
|
+
break;
|
|
19077
|
+
case 25541 /* TagTrackUID */:
|
|
19078
|
+
case 25545 /* TagEditionUID */:
|
|
19079
|
+
case 25540 /* TagChapterUID */:
|
|
19080
|
+
case 25542 /* TagAttachmentUID */:
|
|
19081
|
+
{
|
|
19082
|
+
this.currentTagTargetIsMovie = false;
|
|
19083
|
+
}
|
|
19084
|
+
;
|
|
19085
|
+
break;
|
|
19086
|
+
case 26568 /* SimpleTag */:
|
|
19087
|
+
{
|
|
19088
|
+
if (!this.currentTagTargetIsMovie) break;
|
|
19089
|
+
this.currentSimpleTagName = null;
|
|
19090
|
+
this.readContiguousElements(slice.slice(dataStartPos, size));
|
|
19091
|
+
}
|
|
19092
|
+
;
|
|
19093
|
+
break;
|
|
19094
|
+
case 17827 /* TagName */:
|
|
19095
|
+
{
|
|
19096
|
+
this.currentSimpleTagName = readUnicodeString(slice, size);
|
|
19097
|
+
}
|
|
19098
|
+
;
|
|
19099
|
+
break;
|
|
19100
|
+
case 17543 /* TagString */:
|
|
19101
|
+
{
|
|
19102
|
+
if (!this.currentSimpleTagName) break;
|
|
19103
|
+
const value = readUnicodeString(slice, size);
|
|
19104
|
+
this.processTagValue(this.currentSimpleTagName, value);
|
|
19105
|
+
}
|
|
19106
|
+
;
|
|
19107
|
+
break;
|
|
19108
|
+
case 17541 /* TagBinary */:
|
|
19109
|
+
{
|
|
19110
|
+
if (!this.currentSimpleTagName) break;
|
|
19111
|
+
const value = readBytes(slice, size);
|
|
19112
|
+
this.processTagValue(this.currentSimpleTagName, value);
|
|
19113
|
+
}
|
|
19114
|
+
;
|
|
19115
|
+
break;
|
|
19116
|
+
case 24999 /* AttachedFile */:
|
|
19117
|
+
{
|
|
19118
|
+
if (!this.currentSegment) break;
|
|
19119
|
+
this.currentAttachedFile = {
|
|
19120
|
+
fileName: null,
|
|
19121
|
+
fileMediaType: null,
|
|
19122
|
+
fileData: null,
|
|
19123
|
+
fileDescription: null
|
|
19124
|
+
};
|
|
19125
|
+
this.readContiguousElements(slice.slice(dataStartPos, size));
|
|
19126
|
+
if (this.currentAttachedFile.fileMediaType?.startsWith("image/") && this.currentAttachedFile.fileData) {
|
|
19127
|
+
const fileName = this.currentAttachedFile.fileName;
|
|
19128
|
+
let kind = "unknown";
|
|
19129
|
+
if (fileName) {
|
|
19130
|
+
const lowerName = fileName.toLowerCase();
|
|
19131
|
+
if (lowerName.startsWith("cover.")) {
|
|
19132
|
+
kind = "coverFront";
|
|
19133
|
+
} else if (lowerName.startsWith("back.")) {
|
|
19134
|
+
kind = "coverBack";
|
|
19135
|
+
}
|
|
19136
|
+
}
|
|
19137
|
+
this.currentSegment.metadataTags.images ??= [];
|
|
19138
|
+
this.currentSegment.metadataTags.images.push({
|
|
19139
|
+
data: this.currentAttachedFile.fileData,
|
|
19140
|
+
mimeType: this.currentAttachedFile.fileMediaType,
|
|
19141
|
+
kind,
|
|
19142
|
+
name: this.currentAttachedFile.fileName ?? void 0,
|
|
19143
|
+
description: this.currentAttachedFile.fileDescription ?? void 0
|
|
19144
|
+
});
|
|
19145
|
+
}
|
|
19146
|
+
this.currentAttachedFile = null;
|
|
19147
|
+
}
|
|
19148
|
+
;
|
|
19149
|
+
break;
|
|
19150
|
+
case 18030 /* FileName */:
|
|
19151
|
+
{
|
|
19152
|
+
if (!this.currentAttachedFile) break;
|
|
19153
|
+
this.currentAttachedFile.fileName = readUnicodeString(slice, size);
|
|
19154
|
+
}
|
|
19155
|
+
;
|
|
19156
|
+
break;
|
|
19157
|
+
case 18016 /* FileMediaType */:
|
|
19158
|
+
{
|
|
19159
|
+
if (!this.currentAttachedFile) break;
|
|
19160
|
+
this.currentAttachedFile.fileMediaType = readAsciiString(slice, size);
|
|
19161
|
+
}
|
|
19162
|
+
;
|
|
19163
|
+
break;
|
|
19164
|
+
case 18012 /* FileData */:
|
|
19165
|
+
{
|
|
19166
|
+
if (!this.currentAttachedFile) break;
|
|
19167
|
+
this.currentAttachedFile.fileData = readBytes(slice, size);
|
|
19168
|
+
}
|
|
19169
|
+
;
|
|
19170
|
+
break;
|
|
19171
|
+
case 18046 /* FileDescription */:
|
|
19172
|
+
{
|
|
19173
|
+
if (!this.currentAttachedFile) break;
|
|
19174
|
+
this.currentAttachedFile.fileDescription = readUnicodeString(slice, size);
|
|
19175
|
+
}
|
|
19176
|
+
;
|
|
19177
|
+
break;
|
|
16359
19178
|
}
|
|
16360
19179
|
slice.filePos = dataStartPos + size;
|
|
16361
19180
|
return true;
|
|
16362
19181
|
}
|
|
19182
|
+
processTagValue(name, value) {
|
|
19183
|
+
if (!this.currentSegment?.metadataTags) return;
|
|
19184
|
+
const metadataTags = this.currentSegment.metadataTags;
|
|
19185
|
+
metadataTags.raw ??= {};
|
|
19186
|
+
metadataTags.raw[name] ??= value;
|
|
19187
|
+
if (typeof value === "string") {
|
|
19188
|
+
switch (name.toLowerCase()) {
|
|
19189
|
+
case "title":
|
|
19190
|
+
{
|
|
19191
|
+
metadataTags.title ??= value;
|
|
19192
|
+
}
|
|
19193
|
+
;
|
|
19194
|
+
break;
|
|
19195
|
+
case "description":
|
|
19196
|
+
{
|
|
19197
|
+
metadataTags.description ??= value;
|
|
19198
|
+
}
|
|
19199
|
+
;
|
|
19200
|
+
break;
|
|
19201
|
+
case "artist":
|
|
19202
|
+
{
|
|
19203
|
+
metadataTags.artist ??= value;
|
|
19204
|
+
}
|
|
19205
|
+
;
|
|
19206
|
+
break;
|
|
19207
|
+
case "album":
|
|
19208
|
+
{
|
|
19209
|
+
metadataTags.album ??= value;
|
|
19210
|
+
}
|
|
19211
|
+
;
|
|
19212
|
+
break;
|
|
19213
|
+
case "album_artist":
|
|
19214
|
+
{
|
|
19215
|
+
metadataTags.albumArtist ??= value;
|
|
19216
|
+
}
|
|
19217
|
+
;
|
|
19218
|
+
break;
|
|
19219
|
+
case "genre":
|
|
19220
|
+
{
|
|
19221
|
+
metadataTags.genre ??= value;
|
|
19222
|
+
}
|
|
19223
|
+
;
|
|
19224
|
+
break;
|
|
19225
|
+
case "comment":
|
|
19226
|
+
{
|
|
19227
|
+
metadataTags.comment ??= value;
|
|
19228
|
+
}
|
|
19229
|
+
;
|
|
19230
|
+
break;
|
|
19231
|
+
case "lyrics":
|
|
19232
|
+
{
|
|
19233
|
+
metadataTags.lyrics ??= value;
|
|
19234
|
+
}
|
|
19235
|
+
;
|
|
19236
|
+
break;
|
|
19237
|
+
case "date":
|
|
19238
|
+
{
|
|
19239
|
+
const date = new Date(value);
|
|
19240
|
+
if (!Number.isNaN(date.getTime())) {
|
|
19241
|
+
metadataTags.date ??= date;
|
|
19242
|
+
}
|
|
19243
|
+
}
|
|
19244
|
+
;
|
|
19245
|
+
break;
|
|
19246
|
+
case "track_number":
|
|
19247
|
+
case "part_number":
|
|
19248
|
+
{
|
|
19249
|
+
const parts = value.split("/");
|
|
19250
|
+
const trackNum = Number.parseInt(parts[0], 10);
|
|
19251
|
+
const tracksTotal = parts[1] && Number.parseInt(parts[1], 10);
|
|
19252
|
+
if (Number.isInteger(trackNum) && trackNum > 0) {
|
|
19253
|
+
metadataTags.trackNumber ??= trackNum;
|
|
19254
|
+
}
|
|
19255
|
+
if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) {
|
|
19256
|
+
metadataTags.tracksTotal ??= tracksTotal;
|
|
19257
|
+
}
|
|
19258
|
+
}
|
|
19259
|
+
;
|
|
19260
|
+
break;
|
|
19261
|
+
case "disc_number":
|
|
19262
|
+
case "disc":
|
|
19263
|
+
{
|
|
19264
|
+
const discParts = value.split("/");
|
|
19265
|
+
const discNum = Number.parseInt(discParts[0], 10);
|
|
19266
|
+
const discsTotal = discParts[1] && Number.parseInt(discParts[1], 10);
|
|
19267
|
+
if (Number.isInteger(discNum) && discNum > 0) {
|
|
19268
|
+
metadataTags.discNumber ??= discNum;
|
|
19269
|
+
}
|
|
19270
|
+
if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) {
|
|
19271
|
+
metadataTags.discsTotal ??= discsTotal;
|
|
19272
|
+
}
|
|
19273
|
+
}
|
|
19274
|
+
;
|
|
19275
|
+
break;
|
|
19276
|
+
}
|
|
19277
|
+
}
|
|
19278
|
+
}
|
|
16363
19279
|
};
|
|
16364
19280
|
var MatroskaTrackBacking = class {
|
|
16365
19281
|
constructor(internalTrack) {
|
|
@@ -16881,43 +19797,6 @@ ${cue.notes ?? ""}`;
|
|
|
16881
19797
|
return result;
|
|
16882
19798
|
};
|
|
16883
19799
|
|
|
16884
|
-
// src/mp3/mp3-reader.ts
|
|
16885
|
-
var readId3 = (slice) => {
|
|
16886
|
-
const tag = readAscii(slice, 3);
|
|
16887
|
-
if (tag !== "ID3") {
|
|
16888
|
-
slice.skip(-3);
|
|
16889
|
-
return null;
|
|
16890
|
-
}
|
|
16891
|
-
slice.skip(3);
|
|
16892
|
-
const size = decodeSynchsafe(readU32Be(slice));
|
|
16893
|
-
return { size };
|
|
16894
|
-
};
|
|
16895
|
-
var readNextFrameHeader = async (reader, startPos, until) => {
|
|
16896
|
-
let currentPos = startPos;
|
|
16897
|
-
while (until === null || currentPos < until) {
|
|
16898
|
-
let slice = reader.requestSlice(currentPos, FRAME_HEADER_SIZE);
|
|
16899
|
-
if (slice instanceof Promise) slice = await slice;
|
|
16900
|
-
if (!slice) break;
|
|
16901
|
-
const word = readU32Be(slice);
|
|
16902
|
-
const result = readFrameHeader(word, reader.fileSize !== null ? reader.fileSize - currentPos : null);
|
|
16903
|
-
if (result.header) {
|
|
16904
|
-
return { header: result.header, startPos: currentPos };
|
|
16905
|
-
}
|
|
16906
|
-
currentPos += result.bytesAdvanced;
|
|
16907
|
-
}
|
|
16908
|
-
return null;
|
|
16909
|
-
};
|
|
16910
|
-
var decodeSynchsafe = (synchsafed) => {
|
|
16911
|
-
let mask = 2130706432;
|
|
16912
|
-
let unsynchsafed = 0;
|
|
16913
|
-
while (mask !== 0) {
|
|
16914
|
-
unsynchsafed >>= 1;
|
|
16915
|
-
unsynchsafed |= synchsafed & mask;
|
|
16916
|
-
mask >>= 8;
|
|
16917
|
-
}
|
|
16918
|
-
return unsynchsafed;
|
|
16919
|
-
};
|
|
16920
|
-
|
|
16921
19800
|
// src/mp3/mp3-demuxer.ts
|
|
16922
19801
|
var Mp3Demuxer = class extends Demuxer {
|
|
16923
19802
|
constructor(input) {
|
|
@@ -16926,6 +19805,7 @@ ${cue.notes ?? ""}`;
|
|
|
16926
19805
|
this.firstFrameHeader = null;
|
|
16927
19806
|
this.loadedSamples = [];
|
|
16928
19807
|
// All samples from the start of the file to lastLoadedPos
|
|
19808
|
+
this.metadataTags = null;
|
|
16929
19809
|
this.tracks = [];
|
|
16930
19810
|
this.readingMutex = new AsyncMutex();
|
|
16931
19811
|
this.lastSampleLoaded = false;
|
|
@@ -16938,21 +19818,26 @@ ${cue.notes ?? ""}`;
|
|
|
16938
19818
|
while (!this.firstFrameHeader && !this.lastSampleLoaded) {
|
|
16939
19819
|
await this.advanceReader();
|
|
16940
19820
|
}
|
|
16941
|
-
|
|
19821
|
+
if (!this.firstFrameHeader) {
|
|
19822
|
+
throw new Error("No valid MP3 frame found.");
|
|
19823
|
+
}
|
|
16942
19824
|
this.tracks = [new InputAudioTrack(new Mp3AudioTrackBacking(this))];
|
|
16943
19825
|
})();
|
|
16944
19826
|
}
|
|
16945
19827
|
async advanceReader() {
|
|
16946
19828
|
if (this.lastLoadedPos === 0) {
|
|
16947
|
-
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16955
|
-
|
|
19829
|
+
while (true) {
|
|
19830
|
+
let slice2 = this.reader.requestSlice(this.lastLoadedPos, ID3_V2_HEADER_SIZE);
|
|
19831
|
+
if (slice2 instanceof Promise) slice2 = await slice2;
|
|
19832
|
+
if (!slice2) {
|
|
19833
|
+
this.lastSampleLoaded = true;
|
|
19834
|
+
return;
|
|
19835
|
+
}
|
|
19836
|
+
const id3V2Header = readId3V2Header(slice2);
|
|
19837
|
+
if (!id3V2Header) {
|
|
19838
|
+
break;
|
|
19839
|
+
}
|
|
19840
|
+
this.lastLoadedPos = slice2.filePos + id3V2Header.size;
|
|
16956
19841
|
}
|
|
16957
19842
|
}
|
|
16958
19843
|
const result = await readNextFrameHeader(this.reader, this.lastLoadedPos, this.reader.fileSize);
|
|
@@ -16999,6 +19884,45 @@ ${cue.notes ?? ""}`;
|
|
|
16999
19884
|
assert(track);
|
|
17000
19885
|
return track.computeDuration();
|
|
17001
19886
|
}
|
|
19887
|
+
async getMetadataTags() {
|
|
19888
|
+
const release = await this.readingMutex.acquire();
|
|
19889
|
+
try {
|
|
19890
|
+
await this.readMetadata();
|
|
19891
|
+
if (this.metadataTags) {
|
|
19892
|
+
return this.metadataTags;
|
|
19893
|
+
}
|
|
19894
|
+
this.metadataTags = {};
|
|
19895
|
+
let currentPos = 0;
|
|
19896
|
+
let id3V2HeaderFound = false;
|
|
19897
|
+
while (true) {
|
|
19898
|
+
let headerSlice = this.reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE);
|
|
19899
|
+
if (headerSlice instanceof Promise) headerSlice = await headerSlice;
|
|
19900
|
+
if (!headerSlice) break;
|
|
19901
|
+
const id3V2Header = readId3V2Header(headerSlice);
|
|
19902
|
+
if (!id3V2Header) {
|
|
19903
|
+
break;
|
|
19904
|
+
}
|
|
19905
|
+
id3V2HeaderFound = true;
|
|
19906
|
+
let contentSlice = this.reader.requestSlice(headerSlice.filePos, id3V2Header.size);
|
|
19907
|
+
if (contentSlice instanceof Promise) contentSlice = await contentSlice;
|
|
19908
|
+
if (!contentSlice) break;
|
|
19909
|
+
parseId3V2Tag(contentSlice, id3V2Header, this.metadataTags);
|
|
19910
|
+
currentPos = headerSlice.filePos + id3V2Header.size;
|
|
19911
|
+
}
|
|
19912
|
+
if (!id3V2HeaderFound && this.reader.fileSize !== null && this.reader.fileSize >= ID3_V1_TAG_SIZE) {
|
|
19913
|
+
let slice = this.reader.requestSlice(this.reader.fileSize - ID3_V1_TAG_SIZE, ID3_V1_TAG_SIZE);
|
|
19914
|
+
if (slice instanceof Promise) slice = await slice;
|
|
19915
|
+
assert(slice);
|
|
19916
|
+
const tag = readAscii(slice, 3);
|
|
19917
|
+
if (tag === "TAG") {
|
|
19918
|
+
parseId3V1Tag(slice, this.metadataTags);
|
|
19919
|
+
}
|
|
19920
|
+
}
|
|
19921
|
+
return this.metadataTags;
|
|
19922
|
+
} finally {
|
|
19923
|
+
release();
|
|
19924
|
+
}
|
|
19925
|
+
}
|
|
17002
19926
|
};
|
|
17003
19927
|
var Mp3AudioTrackBacking = class {
|
|
17004
19928
|
constructor(demuxer) {
|
|
@@ -17136,6 +20060,7 @@ ${cue.notes ?? ""}`;
|
|
|
17136
20060
|
this.metadataPromise = null;
|
|
17137
20061
|
this.bitstreams = [];
|
|
17138
20062
|
this.tracks = [];
|
|
20063
|
+
this.metadataTags = {};
|
|
17139
20064
|
this.reader = input._reader;
|
|
17140
20065
|
}
|
|
17141
20066
|
async readMetadata() {
|
|
@@ -17256,6 +20181,7 @@ ${cue.notes ?? ""}`;
|
|
|
17256
20181
|
],
|
|
17257
20182
|
modeBlockflags: parseModesFromVorbisSetupPacket(thirdPacket.data).modeBlockflags
|
|
17258
20183
|
};
|
|
20184
|
+
this.readVorbisComments(secondPacket.data.subarray(7));
|
|
17259
20185
|
}
|
|
17260
20186
|
async readOpusMetadata(firstPacket, bitstream) {
|
|
17261
20187
|
const nextPacketPosition = await this.findNextPacketStart(firstPacket);
|
|
@@ -17278,6 +20204,172 @@ ${cue.notes ?? ""}`;
|
|
|
17278
20204
|
bitstream.codecInfo.opusInfo = {
|
|
17279
20205
|
preSkip: header.preSkip
|
|
17280
20206
|
};
|
|
20207
|
+
this.readVorbisComments(secondPacket.data.subarray(8));
|
|
20208
|
+
}
|
|
20209
|
+
readVorbisComments(bytes2) {
|
|
20210
|
+
const commentView = toDataView(bytes2);
|
|
20211
|
+
let commentPos = 0;
|
|
20212
|
+
const vendorStringLength = commentView.getUint32(commentPos, true);
|
|
20213
|
+
commentPos += 4;
|
|
20214
|
+
const vendorString = textDecoder.decode(
|
|
20215
|
+
bytes2.subarray(commentPos, commentPos + vendorStringLength)
|
|
20216
|
+
);
|
|
20217
|
+
commentPos += vendorStringLength;
|
|
20218
|
+
if (vendorStringLength > 0) {
|
|
20219
|
+
this.metadataTags.raw ??= {};
|
|
20220
|
+
this.metadataTags.raw["vendor"] ??= vendorString;
|
|
20221
|
+
}
|
|
20222
|
+
const listLength = commentView.getUint32(commentPos, true);
|
|
20223
|
+
commentPos += 4;
|
|
20224
|
+
for (let i = 0; i < listLength; i++) {
|
|
20225
|
+
const stringLength = commentView.getUint32(commentPos, true);
|
|
20226
|
+
commentPos += 4;
|
|
20227
|
+
const string = textDecoder.decode(
|
|
20228
|
+
bytes2.subarray(commentPos, commentPos + stringLength)
|
|
20229
|
+
);
|
|
20230
|
+
commentPos += stringLength;
|
|
20231
|
+
const separatorIndex = string.indexOf("=");
|
|
20232
|
+
if (separatorIndex === -1) {
|
|
20233
|
+
continue;
|
|
20234
|
+
}
|
|
20235
|
+
const key = string.slice(0, separatorIndex).toUpperCase();
|
|
20236
|
+
const value = string.slice(separatorIndex + 1);
|
|
20237
|
+
this.metadataTags.raw ??= {};
|
|
20238
|
+
this.metadataTags.raw[key] ??= value;
|
|
20239
|
+
switch (key) {
|
|
20240
|
+
case "TITLE":
|
|
20241
|
+
{
|
|
20242
|
+
this.metadataTags.title ??= value;
|
|
20243
|
+
}
|
|
20244
|
+
;
|
|
20245
|
+
break;
|
|
20246
|
+
case "DESCRIPTION":
|
|
20247
|
+
{
|
|
20248
|
+
this.metadataTags.description ??= value;
|
|
20249
|
+
}
|
|
20250
|
+
;
|
|
20251
|
+
break;
|
|
20252
|
+
case "ARTIST":
|
|
20253
|
+
{
|
|
20254
|
+
this.metadataTags.artist ??= value;
|
|
20255
|
+
}
|
|
20256
|
+
;
|
|
20257
|
+
break;
|
|
20258
|
+
case "ALBUM":
|
|
20259
|
+
{
|
|
20260
|
+
this.metadataTags.album ??= value;
|
|
20261
|
+
}
|
|
20262
|
+
;
|
|
20263
|
+
break;
|
|
20264
|
+
case "ALBUMARTIST":
|
|
20265
|
+
{
|
|
20266
|
+
this.metadataTags.albumArtist ??= value;
|
|
20267
|
+
}
|
|
20268
|
+
;
|
|
20269
|
+
break;
|
|
20270
|
+
case "COMMENT":
|
|
20271
|
+
{
|
|
20272
|
+
this.metadataTags.comment ??= value;
|
|
20273
|
+
}
|
|
20274
|
+
;
|
|
20275
|
+
break;
|
|
20276
|
+
case "LYRICS":
|
|
20277
|
+
{
|
|
20278
|
+
this.metadataTags.lyrics ??= value;
|
|
20279
|
+
}
|
|
20280
|
+
;
|
|
20281
|
+
break;
|
|
20282
|
+
case "TRACKNUMBER":
|
|
20283
|
+
{
|
|
20284
|
+
const parts = value.split("/");
|
|
20285
|
+
const trackNum = Number.parseInt(parts[0], 10);
|
|
20286
|
+
const tracksTotal = parts[1] && Number.parseInt(parts[1], 10);
|
|
20287
|
+
if (Number.isInteger(trackNum) && trackNum > 0) {
|
|
20288
|
+
this.metadataTags.trackNumber ??= trackNum;
|
|
20289
|
+
}
|
|
20290
|
+
if (tracksTotal && Number.isInteger(tracksTotal) && tracksTotal > 0) {
|
|
20291
|
+
this.metadataTags.tracksTotal ??= tracksTotal;
|
|
20292
|
+
}
|
|
20293
|
+
}
|
|
20294
|
+
;
|
|
20295
|
+
break;
|
|
20296
|
+
case "TRACKTOTAL":
|
|
20297
|
+
{
|
|
20298
|
+
const tracksTotal = Number.parseInt(value, 10);
|
|
20299
|
+
if (Number.isInteger(tracksTotal) && tracksTotal > 0) {
|
|
20300
|
+
this.metadataTags.tracksTotal ??= tracksTotal;
|
|
20301
|
+
}
|
|
20302
|
+
}
|
|
20303
|
+
;
|
|
20304
|
+
break;
|
|
20305
|
+
case "DISCNUMBER":
|
|
20306
|
+
{
|
|
20307
|
+
const parts = value.split("/");
|
|
20308
|
+
const discNum = Number.parseInt(parts[0], 10);
|
|
20309
|
+
const discsTotal = parts[1] && Number.parseInt(parts[1], 10);
|
|
20310
|
+
if (Number.isInteger(discNum) && discNum > 0) {
|
|
20311
|
+
this.metadataTags.discNumber ??= discNum;
|
|
20312
|
+
}
|
|
20313
|
+
if (discsTotal && Number.isInteger(discsTotal) && discsTotal > 0) {
|
|
20314
|
+
this.metadataTags.discsTotal ??= discsTotal;
|
|
20315
|
+
}
|
|
20316
|
+
}
|
|
20317
|
+
;
|
|
20318
|
+
break;
|
|
20319
|
+
case "DISCTOTAL":
|
|
20320
|
+
{
|
|
20321
|
+
const discsTotal = Number.parseInt(value, 10);
|
|
20322
|
+
if (Number.isInteger(discsTotal) && discsTotal > 0) {
|
|
20323
|
+
this.metadataTags.discsTotal ??= discsTotal;
|
|
20324
|
+
}
|
|
20325
|
+
}
|
|
20326
|
+
;
|
|
20327
|
+
break;
|
|
20328
|
+
case "DATE":
|
|
20329
|
+
{
|
|
20330
|
+
const date = new Date(value);
|
|
20331
|
+
if (!Number.isNaN(date.getTime())) {
|
|
20332
|
+
this.metadataTags.date ??= date;
|
|
20333
|
+
}
|
|
20334
|
+
}
|
|
20335
|
+
;
|
|
20336
|
+
break;
|
|
20337
|
+
case "GENRE":
|
|
20338
|
+
{
|
|
20339
|
+
this.metadataTags.genre ??= value;
|
|
20340
|
+
}
|
|
20341
|
+
;
|
|
20342
|
+
break;
|
|
20343
|
+
case "METADATA_BLOCK_PICTURE":
|
|
20344
|
+
{
|
|
20345
|
+
const decoded = base64ToBytes(value);
|
|
20346
|
+
const view2 = toDataView(decoded);
|
|
20347
|
+
const pictureType = view2.getUint32(0, false);
|
|
20348
|
+
const mediaTypeLength = view2.getUint32(4, false);
|
|
20349
|
+
const mediaType = String.fromCharCode(...decoded.subarray(8, 8 + mediaTypeLength));
|
|
20350
|
+
const descriptionLength = view2.getUint32(8 + mediaTypeLength, false);
|
|
20351
|
+
const description = textDecoder.decode(decoded.subarray(
|
|
20352
|
+
12 + mediaTypeLength,
|
|
20353
|
+
12 + mediaTypeLength + descriptionLength
|
|
20354
|
+
));
|
|
20355
|
+
const dataLength = view2.getUint32(mediaTypeLength + descriptionLength + 28);
|
|
20356
|
+
const data = decoded.subarray(
|
|
20357
|
+
mediaTypeLength + descriptionLength + 32,
|
|
20358
|
+
mediaTypeLength + descriptionLength + 32 + dataLength
|
|
20359
|
+
);
|
|
20360
|
+
this.metadataTags.images ??= [];
|
|
20361
|
+
this.metadataTags.images.push({
|
|
20362
|
+
data,
|
|
20363
|
+
mimeType: mediaType,
|
|
20364
|
+
kind: pictureType === 3 ? "coverFront" : pictureType === 4 ? "coverBack" : "unknown",
|
|
20365
|
+
name: void 0,
|
|
20366
|
+
description: description || void 0
|
|
20367
|
+
});
|
|
20368
|
+
}
|
|
20369
|
+
;
|
|
20370
|
+
break;
|
|
20371
|
+
}
|
|
20372
|
+
}
|
|
17281
20373
|
}
|
|
17282
20374
|
async readPacket(startPage, startSegmentIndex) {
|
|
17283
20375
|
assert(startSegmentIndex < startPage.lacingValues.length);
|
|
@@ -17384,6 +20476,10 @@ ${cue.notes ?? ""}`;
|
|
|
17384
20476
|
const trackDurations = await Promise.all(tracks.map((x) => x.computeDuration()));
|
|
17385
20477
|
return Math.max(0, ...trackDurations);
|
|
17386
20478
|
}
|
|
20479
|
+
async getMetadataTags() {
|
|
20480
|
+
await this.readMetadata();
|
|
20481
|
+
return this.metadataTags;
|
|
20482
|
+
}
|
|
17387
20483
|
};
|
|
17388
20484
|
var OggAudioTrackBacking = class {
|
|
17389
20485
|
constructor(bitstream, demuxer) {
|
|
@@ -17973,6 +21069,9 @@ ${cue.notes ?? ""}`;
|
|
|
17973
21069
|
assert(track);
|
|
17974
21070
|
return track.computeDuration();
|
|
17975
21071
|
}
|
|
21072
|
+
async getMetadataTags() {
|
|
21073
|
+
return {};
|
|
21074
|
+
}
|
|
17976
21075
|
};
|
|
17977
21076
|
var AdtsAudioTrackBacking = class {
|
|
17978
21077
|
constructor(demuxer) {
|
|
@@ -18274,15 +21373,23 @@ ${cue.notes ?? ""}`;
|
|
|
18274
21373
|
if (slice instanceof Promise) slice = await slice;
|
|
18275
21374
|
if (!slice) return false;
|
|
18276
21375
|
let currentPos = 0;
|
|
18277
|
-
|
|
18278
|
-
|
|
18279
|
-
|
|
21376
|
+
let id3V2HeaderFound = false;
|
|
21377
|
+
while (true) {
|
|
21378
|
+
let slice2 = input._reader.requestSlice(currentPos, ID3_V2_HEADER_SIZE);
|
|
21379
|
+
if (slice2 instanceof Promise) slice2 = await slice2;
|
|
21380
|
+
if (!slice2) break;
|
|
21381
|
+
const id3V2Header = readId3V2Header(slice2);
|
|
21382
|
+
if (!id3V2Header) {
|
|
21383
|
+
break;
|
|
21384
|
+
}
|
|
21385
|
+
id3V2HeaderFound = true;
|
|
21386
|
+
currentPos = slice2.filePos + id3V2Header.size;
|
|
18280
21387
|
}
|
|
18281
21388
|
const firstResult = await readNextFrameHeader(input._reader, currentPos, currentPos + 4096);
|
|
18282
21389
|
if (!firstResult) {
|
|
18283
21390
|
return false;
|
|
18284
21391
|
}
|
|
18285
|
-
if (
|
|
21392
|
+
if (id3V2HeaderFound) {
|
|
18286
21393
|
return true;
|
|
18287
21394
|
}
|
|
18288
21395
|
currentPos = firstResult.startPos += firstResult.header.totalSize;
|
|
@@ -18485,6 +21592,11 @@ ${cue.notes ?? ""}`;
|
|
|
18485
21592
|
const demuxer = await this._getDemuxer();
|
|
18486
21593
|
return demuxer.getMimeType();
|
|
18487
21594
|
}
|
|
21595
|
+
/** Returns descriptive metadata tags about the media file, such as title, author, date, or cover art. */
|
|
21596
|
+
async getMetadataTags() {
|
|
21597
|
+
const demuxer = await this._getDemuxer();
|
|
21598
|
+
return demuxer.getMetadataTags();
|
|
21599
|
+
}
|
|
18488
21600
|
};
|
|
18489
21601
|
|
|
18490
21602
|
// src/conversion.ts
|
|
@@ -18626,6 +21738,9 @@ ${cue.notes ?? ""}`;
|
|
|
18626
21738
|
if (options.trim?.start !== void 0 && options.trim.end !== void 0 && options.trim.start >= options.trim.end) {
|
|
18627
21739
|
throw new TypeError("options.trim.start must be less than options.trim.end.");
|
|
18628
21740
|
}
|
|
21741
|
+
if (options.tags !== void 0 && typeof options.tags !== "function") {
|
|
21742
|
+
throw new TypeError("options.tags, when provided, must be a function.");
|
|
21743
|
+
}
|
|
18629
21744
|
this._options = options;
|
|
18630
21745
|
this.input = options.input;
|
|
18631
21746
|
this.output = options.output;
|
|
@@ -18703,6 +21818,21 @@ ${cue.notes ?? ""}`;
|
|
|
18703
21818
|
if (unintentionallyDiscardedTracks.length > 0) {
|
|
18704
21819
|
console.warn("Some tracks had to be discarded from the conversion:", unintentionallyDiscardedTracks);
|
|
18705
21820
|
}
|
|
21821
|
+
const inputTags = await this.input.getMetadataTags();
|
|
21822
|
+
let outputTags;
|
|
21823
|
+
if (this._options.tags) {
|
|
21824
|
+
const result = await this._options.tags(inputTags);
|
|
21825
|
+
validateMetadataTags(result);
|
|
21826
|
+
outputTags = result;
|
|
21827
|
+
} else {
|
|
21828
|
+
outputTags = inputTags;
|
|
21829
|
+
}
|
|
21830
|
+
const inputAndOutputFormatMatch = (await this.input.getFormat()).mimeType === this.output.format.mimeType;
|
|
21831
|
+
const rawTagsAreUnchanged = inputTags.raw === outputTags.raw;
|
|
21832
|
+
if (inputTags.raw && rawTagsAreUnchanged && !inputAndOutputFormatMatch) {
|
|
21833
|
+
delete outputTags.raw;
|
|
21834
|
+
}
|
|
21835
|
+
this.output.setMetadataTags(outputTags);
|
|
18706
21836
|
}
|
|
18707
21837
|
/** Executes the conversion process. Resolves once conversion is complete. */
|
|
18708
21838
|
async execute() {
|
|
@@ -18788,7 +21918,7 @@ ${cue.notes ?? ""}`;
|
|
|
18788
21918
|
await this._started;
|
|
18789
21919
|
const sink = new EncodedPacketSink(track);
|
|
18790
21920
|
const decoderConfig = await track.getDecoderConfig();
|
|
18791
|
-
const
|
|
21921
|
+
const meta2 = { decoderConfig: decoderConfig ?? void 0 };
|
|
18792
21922
|
const endPacket = Number.isFinite(this._endTimestamp) ? await sink.getPacket(this._endTimestamp, { metadataOnly: true }) ?? void 0 : void 0;
|
|
18793
21923
|
for await (const packet of sink.packets(void 0, endPacket, { verifyKeyPackets: true })) {
|
|
18794
21924
|
if (this._synchronizer.shouldWait(track.id, packet.timestamp)) {
|
|
@@ -18797,7 +21927,7 @@ ${cue.notes ?? ""}`;
|
|
|
18797
21927
|
if (this._canceled) {
|
|
18798
21928
|
return;
|
|
18799
21929
|
}
|
|
18800
|
-
await source.add(packet,
|
|
21930
|
+
await source.add(packet, meta2);
|
|
18801
21931
|
this._reportProgress(track.id, packet.timestamp + packet.duration);
|
|
18802
21932
|
}
|
|
18803
21933
|
source.close();
|
|
@@ -19027,7 +22157,7 @@ ${cue.notes ?? ""}`;
|
|
|
19027
22157
|
await this._started;
|
|
19028
22158
|
const sink = new EncodedPacketSink(track);
|
|
19029
22159
|
const decoderConfig = await track.getDecoderConfig();
|
|
19030
|
-
const
|
|
22160
|
+
const meta2 = { decoderConfig: decoderConfig ?? void 0 };
|
|
19031
22161
|
const endPacket = Number.isFinite(this._endTimestamp) ? await sink.getPacket(this._endTimestamp, { metadataOnly: true }) ?? void 0 : void 0;
|
|
19032
22162
|
for await (const packet of sink.packets(void 0, endPacket)) {
|
|
19033
22163
|
if (this._synchronizer.shouldWait(track.id, packet.timestamp)) {
|
|
@@ -19036,7 +22166,7 @@ ${cue.notes ?? ""}`;
|
|
|
19036
22166
|
if (this._canceled) {
|
|
19037
22167
|
return;
|
|
19038
22168
|
}
|
|
19039
|
-
await source.add(packet,
|
|
22169
|
+
await source.add(packet, meta2);
|
|
19040
22170
|
this._reportProgress(track.id, packet.timestamp + packet.duration);
|
|
19041
22171
|
}
|
|
19042
22172
|
source.close();
|