mediabunny 1.58.1 → 1.59.1

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.
Files changed (49) hide show
  1. package/dist/bundles/mediabunny.cjs +137 -56
  2. package/dist/bundles/mediabunny.min.cjs +12 -12
  3. package/dist/bundles/mediabunny.min.mjs +12 -12
  4. package/dist/bundles/mediabunny.mjs +137 -56
  5. package/dist/bundles/mediabunny.node.cjs +137 -56
  6. package/dist/mediabunny.d.ts +2 -0
  7. package/dist/modules/src/codec-data.d.ts.map +1 -1
  8. package/dist/modules/src/codec-data.js +15 -0
  9. package/dist/modules/src/conversion.d.ts.map +1 -1
  10. package/dist/modules/src/conversion.js +8 -1
  11. package/dist/modules/src/hls/hls-demuxer.d.ts.map +1 -1
  12. package/dist/modules/src/hls/hls-demuxer.js +4 -28
  13. package/dist/modules/src/id3.d.ts.map +1 -1
  14. package/dist/modules/src/id3.js +18 -0
  15. package/dist/modules/src/input-track.d.ts.map +1 -1
  16. package/dist/modules/src/input-track.js +0 -2
  17. package/dist/modules/src/isobmff/isobmff-boxes.js +13 -0
  18. package/dist/modules/src/isobmff/isobmff-demuxer.d.ts.map +1 -1
  19. package/dist/modules/src/isobmff/isobmff-demuxer.js +11 -2
  20. package/dist/modules/src/matroska/matroska-demuxer.d.ts.map +1 -1
  21. package/dist/modules/src/matroska/matroska-demuxer.js +40 -2
  22. package/dist/modules/src/matroska/matroska-muxer.d.ts.map +1 -1
  23. package/dist/modules/src/matroska/matroska-muxer.js +7 -0
  24. package/dist/modules/src/media-source.js +0 -6
  25. package/dist/modules/src/metadata.d.ts +2 -0
  26. package/dist/modules/src/metadata.d.ts.map +1 -1
  27. package/dist/modules/src/metadata.js +5 -0
  28. package/dist/modules/src/resample.d.ts +1 -0
  29. package/dist/modules/src/resample.d.ts.map +1 -1
  30. package/dist/modules/src/resample.js +20 -9
  31. package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
  32. package/dist/modules/src/wave/wave-muxer.d.ts.map +1 -1
  33. package/dist/modules/src/wave/wave-muxer.js +1 -0
  34. package/package.json +1 -1
  35. package/src/codec-data.ts +11 -0
  36. package/src/conversion.ts +10 -1
  37. package/src/hls/hls-demuxer.ts +6 -45
  38. package/src/id3.ts +15 -0
  39. package/src/input-track.ts +2 -6
  40. package/src/isobmff/isobmff-boxes.ts +11 -0
  41. package/src/isobmff/isobmff-demuxer.ts +11 -4
  42. package/src/matroska/matroska-demuxer.ts +49 -4
  43. package/src/matroska/matroska-muxer.ts +5 -0
  44. package/src/media-source.ts +3 -3
  45. package/src/metadata.ts +9 -0
  46. package/src/mpeg-ts/mpeg-ts-demuxer.ts +2 -2
  47. package/src/resample.ts +25 -11
  48. package/src/segmented-input.ts +2 -2
  49. 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";
