mediabunny 1.15.2 → 1.16.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 (45) hide show
  1. package/README.md +4 -0
  2. package/dist/bundles/mediabunny.cjs +253 -42
  3. package/dist/bundles/mediabunny.min.cjs +4 -4
  4. package/dist/bundles/mediabunny.min.mjs +4 -4
  5. package/dist/bundles/mediabunny.mjs +253 -42
  6. package/dist/mediabunny.d.ts +21 -1
  7. package/dist/modules/src/codec-data.d.ts.map +1 -1
  8. package/dist/modules/src/codec-data.js +2 -2
  9. package/dist/modules/src/isobmff/isobmff-boxes.d.ts +3 -1
  10. package/dist/modules/src/isobmff/isobmff-boxes.d.ts.map +1 -1
  11. package/dist/modules/src/isobmff/isobmff-boxes.js +4 -2
  12. package/dist/modules/src/isobmff/isobmff-muxer.d.ts +4 -1
  13. package/dist/modules/src/isobmff/isobmff-muxer.d.ts.map +1 -1
  14. package/dist/modules/src/isobmff/isobmff-muxer.js +100 -12
  15. package/dist/modules/src/matroska/ebml.d.ts +9 -1
  16. package/dist/modules/src/matroska/ebml.d.ts.map +1 -1
  17. package/dist/modules/src/matroska/ebml.js +8 -0
  18. package/dist/modules/src/matroska/matroska-demuxer.d.ts +30 -2
  19. package/dist/modules/src/matroska/matroska-demuxer.d.ts.map +1 -1
  20. package/dist/modules/src/matroska/matroska-demuxer.js +180 -14
  21. package/dist/modules/src/matroska/matroska-muxer.d.ts.map +1 -1
  22. package/dist/modules/src/matroska/matroska-muxer.js +2 -4
  23. package/dist/modules/src/muxer.js +3 -3
  24. package/dist/modules/src/ogg/ogg-demuxer.js +1 -1
  25. package/dist/modules/src/output-format.d.ts +6 -1
  26. package/dist/modules/src/output-format.d.ts.map +1 -1
  27. package/dist/modules/src/output-format.js +3 -2
  28. package/dist/modules/src/output.d.ts +15 -0
  29. package/dist/modules/src/output.d.ts.map +1 -1
  30. package/dist/modules/src/output.js +4 -0
  31. package/dist/modules/src/reader.d.ts.map +1 -1
  32. package/dist/modules/src/reader.js +4 -4
  33. package/dist/modules/src/tsconfig.tsbuildinfo +1 -1
  34. package/package.json +1 -1
  35. package/src/codec-data.ts +2 -1
  36. package/src/isobmff/isobmff-boxes.ts +5 -5
  37. package/src/isobmff/isobmff-muxer.ts +123 -14
  38. package/src/matroska/ebml.ts +8 -0
  39. package/src/matroska/matroska-demuxer.ts +194 -15
  40. package/src/matroska/matroska-muxer.ts +2 -4
  41. package/src/muxer.ts +3 -3
  42. package/src/ogg/ogg-demuxer.ts +1 -1
  43. package/src/output-format.ts +13 -3
  44. package/src/output.ts +21 -0
  45. package/src/reader.ts +5 -4
package/README.md CHANGED
@@ -39,6 +39,10 @@ Mediabunny is a JavaScript library for reading, writing, and converting media fi
39
39
  <a href="https://www.reactvideoeditor.com/" target="_blank">
40
40
  <img src="./docs/public/sponsors/rve.svg" width="40" height="40" alt="React Video Editor">
41
41
  </a>
42
+ &nbsp;&nbsp;&nbsp;&nbsp;
43
+ <a href="https://www.mux.com/" target="_blank">
44
+ <img src="./docs/public/sponsors/mux.jpg" width="40" height="40" alt="Mux">
45
+ </a>
42
46
  </div>
43
47
 
