mediabunny 1.58.0 → 1.59.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 +176 -87
- package/dist/bundles/mediabunny.min.cjs +9 -9
- package/dist/bundles/mediabunny.min.mjs +8 -8
- package/dist/bundles/mediabunny.mjs +176 -87
- package/dist/bundles/mediabunny.node.cjs +176 -87
- package/dist/mediabunny.d.ts +2 -0
- package/dist/modules/src/codec-data.d.ts.map +1 -1
- package/dist/modules/src/codec-data.js +15 -0
- package/dist/modules/src/hls/hls-demuxer.d.ts.map +1 -1
- package/dist/modules/src/hls/hls-demuxer.js +4 -28
- package/dist/modules/src/id3.d.ts.map +1 -1
- package/dist/modules/src/id3.js +18 -0
- package/dist/modules/src/input-track.d.ts.map +1 -1
- package/dist/modules/src/input-track.js +2 -3
- package/dist/modules/src/isobmff/isobmff-boxes.js +13 -0
- package/dist/modules/src/isobmff/isobmff-demuxer.d.ts.map +1 -1
- package/dist/modules/src/isobmff/isobmff-demuxer.js +11 -2
- package/dist/modules/src/matroska/matroska-demuxer.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-demuxer.js +9 -2
- package/dist/modules/src/matroska/matroska-muxer.d.ts.map +1 -1
- package/dist/modules/src/matroska/matroska-muxer.js +7 -0
- package/dist/modules/src/media-source.d.ts.map +1 -1
- package/dist/modules/src/media-source.js +18 -19
- package/dist/modules/src/metadata.d.ts +2 -0
- package/dist/modules/src/metadata.d.ts.map +1 -1
- package/dist/modules/src/metadata.js +5 -0
- package/dist/modules/src/pcm.d.ts.map +1 -1
- package/dist/modules/src/pcm.js +8 -5
- package/dist/modules/src/resample.d.ts +1 -0
- package/dist/modules/src/resample.d.ts.map +1 -1
- package/dist/modules/src/resample.js +20 -9
- package/dist/modules/src/sample.js +3 -3
- package/dist/modules/src/source.d.ts.map +1 -1
- package/dist/modules/src/source.js +36 -9
- package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
- package/dist/modules/src/wave/wave-muxer.d.ts.map +1 -1
- package/dist/modules/src/wave/wave-muxer.js +1 -0
- package/package.json +1 -1
- package/src/codec-data.ts +11 -0
- package/src/hls/hls-demuxer.ts +6 -45
- package/src/id3.ts +15 -0
- package/src/input-track.ts +4 -8
- package/src/isobmff/isobmff-boxes.ts +11 -0
- package/src/isobmff/isobmff-demuxer.ts +11 -4
- package/src/matroska/matroska-demuxer.ts +9 -4
- package/src/matroska/matroska-muxer.ts +5 -0
- package/src/media-source.ts +31 -16
- package/src/metadata.ts +9 -0
- package/src/mpeg-ts/mpeg-ts-demuxer.ts +2 -2
- package/src/pcm.ts +7 -5
- package/src/resample.ts +25 -11
- package/src/sample.ts +3 -3
- package/src/segmented-input.ts +2 -2
- package/src/source.ts +42 -9
- package/src/wave/wave-muxer.ts +1 -0
|
@@ -1491,6 +1491,9 @@ var Mediabunny = (() => {
|
|
|
1491
1491
|
if (tags.date !== void 0 && (!(tags.date instanceof Date) || Number.isNaN(tags.date.getTime()))) {
|
|
1492
1492
|
throw new TypeError("tags.date, when provided, must be a valid Date.");
|
|
1493
1493
|
}
|
|
1494
|
+
if (tags.beatsPerMinute !== void 0 && (!Number.isInteger(tags.beatsPerMinute) || tags.beatsPerMinute <= 0)) {
|
|
1495
|
+
throw new TypeError("tags.beatsPerMinute, when provided, must be a positive integer.");
|
|
1496
|
+
}
|
|
1494
1497
|
if (tags.lyrics !== void 0 && typeof tags.lyrics !== "string") {
|
|
1495
1498
|
throw new TypeError("tags.lyrics, when provided, must be a string.");
|
|
1496
1499
|
}
|
|
@@ -1530,7 +1533,7 @@ var Mediabunny = (() => {
|
|
|
1530
1533
|
}
|
|
1531
1534
|
};
|
|
1532
1535
|
var metadataTagsAreEmpty = (tags) => {
|
|
1533
|
-
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);
|
|
1536
|
+
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.beatsPerMinute === 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);
|
|
1534
1537
|
};
|
|
1535
1538
|
var DEFAULT_TRACK_DISPOSITION = {
|
|
1536
1539
|
default: true,
|
|
@@ -3814,6 +3817,15 @@ var Mediabunny = (() => {
|
|
|
3814
3817
|
}
|
|
3815
3818
|
;
|
|
3816
3819
|
break;
|
|
3820
|
+
case "BPM":
|
|
3821
|
+
{
|
|
3822
|
+
const bpm = Number.parseInt(value, 10);
|
|
3823
|
+
if (Number.isInteger(bpm) && bpm > 0) {
|
|
3824
|
+
metadataTags.beatsPerMinute ??= bpm;
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
;
|
|
3828
|
+
break;
|
|
3817
3829
|
case "GENRE":
|
|
3818
3830
|
{
|
|
3819
3831
|
metadataTags.genre ??= value;
|
|
@@ -3953,6 +3965,12 @@ var Mediabunny = (() => {
|
|
|
3953
3965
|
}
|
|
3954
3966
|
;
|
|
3955
3967
|
break;
|
|
3968
|
+
case "beatsPerMinute":
|
|
3969
|
+
{
|
|
3970
|
+
addCommentTag("BPM", value.toString());
|
|
3971
|
+
}
|
|
3972
|
+
;
|
|
3973
|
+
break;
|
|
3956
3974
|
case "images":
|
|
3957
3975
|
{
|
|
3958
3976
|
if (!writeImages) {
|
|
@@ -8592,6 +8610,17 @@ var Mediabunny = (() => {
|
|
|
8592
8610
|
}
|
|
8593
8611
|
;
|
|
8594
8612
|
break;
|
|
8613
|
+
case "tmpo":
|
|
8614
|
+
{
|
|
8615
|
+
if (data instanceof Uint8Array && data.length >= 2) {
|
|
8616
|
+
const bpm = toDataView(data).getInt16(0, false);
|
|
8617
|
+
if (bpm > 0) {
|
|
8618
|
+
this.metadataTags.beatsPerMinute ??= bpm;
|
|
8619
|
+
}
|
|
8620
|
+
}
|
|
8621
|
+
}
|
|
8622
|
+
;
|
|
8623
|
+
break;
|
|
8595
8624
|
case "covr":
|
|
8596
8625
|
case "com.apple.quicktime.artwork":
|
|
8597
8626
|
{
|
|
@@ -9099,7 +9128,6 @@ var Mediabunny = (() => {
|
|
|
9099
9128
|
constructor(internalTrack) {
|
|
9100
9129
|
super(internalTrack);
|
|
9101
9130
|
this.decoderConfigPromise = null;
|
|
9102
|
-
this.internalTrack = internalTrack;
|
|
9103
9131
|
}
|
|
9104
9132
|
getType() {
|
|
9105
9133
|
return "video";
|
|
@@ -9198,7 +9226,6 @@ var Mediabunny = (() => {
|
|
|
9198
9226
|
constructor(internalTrack) {
|
|
9199
9227
|
super(internalTrack);
|
|
9200
9228
|
this.decoderConfigPromise = null;
|
|
9201
|
-
this.internalTrack = internalTrack;
|
|
9202
9229
|
}
|
|
9203
9230
|
getType() {
|
|
9204
9231
|
return "audio";
|
|
@@ -11608,6 +11635,15 @@ var Mediabunny = (() => {
|
|
|
11608
11635
|
}
|
|
11609
11636
|
;
|
|
11610
11637
|
break;
|
|
11638
|
+
case "bpm":
|
|
11639
|
+
{
|
|
11640
|
+
const bpm = Number.parseInt(value, 10);
|
|
11641
|
+
if (Number.isInteger(bpm) && bpm > 0) {
|
|
11642
|
+
metadataTags.beatsPerMinute ??= bpm;
|
|
11643
|
+
}
|
|
11644
|
+
}
|
|
11645
|
+
;
|
|
11646
|
+
break;
|
|
11611
11647
|
case "comment":
|
|
11612
11648
|
{
|
|
11613
11649
|
metadataTags.comment ??= value;
|
|
@@ -12060,7 +12096,6 @@ var Mediabunny = (() => {
|
|
|
12060
12096
|
constructor(internalTrack) {
|
|
12061
12097
|
super(internalTrack);
|
|
12062
12098
|
this.decoderConfigPromise = null;
|
|
12063
|
-
this.internalTrack = internalTrack;
|
|
12064
12099
|
}
|
|
12065
12100
|
getType() {
|
|
12066
12101
|
return "video";
|
|
@@ -12154,7 +12189,6 @@ var Mediabunny = (() => {
|
|
|
12154
12189
|
constructor(internalTrack) {
|
|
12155
12190
|
super(internalTrack);
|
|
12156
12191
|
this.decoderConfigPromise = null;
|
|
12157
|
-
this.internalTrack = internalTrack;
|
|
12158
12192
|
}
|
|
12159
12193
|
getType() {
|
|
12160
12194
|
return "audio";
|
|
@@ -17527,7 +17561,8 @@ var Mediabunny = (() => {
|
|
|
17527
17561
|
}
|
|
17528
17562
|
this._orchestrator.signalWorkerStoppedRunning(worker);
|
|
17529
17563
|
if (worker.aborted) {
|
|
17530
|
-
await reader?.cancel()
|
|
17564
|
+
await reader?.cancel().catch(() => {
|
|
17565
|
+
});
|
|
17531
17566
|
}
|
|
17532
17567
|
}
|
|
17533
17568
|
/** @internal */
|
|
@@ -17610,6 +17645,10 @@ var Mediabunny = (() => {
|
|
|
17610
17645
|
* @internal
|
|
17611
17646
|
*/
|
|
17612
17647
|
this._sequentialBacking = null;
|
|
17648
|
+
/** @internal */
|
|
17649
|
+
this._abortControllers = /* @__PURE__ */ new Map();
|
|
17650
|
+
/** @internal */
|
|
17651
|
+
this._sequentialAbortController = null;
|
|
17613
17652
|
this._url = url2;
|
|
17614
17653
|
this._options = options;
|
|
17615
17654
|
this._getRetryDelay = options.getRetryDelay ?? DEFAULT_RETRY_DELAY;
|
|
@@ -17645,6 +17684,7 @@ var Mediabunny = (() => {
|
|
|
17645
17684
|
maxCacheSize: options.maxCacheSize ?? 64 * 2 ** 20,
|
|
17646
17685
|
maxWorkerCount: options.parallelism ?? DEFAULT_PARALLELISM,
|
|
17647
17686
|
runWorker: this._runWorker.bind(this),
|
|
17687
|
+
onIdleWorkerRemoved: (worker) => this._abortControllers.delete(worker),
|
|
17648
17688
|
prefetchProfile: PREFETCH_PROFILES.network,
|
|
17649
17689
|
handleUnhandledError: options.handleUnhandledError
|
|
17650
17690
|
});
|
|
@@ -17688,7 +17728,12 @@ var Mediabunny = (() => {
|
|
|
17688
17728
|
/** @internal */
|
|
17689
17729
|
async _runWorker(worker) {
|
|
17690
17730
|
while (true) {
|
|
17731
|
+
if (worker.aborted) {
|
|
17732
|
+
this._orchestrator.signalWorkerStoppedRunning(worker);
|
|
17733
|
+
return;
|
|
17734
|
+
}
|
|
17691
17735
|
const abortController = new AbortController();
|
|
17736
|
+
this._abortControllers.set(worker, abortController);
|
|
17692
17737
|
const response = await retriedFetch(
|
|
17693
17738
|
this._options.fetchFn ?? fetch,
|
|
17694
17739
|
this._url,
|
|
@@ -17700,7 +17745,7 @@ var Mediabunny = (() => {
|
|
|
17700
17745
|
signal: abortController.signal
|
|
17701
17746
|
}),
|
|
17702
17747
|
this._getRetryDelay,
|
|
17703
|
-
() =>
|
|
17748
|
+
() => abortController.signal.aborted
|
|
17704
17749
|
);
|
|
17705
17750
|
if (!response.ok) {
|
|
17706
17751
|
throw new Error(`Error fetching ${String(this._url)}: ${response.status} ${response.statusText}`);
|
|
@@ -17732,7 +17777,8 @@ var Mediabunny = (() => {
|
|
|
17732
17777
|
}
|
|
17733
17778
|
if (response.status !== 206) {
|
|
17734
17779
|
if (this._sequentialBacking) {
|
|
17735
|
-
void response.body.cancel()
|
|
17780
|
+
void response.body.cancel().catch(() => {
|
|
17781
|
+
});
|
|
17736
17782
|
return;
|
|
17737
17783
|
}
|
|
17738
17784
|
if (!this._usedForHls) {
|
|
@@ -17749,7 +17795,8 @@ var Mediabunny = (() => {
|
|
|
17749
17795
|
}
|
|
17750
17796
|
}
|
|
17751
17797
|
}
|
|
17752
|
-
this.
|
|
17798
|
+
this._abortControllers.delete(worker);
|
|
17799
|
+
this._transitionToSequentialMode(response.body, abortController);
|
|
17753
17800
|
return;
|
|
17754
17801
|
}
|
|
17755
17802
|
const reader = response.body.getReader();
|
|
@@ -17763,7 +17810,7 @@ var Mediabunny = (() => {
|
|
|
17763
17810
|
try {
|
|
17764
17811
|
readResult = await reader.read();
|
|
17765
17812
|
} catch (error) {
|
|
17766
|
-
if (
|
|
17813
|
+
if (abortController.signal.aborted) {
|
|
17767
17814
|
throw error;
|
|
17768
17815
|
}
|
|
17769
17816
|
const retryDelayInSeconds = this._getRetryDelay(1, error, this._url);
|
|
@@ -17797,7 +17844,8 @@ var Mediabunny = (() => {
|
|
|
17797
17844
|
}
|
|
17798
17845
|
}
|
|
17799
17846
|
/** @internal */
|
|
17800
|
-
_transitionToSequentialMode(body) {
|
|
17847
|
+
_transitionToSequentialMode(body, abortController) {
|
|
17848
|
+
this._sequentialAbortController = abortController;
|
|
17801
17849
|
let currentReader = body.getReader();
|
|
17802
17850
|
let streamPosition = 0;
|
|
17803
17851
|
let skipRemaining = 0;
|
|
@@ -17817,6 +17865,10 @@ var Mediabunny = (() => {
|
|
|
17817
17865
|
}
|
|
17818
17866
|
Logging._error("Error while reading response stream. Attempting to resume.", error);
|
|
17819
17867
|
await wait(1e3 * retryDelayInSeconds);
|
|
17868
|
+
this._sequentialAbortController = new AbortController();
|
|
17869
|
+
if (this._disposed) {
|
|
17870
|
+
this._sequentialAbortController.abort();
|
|
17871
|
+
}
|
|
17820
17872
|
const newResponse = await retriedFetch(
|
|
17821
17873
|
this._options.fetchFn ?? fetch,
|
|
17822
17874
|
this._url,
|
|
@@ -17824,7 +17876,8 @@ var Mediabunny = (() => {
|
|
|
17824
17876
|
headers: {
|
|
17825
17877
|
// Who knows, maybe the server honors range requests this time
|
|
17826
17878
|
Range: `bytes=${streamPosition}-`
|
|
17827
|
-
}
|
|
17879
|
+
},
|
|
17880
|
+
signal: this._sequentialAbortController.signal
|
|
17828
17881
|
}),
|
|
17829
17882
|
this._getRetryDelay,
|
|
17830
17883
|
() => this._disposed
|
|
@@ -17862,7 +17915,8 @@ var Mediabunny = (() => {
|
|
|
17862
17915
|
return;
|
|
17863
17916
|
}
|
|
17864
17917
|
},
|
|
17865
|
-
cancel: () => currentReader.cancel()
|
|
17918
|
+
cancel: () => currentReader.cancel().catch(() => {
|
|
17919
|
+
})
|
|
17866
17920
|
});
|
|
17867
17921
|
const backing = new ReadableStreamSource(wrappedStream, {
|
|
17868
17922
|
maxCacheSize: this._orchestrator.options.maxCacheSize,
|
|
@@ -17887,6 +17941,10 @@ var Mediabunny = (() => {
|
|
|
17887
17941
|
}
|
|
17888
17942
|
this._orchestrator.workers.length = 0;
|
|
17889
17943
|
this._orchestrator.queuedReads.length = 0;
|
|
17944
|
+
for (const [, otherAbortController] of this._abortControllers) {
|
|
17945
|
+
otherAbortController.abort();
|
|
17946
|
+
}
|
|
17947
|
+
this._abortControllers.clear();
|
|
17890
17948
|
for (const slice of uniqueSlices) {
|
|
17891
17949
|
const result = backing._read(slice.start, slice.start + slice.bytes.length);
|
|
17892
17950
|
if (isThenable(result)) {
|
|
@@ -17907,6 +17965,11 @@ var Mediabunny = (() => {
|
|
|
17907
17965
|
/** @internal */
|
|
17908
17966
|
_dispose() {
|
|
17909
17967
|
this._orchestrator.dispose();
|
|
17968
|
+
for (const [, abortController] of this._abortControllers) {
|
|
17969
|
+
abortController.abort();
|
|
17970
|
+
}
|
|
17971
|
+
this._abortControllers.clear();
|
|
17972
|
+
this._sequentialAbortController?.abort();
|
|
17910
17973
|
if (this._sequentialBacking) {
|
|
17911
17974
|
this._sequentialBacking._disposed = true;
|
|
17912
17975
|
this._sequentialBacking._dispose();
|
|
@@ -18062,7 +18125,8 @@ var Mediabunny = (() => {
|
|
|
18062
18125
|
if (isThenable(data)) data = await data;
|
|
18063
18126
|
if (worker.aborted) {
|
|
18064
18127
|
if (data instanceof ReadableStream) {
|
|
18065
|
-
await data.cancel()
|
|
18128
|
+
await data.cancel().catch(() => {
|
|
18129
|
+
});
|
|
18066
18130
|
}
|
|
18067
18131
|
break;
|
|
18068
18132
|
}
|
|
@@ -18307,7 +18371,8 @@ var Mediabunny = (() => {
|
|
|
18307
18371
|
}
|
|
18308
18372
|
this._pendingSlices.length = 0;
|
|
18309
18373
|
this._cache.length = 0;
|
|
18310
|
-
void this._reader?.cancel()
|
|
18374
|
+
void this._reader?.cancel().catch(() => {
|
|
18375
|
+
});
|
|
18311
18376
|
}
|
|
18312
18377
|
};
|
|
18313
18378
|
var PREFETCH_PROFILES = {
|
|
@@ -19543,16 +19608,6 @@ var Mediabunny = (() => {
|
|
|
19543
19608
|
return;
|
|
19544
19609
|
}
|
|
19545
19610
|
}
|
|
19546
|
-
const videoGroupIds = [
|
|
19547
|
-
...new Set(
|
|
19548
|
-
mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "video").map((tag) => tag.attributes.get("group-id"))
|
|
19549
|
-
)
|
|
19550
|
-
];
|
|
19551
|
-
const audioGroupIds = [
|
|
19552
|
-
...new Set(
|
|
19553
|
-
mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "audio").map((tag) => tag.attributes.get("group-id"))
|
|
19554
|
-
)
|
|
19555
|
-
];
|
|
19556
19611
|
const internalTracksByVariant = await Promise.all(variantStreams.map(async (variantStream, i) => {
|
|
19557
19612
|
const result = [];
|
|
19558
19613
|
const codecsList = variantStream.attributes.get("codecs");
|
|
@@ -19578,11 +19633,6 @@ var Mediabunny = (() => {
|
|
|
19578
19633
|
(x) => AUDIO_CODECS.includes(inferCodecFromCodecString(x))
|
|
19579
19634
|
);
|
|
19580
19635
|
if (videoGroupId !== null && !containsVideoCodecs) {
|
|
19581
|
-
if (!videoGroupIds.includes(videoGroupId)) {
|
|
19582
|
-
throw new Error(
|
|
19583
|
-
`Invalid M3U8 file; variant stream references video group "${videoGroupId}" which is not defined in any #EXT-X-MEDIA tags.`
|
|
19584
|
-
);
|
|
19585
|
-
}
|
|
19586
19636
|
const matchingVideoMediaTag = mediaTags.find((mediaTag) => {
|
|
19587
19637
|
const groupId = mediaTag.attributes.get("group-id");
|
|
19588
19638
|
const type = mediaTag.attributes.get("type");
|
|
@@ -19607,11 +19657,6 @@ var Mediabunny = (() => {
|
|
|
19607
19657
|
}
|
|
19608
19658
|
}
|
|
19609
19659
|
if (audioGroupId !== null && !containsAudioCodecs) {
|
|
19610
|
-
if (!audioGroupIds.includes(audioGroupId)) {
|
|
19611
|
-
throw new Error(
|
|
19612
|
-
`Invalid M3U8 file; variant stream references audio group "${audioGroupId}" which is not defined in any #EXT-X-MEDIA tags.`
|
|
19613
|
-
);
|
|
19614
|
-
}
|
|
19615
19660
|
const matchingAudioMediaTag = mediaTags.find((tag) => {
|
|
19616
19661
|
const groupId = tag.attributes.get("group-id");
|
|
19617
19662
|
const type = tag.attributes.get("type");
|
|
@@ -19688,11 +19733,6 @@ var Mediabunny = (() => {
|
|
|
19688
19733
|
}
|
|
19689
19734
|
});
|
|
19690
19735
|
} else {
|
|
19691
|
-
if (!videoGroupIds.includes(videoGroupId2)) {
|
|
19692
|
-
throw new Error(
|
|
19693
|
-
`Invalid M3U8 file; variant stream references video group "${videoGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`
|
|
19694
|
-
);
|
|
19695
|
-
}
|
|
19696
19736
|
for (const mediaTag of mediaTags) {
|
|
19697
19737
|
const groupId = mediaTag.attributes.get("group-id");
|
|
19698
19738
|
const type = mediaTag.attributes.get("type");
|
|
@@ -19721,8 +19761,8 @@ var Mediabunny = (() => {
|
|
|
19721
19761
|
fullPath: mediaTag.fullPath ?? variantStream.fullPath,
|
|
19722
19762
|
fullCodecString: videoCodecString,
|
|
19723
19763
|
pairingMask: 1n << BigInt(i),
|
|
19724
|
-
peakBitrate: null,
|
|
19725
|
-
averageBitrate: null,
|
|
19764
|
+
peakBitrate: mediaTag.fullPath === null ? bandwidth : null,
|
|
19765
|
+
averageBitrate: mediaTag.fullPath === null ? averageBandwidth : null,
|
|
19726
19766
|
name: mediaTag.attributes.get("name"),
|
|
19727
19767
|
hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets,
|
|
19728
19768
|
info: {
|
|
@@ -19765,11 +19805,6 @@ var Mediabunny = (() => {
|
|
|
19765
19805
|
}
|
|
19766
19806
|
});
|
|
19767
19807
|
} else {
|
|
19768
|
-
if (!audioGroupIds.includes(audioGroupId2)) {
|
|
19769
|
-
throw new Error(
|
|
19770
|
-
`Invalid M3U8 file; variant stream references audio group "${audioGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`
|
|
19771
|
-
);
|
|
19772
|
-
}
|
|
19773
19808
|
for (const mediaTag of mediaTags) {
|
|
19774
19809
|
const groupId = mediaTag.attributes.get("group-id");
|
|
19775
19810
|
const type = mediaTag.attributes.get("type");
|
|
@@ -19790,8 +19825,8 @@ var Mediabunny = (() => {
|
|
|
19790
19825
|
fullPath: mediaTag.fullPath ?? variantStream.fullPath,
|
|
19791
19826
|
fullCodecString: audioCodecString,
|
|
19792
19827
|
pairingMask: 1n << BigInt(i),
|
|
19793
|
-
peakBitrate: null,
|
|
19794
|
-
averageBitrate: null,
|
|
19828
|
+
peakBitrate: mediaTag.fullPath === null ? bandwidth : null,
|
|
19829
|
+
averageBitrate: mediaTag.fullPath === null ? averageBandwidth : null,
|
|
19795
19830
|
name: mediaTag.attributes.get("name"),
|
|
19796
19831
|
hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets,
|
|
19797
19832
|
info: {
|
|
@@ -22860,13 +22895,13 @@ var Mediabunny = (() => {
|
|
|
22860
22895
|
switch (format) {
|
|
22861
22896
|
case "u8":
|
|
22862
22897
|
case "u8-planar":
|
|
22863
|
-
return (view2, offset, value) => view2.setUint8(offset, clamp((value
|
|
22898
|
+
return (view2, offset, value) => view2.setUint8(offset, clamp(Math.round(value * 128) + 128, 0, 255));
|
|
22864
22899
|
case "s16":
|
|
22865
22900
|
case "s16-planar":
|
|
22866
|
-
return (view2, offset, value) => view2.setInt16(offset, clamp(Math.round(value *
|
|
22901
|
+
return (view2, offset, value) => view2.setInt16(offset, clamp(Math.round(value * 32768), -32768, 32767), true);
|
|
22867
22902
|
case "s32":
|
|
22868
22903
|
case "s32-planar":
|
|
22869
|
-
return (view2, offset, value) => view2.setInt32(offset, clamp(Math.round(value *
|
|
22904
|
+
return (view2, offset, value) => view2.setInt32(offset, clamp(Math.round(value * 2147483648), -2147483648, 2147483647), true);
|
|
22870
22905
|
case "f32":
|
|
22871
22906
|
case "f32-planar":
|
|
22872
22907
|
return (view2, offset, value) => view2.setFloat32(offset, value, true);
|
|
@@ -23780,7 +23815,7 @@ var Mediabunny = (() => {
|
|
|
23780
23815
|
var toUlaw = (s16) => {
|
|
23781
23816
|
const MULAW_MAX = 8191;
|
|
23782
23817
|
const MULAW_BIAS = 33;
|
|
23783
|
-
let number = s16;
|
|
23818
|
+
let number = s16 >> 2;
|
|
23784
23819
|
let mask = 4096;
|
|
23785
23820
|
let sign = 0;
|
|
23786
23821
|
let position = 12;
|
|
@@ -23811,7 +23846,7 @@ var Mediabunny = (() => {
|
|
|
23811
23846
|
}
|
|
23812
23847
|
position = ((number & 240) >> 4) + 5;
|
|
23813
23848
|
const decoded = (1 << position | (number & 15) << position - 4 | 1 << position - 5) - MULAW_BIAS;
|
|
23814
|
-
return sign === 0 ? decoded : -decoded;
|
|
23849
|
+
return (sign === 0 ? decoded : -decoded) << 2;
|
|
23815
23850
|
};
|
|
23816
23851
|
var toAlaw = (s16) => {
|
|
23817
23852
|
const ALAW_MAX = 4095;
|
|
@@ -23819,9 +23854,10 @@ var Mediabunny = (() => {
|
|
|
23819
23854
|
let sign = 0;
|
|
23820
23855
|
let position = 11;
|
|
23821
23856
|
let lsb = 0;
|
|
23822
|
-
let number = s16;
|
|
23857
|
+
let number = s16 >> 3;
|
|
23823
23858
|
if (number < 0) {
|
|
23824
|
-
number = -number;
|
|
23859
|
+
number = -number - 1;
|
|
23860
|
+
} else {
|
|
23825
23861
|
sign = 128;
|
|
23826
23862
|
}
|
|
23827
23863
|
if (number > ALAW_MAX) {
|
|
@@ -23849,7 +23885,7 @@ var Mediabunny = (() => {
|
|
|
23849
23885
|
} else {
|
|
23850
23886
|
decoded = number << 1 | 1;
|
|
23851
23887
|
}
|
|
23852
|
-
return sign === 0 ? decoded :
|
|
23888
|
+
return (sign === 0 ? -decoded : decoded) << 3;
|
|
23853
23889
|
};
|
|
23854
23890
|
|
|
23855
23891
|
// src/media-sink.ts
|
|
@@ -26056,7 +26092,6 @@ var Mediabunny = (() => {
|
|
|
26056
26092
|
super(input, backing);
|
|
26057
26093
|
/** @internal */
|
|
26058
26094
|
this._pixelAspectRatioCache = null;
|
|
26059
|
-
this._backing = backing;
|
|
26060
26095
|
}
|
|
26061
26096
|
get type() {
|
|
26062
26097
|
return "video";
|
|
@@ -26395,7 +26430,6 @@ var Mediabunny = (() => {
|
|
|
26395
26430
|
/** @internal */
|
|
26396
26431
|
constructor(input, backing) {
|
|
26397
26432
|
super(input, backing);
|
|
26398
|
-
this._backing = backing;
|
|
26399
26433
|
}
|
|
26400
26434
|
get type() {
|
|
26401
26435
|
return "audio";
|
|
@@ -26463,7 +26497,7 @@ var Mediabunny = (() => {
|
|
|
26463
26497
|
if (customAudioDecoders.some((x) => x.supports(codec, decoderConfig))) {
|
|
26464
26498
|
return true;
|
|
26465
26499
|
}
|
|
26466
|
-
if (decoderConfig.codec
|
|
26500
|
+
if (PCM_AUDIO_CODECS.includes(decoderConfig.codec)) {
|
|
26467
26501
|
return true;
|
|
26468
26502
|
} else {
|
|
26469
26503
|
if (typeof AudioDecoder === "undefined") {
|
|
@@ -27875,6 +27909,17 @@ var Mediabunny = (() => {
|
|
|
27875
27909
|
}
|
|
27876
27910
|
;
|
|
27877
27911
|
break;
|
|
27912
|
+
case "TBPM":
|
|
27913
|
+
case "TBP":
|
|
27914
|
+
{
|
|
27915
|
+
const bpmText = reader.readId3V2EncodingAndText(frameEndPos);
|
|
27916
|
+
const bpm = Number.parseInt(bpmText, 10);
|
|
27917
|
+
if (Number.isInteger(bpm)) {
|
|
27918
|
+
tags.beatsPerMinute ??= bpm;
|
|
27919
|
+
}
|
|
27920
|
+
}
|
|
27921
|
+
;
|
|
27922
|
+
break;
|
|
27878
27923
|
case "USLT":
|
|
27879
27924
|
case "ULT":
|
|
27880
27925
|
{
|
|
@@ -28204,6 +28249,13 @@ var Mediabunny = (() => {
|
|
|
28204
28249
|
}
|
|
28205
28250
|
;
|
|
28206
28251
|
break;
|
|
28252
|
+
case "beatsPerMinute":
|
|
28253
|
+
{
|
|
28254
|
+
this.writeId3V2TextFrame("TBPM", `${value}`);
|
|
28255
|
+
writtenTags.add("TBPM");
|
|
28256
|
+
}
|
|
28257
|
+
;
|
|
28258
|
+
break;
|
|
28207
28259
|
case "lyrics":
|
|
28208
28260
|
{
|
|
28209
28261
|
this.writeId3V2LyricsFrame(value);
|
|
@@ -30223,6 +30275,7 @@ var Mediabunny = (() => {
|
|
|
30223
30275
|
case "discsTotal":
|
|
30224
30276
|
case "trackNumber":
|
|
30225
30277
|
case "tracksTotal":
|
|
30278
|
+
case "beatsPerMinute":
|
|
30226
30279
|
case "images":
|
|
30227
30280
|
{
|
|
30228
30281
|
}
|
|
@@ -30305,6 +30358,20 @@ var Mediabunny = (() => {
|
|
|
30305
30358
|
}
|
|
30306
30359
|
;
|
|
30307
30360
|
break;
|
|
30361
|
+
case "beatsPerMinute":
|
|
30362
|
+
{
|
|
30363
|
+
if (!isMdta) {
|
|
30364
|
+
pairs.push({ key: "tmpo", value: box("data", [
|
|
30365
|
+
u32(21),
|
|
30366
|
+
// Type indicator
|
|
30367
|
+
u32(0),
|
|
30368
|
+
// Locale indicator
|
|
30369
|
+
u16(value)
|
|
30370
|
+
]) });
|
|
30371
|
+
}
|
|
30372
|
+
}
|
|
30373
|
+
;
|
|
30374
|
+
break;
|
|
30308
30375
|
case "lyrics":
|
|
30309
30376
|
{
|
|
30310
30377
|
pairs.push({ key: isMdta ? "lyrics" : "\xA9lyr", value: dataStringBoxLong(value) });
|
|
@@ -32768,6 +32835,13 @@ var Mediabunny = (() => {
|
|
|
32768
32835
|
}
|
|
32769
32836
|
;
|
|
32770
32837
|
break;
|
|
32838
|
+
case "beatsPerMinute":
|
|
32839
|
+
{
|
|
32840
|
+
addSimpleTag("BPM", value.toString());
|
|
32841
|
+
writtenTags.add("BPM");
|
|
32842
|
+
}
|
|
32843
|
+
;
|
|
32844
|
+
break;
|
|
32771
32845
|
case "comment":
|
|
32772
32846
|
{
|
|
32773
32847
|
addSimpleTag("COMMENT", value);
|
|
@@ -34872,6 +34946,7 @@ ${cue.notes ?? ""}`;
|
|
|
34872
34946
|
case "discNumber":
|
|
34873
34947
|
case "tracksTotal":
|
|
34874
34948
|
case "discsTotal":
|
|
34949
|
+
case "beatsPerMinute":
|
|
34875
34950
|
case "description":
|
|
34876
34951
|
case "lyrics":
|
|
34877
34952
|
case "images":
|
|
@@ -34967,7 +35042,6 @@ ${cue.notes ?? ""}`;
|
|
|
34967
35042
|
this.onSample = options.onSample;
|
|
34968
35043
|
this.bufferSizeInFrames = Math.floor(this.targetSampleRate * 5);
|
|
34969
35044
|
this.bufferSizeInSamples = this.bufferSizeInFrames * this.targetNumberOfChannels;
|
|
34970
|
-
this.outputBuffer = new Float32Array(this.bufferSizeInSamples);
|
|
34971
35045
|
}
|
|
34972
35046
|
/**
|
|
34973
35047
|
* Sets up the channel mixer to handle up/downmixing in the case where input and output channel counts don't match.
|
|
@@ -35058,6 +35132,11 @@ ${cue.notes ?? ""}`;
|
|
|
35058
35132
|
this.sourceSampleRate = audioSample.sampleRate;
|
|
35059
35133
|
this.sourceNumberOfChannels = audioSample.numberOfChannels;
|
|
35060
35134
|
this.startTime = audioSample.timestamp;
|
|
35135
|
+
const overflowFrames = Math.ceil(this.targetSampleRate / this.sourceSampleRate);
|
|
35136
|
+
this.bufferCapacityInFrames = this.bufferSizeInFrames + overflowFrames;
|
|
35137
|
+
this.outputBuffer = new Float32Array(
|
|
35138
|
+
this.bufferCapacityInFrames * this.targetNumberOfChannels
|
|
35139
|
+
);
|
|
35061
35140
|
this.tempSourceBuffer = new Float32Array(this.sourceSampleRate * this.sourceNumberOfChannels);
|
|
35062
35141
|
this.doChannelMixerSetup();
|
|
35063
35142
|
}
|
|
@@ -35075,12 +35154,12 @@ ${cue.notes ?? ""}`;
|
|
|
35075
35154
|
if (outputFrame < this.bufferStartFrame) {
|
|
35076
35155
|
continue;
|
|
35077
35156
|
}
|
|
35078
|
-
while (outputFrame >= this.bufferStartFrame + this.
|
|
35157
|
+
while (outputFrame >= this.bufferStartFrame + this.bufferCapacityInFrames) {
|
|
35079
35158
|
await this.finalizeCurrentBuffer();
|
|
35080
35159
|
this.bufferStartFrame += this.bufferSizeInFrames;
|
|
35081
35160
|
}
|
|
35082
35161
|
const bufferFrameIndex = outputFrame - this.bufferStartFrame;
|
|
35083
|
-
assert(bufferFrameIndex < this.
|
|
35162
|
+
assert(bufferFrameIndex < this.bufferCapacityInFrames);
|
|
35084
35163
|
const outputTime = outputFrame / this.targetSampleRate;
|
|
35085
35164
|
const inputTime = outputTime - inputStartTime;
|
|
35086
35165
|
const sourcePosition = inputTime * this.sourceSampleRate;
|
|
@@ -35112,7 +35191,7 @@ ${cue.notes ?? ""}`;
|
|
|
35112
35191
|
return;
|
|
35113
35192
|
}
|
|
35114
35193
|
assert(this.startTime !== null);
|
|
35115
|
-
const samplesWritten = (this.maxWrittenFrame + 1) * this.targetNumberOfChannels;
|
|
35194
|
+
const samplesWritten = Math.min(this.maxWrittenFrame + 1, this.bufferSizeInFrames) * this.targetNumberOfChannels;
|
|
35116
35195
|
const outputData = new Float32Array(samplesWritten);
|
|
35117
35196
|
outputData.set(this.outputBuffer.subarray(0, samplesWritten));
|
|
35118
35197
|
const audioSample = new AudioSample({
|
|
@@ -35123,11 +35202,15 @@ ${cue.notes ?? ""}`;
|
|
|
35123
35202
|
data: outputData
|
|
35124
35203
|
});
|
|
35125
35204
|
await this.onSample(audioSample);
|
|
35126
|
-
this.outputBuffer.
|
|
35127
|
-
this.
|
|
35205
|
+
this.outputBuffer.copyWithin(0, this.bufferSizeInSamples);
|
|
35206
|
+
this.outputBuffer.fill(0, this.outputBuffer.length - this.bufferSizeInSamples);
|
|
35207
|
+
this.maxWrittenFrame = this.maxWrittenFrame >= this.bufferSizeInFrames ? this.maxWrittenFrame - this.bufferSizeInFrames : null;
|
|
35128
35208
|
}
|
|
35129
|
-
finalize() {
|
|
35130
|
-
|
|
35209
|
+
async finalize() {
|
|
35210
|
+
while (this.maxWrittenFrame !== null) {
|
|
35211
|
+
await this.finalizeCurrentBuffer();
|
|
35212
|
+
this.bufferStartFrame += this.bufferSizeInFrames;
|
|
35213
|
+
}
|
|
35131
35214
|
}
|
|
35132
35215
|
};
|
|
35133
35216
|
|
|
@@ -35208,8 +35291,6 @@ ${cue.notes ?? ""}`;
|
|
|
35208
35291
|
/** Internal constructor. */
|
|
35209
35292
|
constructor(codec) {
|
|
35210
35293
|
super();
|
|
35211
|
-
/** @internal */
|
|
35212
|
-
this._connectedTrack = null;
|
|
35213
35294
|
if (!VIDEO_CODECS.includes(codec)) {
|
|
35214
35295
|
throw new TypeError(`Invalid video codec '${codec}'. Must be one of: ${VIDEO_CODECS.join(", ")}.`);
|
|
35215
35296
|
}
|
|
@@ -36350,8 +36431,6 @@ ${cue.notes ?? ""}`;
|
|
|
36350
36431
|
/** Internal constructor. */
|
|
36351
36432
|
constructor(codec) {
|
|
36352
36433
|
super();
|
|
36353
|
-
/** @internal */
|
|
36354
|
-
this._connectedTrack = null;
|
|
36355
36434
|
if (!AUDIO_CODECS.includes(codec)) {
|
|
36356
36435
|
throw new TypeError(`Invalid audio codec '${codec}'. Must be one of: ${AUDIO_CODECS.join(", ")}.`);
|
|
36357
36436
|
}
|
|
@@ -36596,17 +36675,20 @@ ${cue.notes ?? ""}`;
|
|
|
36596
36675
|
const outputView = new DataView(outputBuffer);
|
|
36597
36676
|
outputs.push({ frameCount, view: outputView });
|
|
36598
36677
|
}
|
|
36599
|
-
const
|
|
36600
|
-
const
|
|
36678
|
+
const isS32 = audioSample.format === "s32" || audioSample.format === "s32-planar";
|
|
36679
|
+
const readFormat = isS32 ? "s32-planar" : "f32-planar";
|
|
36680
|
+
const scale = isS32 ? 1 / 2147483648 : 1;
|
|
36681
|
+
const allocationSize = audioSample.allocationSize({ planeIndex: 0, format: readFormat });
|
|
36682
|
+
const values = isS32 ? new Int32Array(allocationSize / 4) : new Float32Array(allocationSize / 4);
|
|
36601
36683
|
for (let i = 0; i < numberOfChannels; i++) {
|
|
36602
|
-
audioSample.copyTo(
|
|
36684
|
+
audioSample.copyTo(values, { planeIndex: i, format: readFormat });
|
|
36603
36685
|
for (let j = 0; j < outputs.length; j++) {
|
|
36604
36686
|
const { frameCount, view: view2 } = outputs[j];
|
|
36605
36687
|
for (let k = 0; k < frameCount; k++) {
|
|
36606
36688
|
this.writeOutputValue(
|
|
36607
36689
|
view2,
|
|
36608
36690
|
(k * numberOfChannels + i) * this.outputSampleSize,
|
|
36609
|
-
|
|
36691
|
+
values[j * CHUNK_SIZE + k] * scale
|
|
36610
36692
|
);
|
|
36611
36693
|
}
|
|
36612
36694
|
}
|
|
@@ -36742,19 +36824,19 @@ ${cue.notes ?? ""}`;
|
|
|
36742
36824
|
case 1:
|
|
36743
36825
|
{
|
|
36744
36826
|
if (dataType === "unsigned") {
|
|
36745
|
-
this.writeOutputValue = (view2, byteOffset, value) => view2.setUint8(byteOffset, clamp((value
|
|
36827
|
+
this.writeOutputValue = (view2, byteOffset, value) => view2.setUint8(byteOffset, clamp(Math.round(value * 128) + 128, 0, 255));
|
|
36746
36828
|
} else if (dataType === "signed") {
|
|
36747
36829
|
this.writeOutputValue = (view2, byteOffset, value) => {
|
|
36748
36830
|
view2.setInt8(byteOffset, clamp(Math.round(value * 128), -128, 127));
|
|
36749
36831
|
};
|
|
36750
36832
|
} else if (dataType === "ulaw") {
|
|
36751
36833
|
this.writeOutputValue = (view2, byteOffset, value) => {
|
|
36752
|
-
const int16 = clamp(Math.
|
|
36834
|
+
const int16 = clamp(Math.round(value * 32768), -32768, 32767);
|
|
36753
36835
|
view2.setUint8(byteOffset, toUlaw(int16));
|
|
36754
36836
|
};
|
|
36755
36837
|
} else if (dataType === "alaw") {
|
|
36756
36838
|
this.writeOutputValue = (view2, byteOffset, value) => {
|
|
36757
|
-
const int16 = clamp(Math.
|
|
36839
|
+
const int16 = clamp(Math.round(value * 32768), -32768, 32767);
|
|
36758
36840
|
view2.setUint8(byteOffset, toAlaw(int16));
|
|
36759
36841
|
};
|
|
36760
36842
|
} else {
|
|
@@ -36766,9 +36848,9 @@ ${cue.notes ?? ""}`;
|
|
|
36766
36848
|
case 2:
|
|
36767
36849
|
{
|
|
36768
36850
|
if (dataType === "unsigned") {
|
|
36769
|
-
this.writeOutputValue = (view2, byteOffset, value) => view2.setUint16(byteOffset, clamp((value
|
|
36851
|
+
this.writeOutputValue = (view2, byteOffset, value) => view2.setUint16(byteOffset, clamp(Math.round(value * 32768) + 32768, 0, 65535), littleEndian);
|
|
36770
36852
|
} else if (dataType === "signed") {
|
|
36771
|
-
this.writeOutputValue = (view2, byteOffset, value) => view2.setInt16(byteOffset, clamp(Math.round(value *
|
|
36853
|
+
this.writeOutputValue = (view2, byteOffset, value) => view2.setInt16(byteOffset, clamp(Math.round(value * 32768), -32768, 32767), littleEndian);
|
|
36772
36854
|
} else {
|
|
36773
36855
|
assert(false);
|
|
36774
36856
|
}
|
|
@@ -36778,12 +36860,17 @@ ${cue.notes ?? ""}`;
|
|
|
36778
36860
|
case 3:
|
|
36779
36861
|
{
|
|
36780
36862
|
if (dataType === "unsigned") {
|
|
36781
|
-
this.writeOutputValue = (view2, byteOffset, value) => setUint24(
|
|
36863
|
+
this.writeOutputValue = (view2, byteOffset, value) => setUint24(
|
|
36864
|
+
view2,
|
|
36865
|
+
byteOffset,
|
|
36866
|
+
clamp(Math.round(value * 8388608) + 8388608, 0, 16777215),
|
|
36867
|
+
littleEndian
|
|
36868
|
+
);
|
|
36782
36869
|
} else if (dataType === "signed") {
|
|
36783
36870
|
this.writeOutputValue = (view2, byteOffset, value) => setInt24(
|
|
36784
36871
|
view2,
|
|
36785
36872
|
byteOffset,
|
|
36786
|
-
clamp(Math.round(value *
|
|
36873
|
+
clamp(Math.round(value * 8388608), -8388608, 8388607),
|
|
36787
36874
|
littleEndian
|
|
36788
36875
|
);
|
|
36789
36876
|
} else {
|
|
@@ -36795,11 +36882,15 @@ ${cue.notes ?? ""}`;
|
|
|
36795
36882
|
case 4:
|
|
36796
36883
|
{
|
|
36797
36884
|
if (dataType === "unsigned") {
|
|
36798
|
-
this.writeOutputValue = (view2, byteOffset, value) => view2.setUint32(
|
|
36885
|
+
this.writeOutputValue = (view2, byteOffset, value) => view2.setUint32(
|
|
36886
|
+
byteOffset,
|
|
36887
|
+
clamp(Math.round(value * 2147483648) + 2147483648, 0, 4294967295),
|
|
36888
|
+
littleEndian
|
|
36889
|
+
);
|
|
36799
36890
|
} else if (dataType === "signed") {
|
|
36800
36891
|
this.writeOutputValue = (view2, byteOffset, value) => view2.setInt32(
|
|
36801
36892
|
byteOffset,
|
|
36802
|
-
clamp(Math.round(value *
|
|
36893
|
+
clamp(Math.round(value * 2147483648), -2147483648, 2147483647),
|
|
36803
36894
|
littleEndian
|
|
36804
36895
|
);
|
|
36805
36896
|
} else if (dataType === "float") {
|
|
@@ -37220,8 +37311,6 @@ ${cue.notes ?? ""}`;
|
|
|
37220
37311
|
/** Internal constructor. */
|
|
37221
37312
|
constructor(codec) {
|
|
37222
37313
|
super();
|
|
37223
|
-
/** @internal */
|
|
37224
|
-
this._connectedTrack = null;
|
|
37225
37314
|
if (!SUBTITLE_CODECS.includes(codec)) {
|
|
37226
37315
|
throw new TypeError(`Invalid subtitle codec '${codec}'. Must be one of: ${SUBTITLE_CODECS.join(", ")}.`);
|
|
37227
37316
|
}
|