@@ -10251,6 +10278,7 @@ var Mediabunny = (() => {
10251
10278
  };
10252
10279
  this.segments.push(this.currentSegment);
10253
10280
  let currentPos = segmentDataStart;
10281
+ const visitedSeekHeadPositions = /* @__PURE__ */ new Set();
10254
10282
  while (this.currentSegment.elementEndPos === null || currentPos < this.currentSegment.elementEndPos) {
10255
10283
  let slice = this.reader.requestSliceRange(currentPos, MIN_HEADER_SIZE, MAX_HEADER_SIZE);
10256
10284
  if (isThenable(slice)) slice = await slice;
@@ -10277,6 +10305,9 @@ var Mediabunny = (() => {
10277
10305
  if (metadataElementIndex !== -1) {
10278
10306
  const field = METADATA_ELEMENTS[metadataElementIndex].flag;
10279
10307
  this.currentSegment[field] = true;
10308
+ if (id === 290298740 /* SeekHead */) {
10309
+ visitedSeekHeadPositions.add(elementStartPos - segmentDataStart);
10310
+ }
10280
10311
  assertDefinedSize(size);
10281
10312
  let slice2 = this.reader.requestSlice(dataStartPos, size);
10282
10313
  if (isThenable(slice2)) slice2 = await slice2;
@@ -10305,6 +10336,32 @@ var Mediabunny = (() => {
10305
10336
  currentPos = dataStartPos + size;
10306
10337
  }
10307
10338
  }
10339
+ if (this.reader.fileSize !== null) {
10340
+ while (true) {
10341
+ const seekEntry = this.currentSegment.seekEntries.find(
10342
+ (x) => x.id === 290298740 /* SeekHead */ && !visitedSeekHeadPositions.has(x.segmentPosition)
10343
+ );
10344
+ if (!seekEntry) {
10345
+ break;
10346
+ }
10347
+ visitedSeekHeadPositions.add(seekEntry.segmentPosition);
10348
+ let slice = this.reader.requestSliceRange(
10349
+ segmentDataStart + seekEntry.segmentPosition,
10350
+ MIN_HEADER_SIZE,
10351
+ MAX_HEADER_SIZE
10352
+ );
10353
+ if (isThenable(slice)) slice = await slice;
10354
+ if (!slice) continue;
10355
+ const header = readElementHeader(slice);
10356
+ if (!header || header.id !== 290298740 /* SeekHead */) continue;
10357
+ const { size } = header;
10358
+ assertDefinedSize(size);
10359
+ let dataSlice = this.reader.requestSlice(slice.filePos, size);
10360
+ if (isThenable(dataSlice)) dataSlice = await dataSlice;
10361
+ if (!dataSlice) continue;
10362
+ this.readContiguousElements(dataSlice);
10363
+ }
10364
+ }
10308
10365
  this.currentSegment.seekEntries.sort((a, b) => a.segmentPosition - b.segmentPosition);
10309
10366
  if (this.reader.fileSize !== null) {
10310
10367
  for (const seekEntry of this.currentSegment.seekEntries) {
@@ -11608,6 +11665,15 @@ var Mediabunny = (() => {
11608
11665
  }
11609
11666
  ;
11610
11667
  break;
11668
+ case "bpm":
11669
+ {
11670
+ const bpm = Number.parseInt(value, 10);
11671
+ if (Number.isInteger(bpm) && bpm > 0) {
11672
+ metadataTags.beatsPerMinute ??= bpm;
11673
+ }
11674
+ }
11675
+ ;
11676
+ break;
11611
11677
  case "comment":
11612
11678
  {
11613
11679
  metadataTags.comment ??= value;
@@ -12060,7 +12126,6 @@ var Mediabunny = (() => {
12060
12126
  constructor(internalTrack) {
12061
12127
  super(internalTrack);
12062
12128
  this.decoderConfigPromise = null;
12063
- this.internalTrack = internalTrack;
12064
12129
  }
12065
12130
  getType() {
12066
12131
  return "video";
@@ -12154,7 +12219,6 @@ var Mediabunny = (() => {
12154
12219
  constructor(internalTrack) {
12155
12220
  super(internalTrack);
12156
12221
  this.decoderConfigPromise = null;
12157
- this.internalTrack = internalTrack;
12158
12222
  }
12159
12223
  getType() {
12160
12224
  return "audio";
@@ -19574,16 +19638,6 @@ var Mediabunny = (() => {
19574
19638
  return;
19575
19639
  }
19576
19640
  }
19577
- const videoGroupIds = [
19578
- ...new Set(
19579
- mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "video").map((tag) => tag.attributes.get("group-id"))
19580
- )
19581
- ];
19582
- const audioGroupIds = [
19583
- ...new Set(
19584
- mediaTags.filter((tag) => tag.attributes.get("type").toLowerCase() === "audio").map((tag) => tag.attributes.get("group-id"))
19585
- )
19586
- ];
19587
19641
  const internalTracksByVariant = await Promise.all(variantStreams.map(async (variantStream, i) => {
19588
19642
  const result = [];
19589
19643
  const codecsList = variantStream.attributes.get("codecs");
@@ -19609,11 +19663,6 @@ var Mediabunny = (() => {
19609
19663
  (x) => AUDIO_CODECS.includes(inferCodecFromCodecString(x))
19610
19664
  );
19611
19665
  if (videoGroupId !== null && !containsVideoCodecs) {
19612
- if (!videoGroupIds.includes(videoGroupId)) {
19613
- throw new Error(
19614
- `Invalid M3U8 file; variant stream references video group "${videoGroupId}" which is not defined in any #EXT-X-MEDIA tags.`
19615
- );
19616
- }
19617
19666
  const matchingVideoMediaTag = mediaTags.find((mediaTag) => {
19618
19667
  const groupId = mediaTag.attributes.get("group-id");
19619
19668
  const type = mediaTag.attributes.get("type");
@@ -19638,11 +19687,6 @@ var Mediabunny = (() => {
19638
19687
  }
19639
19688
  }
19640
19689
  if (audioGroupId !== null && !containsAudioCodecs) {
19641
- if (!audioGroupIds.includes(audioGroupId)) {
19642
- throw new Error(
19643
- `Invalid M3U8 file; variant stream references audio group "${audioGroupId}" which is not defined in any #EXT-X-MEDIA tags.`
19644
- );
19645
- }
19646
19690
  const matchingAudioMediaTag = mediaTags.find((tag) => {
19647
19691
  const groupId = tag.attributes.get("group-id");
19648
19692
  const type = tag.attributes.get("type");
@@ -19719,11 +19763,6 @@ var Mediabunny = (() => {
19719
19763
  }
19720
19764
  });
19721
19765
  } else {
19722
- if (!videoGroupIds.includes(videoGroupId2)) {
19723
- throw new Error(
19724
- `Invalid M3U8 file; variant stream references video group "${videoGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`
19725
- );
19726
- }
19727
19766
  for (const mediaTag of mediaTags) {
19728
19767
  const groupId = mediaTag.attributes.get("group-id");
19729
19768
  const type = mediaTag.attributes.get("type");
@@ -19752,8 +19791,8 @@ var Mediabunny = (() => {
19752
19791
  fullPath: mediaTag.fullPath ?? variantStream.fullPath,
19753
19792
  fullCodecString: videoCodecString,
19754
19793
  pairingMask: 1n << BigInt(i),
19755
- peakBitrate: null,
19756
- averageBitrate: null,
19794
+ peakBitrate: mediaTag.fullPath === null ? bandwidth : null,
19795
+ averageBitrate: mediaTag.fullPath === null ? averageBandwidth : null,
19757
19796
  name: mediaTag.attributes.get("name"),
19758
19797
  hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets,
19759
19798
  info: {
@@ -19796,11 +19835,6 @@ var Mediabunny = (() => {
19796
19835
  }
19797
19836
  });
19798
19837
  } else {
19799
- if (!audioGroupIds.includes(audioGroupId2)) {
19800
- throw new Error(
19801
- `Invalid M3U8 file; variant stream references audio group "${audioGroupId2}" which is not defined in any #EXT-X-MEDIA tags.`
19802
- );
19803
- }
19804
19838
  for (const mediaTag of mediaTags) {
19805
19839
  const groupId = mediaTag.attributes.get("group-id");
19806
19840
  const type = mediaTag.attributes.get("type");
@@ -19821,8 +19855,8 @@ var Mediabunny = (() => {
19821
19855
  fullPath: mediaTag.fullPath ?? variantStream.fullPath,
19822
19856
  fullCodecString: audioCodecString,
19823
19857
  pairingMask: 1n << BigInt(i),
19824
- peakBitrate: null,
19825
- averageBitrate: null,
19858
+ peakBitrate: mediaTag.fullPath === null ? bandwidth : null,
19859
+ averageBitrate: mediaTag.fullPath === null ? averageBandwidth : null,
19826
19860
  name: mediaTag.attributes.get("name"),
19827
19861
  hasOnlyKeyPackets: variantStream.hasOnlyKeyPackets,
19828
19862
  info: {
@@ -26088,7 +26122,6 @@ var Mediabunny = (() => {
26088
26122
  super(input, backing);
26089
26123
  /** @internal */
26090
26124
  this._pixelAspectRatioCache = null;
26091
- this._backing = backing;
26092
26125
  }
26093
26126
  get type() {
26094
26127
  return "video";
@@ -26427,7 +26460,6 @@ var Mediabunny = (() => {
26427
26460
  /** @internal */
26428
26461
  constructor(input, backing) {
26429
26462
  super(input, backing);
26430
- this._backing = backing;
26431
26463
  }
26432
26464
  get type() {
26433
26465
  return "audio";
@@ -27907,6 +27939,17 @@ var Mediabunny = (() => {
27907
27939
  }
27908
27940
  ;
27909
27941
  break;
27942
+ case "TBPM":
27943
+ case "TBP":
27944
+ {
27945
+ const bpmText = reader.readId3V2EncodingAndText(frameEndPos);
27946
+ const bpm = Number.parseInt(bpmText, 10);
27947
+ if (Number.isInteger(bpm)) {
27948
+ tags.beatsPerMinute ??= bpm;
27949
+ }
27950
+ }
27951
+ ;
27952
+ break;
27910
27953
  case "USLT":
27911
27954
  case "ULT":
27912
27955
  {
@@ -28236,6 +28279,13 @@ var Mediabunny = (() => {
28236
28279
  }
28237
28280
  ;
28238
28281
  break;
28282
+ case "beatsPerMinute":
28283
+ {
28284
+ this.writeId3V2TextFrame("TBPM", `${value}`);
28285
+ writtenTags.add("TBPM");
28286
+ }
28287
+ ;
28288
+ break;
28239
28289
  case "lyrics":
28240
28290
  {
28241
28291
  this.writeId3V2LyricsFrame(value);
@@ -30255,6 +30305,7 @@ var Mediabunny = (() => {
30255
30305
  case "discsTotal":
30256
30306
  case "trackNumber":
30257
30307
  case "tracksTotal":
30308
+ case "beatsPerMinute":
30258
30309
  case "images":
30259
30310
  {
30260
30311
  }
@@ -30337,6 +30388,20 @@ var Mediabunny = (() => {
30337
30388
  }
30338
30389
  ;
30339
30390
  break;
30391
+ case "beatsPerMinute":
30392
+ {
30393
+ if (!isMdta) {
30394
+ pairs.push({ key: "tmpo", value: box("data", [
30395
+ u32(21),
30396
+ // Type indicator
30397
+ u32(0),
30398
+ // Locale indicator
30399
+ u16(value)
30400
+ ]) });
30401
+ }
30402
+ }
30403
+ ;
30404
+ break;
30340
30405
  case "lyrics":
30341
30406
  {
30342
30407
  pairs.push({ key: isMdta ? "lyrics" : "\xA9lyr", value: dataStringBoxLong(value) });
@@ -32800,6 +32865,13 @@ var Mediabunny = (() => {
32800
32865
  }
32801
32866
  ;
32802
32867
  break;
32868
+ case "beatsPerMinute":
32869
+ {
32870
+ addSimpleTag("BPM", value.toString());
32871
+ writtenTags.add("BPM");
32872
+ }
32873
+ ;
32874
+ break;
32803
32875
  case "comment":
32804
32876
  {
32805
32877
  addSimpleTag("COMMENT", value);
@@ -34904,6 +34976,7 @@ ${cue.notes ?? ""}`;
34904
34976
  case "discNumber":
34905
34977
  case "tracksTotal":
34906
34978
  case "discsTotal":
34979
+ case "beatsPerMinute":
34907
34980
  case "description":
34908
34981
  case "lyrics":
34909
34982
  case "images":
@@ -34999,7 +35072,6 @@ ${cue.notes ?? ""}`;
34999
35072
  this.onSample = options.onSample;
35000
35073
  this.bufferSizeInFrames = Math.floor(this.targetSampleRate * 5);
35001
35074
  this.bufferSizeInSamples = this.bufferSizeInFrames * this.targetNumberOfChannels;
35002
- this.outputBuffer = new Float32Array(this.bufferSizeInSamples);
35003
35075
  }
35004
35076
  /**
35005
35077
  * Sets up the channel mixer to handle up/downmixing in the case where input and output channel counts don't match.
@@ -35090,6 +35162,11 @@ ${cue.notes ?? ""}`;
35090
35162
  this.sourceSampleRate = audioSample.sampleRate;
35091
35163
  this.sourceNumberOfChannels = audioSample.numberOfChannels;
35092
35164
  this.startTime = audioSample.timestamp;
35165
+ const overflowFrames = Math.ceil(this.targetSampleRate / this.sourceSampleRate);
35166
+ this.bufferCapacityInFrames = this.bufferSizeInFrames + overflowFrames;
35167
+ this.outputBuffer = new Float32Array(
35168
+ this.bufferCapacityInFrames * this.targetNumberOfChannels
35169
+ );
35093
35170
  this.tempSourceBuffer = new Float32Array(this.sourceSampleRate * this.sourceNumberOfChannels);
35094
35171
  this.doChannelMixerSetup();
35095
35172
  }
@@ -35107,12 +35184,12 @@ ${cue.notes ?? ""}`;
35107
35184
  if (outputFrame < this.bufferStartFrame) {
35108
35185
  continue;
35109
35186
  }
35110
- while (outputFrame >= this.bufferStartFrame + this.bufferSizeInFrames) {
35187
+ while (outputFrame >= this.bufferStartFrame + this.bufferCapacityInFrames) {
35111
35188
  await this.finalizeCurrentBuffer();
35112
35189
  this.bufferStartFrame += this.bufferSizeInFrames;
35113
35190
  }
35114
35191
  const bufferFrameIndex = outputFrame - this.bufferStartFrame;
35115
- assert(bufferFrameIndex < this.bufferSizeInFrames);
35192
+ assert(bufferFrameIndex < this.bufferCapacityInFrames);
35116
35193
  const outputTime = outputFrame / this.targetSampleRate;
35117
35194
  const inputTime = outputTime - inputStartTime;
35118
35195
  const sourcePosition = inputTime * this.sourceSampleRate;
@@ -35144,7 +35221,7 @@ ${cue.notes ?? ""}`;
35144
35221
  return;
35145
35222
  }
35146
35223
  assert(this.startTime !== null);
35147
- const samplesWritten = (this.maxWrittenFrame + 1) * this.targetNumberOfChannels;
35224
+ const samplesWritten = Math.min(this.maxWrittenFrame + 1, this.bufferSizeInFrames) * this.targetNumberOfChannels;
35148
35225
  const outputData = new Float32Array(samplesWritten);
35149
35226
  outputData.set(this.outputBuffer.subarray(0, samplesWritten));
35150
35227
  const audioSample = new AudioSample({
@@ -35155,11 +35232,15 @@ ${cue.notes ?? ""}`;
35155
35232
  data: outputData
35156
35233
  });
35157
35234
  await this.onSample(audioSample);
35158
- this.outputBuffer.fill(0);
35159
- this.maxWrittenFrame = null;
35235
+ this.outputBuffer.copyWithin(0, this.bufferSizeInSamples);
35236
+ this.outputBuffer.fill(0, this.outputBuffer.length - this.bufferSizeInSamples);
35237
+ this.maxWrittenFrame = this.maxWrittenFrame >= this.bufferSizeInFrames ? this.maxWrittenFrame - this.bufferSizeInFrames : null;
35160
35238
  }
35161
- finalize() {
35162
- return this.finalizeCurrentBuffer();
35239
+ async finalize() {
35240
+ while (this.maxWrittenFrame !== null) {
35241
+ await this.finalizeCurrentBuffer();
35242
+ this.bufferStartFrame += this.bufferSizeInFrames;
35243
+ }
35163
35244
  }
35164
35245
  };
35165
35246
 
@@ -35240,8 +35321,6 @@ ${cue.notes ?? ""}`;
35240
35321
  /** Internal constructor. */
35241
35322
  constructor(codec) {
35242
35323
  super();
35243
- /** @internal */
35244
- this._connectedTrack = null;
35245
35324
  if (!VIDEO_CODECS.includes(codec)) {
35246
35325
  throw new TypeError(`Invalid video codec '${codec}'. Must be one of: ${VIDEO_CODECS.join(", ")}.`);
35247
35326
  }
@@ -36382,8 +36461,6 @@ ${cue.notes ?? ""}`;
36382
36461
  /** Internal constructor. */
36383
36462
  constructor(codec) {
36384
36463
  super();
36385
- /** @internal */
36386
- this._connectedTrack = null;
36387
36464
  if (!AUDIO_CODECS.includes(codec)) {
36388
36465
  throw new TypeError(`Invalid audio codec '${codec}'. Must be one of: ${AUDIO_CODECS.join(", ")}.`);
36389
36466
  }
@@ -37264,8 +37341,6 @@ ${cue.notes ?? ""}`;
37264
37341
  /** Internal constructor. */
37265
37342
  constructor(codec) {
37266
37343
  super();
37267
- /** @internal */
37268
- this._connectedTrack = null;
37269
37344
  if (!SUBTITLE_CODECS.includes(codec)) {
37270
37345
  throw new TypeError(`Invalid subtitle codec '${codec}'. Must be one of: ${SUBTITLE_CODECS.join(", ")}.`);
37271
37346
  }
@@ -40927,6 +41002,7 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
40927
41002
  const sink = new EncodedPacketSink(track);
40928
41003
  const decoderConfig = await track.getDecoderConfig();
40929
41004
  const meta = { decoderConfig: decoderConfig ?? void 0 };
41005
+ let maxTimestamp = null;
40930
41006
  if (copyStartPacket) for await (const packet of sink.packets(copyStartPacket)) {
40931
41007
  if (this._state === "canceled") {
40932
41008
  break;
@@ -40937,8 +41013,13 @@ The @mediabunny/mp3-encoder extension package provides support for encoding MP3.
40937
41013
  if (this._copyBoundaryPolicy === "shrink" && packet.timestamp + packet.duration > this._endTimestamp) {
40938
41014
  break;
40939
41015
  }
41016
+ const packetTimestamp = packet.timestamp + this._timestampOffset;
41017
+ if (maxTimestamp !== null && packetTimestamp < maxTimestamp) {
41018
+ continue;
41019
+ }
41020
+ maxTimestamp = packetTimestamp;
40940
41021
  const modifiedPacket = packet.clone({
40941
- timestamp: packet.timestamp + this._timestampOffset,
41022
+ timestamp: packetTimestamp,
40942
41023
  duration: packet.duration
40943
41024
  });
40944
41025
  this._reportProgress(outputTrackId, modifiedPacket.timestamp + modifiedPacket.duration);