44
48
  [Sponsor Mediabunny's development](https://github.com/sponsors/Vanilagy)
@@ -1610,7 +1610,7 @@ var Mediabunny = (() => {
1610
1610
  }
1611
1611
  if (timestampInSeconds < timestampInfo.maxTimestampBeforeLastKeyFrame) {
1612
1612
  throw new Error(
1613
- `Timestamps cannot be smaller than the highest timestamp of the previous run (a run begins with a key frame and ends right before the next key frame). Got ${timestampInSeconds}s, but highest timestamp is ${timestampInfo.maxTimestampBeforeLastKeyFrame}s.`
1613
+ `Timestamps cannot be smaller than the highest timestamp of the previous GOP (a GOP begins with a key frame and ends right before the next key frame). Got ${timestampInSeconds}s, but highest timestamp is ${timestampInfo.maxTimestampBeforeLastKeyFrame}s.`
1614
1614
  );
1615
1615
  }
1616
1616
  timestampInfo.maxTimestamp = Math.max(timestampInfo.maxTimestamp, timestampInSeconds);
@@ -1812,7 +1812,7 @@ var Mediabunny = (() => {
1812
1812
  } else if (lengthSize === 2) {
1813
1813
  nalUnitLength = dataView.getUint16(offset, false);
1814
1814
  } else if (lengthSize === 3) {
1815
- nalUnitLength = (dataView.getUint16(offset, false) << 8) + dataView.getUint8(offset + 2);
1815
+ nalUnitLength = getUint24(dataView, offset, false);
1816
1816
  } else if (lengthSize === 4) {
1817
1817
  nalUnitLength = dataView.getUint32(offset, false);
1818
1818
  } else {
@@ -3077,10 +3077,11 @@ var Mediabunny = (() => {
3077
3077
  ]);
3078
3078
  };
3079
3079
  var mdat = (reserveLargeSize) => ({ type: "mdat", largeSize: reserveLargeSize });
3080
- var moov = (muxer, fragmented = false) => box("moov", void 0, [
3080
+ var free = (size) => ({ type: "free", size });
3081
+ var moov = (muxer) => box("moov", void 0, [
3081
3082
  mvhd(muxer.creationTime, muxer.trackDatas),
3082
3083
  ...muxer.trackDatas.map((x) => trak(x, muxer.creationTime)),
3083
- fragmented ? mvex(muxer.trackDatas) : null,
3084
+ muxer.isFragmented ? mvex(muxer.trackDatas) : null,
3084
3085
  udta(muxer)
3085
3086
  ]);
3086
3087
  var mvhd = (creationTime, trackDatas) => {
@@ -4883,9 +4884,9 @@ var Mediabunny = (() => {
4883
4884
  return value;
4884
4885
  };
4885
4886
  var readU24Be = (slice) => {
4886
- const high = readU16Be(slice);
4887
- const low = readU8(slice);
4888
- return high * 256 + low;
4887
+ const value = getUint24(slice.view, slice.bufferPos, false);
4888
+ slice.bufferPos += 3;
4889
+ return value;
4889
4890
  };
4890
4891
  var readI16Be = (slice) => {
4891
4892
  const value = slice.view.getInt16(slice.bufferPos, false);
@@ -5054,6 +5055,7 @@ var Mediabunny = (() => {
5054
5055
  this.auxWriter = this.auxTarget._createWriter();
5055
5056
  this.auxBoxWriter = new IsobmffBoxWriter(this.auxWriter);
5056
5057
  this.mdat = null;
5058
+ this.ftypSize = null;
5057
5059
  this.trackDatas = [];
5058
5060
  this.allTracksKnown = promiseWithResolvers();
5059
5061
  this.creationTime = Math.floor(Date.now() / 1e3) + TIMESTAMP_OFFSET;
@@ -5090,8 +5092,16 @@ var Mediabunny = (() => {
5090
5092
  this.format._options.onFtyp(data, start);
5091
5093
  }
5092
5094
  }
5095
+ this.ftypSize = this.writer.getPos();
5093
5096
  if (this.fastStart === "in-memory") {
5094
- this.mdat = mdat(false);
5097
+ } else if (this.fastStart === "reserve") {
5098
+ for (const track of this.output._tracks) {
5099
+ if (track.metadata.maximumPacketCount === void 0) {
5100
+ throw new Error(
5101
+ "All tracks must specify maximumPacketCount in their metadata when using fastStart: 'reserve'."
5102
+ );
5103
+ }
5104
+ }
5095
5105
  } else if (this.isFragmented) {
5096
5106
  } else {
5097
5107
  if (this.format._options.onMdat) {
@@ -5548,6 +5558,8 @@ var Mediabunny = (() => {
5548
5558
  if (this.isFragmented) {
5549
5559
  trackData.sampleQueue.push(sample);
5550
5560
  await this.interleaveSamples();
5561
+ } else if (this.fastStart === "reserve") {
5562
+ await this.registerSampleFastStartReserve(trackData, sample);
5551
5563
  } else {
5552
5564
  await this.addSampleToTrack(trackData, sample);
5553
5565
  }
@@ -5555,6 +5567,15 @@ var Mediabunny = (() => {
5555
5567
  async addSampleToTrack(trackData, sample) {
5556
5568
  if (!this.isFragmented) {
5557
5569
  trackData.samples.push(sample);
5570
+ if (this.fastStart === "reserve") {
5571
+ const maximumPacketCount = trackData.track.metadata.maximumPacketCount;
5572
+ assert(maximumPacketCount !== void 0);
5573
+ if (trackData.samples.length > maximumPacketCount) {
5574
+ throw new Error(
5575
+ `Track #${trackData.track.id} has already reached the maximum packet count (${maximumPacketCount}). Either add less packets or increase the maximum packet count.`
5576
+ );
5577
+ }
5578
+ }
5558
5579
  }
5559
5580
  let beginNewChunk = false;
5560
5581
  if (!trackData.currentChunk) {
@@ -5631,10 +5652,8 @@ var Mediabunny = (() => {
5631
5652
  }
5632
5653
  async interleaveSamples(isFinalCall = false) {
5633
5654
  assert(this.isFragmented);
5634
- if (!isFinalCall) {
5635
- if (!this.allTracksAreKnown()) {
5636
- return;
5637
- }
5655
+ if (!isFinalCall && !this.allTracksAreKnown()) {
5656
+ return;
5638
5657
  }
5639
5658
  outer:
5640
5659
  while (true) {
@@ -5663,7 +5682,7 @@ var Mediabunny = (() => {
5663
5682
  if (this.format._options.onMoov) {
5664
5683
  this.writer.startTrackingWrites();
5665
5684
  }
5666
- const movieBox = moov(this, true);
5685
+ const movieBox = moov(this);
5667
5686
  this.boxWriter.writeBox(movieBox);
5668
5687
  if (this.format._options.onMoov) {
5669
5688
  const { data, start } = this.writer.stopTrackingWrites();
@@ -5727,6 +5746,46 @@ var Mediabunny = (() => {
5727
5746
  await this.writer.flush();
5728
5747
  }
5729
5748
  }
5749
+ async registerSampleFastStartReserve(trackData, sample) {
5750
+ if (this.allTracksAreKnown()) {
5751
+ if (!this.mdat) {
5752
+ const moovBox = moov(this);
5753
+ const moovSize = this.boxWriter.measureBox(moovBox);
5754
+ const reservedSize = moovSize + this.computeSampleTableSizeUpperBound() + 4096;
5755
+ assert(this.ftypSize !== null);
5756
+ this.writer.seek(this.ftypSize + reservedSize);
5757
+ if (this.format._options.onMdat) {
5758
+ this.writer.startTrackingWrites();
5759
+ }
5760
+ this.mdat = mdat(true);
5761
+ this.boxWriter.writeBox(this.mdat);
5762
+ for (const trackData2 of this.trackDatas) {
5763
+ for (const sample2 of trackData2.sampleQueue) {
5764
+ await this.addSampleToTrack(trackData2, sample2);
5765
+ }
5766
+ trackData2.sampleQueue.length = 0;
5767
+ }
5768
+ }
5769
+ await this.addSampleToTrack(trackData, sample);
5770
+ } else {
5771
+ trackData.sampleQueue.push(sample);
5772
+ }
5773
+ }
5774
+ computeSampleTableSizeUpperBound() {
5775
+ assert(this.fastStart === "reserve");
5776
+ let upperBound = 0;
5777
+ for (const trackData of this.trackDatas) {
5778
+ const n = trackData.track.metadata.maximumPacketCount;
5779
+ assert(n !== void 0);
5780
+ upperBound += (4 + 4) * Math.ceil(2 / 3 * n);
5781
+ upperBound += 4 * n;
5782
+ upperBound += (4 + 4) * Math.ceil(2 / 3 * n);
5783
+ upperBound += (4 + 4 + 4) * Math.ceil(2 / 3 * n);
5784
+ upperBound += 4 * n;
5785
+ upperBound += 8 * n;
5786
+ }
5787
+ return upperBound;
5788
+ }
5730
5789
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
5731
5790
  async onTrackClose(track) {
5732
5791
  const release = await this.mutex.acquire();
@@ -5766,7 +5825,7 @@ var Mediabunny = (() => {
5766
5825
  }
5767
5826
  }
5768
5827
  if (this.fastStart === "in-memory") {
5769
- assert(this.mdat);
5828
+ this.mdat = mdat(false);
5770
5829
  let mdatSize;
5771
5830
  for (let i = 0; i < 2; i++) {
5772
5831
  const movieBox2 = moov(this);
@@ -5828,11 +5887,22 @@ var Mediabunny = (() => {
5828
5887
  const { data, start } = this.writer.stopTrackingWrites();
5829
5888
  this.format._options.onMdat(data, start);
5830
5889
  }
5831
- if (this.format._options.onMoov) {
5832
- this.writer.startTrackingWrites();
5833
- }
5834
5890
  const movieBox = moov(this);
5835
- this.boxWriter.writeBox(movieBox);
5891
+ if (this.fastStart === "reserve") {
5892
+ assert(this.ftypSize !== null);
5893
+ this.writer.seek(this.ftypSize);
5894
+ if (this.format._options.onMoov) {
5895
+ this.writer.startTrackingWrites();
5896
+ }
5897
+ this.boxWriter.writeBox(movieBox);
5898
+ const remainingSpace = this.boxWriter.offsets.get(this.mdat) - this.writer.getPos();
5899
+ this.boxWriter.writeBox(free(remainingSpace));
5900
+ } else {
5901
+ if (this.format._options.onMoov) {
5902
+ this.writer.startTrackingWrites();
5903
+ }
5904
+ this.boxWriter.writeBox(movieBox);
5905
+ }
5836
5906
  if (this.format._options.onMoov) {
5837
5907
  const { data, start } = this.writer.stopTrackingWrites();
5838
5908
  this.format._options.onMoov(data, start);
@@ -6897,10 +6967,8 @@ ${cue.notes ?? ""}`;
6897
6967
  }
6898
6968
  }
6899
6969
  async interleaveChunks(isFinalCall = false) {
6900
- if (!isFinalCall) {
6901
- if (!this.allTracksAreKnown()) {
6902
- return;
6903
- }
6970
+ if (!isFinalCall && !this.allTracksAreKnown()) {
6971
+ return;
6904
6972
  }
6905
6973
  outer:
6906
6974
  while (true) {
@@ -12410,8 +12478,10 @@ ${cue.notes ?? ""}`;
12410
12478
  if (!options || typeof options !== "object") {
12411
12479
  throw new TypeError("options must be an object.");
12412
12480
  }
12413
- if (options.fastStart !== void 0 && ![false, "in-memory", "fragmented"].includes(options.fastStart)) {
12414
- throw new TypeError('options.fastStart, when provided, must be false, "in-memory", or "fragmented".');
12481
+ if (options.fastStart !== void 0 && ![false, "in-memory", "reserve", "fragmented"].includes(options.fastStart)) {
12482
+ throw new TypeError(
12483
+ "options.fastStart, when provided, must be false, 'in-memory', 'reserve', or 'fragmented'."
12484
+ );
12415
12485
  }
12416
12486
  if (options.minimumFragmentDuration !== void 0 && (!Number.isFinite(options.minimumFragmentDuration) || options.minimumFragmentDuration < 0)) {
12417
12487
  throw new TypeError("options.minimumFragmentDuration, when provided, must be a non-negative number.");
@@ -14381,6 +14451,9 @@ ${cue.notes ?? ""}`;
14381
14451
  if (metadata.name !== void 0 && typeof metadata.name !== "string") {
14382
14452
  throw new TypeError("metadata.name, when provided, must be a string.");
14383
14453
  }
14454
+ if (metadata.maximumPacketCount !== void 0 && (!Number.isInteger(metadata.maximumPacketCount) || metadata.maximumPacketCount < 0)) {
14455
+ throw new TypeError("metadata.maximumPacketCount, when provided, must be a non-negative integer.");
14456
+ }
14384
14457
  };
14385
14458
  var Output = class {
14386
14459
  /**
@@ -18232,6 +18305,7 @@ ${cue.notes ?? ""}`;
18232
18305
  this.currentCluster = null;
18233
18306
  this.currentBlock = null;
18234
18307
  this.currentCueTime = null;
18308
+ this.currentDecodingInstruction = null;
18235
18309
  this.currentTagTargetIsMovie = true;
18236
18310
  this.currentSimpleTagName = null;
18237
18311
  this.currentAttachedFile = null;
@@ -18494,6 +18568,7 @@ ${cue.notes ?? ""}`;
18494
18568
  let dataSlice = this.reader.requestSlice(dataStartPos, size);
18495
18569
  if (dataSlice instanceof Promise) dataSlice = await dataSlice;
18496
18570
  const cluster = {
18571
+ segment,
18497
18572
  elementStartPos,
18498
18573
  elementEndPos: dataStartPos + size,
18499
18574
  dataStartPos,
@@ -18506,8 +18581,8 @@ ${cue.notes ?? ""}`;
18506
18581
  if (dataSlice) {
18507
18582
  this.readContiguousElements(dataSlice);
18508
18583
  }
18509
- for (const [trackId, trackData] of cluster.trackData) {
18510
- const track = segment.tracks.find((x) => x.id === trackId) ?? null;
18584
+ for (const [, trackData] of cluster.trackData) {
18585
+ const track = trackData.track;
18511
18586
  assert(trackData.blocks.length > 0);
18512
18587
  let blockReferencesExist = false;
18513
18588
  let hasLacedBlocks = false;
@@ -18531,7 +18606,7 @@ ${cue.notes ?? ""}`;
18531
18606
  const nextEntry = trackData.presentationTimestamps[i + 1];
18532
18607
  currentBlock.duration = nextEntry.timestamp - currentBlock.timestamp;
18533
18608
  } else if (currentBlock.duration === 0) {
18534
- if (track?.defaultDuration != null) {
18609
+ if (track.defaultDuration != null) {
18535
18610
  if (currentBlock.lacing === 0 /* None */) {
18536
18611
  currentBlock.duration = track.defaultDuration;
18537
18612
  } else {
@@ -18547,12 +18622,10 @@ ${cue.notes ?? ""}`;
18547
18622
  const lastBlock = trackData.blocks[last(trackData.presentationTimestamps).blockIndex];
18548
18623
  trackData.startTimestamp = firstBlock.timestamp;
18549
18624
  trackData.endTimestamp = lastBlock.timestamp + lastBlock.duration;
18550
- if (track) {
18551
- insertSorted(track.clusters, cluster, (x) => x.elementStartPos);
18552
- const hasKeyFrame = trackData.firstKeyFrameTimestamp !== null;
18553
- if (hasKeyFrame) {
18554
- insertSorted(track.clustersWithKeyFrame, cluster, (x) => x.elementStartPos);
18555
- }
18625
+ insertSorted(track.clusters, cluster, (x) => x.elementStartPos);
18626
+ const hasKeyFrame = trackData.firstKeyFrameTimestamp !== null;
18627
+ if (hasKeyFrame) {
18628
+ insertSorted(track.clustersWithKeyFrame, cluster, (x) => x.elementStartPos);
18556
18629
  }
18557
18630
  }
18558
18631
  insertSorted(segment.clusters, cluster, (x) => x.elementStartPos);
@@ -18562,7 +18635,12 @@ ${cue.notes ?? ""}`;
18562
18635
  getTrackDataInCluster(cluster, trackNumber) {
18563
18636
  let trackData = cluster.trackData.get(trackNumber);
18564
18637
  if (!trackData) {
18638
+ const track = cluster.segment.tracks.find((x) => x.id === trackNumber);
18639
+ if (!track) {
18640
+ return null;
18641
+ }
18565
18642
  trackData = {
18643
+ track,
18566
18644
  startTimestamp: 0,
18567
18645
  endTimestamp: 0,
18568
18646
  firstKeyFrameTimestamp: null,
@@ -18579,6 +18657,10 @@ ${cue.notes ?? ""}`;
18579
18657
  if (originalBlock.lacing === 0 /* None */) {
18580
18658
  continue;
18581
18659
  }
18660
+ if (!originalBlock.decoded) {
18661
+ originalBlock.data = this.decodeBlockData(track, originalBlock.data);
18662
+ originalBlock.decoded = true;
18663
+ }
18582
18664
  const slice = FileSlice.tempFromBytes(originalBlock.data);
18583
18665
  const frameSizes = [];
18584
18666
  const frameCount = readU8(slice) + 1;
@@ -18643,7 +18725,7 @@ ${cue.notes ?? ""}`;
18643
18725
  for (let i = 0; i < frameCount; i++) {
18644
18726
  const frameSize = frameSizes[i];
18645
18727
  const frameData = readBytes(slice, frameSize);
18646
- const blockDuration = originalBlock.duration || frameCount * (track?.defaultDuration ?? 0);
18728
+ const blockDuration = originalBlock.duration || frameCount * (track.defaultDuration ?? 0);
18647
18729
  const frameTimestamp = originalBlock.timestamp + blockDuration * i / frameCount;
18648
18730
  const frameDuration = blockDuration / frameCount;
18649
18731
  blocks.splice(blockIndex + i, 0, {
@@ -18652,7 +18734,8 @@ ${cue.notes ?? ""}`;
18652
18734
  isKeyFrame: originalBlock.isKeyFrame,
18653
18735
  referencedTimestamps: originalBlock.referencedTimestamps,
18654
18736
  data: frameData,
18655
- lacing: 0 /* None */
18737
+ lacing: 0 /* None */,
18738
+ decoded: true
18656
18739
  });
18657
18740
  }
18658
18741
  blockIndex += frameCount;
@@ -18776,9 +18859,16 @@ ${cue.notes ?? ""}`;
18776
18859
  defaultDuration: null,
18777
18860
  name: null,
18778
18861
  languageCode: UNDETERMINED_LANGUAGE,
18862
+ decodingInstructions: [],
18779
18863
  info: null
18780
18864
  };
18781
18865
  this.readContiguousElements(slice.slice(dataStartPos, size));
18866
+ if (this.currentTrack.decodingInstructions.some((instruction) => {
18867
+ return instruction.data?.type !== "decompress" || instruction.data.algorithm !== 3 /* HeaderStripping */;
18868
+ })) {
18869
+ console.warn(`Track #${this.currentTrack.id} has an unsupported content encoding; dropping.`);
18870
+ this.currentTrack = null;
18871
+ }
18782
18872
  if (this.currentTrack && this.currentTrack.id !== -1 && this.currentTrack.codecId && this.currentTrack.info) {
18783
18873
  const slashIndex = this.currentTrack.codecId.indexOf("/");
18784
18874
  const codecIdWithoutSuffix = slashIndex === -1 ? this.currentTrack.codecId : this.currentTrack.codecId.slice(0, slashIndex);
@@ -19129,11 +19219,14 @@ ${cue.notes ?? ""}`;
19129
19219
  if (!this.currentCluster) break;
19130
19220
  const trackNumber = readVarInt(slice);
19131
19221
  if (trackNumber === null) break;
19222
+ const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber);
19223
+ if (!trackData) break;
19132
19224
  const relativeTimestamp = readI16Be(slice);
19133
19225
  const flags = readU8(slice);
19134
19226
  const isKeyFrame = !!(flags & 128);
19135
19227
  const lacing = flags >> 1 & 3;
19136
- const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber);
19228
+ const blockData = readBytes(slice, size - (slice.filePos - dataStartPos));
19229
+ const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0;
19137
19230
  trackData.blocks.push({
19138
19231
  timestamp: relativeTimestamp,
19139
19232
  // We'll add the cluster's timestamp to this later
@@ -19141,8 +19234,9 @@ ${cue.notes ?? ""}`;
19141
19234
  // Will set later
19142
19235
  isKeyFrame,
19143
19236
  referencedTimestamps: [],
19144
- data: readBytes(slice, size - (slice.filePos - dataStartPos)),
19145
- lacing
19237
+ data: blockData,
19238
+ lacing,
19239
+ decoded: !hasDecodingInstructions
19146
19240
  });
19147
19241
  }
19148
19242
  ;
@@ -19165,10 +19259,13 @@ ${cue.notes ?? ""}`;
19165
19259
  if (!this.currentCluster) break;
19166
19260
  const trackNumber = readVarInt(slice);
19167
19261
  if (trackNumber === null) break;
19262
+ const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber);
19263
+ if (!trackData) break;
19168
19264
  const relativeTimestamp = readI16Be(slice);
19169
19265
  const flags = readU8(slice);
19170
19266
  const lacing = flags >> 1 & 3;
19171
- const trackData = this.getTrackDataInCluster(this.currentCluster, trackNumber);
19267
+ const blockData = readBytes(slice, size - (slice.filePos - dataStartPos));
19268
+ const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0;
19172
19269
  this.currentBlock = {
19173
19270
  timestamp: relativeTimestamp,
19174
19271
  // We'll add the cluster's timestamp to this later
@@ -19176,8 +19273,9 @@ ${cue.notes ?? ""}`;
19176
19273
  // Will set later
19177
19274
  isKeyFrame: true,
19178
19275
  referencedTimestamps: [],
19179
- data: readBytes(slice, size - (slice.filePos - dataStartPos)),
19180
- lacing
19276
+ data: blockData,
19277
+ lacing,
19278
+ decoded: !hasDecodingInstructions
19181
19279
  };
19182
19280
  trackData.blocks.push(this.currentBlock);
19183
19281
  }
@@ -19322,10 +19420,119 @@ ${cue.notes ?? ""}`;
19322
19420
  }
19323
19421
  ;
19324
19422
  break;
19423
+ case 28032 /* ContentEncodings */:
19424
+ {
19425
+ if (!this.currentTrack) break;
19426
+ this.readContiguousElements(slice.slice(dataStartPos, size));
19427
+ this.currentTrack.decodingInstructions.sort((a, b) => b.order - a.order);
19428
+ }
19429
+ ;
19430
+ break;
19431
+ case 25152 /* ContentEncoding */:
19432
+ {
19433
+ this.currentDecodingInstruction = {
19434
+ order: 0,
19435
+ scope: 1 /* Block */,
19436
+ data: null
19437
+ };
19438
+ this.readContiguousElements(slice.slice(dataStartPos, size));
19439
+ if (this.currentDecodingInstruction.data) {
19440
+ this.currentTrack.decodingInstructions.push(this.currentDecodingInstruction);
19441
+ }
19442
+ this.currentDecodingInstruction = null;
19443
+ }
19444
+ ;
19445
+ break;
19446
+ case 20529 /* ContentEncodingOrder */:
19447
+ {
19448
+ if (!this.currentDecodingInstruction) break;
19449
+ this.currentDecodingInstruction.order = readUnsignedInt(slice, size);
19450
+ }
19451
+ ;
19452
+ break;
19453
+ case 20530 /* ContentEncodingScope */:
19454
+ {
19455
+ if (!this.currentDecodingInstruction) break;
19456
+ this.currentDecodingInstruction.scope = readUnsignedInt(slice, size);
19457
+ }
19458
+ ;
19459
+ break;
19460
+ case 20532 /* ContentCompression */:
19461
+ {
19462
+ if (!this.currentDecodingInstruction) break;
19463
+ this.currentDecodingInstruction.data = {
19464
+ type: "decompress",
19465
+ algorithm: 0 /* Zlib */,
19466
+ settings: null
19467
+ };
19468
+ this.readContiguousElements(slice.slice(dataStartPos, size));
19469
+ }
19470
+ ;
19471
+ break;
19472
+ case 16980 /* ContentCompAlgo */:
19473
+ {
19474
+ if (this.currentDecodingInstruction?.data?.type !== "decompress") break;
19475
+ this.currentDecodingInstruction.data.algorithm = readUnsignedInt(slice, size);
19476
+ }
19477
+ ;
19478
+ break;
19479
+ case 16981 /* ContentCompSettings */:
19480
+ {
19481
+ if (this.currentDecodingInstruction?.data?.type !== "decompress") break;
19482
+ this.currentDecodingInstruction.data.settings = readBytes(slice, size);
19483
+ }
19484
+ ;
19485
+ break;
19486
+ case 20533 /* ContentEncryption */:
19487
+ {
19488
+ if (!this.currentDecodingInstruction) break;
19489
+ this.currentDecodingInstruction.data = {
19490
+ type: "decrypt"
19491
+ };
19492
+ }
19493
+ ;
19494
+ break;
19325
19495
  }
19326
19496
  slice.filePos = dataStartPos + size;
19327
19497
  return true;
19328
19498
  }
19499
+ decodeBlockData(track, rawData) {
19500
+ assert(track.decodingInstructions.length > 0);
19501
+ let currentData = rawData;
19502
+ for (const instruction of track.decodingInstructions) {
19503
+ assert(instruction.data);
19504
+ switch (instruction.data.type) {
19505
+ case "decompress":
19506
+ {
19507
+ switch (instruction.data.algorithm) {
19508
+ case 3 /* HeaderStripping */:
19509
+ {
19510
+ if (instruction.data.settings && instruction.data.settings.length > 0) {
19511
+ const prefix = instruction.data.settings;
19512
+ const newData = new Uint8Array(prefix.length + currentData.length);
19513
+ newData.set(prefix, 0);
19514
+ newData.set(currentData, prefix.length);
19515
+ currentData = newData;
19516
+ }
19517
+ }
19518
+ ;
19519
+ break;
19520
+ default:
19521
+ {
19522
+ }
19523
+ ;
19524
+ }
19525
+ }
19526
+ ;
19527
+ break;
19528
+ default:
19529
+ {
19530
+ }
19531
+ ;
19532
+ }
19533
+ }
19534
+ return currentData;
19535
+ }
19329
19536
  processTagValue(name, value) {
19330
19537
  if (!this.currentSegment?.metadataTags) return;
19331
19538
  const metadataTags = this.currentSegment.metadataTags;
@@ -19626,6 +19833,10 @@ ${cue.notes ?? ""}`;
19626
19833
  const trackData = cluster.trackData.get(this.internalTrack.id);
19627
19834
  const block = trackData.blocks[blockIndex];
19628
19835
  assert(block);
19836
+ if (!block.decoded) {
19837
+ block.data = this.internalTrack.demuxer.decodeBlockData(this.internalTrack, block.data);
19838
+ block.decoded = true;
19839
+ }
19629
19840
  const data = options.metadataOnly ? PLACEHOLDER_DATA : block.data;
19630
19841
  const timestamp = block.timestamp / this.internalTrack.segment.timestampFactor;
19631
19842
  const duration = block.duration / this.internalTrack.segment.timestampFactor;
@@ -20297,7 +20508,7 @@ ${cue.notes ?? ""}`;
20297
20508
  const description = new Uint8Array(
20298
20509
  1 + lacingValues.length + firstPacket.data.length + secondPacket.data.length + thirdPacket.data.length
20299
20510
  );
20300
- description[0] = lacingValues.length;
20511
+ description[0] = 2;
20301
20512
  description.set(
20302
20513
  lacingValues,
20303
20514
  1