mediabunny 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundles/mediabunny.cjs +79 -37
- package/dist/bundles/mediabunny.min.cjs +4 -4
- package/dist/bundles/mediabunny.min.mjs +3 -3
- package/dist/bundles/mediabunny.mjs +79 -37
- package/dist/modules/input-format.d.ts.map +1 -1
- package/dist/modules/input-format.js +5 -3
- package/dist/modules/isobmff/isobmff-demuxer.d.ts +2 -0
- package/dist/modules/isobmff/isobmff-demuxer.d.ts.map +1 -1
- package/dist/modules/isobmff/isobmff-demuxer.js +63 -28
- package/dist/modules/matroska/matroska-demuxer.d.ts.map +1 -1
- package/dist/modules/matroska/matroska-demuxer.js +7 -11
- package/dist/modules/mp3/mp3-misc.d.ts.map +1 -1
- package/dist/modules/mp3/mp3-misc.js +3 -0
- package/dist/modules/mp3/mp3-reader.js +1 -1
- package/package.json +1 -1
- package/src/input-format.ts +5 -3
- package/src/isobmff/isobmff-demuxer.ts +83 -30
- package/src/matroska/matroska-demuxer.ts +7 -12
- package/src/mp3/mp3-misc.ts +4 -0
- package/src/mp3/mp3-reader.ts +1 -1
|
@@ -6224,6 +6224,9 @@ ${cue.notes ?? ""}`;
|
|
|
6224
6224
|
return null;
|
|
6225
6225
|
}
|
|
6226
6226
|
reader.pos += 1;
|
|
6227
|
+
if (firstByte !== 255) {
|
|
6228
|
+
return null;
|
|
6229
|
+
}
|
|
6227
6230
|
if ((secondByte & 224) !== 224) {
|
|
6228
6231
|
return null;
|
|
6229
6232
|
}
|
|
@@ -11823,6 +11826,7 @@ ${cue.notes ?? ""}`;
|
|
|
11823
11826
|
fragmentLookupTable: null,
|
|
11824
11827
|
currentFragmentState: null,
|
|
11825
11828
|
fragments: [],
|
|
11829
|
+
fragmentsWithKeyFrame: [],
|
|
11826
11830
|
editListPreviousSegmentDurations: 0,
|
|
11827
11831
|
editListOffset: 0
|
|
11828
11832
|
};
|
|
@@ -11911,7 +11915,8 @@ ${cue.notes ?? ""}`;
|
|
|
11911
11915
|
continue;
|
|
11912
11916
|
}
|
|
11913
11917
|
if (mediaRate !== 1) {
|
|
11914
|
-
|
|
11918
|
+
console.warn("Unsupported edit list entry: media rate must be 1.");
|
|
11919
|
+
break;
|
|
11915
11920
|
}
|
|
11916
11921
|
track.editListPreviousSegmentDurations = previousSegmentDurations;
|
|
11917
11922
|
track.editListOffset = mediaTime;
|
|
@@ -12099,7 +12104,8 @@ ${cue.notes ?? ""}`;
|
|
|
12099
12104
|
} else if (sampleSize === 16) {
|
|
12100
12105
|
track.info.codec = "pcm-s16be";
|
|
12101
12106
|
} else {
|
|
12102
|
-
|
|
12107
|
+
console.warn(`Unsupported sample size ${sampleSize} for codec 'twos'.`);
|
|
12108
|
+
track.info.codec = null;
|
|
12103
12109
|
}
|
|
12104
12110
|
} else if (lowercaseBoxName === "sowt") {
|
|
12105
12111
|
if (sampleSize === 8) {
|
|
@@ -12107,7 +12113,8 @@ ${cue.notes ?? ""}`;
|
|
|
12107
12113
|
} else if (sampleSize === 16) {
|
|
12108
12114
|
track.info.codec = "pcm-s16";
|
|
12109
12115
|
} else {
|
|
12110
|
-
|
|
12116
|
+
console.warn(`Unsupported sample size ${sampleSize} for codec 'sowt'.`);
|
|
12117
|
+
track.info.codec = null;
|
|
12111
12118
|
}
|
|
12112
12119
|
} else if (lowercaseBoxName === "raw ") {
|
|
12113
12120
|
track.info.codec = "pcm-u8";
|
|
@@ -12327,7 +12334,8 @@ ${cue.notes ?? ""}`;
|
|
|
12327
12334
|
} else if (pcmSampleSize === 32) {
|
|
12328
12335
|
track.info.codec = "pcm-s32";
|
|
12329
12336
|
} else {
|
|
12330
|
-
|
|
12337
|
+
console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`);
|
|
12338
|
+
track.info.codec = null;
|
|
12331
12339
|
}
|
|
12332
12340
|
} else {
|
|
12333
12341
|
if (pcmSampleSize === 16) {
|
|
@@ -12337,7 +12345,8 @@ ${cue.notes ?? ""}`;
|
|
|
12337
12345
|
} else if (pcmSampleSize === 32) {
|
|
12338
12346
|
track.info.codec = "pcm-s32be";
|
|
12339
12347
|
} else {
|
|
12340
|
-
|
|
12348
|
+
console.warn(`Invalid ipcm sample size ${pcmSampleSize}.`);
|
|
12349
|
+
track.info.codec = null;
|
|
12341
12350
|
}
|
|
12342
12351
|
}
|
|
12343
12352
|
} else if (track.info.codec === "pcm-f32be") {
|
|
@@ -12347,7 +12356,8 @@ ${cue.notes ?? ""}`;
|
|
|
12347
12356
|
} else if (pcmSampleSize === 64) {
|
|
12348
12357
|
track.info.codec = "pcm-f64";
|
|
12349
12358
|
} else {
|
|
12350
|
-
|
|
12359
|
+
console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`);
|
|
12360
|
+
track.info.codec = null;
|
|
12351
12361
|
}
|
|
12352
12362
|
} else {
|
|
12353
12363
|
if (pcmSampleSize === 32) {
|
|
@@ -12355,7 +12365,8 @@ ${cue.notes ?? ""}`;
|
|
|
12355
12365
|
} else if (pcmSampleSize === 64) {
|
|
12356
12366
|
track.info.codec = "pcm-f64be";
|
|
12357
12367
|
} else {
|
|
12358
|
-
|
|
12368
|
+
console.warn(`Invalid fpcm sample size ${pcmSampleSize}.`);
|
|
12369
|
+
track.info.codec = null;
|
|
12359
12370
|
}
|
|
12360
12371
|
}
|
|
12361
12372
|
}
|
|
@@ -12505,9 +12516,24 @@ ${cue.notes ?? ""}`;
|
|
|
12505
12516
|
break;
|
|
12506
12517
|
case "stz2":
|
|
12507
12518
|
{
|
|
12508
|
-
|
|
12519
|
+
const track = this.currentTrack;
|
|
12520
|
+
assert(track);
|
|
12521
|
+
if (!track.sampleTable) {
|
|
12522
|
+
break;
|
|
12523
|
+
}
|
|
12524
|
+
this.metadataReader.pos += 4;
|
|
12525
|
+
this.metadataReader.pos += 3;
|
|
12526
|
+
const fieldSize = this.metadataReader.readU8();
|
|
12527
|
+
const sampleCount = this.metadataReader.readU32();
|
|
12528
|
+
const bytes2 = this.metadataReader.readBytes(Math.ceil(sampleCount * fieldSize / 8));
|
|
12529
|
+
const bitstream = new Bitstream(bytes2);
|
|
12530
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
12531
|
+
const sampleSize = bitstream.readBits(fieldSize);
|
|
12532
|
+
track.sampleTable.sampleSizes.push(sampleSize);
|
|
12533
|
+
}
|
|
12509
12534
|
}
|
|
12510
12535
|
;
|
|
12536
|
+
break;
|
|
12511
12537
|
case "stss":
|
|
12512
12538
|
{
|
|
12513
12539
|
const track = this.currentTrack;
|
|
@@ -12705,6 +12731,15 @@ ${cue.notes ?? ""}`;
|
|
|
12705
12731
|
(x) => x.moofOffset
|
|
12706
12732
|
);
|
|
12707
12733
|
this.currentTrack.fragments.splice(insertionIndex + 1, 0, this.currentFragment);
|
|
12734
|
+
const hasKeyFrame = trackData.firstKeyFrameTimestamp !== null;
|
|
12735
|
+
if (hasKeyFrame) {
|
|
12736
|
+
const insertionIndex2 = binarySearchLessOrEqual(
|
|
12737
|
+
this.currentTrack.fragmentsWithKeyFrame,
|
|
12738
|
+
this.currentFragment.moofOffset,
|
|
12739
|
+
(x) => x.moofOffset
|
|
12740
|
+
);
|
|
12741
|
+
this.currentTrack.fragmentsWithKeyFrame.splice(insertionIndex2 + 1, 0, this.currentFragment);
|
|
12742
|
+
}
|
|
12708
12743
|
const { currentFragmentState } = this.currentTrack;
|
|
12709
12744
|
assert(currentFragmentState);
|
|
12710
12745
|
if (currentFragmentState.startTimestamp !== null) {
|
|
@@ -12791,7 +12826,8 @@ ${cue.notes ?? ""}`;
|
|
|
12791
12826
|
assert(this.currentFragment);
|
|
12792
12827
|
assert(track.currentFragmentState);
|
|
12793
12828
|
if (this.currentFragment.trackData.has(track.id)) {
|
|
12794
|
-
|
|
12829
|
+
console.warn("Can't have two trun boxes for the same track in one fragment. Ignoring...");
|
|
12830
|
+
break;
|
|
12795
12831
|
}
|
|
12796
12832
|
const version = this.metadataReader.readU8();
|
|
12797
12833
|
const flags = this.metadataReader.readU24();
|
|
@@ -12819,6 +12855,7 @@ ${cue.notes ?? ""}`;
|
|
|
12819
12855
|
const trackData = {
|
|
12820
12856
|
startTimestamp: 0,
|
|
12821
12857
|
endTimestamp: 0,
|
|
12858
|
+
firstKeyFrameTimestamp: null,
|
|
12822
12859
|
samples: [],
|
|
12823
12860
|
presentationTimestamps: [],
|
|
12824
12861
|
startTimestampIsFinal: false
|
|
@@ -12869,11 +12906,16 @@ ${cue.notes ?? ""}`;
|
|
|
12869
12906
|
currentTimestamp += sampleDuration;
|
|
12870
12907
|
}
|
|
12871
12908
|
trackData.presentationTimestamps = trackData.samples.map((x, i) => ({ presentationTimestamp: x.presentationTimestamp, sampleIndex: i })).sort((a, b) => a.presentationTimestamp - b.presentationTimestamp);
|
|
12872
|
-
for (let i = 0; i < trackData.presentationTimestamps.length
|
|
12873
|
-
const
|
|
12874
|
-
const
|
|
12875
|
-
|
|
12876
|
-
|
|
12909
|
+
for (let i = 0; i < trackData.presentationTimestamps.length; i++) {
|
|
12910
|
+
const currentEntry = trackData.presentationTimestamps[i];
|
|
12911
|
+
const currentSample = trackData.samples[currentEntry.sampleIndex];
|
|
12912
|
+
if (trackData.firstKeyFrameTimestamp === null && currentSample.isKeyFrame) {
|
|
12913
|
+
trackData.firstKeyFrameTimestamp = currentSample.presentationTimestamp;
|
|
12914
|
+
}
|
|
12915
|
+
if (i < trackData.presentationTimestamps.length - 1) {
|
|
12916
|
+
const nextEntry = trackData.presentationTimestamps[i + 1];
|
|
12917
|
+
currentSample.duration = nextEntry.presentationTimestamp - currentEntry.presentationTimestamp;
|
|
12918
|
+
}
|
|
12877
12919
|
}
|
|
12878
12920
|
const firstSample = trackData.samples[trackData.presentationTimestamps[0].sampleIndex];
|
|
12879
12921
|
const lastSample = trackData.samples[last(trackData.presentationTimestamps).sampleIndex];
|
|
@@ -13072,7 +13114,7 @@ ${cue.notes ?? ""}`;
|
|
|
13072
13114
|
while (currentFragment.nextFragment) {
|
|
13073
13115
|
currentFragment = currentFragment.nextFragment;
|
|
13074
13116
|
const trackData2 = currentFragment.trackData.get(this.internalTrack.id);
|
|
13075
|
-
if (trackData2) {
|
|
13117
|
+
if (trackData2 && trackData2.firstKeyFrameTimestamp !== null) {
|
|
13076
13118
|
const fragmentIndex2 = binarySearchExact(
|
|
13077
13119
|
this.internalTrack.fragments,
|
|
13078
13120
|
currentFragment.moofOffset,
|
|
@@ -13080,9 +13122,7 @@ ${cue.notes ?? ""}`;
|
|
|
13080
13122
|
);
|
|
13081
13123
|
assert(fragmentIndex2 !== -1);
|
|
13082
13124
|
const keyFrameIndex = trackData2.samples.findIndex((x) => x.isKeyFrame);
|
|
13083
|
-
|
|
13084
|
-
throw new Error("Not supported: Fragment does not contain key sample.");
|
|
13085
|
-
}
|
|
13125
|
+
assert(keyFrameIndex !== -1);
|
|
13086
13126
|
return {
|
|
13087
13127
|
fragmentIndex: fragmentIndex2,
|
|
13088
13128
|
sampleIndex: keyFrameIndex,
|
|
@@ -13195,24 +13235,29 @@ ${cue.notes ?? ""}`;
|
|
|
13195
13235
|
return { fragmentIndex, sampleIndex, correctSampleFound };
|
|
13196
13236
|
}
|
|
13197
13237
|
findKeySampleInFragmentsForTimestamp(timestampInTimescale) {
|
|
13198
|
-
const
|
|
13238
|
+
const indexInKeyFrameFragments = binarySearchLessOrEqual(
|
|
13199
13239
|
// This array is technically not sorted by start timestamp, but for any reasonable file, it basically is.
|
|
13200
|
-
this.internalTrack.
|
|
13240
|
+
this.internalTrack.fragmentsWithKeyFrame,
|
|
13201
13241
|
timestampInTimescale,
|
|
13202
13242
|
(x) => x.trackData.get(this.internalTrack.id).startTimestamp
|
|
13203
13243
|
);
|
|
13244
|
+
let fragmentIndex = -1;
|
|
13204
13245
|
let sampleIndex = -1;
|
|
13205
13246
|
let correctSampleFound = false;
|
|
13206
|
-
if (
|
|
13207
|
-
const fragment = this.internalTrack.
|
|
13247
|
+
if (indexInKeyFrameFragments !== -1) {
|
|
13248
|
+
const fragment = this.internalTrack.fragmentsWithKeyFrame[indexInKeyFrameFragments];
|
|
13249
|
+
fragmentIndex = binarySearchExact(
|
|
13250
|
+
this.internalTrack.fragments,
|
|
13251
|
+
fragment.moofOffset,
|
|
13252
|
+
(x) => x.moofOffset
|
|
13253
|
+
);
|
|
13254
|
+
assert(fragmentIndex !== -1);
|
|
13208
13255
|
const trackData = fragment.trackData.get(this.internalTrack.id);
|
|
13209
13256
|
const index = findLastIndex(trackData.presentationTimestamps, (x) => {
|
|
13210
13257
|
const sample = trackData.samples[x.sampleIndex];
|
|
13211
13258
|
return sample.isKeyFrame && x.presentationTimestamp <= timestampInTimescale;
|
|
13212
13259
|
});
|
|
13213
|
-
|
|
13214
|
-
throw new Error("Not supported: Fragment does not begin with a key sample.");
|
|
13215
|
-
}
|
|
13260
|
+
assert(index !== -1);
|
|
13216
13261
|
const entry = trackData.presentationTimestamps[index];
|
|
13217
13262
|
sampleIndex = entry.sampleIndex;
|
|
13218
13263
|
correctSampleFound = timestampInTimescale < trackData.endTimestamp;
|
|
@@ -13735,20 +13780,15 @@ ${cue.notes ?? ""}`;
|
|
|
13735
13780
|
trackData.blocks = sortBlocksByReferences(trackData.blocks);
|
|
13736
13781
|
}
|
|
13737
13782
|
trackData.presentationTimestamps = trackData.blocks.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i })).sort((a, b) => a.timestamp - b.timestamp);
|
|
13738
|
-
let hasKeyFrame = false;
|
|
13739
13783
|
for (let i = 0; i < trackData.presentationTimestamps.length; i++) {
|
|
13740
|
-
const
|
|
13741
|
-
const
|
|
13742
|
-
if (
|
|
13743
|
-
|
|
13744
|
-
if (trackData.firstKeyFrameTimestamp === null && block.isKeyFrame) {
|
|
13745
|
-
trackData.firstKeyFrameTimestamp = block.timestamp;
|
|
13746
|
-
}
|
|
13784
|
+
const currentEntry = trackData.presentationTimestamps[i];
|
|
13785
|
+
const currentBlock = trackData.blocks[currentEntry.blockIndex];
|
|
13786
|
+
if (trackData.firstKeyFrameTimestamp === null && currentBlock.isKeyFrame) {
|
|
13787
|
+
trackData.firstKeyFrameTimestamp = currentBlock.timestamp;
|
|
13747
13788
|
}
|
|
13748
13789
|
if (i < trackData.presentationTimestamps.length - 1) {
|
|
13749
13790
|
const nextEntry = trackData.presentationTimestamps[i + 1];
|
|
13750
|
-
|
|
13751
|
-
block.duration = nextBlock.timestamp - block.timestamp;
|
|
13791
|
+
currentBlock.duration = nextEntry.timestamp - currentBlock.timestamp;
|
|
13752
13792
|
}
|
|
13753
13793
|
}
|
|
13754
13794
|
const firstBlock = trackData.blocks[trackData.presentationTimestamps[0].blockIndex];
|
|
@@ -13763,6 +13803,7 @@ ${cue.notes ?? ""}`;
|
|
|
13763
13803
|
(x) => x.elementStartPos
|
|
13764
13804
|
);
|
|
13765
13805
|
track.clusters.splice(insertionIndex2 + 1, 0, cluster);
|
|
13806
|
+
const hasKeyFrame = trackData.firstKeyFrameTimestamp !== null;
|
|
13766
13807
|
if (hasKeyFrame) {
|
|
13767
13808
|
const insertionIndex3 = binarySearchLessOrEqual(
|
|
13768
13809
|
track.clustersWithKeyFrame,
|
|
@@ -14801,7 +14842,7 @@ ${cue.notes ?? ""}`;
|
|
|
14801
14842
|
readNextFrameHeader(until) {
|
|
14802
14843
|
assert(this.fileSize);
|
|
14803
14844
|
until ??= this.fileSize;
|
|
14804
|
-
while (this.pos
|
|
14845
|
+
while (this.pos <= until - FRAME_HEADER_SIZE) {
|
|
14805
14846
|
const word = this.readU32();
|
|
14806
14847
|
this.pos -= 4;
|
|
14807
14848
|
const header = readFrameHeader(word, this);
|
|
@@ -15843,7 +15884,8 @@ ${cue.notes ?? ""}`;
|
|
|
15843
15884
|
return true;
|
|
15844
15885
|
}
|
|
15845
15886
|
mp3Reader.pos = firstHeader.startPos + firstHeader.totalSize;
|
|
15846
|
-
|
|
15887
|
+
await mp3Reader.reader.loadRange(mp3Reader.pos, mp3Reader.pos + FRAME_HEADER_SIZE);
|
|
15888
|
+
const secondHeader = mp3Reader.readNextFrameHeader(mp3Reader.pos + FRAME_HEADER_SIZE);
|
|
15847
15889
|
if (!secondHeader) {
|
|
15848
15890
|
return false;
|
|
15849
15891
|
}
|