@remotion/media-parser 4.0.301 → 4.0.303

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 (94) hide show
  1. package/dist/check-if-done.js +4 -0
  2. package/dist/containers/aac/parse-aac.js +1 -0
  3. package/dist/containers/avc/key.d.ts +1 -1
  4. package/dist/containers/avc/key.js +5 -1
  5. package/dist/containers/avc/max-buffer-size.d.ts +3 -0
  6. package/dist/containers/avc/max-buffer-size.js +40 -0
  7. package/dist/containers/avc/parse-avc.d.ts +6 -7
  8. package/dist/containers/avc/parse-avc.js +83 -7
  9. package/dist/containers/flac/parse-streaminfo.js +1 -0
  10. package/dist/containers/iso-base-media/base-media-box.d.ts +2 -1
  11. package/dist/containers/iso-base-media/elst.d.ts +19 -0
  12. package/dist/containers/iso-base-media/elst.js +33 -0
  13. package/dist/containers/iso-base-media/find-keyframe-before-time.d.ts +2 -1
  14. package/dist/containers/iso-base-media/find-keyframe-before-time.js +3 -3
  15. package/dist/containers/iso-base-media/get-moov-atom.js +1 -0
  16. package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.js +1 -0
  17. package/dist/containers/iso-base-media/get-seeking-byte.js +1 -0
  18. package/dist/containers/iso-base-media/make-track.d.ts +1 -1
  19. package/dist/containers/iso-base-media/make-track.js +4 -1
  20. package/dist/containers/iso-base-media/mdat/get-editlist.d.ts +5 -0
  21. package/dist/containers/iso-base-media/mdat/get-editlist.js +21 -0
  22. package/dist/containers/iso-base-media/mdat/mdat.js +8 -5
  23. package/dist/containers/iso-base-media/parse-boxes.js +1 -0
  24. package/dist/containers/iso-base-media/process-box.d.ts +2 -0
  25. package/dist/containers/iso-base-media/process-box.js +31 -4
  26. package/dist/containers/iso-base-media/traversal.d.ts +2 -0
  27. package/dist/containers/iso-base-media/traversal.js +10 -1
  28. package/dist/containers/mp3/parse-mpeg-header.js +1 -0
  29. package/dist/containers/riff/convert-queued-sample-to-mediaparser-sample.d.ts +14 -0
  30. package/dist/containers/riff/convert-queued-sample-to-mediaparser-sample.js +55 -0
  31. package/dist/containers/riff/get-seeking-byte.d.ts +3 -1
  32. package/dist/containers/riff/get-seeking-byte.js +5 -1
  33. package/dist/containers/riff/get-strh-for-index.d.ts +2 -0
  34. package/dist/containers/riff/get-strh-for-index.js +17 -0
  35. package/dist/containers/riff/get-tracks-from-avi.js +2 -0
  36. package/dist/containers/riff/parse-movi.js +51 -44
  37. package/dist/containers/riff/parse-riff-body.js +8 -0
  38. package/dist/containers/transport-stream/handle-aac-packet.js +1 -0
  39. package/dist/containers/transport-stream/handle-avc-packet.d.ts +3 -1
  40. package/dist/containers/transport-stream/handle-avc-packet.js +4 -3
  41. package/dist/containers/transport-stream/parse-transport-stream.js +1 -0
  42. package/dist/containers/transport-stream/process-audio.d.ts +3 -1
  43. package/dist/containers/transport-stream/process-audio.js +2 -1
  44. package/dist/containers/transport-stream/process-sample-if-possible.js +2 -0
  45. package/dist/containers/transport-stream/process-stream-buffers.d.ts +5 -2
  46. package/dist/containers/transport-stream/process-stream-buffers.js +4 -2
  47. package/dist/containers/transport-stream/process-video.d.ts +3 -1
  48. package/dist/containers/transport-stream/process-video.js +2 -1
  49. package/dist/containers/wav/parse-fmt.js +1 -0
  50. package/dist/containers/webm/get-sample-from-block.d.ts +3 -1
  51. package/dist/containers/webm/get-sample-from-block.js +4 -3
  52. package/dist/containers/webm/make-track.js +2 -0
  53. package/dist/containers/webm/parse-ebml.d.ts +1 -1
  54. package/dist/containers/webm/parse-ebml.js +3 -1
  55. package/dist/containers/webm/state-for-processing.d.ts +3 -1
  56. package/dist/containers/webm/state-for-processing.js +2 -1
  57. package/dist/convert-audio-or-video-sample.js +1 -0
  58. package/dist/esm/index.mjs +597 -127
  59. package/dist/esm/universal.mjs +9 -8
  60. package/dist/esm/web.mjs +9 -8
  61. package/dist/esm/worker-server-entry.mjs +596 -126
  62. package/dist/esm/worker-web-entry.mjs +596 -126
  63. package/dist/get-seeking-byte.d.ts +3 -1
  64. package/dist/get-seeking-byte.js +2 -1
  65. package/dist/get-tracks.d.ts +3 -0
  66. package/dist/get-tracks.js +10 -1
  67. package/dist/index.d.ts +34 -3
  68. package/dist/readers/from-fetch.js +2 -1
  69. package/dist/run-parse-iteration.js +0 -3
  70. package/dist/state/avc/avc-state.d.ts +12 -0
  71. package/dist/state/avc/avc-state.js +44 -0
  72. package/dist/state/iso-base-media/iso-state.d.ts +4 -0
  73. package/dist/state/iso-base-media/iso-state.js +2 -0
  74. package/dist/state/iso-base-media/timescale-state.d.ts +5 -0
  75. package/dist/state/iso-base-media/timescale-state.js +13 -0
  76. package/dist/state/parser-state.d.ts +34 -3
  77. package/dist/state/parser-state.js +3 -0
  78. package/dist/state/riff/queued-b-frames.d.ts +9 -0
  79. package/dist/state/riff/queued-b-frames.js +47 -0
  80. package/dist/state/riff/queued-frames.d.ts +9 -0
  81. package/dist/state/riff/queued-frames.js +39 -0
  82. package/dist/state/riff/riff-keyframes.js +1 -0
  83. package/dist/state/riff/sample-counter.d.ts +13 -2
  84. package/dist/state/riff/sample-counter.js +34 -7
  85. package/dist/state/riff.d.ts +19 -2
  86. package/dist/state/riff.js +3 -0
  87. package/dist/state/transport-stream/last-emitted-sample.d.ts +1 -1
  88. package/dist/state/transport-stream/transport-stream.d.ts +1 -1
  89. package/dist/version.d.ts +1 -1
  90. package/dist/version.js +1 -1
  91. package/dist/webcodec-sample-types.d.ts +11 -0
  92. package/dist/work-on-seek-request.d.ts +2 -0
  93. package/dist/work-on-seek-request.js +5 -2
  94. package/package.json +3 -3
@@ -309,14 +309,7 @@ var fetchReadContent = async ({
309
309
  throw new Error("src must be a string when using `fetchReader`");
310
310
  }
311
311
  const fallbackName = src.toString().split("/").pop();
312
- const {
313
- reader,
314
- contentLength,
315
- needsContentRange,
316
- name,
317
- supportsContentRange,
318
- contentType
319
- } = await makeFetchRequestOrGetCached({
312
+ const res = makeFetchRequestOrGetCached({
320
313
  range,
321
314
  src,
322
315
  controller,
@@ -325,6 +318,14 @@ var fetchReadContent = async ({
325
318
  });
326
319
  const key = cacheKey({ src, range });
327
320
  prefetchCache.delete(key);
321
+ const {
322
+ reader,
323
+ contentLength,
324
+ needsContentRange,
325
+ name,
326
+ supportsContentRange,
327
+ contentType
328
+ } = await res;
328
329
  if (controller) {
329
330
  controller._internals.signal.addEventListener("abort", () => {
330
331
  reader.reader.cancel().catch(() => {});
@@ -1073,6 +1074,14 @@ var getTrakBoxByTrackId = (moovBox, trackId) => {
1073
1074
  return tkhd.trackId === trackId;
1074
1075
  }) ?? null;
1075
1076
  };
1077
+ var getElstBox = (trakBox) => {
1078
+ const edtsBox = trakBox.children.find((s) => s.type === "regular-box" && s.boxType === "edts");
1079
+ if (!edtsBox || edtsBox.type !== "regular-box") {
1080
+ return null;
1081
+ }
1082
+ const elstBox = edtsBox.children.find((s) => s.type === "elst-box");
1083
+ return elstBox;
1084
+ };
1076
1085
 
1077
1086
  // src/containers/riff/traversal.ts
1078
1087
  var isRiffAvi = (structure) => {
@@ -3331,7 +3340,7 @@ var getVideoCodecFromIsoTrak = (trakBox) => {
3331
3340
  };
3332
3341
 
3333
3342
  // src/containers/iso-base-media/make-track.ts
3334
- var makeBaseMediaTrack = (trakBox) => {
3343
+ var makeBaseMediaTrack = (trakBox, startTimeInSeconds) => {
3335
3344
  const tkhdBox = getTkhdBox(trakBox);
3336
3345
  const videoDescriptors = getVideoDescriptors(trakBox);
3337
3346
  const timescaleAndDuration = getTimescaleAndDuration(trakBox);
@@ -3368,7 +3377,8 @@ var makeBaseMediaTrack = (trakBox) => {
3368
3377
  sampleRate: actual.sampleRate,
3369
3378
  description: actual.codecPrivate?.data ?? undefined,
3370
3379
  codecData: actual.codecPrivate,
3371
- codecEnum
3380
+ codecEnum,
3381
+ startInSeconds: startTimeInSeconds
3372
3382
  };
3373
3383
  }
3374
3384
  if (!trakBoxContainsVideo(trakBox)) {
@@ -3376,7 +3386,8 @@ var makeBaseMediaTrack = (trakBox) => {
3376
3386
  type: "other",
3377
3387
  trackId: tkhdBox.trackId,
3378
3388
  timescale: timescaleAndDuration.timescale,
3379
- trakBox
3389
+ trakBox,
3390
+ startInSeconds: startTimeInSeconds
3380
3391
  };
3381
3392
  }
3382
3393
  const videoSample = getStsdVideoConfig(trakBox);
@@ -3423,11 +3434,33 @@ var makeBaseMediaTrack = (trakBox) => {
3423
3434
  colorSpace: mediaParserAdvancedColorToWebCodecsColor(advancedColor),
3424
3435
  advancedColor,
3425
3436
  codecEnum: getVideoCodecFromIsoTrak(trakBox),
3426
- fps: getFpsFromMp4TrakBox(trakBox)
3437
+ fps: getFpsFromMp4TrakBox(trakBox),
3438
+ startInSeconds: startTimeInSeconds
3427
3439
  };
3428
3440
  return track;
3429
3441
  };
3430
3442
 
3443
+ // src/containers/iso-base-media/mdat/get-editlist.ts
3444
+ var findTrackStartTimeInSeconds = ({
3445
+ movieTimeScale,
3446
+ trakBox
3447
+ }) => {
3448
+ const elstBox = getElstBox(trakBox);
3449
+ if (!elstBox) {
3450
+ return 0;
3451
+ }
3452
+ const { entries } = elstBox;
3453
+ let dwellTime = 0;
3454
+ for (const entry of entries) {
3455
+ const { editDuration, mediaTime } = entry;
3456
+ if (mediaTime !== -1) {
3457
+ continue;
3458
+ }
3459
+ dwellTime += editDuration;
3460
+ }
3461
+ return dwellTime / movieTimeScale;
3462
+ };
3463
+
3431
3464
  // src/containers/avc/codec-string.ts
3432
3465
  var getCodecStringFromSpsAndPps = (sps) => {
3433
3466
  return `avc1.${sps.spsData.profile.toString(16).padStart(2, "0")}${sps.spsData.compatibility.toString(16).padStart(2, "0")}${sps.spsData.level.toString(16).padStart(2, "0")}`;
@@ -3526,7 +3559,8 @@ var makeAviAudioTrack = ({
3526
3559
  numberOfChannels: strf.numberOfChannels,
3527
3560
  sampleRate: strf.sampleRate,
3528
3561
  timescale: MEDIA_PARSER_RIFF_TIMESCALE,
3529
- trackId: index
3562
+ trackId: index,
3563
+ startInSeconds: 0
3530
3564
  };
3531
3565
  };
3532
3566
  var makeAviVideoTrack = ({
@@ -3569,7 +3603,8 @@ var makeAviVideoTrack = ({
3569
3603
  numerator: 1,
3570
3604
  denominator: 1
3571
3605
  },
3572
- fps: strh.rate / strh.scale
3606
+ fps: strh.rate / strh.scale,
3607
+ startInSeconds: 0
3573
3608
  };
3574
3609
  };
3575
3610
  var getTracksFromAvi = (structure, state) => {
@@ -4222,7 +4257,8 @@ var getTrack = ({
4222
4257
  colorSpace: mediaParserAdvancedColorToWebCodecsColor(advancedColor),
4223
4258
  advancedColor,
4224
4259
  codecEnum,
4225
- fps: null
4260
+ fps: null,
4261
+ startInSeconds: 0
4226
4262
  };
4227
4263
  }
4228
4264
  if (trackTypeToString(trackType2.value.value) === "audio") {
@@ -4244,7 +4280,8 @@ var getTrack = ({
4244
4280
  codecData: codecPrivate2 ? codecString === "opus" ? { type: "ogg-identification", data: codecPrivate2 } : { type: "unknown-data", data: codecPrivate2 } : null,
4245
4281
  codecEnum: getMatroskaAudioCodecEnum({
4246
4282
  track
4247
- })
4283
+ }),
4284
+ startInSeconds: 0
4248
4285
  };
4249
4286
  }
4250
4287
  return null;
@@ -4365,7 +4402,15 @@ var getTracksFromMoovBox = (moovBox) => {
4365
4402
  const mediaParserTracks = [];
4366
4403
  const tracks2 = getTraks(moovBox);
4367
4404
  for (const trakBox of tracks2) {
4368
- const track = makeBaseMediaTrack(trakBox);
4405
+ const mvhdBox = getMvhdBox(moovBox);
4406
+ if (!mvhdBox) {
4407
+ throw new Error("Mvhd box is not found");
4408
+ }
4409
+ const startTime = findTrackStartTimeInSeconds({
4410
+ movieTimeScale: mvhdBox.timeScale,
4411
+ trakBox
4412
+ });
4413
+ const track = makeBaseMediaTrack(trakBox, startTime);
4369
4414
  if (!track) {
4370
4415
  continue;
4371
4416
  }
@@ -5827,13 +5872,14 @@ var findKeyframeBeforeTime = ({
5827
5872
  time,
5828
5873
  timescale,
5829
5874
  mediaSections,
5830
- logLevel
5875
+ logLevel,
5876
+ startInSeconds
5831
5877
  }) => {
5832
5878
  let videoByte = 0;
5833
5879
  let videoSample = null;
5834
5880
  for (const sample of samplePositions) {
5835
- const ctsInSeconds = sample.cts / timescale;
5836
- const dtsInSeconds = sample.dts / timescale;
5881
+ const ctsInSeconds = sample.cts / timescale + startInSeconds;
5882
+ const dtsInSeconds = sample.dts / timescale + startInSeconds;
5837
5883
  if (!sample.isKeyframe) {
5838
5884
  continue;
5839
5885
  }
@@ -6078,7 +6124,8 @@ var getSeekingByteFromFragmentedMp4 = async ({
6078
6124
  time,
6079
6125
  timescale: firstTrack.timescale,
6080
6126
  logLevel,
6081
- mediaSections: info.mediaSections
6127
+ mediaSections: info.mediaSections,
6128
+ startInSeconds: firstTrack.startInSeconds
6082
6129
  });
6083
6130
  if (kf) {
6084
6131
  return {
@@ -6180,7 +6227,8 @@ var getSeekingByteFromIsoBaseMedia = ({
6180
6227
  time,
6181
6228
  timescale: track.timescale,
6182
6229
  logLevel,
6183
- mediaSections: info.mediaSections
6230
+ mediaSections: info.mediaSections,
6231
+ startInSeconds: track.startInSeconds
6184
6232
  });
6185
6233
  if (keyframe) {
6186
6234
  return Promise.resolve({
@@ -6486,7 +6534,8 @@ function findLastKeyframe({
6486
6534
  var getSeekingByteForRiff = async ({
6487
6535
  info,
6488
6536
  time,
6489
- riffState
6537
+ riffState,
6538
+ avcState
6490
6539
  }) => {
6491
6540
  const idx1Entries = await (info.hasIndex ? riffState.lazyIdx1.waitForLoaded() : Promise.resolve(null));
6492
6541
  if (idx1Entries === null) {
@@ -6500,6 +6549,8 @@ var getSeekingByteForRiff = async ({
6500
6549
  };
6501
6550
  }
6502
6551
  riffState.sampleCounter.setSamplesFromSeek(lastKeyframe.sampleCounts);
6552
+ riffState.queuedBFrames.clear();
6553
+ avcState.clear();
6503
6554
  return {
6504
6555
  type: "do-seek",
6505
6556
  byte: lastKeyframe.positionInBytes
@@ -6529,6 +6580,8 @@ var getSeekingByteForRiff = async ({
6529
6580
  throw new Error("moviOffset is null");
6530
6581
  }
6531
6582
  riffState.sampleCounter.setSamplesFromSeek(bestEntry.sampleCounts);
6583
+ riffState.queuedBFrames.clear();
6584
+ avcState.clear();
6532
6585
  return {
6533
6586
  type: "do-seek",
6534
6587
  byte: bestEntry.offset + info.moviOffset - 4
@@ -6677,7 +6730,8 @@ var convertAudioOrVideoSampleToWebCodecsTimestamps = ({
6677
6730
  trackId: sample.trackId,
6678
6731
  type: sample.type,
6679
6732
  offset: sample.offset,
6680
- timescale: TARGET_TIMESCALE
6733
+ timescale: TARGET_TIMESCALE,
6734
+ ..."avc" in sample ? { avc: sample.avc } : {}
6681
6735
  };
6682
6736
  };
6683
6737
 
@@ -6790,11 +6844,38 @@ var getKeyFrameOrDeltaFromAvcInfo = (infos) => {
6790
6844
  if (!keyOrDelta) {
6791
6845
  throw new Error("expected avc to contain info about key or delta");
6792
6846
  }
6793
- return keyOrDelta.type === "keyframe" ? "key" : "delta";
6847
+ return keyOrDelta.type === "keyframe" ? "key" : keyOrDelta.isBidirectionalFrame ? "bidirectional" : "delta";
6794
6848
  };
6795
6849
 
6796
6850
  // src/containers/avc/parse-avc.ts
6797
6851
  var Extended_SAR = 255;
6852
+ var getPoc = (iterator, sps, avcState, isReferencePicture) => {
6853
+ const { pic_order_cnt_type, log2_max_pic_order_cnt_lsb_minus4 } = sps;
6854
+ if (pic_order_cnt_type !== 0) {
6855
+ return null;
6856
+ }
6857
+ const prevPicOrderCntLsb = avcState.getPrevPicOrderCntLsb();
6858
+ const prevPicOrderCntMsb = avcState.getPrevPicOrderCntMsb();
6859
+ if (log2_max_pic_order_cnt_lsb_minus4 === null) {
6860
+ throw new Error("log2_max_pic_order_cnt_lsb_minus4 is null");
6861
+ }
6862
+ const max_pic_order_cnt_lsb = 2 ** (log2_max_pic_order_cnt_lsb_minus4 + 4);
6863
+ const pic_order_cnt_lsb = iterator.getBits(log2_max_pic_order_cnt_lsb_minus4 + 4);
6864
+ let picOrderCntMsb;
6865
+ if (pic_order_cnt_lsb < prevPicOrderCntLsb && prevPicOrderCntLsb - pic_order_cnt_lsb >= max_pic_order_cnt_lsb / 2) {
6866
+ picOrderCntMsb = prevPicOrderCntMsb + max_pic_order_cnt_lsb;
6867
+ } else if (pic_order_cnt_lsb > prevPicOrderCntLsb && pic_order_cnt_lsb - prevPicOrderCntLsb > max_pic_order_cnt_lsb / 2) {
6868
+ picOrderCntMsb = prevPicOrderCntMsb - max_pic_order_cnt_lsb;
6869
+ } else {
6870
+ picOrderCntMsb = prevPicOrderCntMsb;
6871
+ }
6872
+ const poc = picOrderCntMsb + pic_order_cnt_lsb;
6873
+ if (isReferencePicture) {
6874
+ avcState.setPrevPicOrderCntLsb(pic_order_cnt_lsb);
6875
+ avcState.setPrevPicOrderCntMsb(picOrderCntMsb);
6876
+ }
6877
+ return poc;
6878
+ };
6798
6879
  var readVuiParameters = (iterator) => {
6799
6880
  let sar_width = null;
6800
6881
  let sar_height = null;
@@ -6940,7 +7021,8 @@ var readSps = (iterator) => {
6940
7021
  frame_crop_right_offset,
6941
7022
  frame_crop_top_offset,
6942
7023
  mb_adaptive_frame_field_flag,
6943
- vui_parameters
7024
+ vui_parameters,
7025
+ pic_order_cnt_type
6944
7026
  };
6945
7027
  };
6946
7028
  var findEnd = (buffer) => {
@@ -6958,17 +7040,23 @@ var findEnd = (buffer) => {
6958
7040
  }
6959
7041
  return null;
6960
7042
  };
6961
- var inspect = (buffer) => {
7043
+ var inspect = (buffer, avcState) => {
6962
7044
  const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
6963
7045
  iterator.startReadingBits();
6964
7046
  iterator.getBits(1);
6965
- iterator.getBits(2);
7047
+ const nal_ref_idc = iterator.getBits(2);
7048
+ const isReferencePicture = nal_ref_idc !== 0;
6966
7049
  const type = iterator.getBits(5);
6967
- iterator.stopReadingBits();
6968
7050
  if (type === 7) {
7051
+ iterator.stopReadingBits();
6969
7052
  const end = findEnd(buffer);
6970
7053
  const data = readSps(iterator);
6971
7054
  const sps = buffer.slice(0, end === null ? Infinity : end);
7055
+ avcState.setSps(data);
7056
+ if (isReferencePicture) {
7057
+ avcState.setPrevPicOrderCntLsb(0);
7058
+ avcState.setPrevPicOrderCntMsb(0);
7059
+ }
6972
7060
  return {
6973
7061
  spsData: data,
6974
7062
  sps,
@@ -6976,11 +7064,31 @@ var inspect = (buffer) => {
6976
7064
  };
6977
7065
  }
6978
7066
  if (type === 5) {
7067
+ avcState.setPrevPicOrderCntLsb(0);
7068
+ avcState.setPrevPicOrderCntMsb(0);
7069
+ iterator.readExpGolomb();
7070
+ iterator.readExpGolomb();
7071
+ iterator.readExpGolomb();
7072
+ const sps = avcState.getSps();
7073
+ if (!sps) {
7074
+ throw new Error("SPS not found");
7075
+ }
7076
+ const numberOfBitsForFrameNum = sps.log2_max_frame_num_minus4 + 4;
7077
+ iterator.getBits(numberOfBitsForFrameNum);
7078
+ iterator.readExpGolomb();
7079
+ const { pic_order_cnt_type } = sps;
7080
+ let poc = null;
7081
+ if (pic_order_cnt_type === 0) {
7082
+ poc = getPoc(iterator, sps, avcState, isReferencePicture);
7083
+ }
7084
+ iterator.stopReadingBits();
6979
7085
  return {
6980
- type: "keyframe"
7086
+ type: "keyframe",
7087
+ poc
6981
7088
  };
6982
7089
  }
6983
7090
  if (type === 8) {
7091
+ iterator.stopReadingBits();
6984
7092
  const end = findEnd(buffer);
6985
7093
  const pps = buffer.slice(0, end === null ? Infinity : end);
6986
7094
  return {
@@ -6989,14 +7097,32 @@ var inspect = (buffer) => {
6989
7097
  };
6990
7098
  }
6991
7099
  if (type === 1) {
7100
+ iterator.readExpGolomb();
7101
+ const slice_type = iterator.readExpGolomb();
7102
+ const isBidirectionalFrame = slice_type === 6;
7103
+ iterator.readExpGolomb();
7104
+ const sps = avcState.getSps();
7105
+ if (!sps) {
7106
+ throw new Error("SPS not found");
7107
+ }
7108
+ const numberOfBitsForFrameNum = sps.log2_max_frame_num_minus4 + 4;
7109
+ iterator.getBits(numberOfBitsForFrameNum);
7110
+ const { pic_order_cnt_type } = sps;
7111
+ let poc = null;
7112
+ if (pic_order_cnt_type === 0) {
7113
+ poc = getPoc(iterator, sps, avcState, isReferencePicture);
7114
+ }
7115
+ iterator.stopReadingBits();
6992
7116
  return {
6993
- type: "delta-frame"
7117
+ type: "delta-frame",
7118
+ isBidirectionalFrame,
7119
+ poc
6994
7120
  };
6995
7121
  }
6996
7122
  iterator.destroy();
6997
7123
  return null;
6998
7124
  };
6999
- var parseAvc = (buffer) => {
7125
+ var parseAvc = (buffer, avcState) => {
7000
7126
  let zeroesInARow = 0;
7001
7127
  const infos = [];
7002
7128
  for (let i = 0;i < buffer.length; i++) {
@@ -7007,7 +7133,7 @@ var parseAvc = (buffer) => {
7007
7133
  }
7008
7134
  if (zeroesInARow >= 2 && val === 1) {
7009
7135
  zeroesInARow = 0;
7010
- const info = inspect(buffer.slice(i + 1, i + 100));
7136
+ const info = inspect(buffer.slice(i + 1, i + 100), avcState);
7011
7137
  if (info) {
7012
7138
  infos.push(info);
7013
7139
  if (info.type === "keyframe" || info.type === "delta-frame") {
@@ -7042,9 +7168,10 @@ var handleAvcPacket = async ({
7042
7168
  logLevel,
7043
7169
  onVideoTrack,
7044
7170
  transportStream,
7045
- makeSamplesStartAtZero
7171
+ makeSamplesStartAtZero,
7172
+ avcState
7046
7173
  }) => {
7047
- const avc = parseAvc(streamBuffer.getBuffer());
7174
+ const avc = parseAvc(streamBuffer.getBuffer(), avcState);
7048
7175
  const isTrackRegistered = sampleCallbacks.tracks.getTracks().find((t) => {
7049
7176
  return t.trackId === programId;
7050
7177
  });
@@ -7081,7 +7208,8 @@ var handleAvcPacket = async ({
7081
7208
  numerator: sampleAspectRatio.width
7082
7209
  },
7083
7210
  colorSpace: mediaParserAdvancedColorToWebCodecsColor(advancedColor),
7084
- advancedColor
7211
+ advancedColor,
7212
+ startInSeconds: 0
7085
7213
  };
7086
7214
  await registerVideoTrack({
7087
7215
  track,
@@ -7100,7 +7228,7 @@ var handleAvcPacket = async ({
7100
7228
  duration: undefined,
7101
7229
  data: streamBuffer.getBuffer(),
7102
7230
  trackId: programId,
7103
- type,
7231
+ type: type === "bidirectional" ? "delta" : type,
7104
7232
  offset,
7105
7233
  timescale: MPEG_TIMESCALE
7106
7234
  };
@@ -7167,7 +7295,8 @@ var getSeekingByte = ({
7167
7295
  m3uPlaylistContext,
7168
7296
  structure,
7169
7297
  riffState,
7170
- m3uState
7298
+ m3uState,
7299
+ avcState
7171
7300
  }) => {
7172
7301
  if (info.type === "iso-base-media-seeking-hints") {
7173
7302
  return getSeekingByteFromIsoBaseMedia({
@@ -7227,7 +7356,8 @@ var getSeekingByte = ({
7227
7356
  return getSeekingByteForRiff({
7228
7357
  info,
7229
7358
  time,
7230
- riffState
7359
+ riffState,
7360
+ avcState
7231
7361
  });
7232
7362
  }
7233
7363
  if (info.type === "mp3-seeking-hints") {
@@ -7790,7 +7920,8 @@ var turnSeekIntoByte = async ({
7790
7920
  mp3State,
7791
7921
  contentLength,
7792
7922
  aacState,
7793
- m3uState
7923
+ m3uState,
7924
+ avcState
7794
7925
  }) => {
7795
7926
  const mediaSections = mediaSectionState2.getMediaSections();
7796
7927
  if (mediaSections.length === 0) {
@@ -7836,7 +7967,8 @@ var turnSeekIntoByte = async ({
7836
7967
  m3uPlaylistContext,
7837
7968
  structure: structureState,
7838
7969
  riffState,
7839
- m3uState
7970
+ m3uState,
7971
+ avcState
7840
7972
  });
7841
7973
  return seekingByte;
7842
7974
  };
@@ -7867,7 +7999,8 @@ var getWorkOnSeekRequestOptions = (state) => {
7867
7999
  mp3State: state.mp3,
7868
8000
  aacState: state.aac,
7869
8001
  m3uState: state.m3u,
7870
- prefetchCache: state.prefetchCache
8002
+ prefetchCache: state.prefetchCache,
8003
+ avcState: state.avc
7871
8004
  };
7872
8005
  };
7873
8006
  var workOnSeekRequest = async (options) => {
@@ -7897,7 +8030,8 @@ var workOnSeekRequest = async (options) => {
7897
8030
  mp3State,
7898
8031
  aacState,
7899
8032
  prefetchCache,
7900
- m3uState
8033
+ m3uState,
8034
+ avcState
7901
8035
  } = options;
7902
8036
  const seek2 = controller._internals.seekSignal.getSeek();
7903
8037
  if (seek2 === null) {
@@ -7922,7 +8056,8 @@ var workOnSeekRequest = async (options) => {
7922
8056
  mp3State,
7923
8057
  contentLength,
7924
8058
  aacState,
7925
- m3uState
8059
+ m3uState,
8060
+ avcState
7926
8061
  });
7927
8062
  Log.trace(logLevel, `Seek action: ${JSON.stringify(resolution)}`);
7928
8063
  if (resolution.type === "intermediary-seek") {
@@ -8501,6 +8636,10 @@ var checkIfDone = async (state) => {
8501
8636
  if (state.structure.getStructure().type === "m3u" && !state.m3u.getAllChunksProcessedOverall()) {
8502
8637
  return false;
8503
8638
  }
8639
+ state.riff.queuedBFrames.flush();
8640
+ if (state.riff.queuedBFrames.hasReleasedFrames()) {
8641
+ return false;
8642
+ }
8504
8643
  Log.verbose(state.logLevel, "Reached end of file");
8505
8644
  await state.discardReadBytes(true);
8506
8645
  return true;
@@ -8579,7 +8718,8 @@ var parseAac = async (state) => {
8579
8718
  sampleRate,
8580
8719
  timescale: 1e6,
8581
8720
  trackId: 0,
8582
- type: "audio"
8721
+ type: "audio",
8722
+ startInSeconds: 0
8583
8723
  },
8584
8724
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
8585
8725
  tracks: state.callbacks.tracks,
@@ -8980,7 +9120,8 @@ var parseStreamInfo = async ({
8980
9120
  numberOfChannels: channels2,
8981
9121
  sampleRate,
8982
9122
  timescale: 1e6,
8983
- trackId: 0
9123
+ trackId: 0,
9124
+ startInSeconds: 0
8984
9125
  },
8985
9126
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
8986
9127
  tracks: state.callbacks.tracks,
@@ -9298,6 +9439,41 @@ var structureState = () => {
9298
9439
  };
9299
9440
  };
9300
9441
 
9442
+ // src/containers/iso-base-media/elst.ts
9443
+ var parseElst = ({
9444
+ iterator,
9445
+ size,
9446
+ offset
9447
+ }) => {
9448
+ const { expectNoMoreBytes } = iterator.startBox(size - 8);
9449
+ const version = iterator.getUint8();
9450
+ const flags = iterator.getUint24();
9451
+ const entryCount = iterator.getUint32();
9452
+ const entries = [];
9453
+ for (let i = 0;i < entryCount; i++) {
9454
+ const editDuration = iterator.getUint32();
9455
+ const mediaTime = iterator.getInt32();
9456
+ const mediaRateInteger = iterator.getUint16();
9457
+ const mediaRateFraction = iterator.getUint16();
9458
+ entries.push({
9459
+ editDuration,
9460
+ mediaTime,
9461
+ mediaRateInteger,
9462
+ mediaRateFraction
9463
+ });
9464
+ }
9465
+ expectNoMoreBytes();
9466
+ const result = {
9467
+ type: "elst-box",
9468
+ version,
9469
+ flags,
9470
+ entries,
9471
+ boxSize: size,
9472
+ offset
9473
+ };
9474
+ return result;
9475
+ };
9476
+
9301
9477
  // src/containers/iso-base-media/esds/decoder-specific-config.ts
9302
9478
  var parseDecoderSpecificConfig = (iterator) => {
9303
9479
  const layerTag = iterator.getUint8();
@@ -10896,6 +11072,16 @@ var processBox = async ({
10896
11072
  box: parseFtyp({ iterator, size: boxSize, offset: fileOffset })
10897
11073
  };
10898
11074
  }
11075
+ if (boxType === "elst") {
11076
+ return {
11077
+ type: "box",
11078
+ box: parseElst({
11079
+ iterator,
11080
+ size: boxSize,
11081
+ offset: fileOffset
11082
+ })
11083
+ };
11084
+ }
10899
11085
  if (boxType === "colr") {
10900
11086
  return {
10901
11087
  type: "box",
@@ -10906,9 +11092,18 @@ var processBox = async ({
10906
11092
  };
10907
11093
  }
10908
11094
  if (boxType === "mvhd") {
11095
+ const mvhdBox = parseMvhd({
11096
+ iterator,
11097
+ offset: fileOffset,
11098
+ size: boxSize
11099
+ });
11100
+ if (!onlyIfMoovAtomExpected) {
11101
+ throw new Error("State is required");
11102
+ }
11103
+ onlyIfMoovAtomExpected.movieTimeScaleState.setTrackTimescale(mvhdBox.timeScale);
10909
11104
  return {
10910
11105
  type: "box",
10911
- box: parseMvhd({ iterator, offset: fileOffset, size: boxSize })
11106
+ box: mvhdBox
10912
11107
  };
10913
11108
  }
10914
11109
  if (boxType === "tkhd") {
@@ -11076,14 +11271,19 @@ var processBox = async ({
11076
11271
  throw new Error("State is required");
11077
11272
  }
11078
11273
  const { tracks: tracks2, onAudioTrack, onVideoTrack } = onlyIfMoovAtomExpected;
11079
- const box = await parseTrak({
11274
+ const trakBox = await parseTrak({
11080
11275
  size: boxSize,
11081
11276
  offsetAtStart: fileOffset,
11082
11277
  iterator,
11083
11278
  logLevel,
11084
11279
  contentLength
11085
11280
  });
11086
- const transformedTrack = makeBaseMediaTrack(box);
11281
+ const movieTimeScale = onlyIfMoovAtomExpected.movieTimeScaleState.getTrackTimescale();
11282
+ if (movieTimeScale === null) {
11283
+ throw new Error("Movie timescale is not set");
11284
+ }
11285
+ const editList = findTrackStartTimeInSeconds({ movieTimeScale, trakBox });
11286
+ const transformedTrack = makeBaseMediaTrack(trakBox, editList);
11087
11287
  if (transformedTrack && transformedTrack.type === "video") {
11088
11288
  await registerVideoTrack({
11089
11289
  track: transformedTrack,
@@ -11104,7 +11304,7 @@ var processBox = async ({
11104
11304
  onAudioTrack
11105
11305
  });
11106
11306
  }
11107
- return { type: "box", box };
11307
+ return { type: "box", box: trakBox };
11108
11308
  }
11109
11309
  if (boxType === "stts") {
11110
11310
  return {
@@ -11177,7 +11377,7 @@ var processBox = async ({
11177
11377
  if (boxType === "moof") {
11178
11378
  await onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
11179
11379
  }
11180
- if (boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "mfra" || boxType === "stsb") {
11380
+ if (boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "mfra" || boxType === "edts" || boxType === "stsb") {
11181
11381
  const children = await getIsoBaseMediaChildren({
11182
11382
  iterator,
11183
11383
  size: boxSize - 8,
@@ -11278,6 +11478,7 @@ var getMoovAtom = async ({
11278
11478
  onlyIfMoovAtomExpected: {
11279
11479
  tracks: tracksState,
11280
11480
  isoState: null,
11481
+ movieTimeScaleState: state.iso.movieTimeScale,
11281
11482
  onAudioTrack,
11282
11483
  onVideoTrack,
11283
11484
  registerVideoSampleCallback: () => Promise.resolve(),
@@ -11518,7 +11719,18 @@ var parseMdatSection = async (state) => {
11518
11719
  if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
11519
11720
  return makeFetchMoreData(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
11520
11721
  }
11521
- const { cts, dts, duration: duration2, isKeyframe, offset, bigEndian, chunkSize } = samplesWithIndex.samplePosition;
11722
+ const {
11723
+ cts: rawCts,
11724
+ dts: rawDts,
11725
+ duration: duration2,
11726
+ isKeyframe,
11727
+ offset,
11728
+ bigEndian,
11729
+ chunkSize
11730
+ } = samplesWithIndex.samplePosition;
11731
+ const { timescale, startInSeconds } = samplesWithIndex.track;
11732
+ const cts = rawCts + startInSeconds * timescale;
11733
+ const dts = rawDts + startInSeconds * timescale;
11522
11734
  const bytes = postprocessBytes({
11523
11735
  bytes: iterator.getSlice(samplesWithIndex.samplePosition.size),
11524
11736
  bigEndian,
@@ -11535,9 +11747,9 @@ var parseMdatSection = async (state) => {
11535
11747
  trackId: samplesWithIndex.track.trackId,
11536
11748
  type: isKeyframe ? "key" : "delta",
11537
11749
  offset,
11538
- timescale: samplesWithIndex.track.timescale
11750
+ timescale
11539
11751
  },
11540
- timescale: samplesWithIndex.track.timescale
11752
+ timescale
11541
11753
  });
11542
11754
  await state.callbacks.onAudioSample(samplesWithIndex.track.trackId, audioSample);
11543
11755
  }
@@ -11558,9 +11770,9 @@ var parseMdatSection = async (state) => {
11558
11770
  trackId: samplesWithIndex.track.trackId,
11559
11771
  type: isKeyframe && !isRecoveryPoint ? "key" : "delta",
11560
11772
  offset,
11561
- timescale: samplesWithIndex.track.timescale
11773
+ timescale
11562
11774
  },
11563
- timescale: samplesWithIndex.track.timescale
11775
+ timescale
11564
11776
  });
11565
11777
  await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, videoSample);
11566
11778
  }
@@ -11585,6 +11797,7 @@ var parseIsoBaseMedia = async (state) => {
11585
11797
  onlyIfMoovAtomExpected: {
11586
11798
  tracks: state.callbacks.tracks,
11587
11799
  isoState: state.iso,
11800
+ movieTimeScaleState: state.iso.movieTimeScale,
11588
11801
  onAudioTrack: state.onAudioTrack,
11589
11802
  onVideoTrack: state.onVideoTrack,
11590
11803
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
@@ -12896,7 +13109,8 @@ var parseMpegHeader = async ({
12896
13109
  numberOfChannels,
12897
13110
  sampleRate,
12898
13111
  timescale: 1e6,
12899
- trackId: 0
13112
+ trackId: 0,
13113
+ startInSeconds: 0
12900
13114
  },
12901
13115
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
12902
13116
  tracks: state.callbacks.tracks,
@@ -12992,6 +13206,73 @@ var parseMp3 = async (state) => {
12992
13206
  throw new Error("Unknown MP3 header " + JSON.stringify(bytes));
12993
13207
  };
12994
13208
 
13209
+ // src/containers/riff/get-strh-for-index.ts
13210
+ var getStrhForIndex = (structure, trackId) => {
13211
+ const boxes = getStrlBoxes(structure);
13212
+ const box = boxes[trackId];
13213
+ if (!box) {
13214
+ throw new Error("Expected box");
13215
+ }
13216
+ const strh = getStrhBox(box.children);
13217
+ if (!strh) {
13218
+ throw new Error("strh");
13219
+ }
13220
+ return strh;
13221
+ };
13222
+
13223
+ // src/containers/riff/convert-queued-sample-to-mediaparser-sample.ts
13224
+ var getKeyFrameOffsetAndPocs = ({
13225
+ state,
13226
+ sample
13227
+ }) => {
13228
+ if (sample.type === "key") {
13229
+ const sampleOffset = state.riff.sampleCounter.getSampleCountForTrack({
13230
+ trackId: sample.trackId
13231
+ });
13232
+ return {
13233
+ sampleOffsetAtKeyframe: sampleOffset,
13234
+ pocsAtKeyframeOffset: [sample.avc?.poc ?? 0]
13235
+ };
13236
+ }
13237
+ const riffKeyframes = state.riff.sampleCounter.riffKeys.getKeyframes();
13238
+ const keyframeAtOffset = riffKeyframes.findLast((k) => k.positionInBytes <= sample.offset);
13239
+ if (!keyframeAtOffset) {
13240
+ throw new Error("no keyframe at offset");
13241
+ }
13242
+ const sampleOffsetAtKeyframe = keyframeAtOffset.sampleCounts[sample.trackId];
13243
+ const pocsAtKeyframeOffset = state.riff.sampleCounter.getPocAtKeyframeOffset({
13244
+ keyframeOffset: keyframeAtOffset.positionInBytes
13245
+ });
13246
+ return {
13247
+ sampleOffsetAtKeyframe,
13248
+ pocsAtKeyframeOffset
13249
+ };
13250
+ };
13251
+ var convertQueuedSampleToMediaParserSample = (sample, state) => {
13252
+ const strh = getStrhForIndex(state.structure.getRiffStructure(), sample.trackId);
13253
+ const samplesPerSecond = strh.rate / strh.scale;
13254
+ const { sampleOffsetAtKeyframe, pocsAtKeyframeOffset } = getKeyFrameOffsetAndPocs({
13255
+ sample,
13256
+ state
13257
+ });
13258
+ const indexOfPoc = pocsAtKeyframeOffset.findIndex((poc) => poc === sample.avc?.poc);
13259
+ if (indexOfPoc === -1) {
13260
+ throw new Error("poc not found");
13261
+ }
13262
+ const nthSample = indexOfPoc + sampleOffsetAtKeyframe;
13263
+ const timestamp = nthSample / samplesPerSecond;
13264
+ const videoSample = convertAudioOrVideoSampleToWebCodecsTimestamps({
13265
+ sample: {
13266
+ ...sample,
13267
+ timestamp,
13268
+ cts: timestamp,
13269
+ dts: timestamp
13270
+ },
13271
+ timescale: 1
13272
+ });
13273
+ return videoSample;
13274
+ };
13275
+
12995
13276
  // src/containers/riff/is-movi.ts
12996
13277
  var isMoviAtom = (iterator, ckId) => {
12997
13278
  if (ckId !== "LIST") {
@@ -13370,18 +13651,6 @@ var expectRiffBox = async ({
13370
13651
  };
13371
13652
 
13372
13653
  // src/containers/riff/parse-movi.ts
13373
- var getStrhForIndex = (structure, trackId) => {
13374
- const boxes = getStrlBoxes(structure);
13375
- const box = boxes[trackId];
13376
- if (!box) {
13377
- throw new Error("Expected box");
13378
- }
13379
- const strh = getStrhBox(box.children);
13380
- if (!strh) {
13381
- throw new Error("strh");
13382
- }
13383
- return strh;
13384
- };
13385
13654
  var handleChunk = async ({
13386
13655
  state,
13387
13656
  ckId,
@@ -13394,42 +13663,60 @@ var handleChunk = async ({
13394
13663
  const trackId = parseInt(videoChunk[1], 10);
13395
13664
  const strh = getStrhForIndex(state.structure.getRiffStructure(), trackId);
13396
13665
  const samplesPerSecond = strh.rate / strh.scale;
13397
- const nthSample = state.riff.sampleCounter.getSamplesForTrack(trackId);
13398
- const timeInSec = nthSample / samplesPerSecond;
13399
- const timestamp = timeInSec;
13400
13666
  const data = iterator.getSlice(ckSize);
13401
- const infos = parseAvc(data);
13667
+ const infos = parseAvc(data, state.avc);
13402
13668
  const keyOrDelta = getKeyFrameOrDeltaFromAvcInfo(infos);
13669
+ const info = infos.find((i) => i.type === "keyframe" || i.type === "delta-frame");
13403
13670
  const avcProfile = infos.find((i) => i.type === "avc-profile");
13404
13671
  const ppsProfile = infos.find((i) => i.type === "avc-pps");
13405
13672
  if (avcProfile && ppsProfile && !state.riff.getAvcProfile()) {
13406
13673
  await state.riff.onProfile({ pps: ppsProfile, sps: avcProfile });
13407
13674
  state.callbacks.tracks.setIsDone(state.logLevel);
13408
13675
  }
13409
- const videoSample = convertAudioOrVideoSampleToWebCodecsTimestamps({
13410
- sample: {
13411
- cts: timestamp,
13412
- dts: timestamp,
13413
- data,
13414
- duration: undefined,
13415
- timestamp,
13416
- trackId,
13417
- type: keyOrDelta,
13418
- offset,
13419
- timescale: samplesPerSecond
13420
- },
13421
- timescale: 1
13422
- });
13423
- state.riff.sampleCounter.onVideoSample(trackId, videoSample);
13676
+ const rawSample = {
13677
+ data,
13678
+ duration: 1 / samplesPerSecond,
13679
+ trackId,
13680
+ type: keyOrDelta === "bidirectional" ? "delta" : keyOrDelta,
13681
+ offset,
13682
+ timescale: samplesPerSecond,
13683
+ avc: info
13684
+ };
13685
+ const maxFramesInBuffer = state.avc.getMaxFramesInBuffer();
13686
+ if (maxFramesInBuffer === null) {
13687
+ throw new Error("maxFramesInBuffer is null");
13688
+ }
13689
+ if ((info?.poc ?? null) === null) {
13690
+ throw new Error("poc is null");
13691
+ }
13692
+ const keyframeOffset = state.riff.sampleCounter.getKeyframeAtOffset(rawSample);
13693
+ if (keyframeOffset !== null) {
13694
+ state.riff.sampleCounter.setPocAtKeyframeOffset({
13695
+ keyframeOffset,
13696
+ poc: info.poc
13697
+ });
13698
+ }
13699
+ state.riff.queuedBFrames.addFrame(rawSample, maxFramesInBuffer);
13700
+ const releasedFrame = state.riff.queuedBFrames.getReleasedFrame();
13701
+ if (!releasedFrame) {
13702
+ return;
13703
+ }
13704
+ const videoSample = convertQueuedSampleToMediaParserSample(releasedFrame, state);
13705
+ state.riff.sampleCounter.onVideoSample(videoSample);
13424
13706
  await state.callbacks.onVideoSample(trackId, videoSample);
13425
- return;
13426
13707
  }
13427
13708
  const audioChunk = ckId.match(/^([0-9]{2})wb$/);
13428
13709
  if (audioChunk) {
13429
13710
  const trackId = parseInt(audioChunk[1], 10);
13430
13711
  const strh = getStrhForIndex(state.structure.getRiffStructure(), trackId);
13431
- const samplesPerSecond = strh.rate / strh.scale;
13432
- const nthSample = state.riff.sampleCounter.getSamplesForTrack(trackId);
13712
+ const { strf } = strh;
13713
+ if (strf.type !== "strf-box-audio") {
13714
+ throw new Error("audio");
13715
+ }
13716
+ const samplesPerSecond = strh.rate / strh.scale * strf.numberOfChannels;
13717
+ const nthSample = state.riff.sampleCounter.getSampleCountForTrack({
13718
+ trackId
13719
+ });
13433
13720
  const timeInSec = nthSample / samplesPerSecond;
13434
13721
  const timestamp = timeInSec;
13435
13722
  const data = iterator.getSlice(ckSize);
@@ -13489,6 +13776,13 @@ var parseMediaSection = async (state) => {
13489
13776
 
13490
13777
  // src/containers/riff/parse-riff-body.ts
13491
13778
  var parseRiffBody = async (state) => {
13779
+ const releasedFrame = state.riff.queuedBFrames.getReleasedFrame();
13780
+ if (releasedFrame) {
13781
+ const converted = convertQueuedSampleToMediaParserSample(releasedFrame, state);
13782
+ state.riff.sampleCounter.onVideoSample(converted);
13783
+ await state.callbacks.onVideoSample(releasedFrame.trackId, converted);
13784
+ return null;
13785
+ }
13492
13786
  if (state.mediaSection.isCurrentByteInMediaSection(state.iterator) === "in-section") {
13493
13787
  if (maySkipVideoData({
13494
13788
  state
@@ -13869,7 +14163,8 @@ var handleAacPacket = async ({
13869
14163
  codec: mapAudioObjectTypeToCodecString(audioObjectType),
13870
14164
  description: codecPrivate2,
13871
14165
  numberOfChannels: channelConfiguration,
13872
- sampleRate
14166
+ sampleRate,
14167
+ startInSeconds: 0
13873
14168
  };
13874
14169
  await registerAudioTrack({
13875
14170
  track,
@@ -13956,7 +14251,8 @@ var processStreamBuffer = async ({
13956
14251
  onAudioTrack,
13957
14252
  onVideoTrack,
13958
14253
  transportStream,
13959
- makeSamplesStartAtZero
14254
+ makeSamplesStartAtZero,
14255
+ avcState
13960
14256
  }) => {
13961
14257
  const stream = getStreamForId(structure, programId);
13962
14258
  if (!stream) {
@@ -13974,7 +14270,8 @@ var processStreamBuffer = async ({
13974
14270
  onVideoTrack,
13975
14271
  offset: streamBuffer.offset,
13976
14272
  transportStream,
13977
- makeSamplesStartAtZero
14273
+ makeSamplesStartAtZero,
14274
+ avcState
13978
14275
  });
13979
14276
  } else if (stream.streamType === 15) {
13980
14277
  await handleAacPacket({
@@ -14003,7 +14300,8 @@ var processFinalStreamBuffers = async ({
14003
14300
  onAudioTrack,
14004
14301
  onVideoTrack,
14005
14302
  transportStream,
14006
- makeSamplesStartAtZero
14303
+ makeSamplesStartAtZero,
14304
+ avcState
14007
14305
  }) => {
14008
14306
  for (const [programId, buffer] of transportStream.streamBuffers) {
14009
14307
  if (buffer.getBuffer().byteLength > 0) {
@@ -14016,7 +14314,8 @@ var processFinalStreamBuffers = async ({
14016
14314
  onAudioTrack,
14017
14315
  onVideoTrack,
14018
14316
  transportStream,
14019
- makeSamplesStartAtZero
14317
+ makeSamplesStartAtZero,
14318
+ avcState
14020
14319
  });
14021
14320
  transportStream.streamBuffers.delete(programId);
14022
14321
  }
@@ -14143,7 +14442,8 @@ var processAudio = async ({
14143
14442
  onAudioTrack,
14144
14443
  onVideoTrack,
14145
14444
  transportStream,
14146
- makeSamplesStartAtZero
14445
+ makeSamplesStartAtZero,
14446
+ avcState
14147
14447
  }) => {
14148
14448
  const { streamBuffers, nextPesHeaderStore: nextPesHeader } = transportStream;
14149
14449
  const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
@@ -14170,7 +14470,8 @@ var processAudio = async ({
14170
14470
  onAudioTrack,
14171
14471
  onVideoTrack,
14172
14472
  transportStream,
14173
- makeSamplesStartAtZero
14473
+ makeSamplesStartAtZero,
14474
+ avcState
14174
14475
  });
14175
14476
  const rest = streamBuffer.getBuffer().slice(expectedLength);
14176
14477
  streamBuffers.set(transportStreamEntry.pid, makeTransportStreamPacketBuffer({
@@ -14199,7 +14500,8 @@ var processVideo = async ({
14199
14500
  onAudioTrack,
14200
14501
  onVideoTrack,
14201
14502
  transportStream,
14202
- makeSamplesStartAtZero
14503
+ makeSamplesStartAtZero,
14504
+ avcState
14203
14505
  }) => {
14204
14506
  const indexOfSeparator = streamBuffer.get2ndSubArrayIndex();
14205
14507
  if (indexOfSeparator === -1 || indexOfSeparator === 0) {
@@ -14221,7 +14523,8 @@ var processVideo = async ({
14221
14523
  onAudioTrack,
14222
14524
  onVideoTrack,
14223
14525
  transportStream,
14224
- makeSamplesStartAtZero
14526
+ makeSamplesStartAtZero,
14527
+ avcState
14225
14528
  });
14226
14529
  return rest;
14227
14530
  };
@@ -14249,7 +14552,8 @@ var processSampleIfPossible = async (state) => {
14249
14552
  onAudioTrack: state.onAudioTrack,
14250
14553
  onVideoTrack: state.onVideoTrack,
14251
14554
  transportStream: state.transportStream,
14252
- makeSamplesStartAtZero: state.makeSamplesStartAtZero
14555
+ makeSamplesStartAtZero: state.makeSamplesStartAtZero,
14556
+ avcState: state.avc
14253
14557
  });
14254
14558
  state.transportStream.streamBuffers.delete(stream.pid);
14255
14559
  state.transportStream.streamBuffers.set(stream.pid, makeTransportStreamPacketBuffer({
@@ -14272,7 +14576,8 @@ var processSampleIfPossible = async (state) => {
14272
14576
  onVideoTrack: state.onVideoTrack,
14273
14577
  transportStream: state.transportStream,
14274
14578
  makeSamplesStartAtZero: state.makeSamplesStartAtZero,
14275
- transportStreamEntry: stream
14579
+ transportStreamEntry: stream,
14580
+ avcState: state.avc
14276
14581
  });
14277
14582
  processed = true;
14278
14583
  break;
@@ -14309,7 +14614,8 @@ var parseTransportStream = async (state) => {
14309
14614
  logLevel: state.logLevel,
14310
14615
  onAudioTrack: state.onAudioTrack,
14311
14616
  onVideoTrack: state.onVideoTrack,
14312
- makeSamplesStartAtZero: state.makeSamplesStartAtZero
14617
+ makeSamplesStartAtZero: state.makeSamplesStartAtZero,
14618
+ avcState: state.avc
14313
14619
  });
14314
14620
  }
14315
14621
  return Promise.resolve(null);
@@ -14376,7 +14682,8 @@ var parseFmt = async ({
14376
14682
  numberOfChannels,
14377
14683
  sampleRate,
14378
14684
  timescale: 1e6,
14379
- trackId: 0
14685
+ trackId: 0,
14686
+ startInSeconds: 0
14380
14687
  },
14381
14688
  container: "wav",
14382
14689
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
@@ -14589,7 +14896,8 @@ var addAvcToTrackAndActivateTrackIfNecessary = async ({
14589
14896
  trackNumber: trackNumber2,
14590
14897
  logLevel,
14591
14898
  callbacks,
14592
- onVideoTrack
14899
+ onVideoTrack,
14900
+ avcState
14593
14901
  }) => {
14594
14902
  if (codec !== "V_MPEG4/ISO/AVC") {
14595
14903
  return;
@@ -14601,7 +14909,7 @@ var addAvcToTrackAndActivateTrackIfNecessary = async ({
14601
14909
  if (missingTracks.length === 0) {
14602
14910
  return;
14603
14911
  }
14604
- const parsed = parseAvc(partialVideoSample.data);
14912
+ const parsed = parseAvc(partialVideoSample.data, avcState);
14605
14913
  for (const parse of parsed) {
14606
14914
  if (parse.type === "avc-profile") {
14607
14915
  webmState.setAvcProfileForTrackNumber(trackNumber2, parse);
@@ -14635,7 +14943,8 @@ var getSampleFromBlock = async ({
14635
14943
  structureState: structureState2,
14636
14944
  callbacks,
14637
14945
  logLevel,
14638
- onVideoTrack
14946
+ onVideoTrack,
14947
+ avcState
14639
14948
  }) => {
14640
14949
  const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
14641
14950
  const trackNumber2 = iterator.getVint();
@@ -14682,7 +14991,8 @@ var getSampleFromBlock = async ({
14682
14991
  trackNumber: trackNumber2,
14683
14992
  callbacks,
14684
14993
  logLevel,
14685
- onVideoTrack
14994
+ onVideoTrack,
14995
+ avcState
14686
14996
  });
14687
14997
  const sample = {
14688
14998
  ...partialVideoSample,
@@ -14816,7 +15126,8 @@ var postprocessEbml = async ({
14816
15126
  logLevel,
14817
15127
  onAudioTrack,
14818
15128
  onVideoTrack,
14819
- structureState: structureState2
15129
+ structureState: structureState2,
15130
+ avcState
14820
15131
  }
14821
15132
  }) => {
14822
15133
  if (ebml.type === "TimestampScale") {
@@ -14865,7 +15176,8 @@ var postprocessEbml = async ({
14865
15176
  structureState: structureState2,
14866
15177
  callbacks,
14867
15178
  logLevel,
14868
- onVideoTrack
15179
+ onVideoTrack,
15180
+ avcState
14869
15181
  });
14870
15182
  if (sample.type === "video-sample") {
14871
15183
  await callbacks.onVideoSample(sample.videoSample.trackId, sample.videoSample);
@@ -14904,7 +15216,8 @@ var postprocessEbml = async ({
14904
15216
  structureState: structureState2,
14905
15217
  callbacks,
14906
15218
  logLevel,
14907
- onVideoTrack
15219
+ onVideoTrack,
15220
+ avcState
14908
15221
  });
14909
15222
  if (sample && sample.type === "partial-video-sample") {
14910
15223
  const completeFrame = {
@@ -15033,7 +15346,8 @@ var selectStatesForProcessing = ({
15033
15346
  onAudioTrack,
15034
15347
  onVideoTrack,
15035
15348
  structure,
15036
- webm
15349
+ webm,
15350
+ avc
15037
15351
  }) => {
15038
15352
  return {
15039
15353
  webmState: webm,
@@ -15041,7 +15355,8 @@ var selectStatesForProcessing = ({
15041
15355
  logLevel,
15042
15356
  onAudioTrack,
15043
15357
  onVideoTrack,
15044
- structureState: structure
15358
+ structureState: structure,
15359
+ avcState: avc
15045
15360
  };
15046
15361
  };
15047
15362
 
@@ -15251,9 +15566,6 @@ var runParseIteration = async ({
15251
15566
  if (structure && structure.type === "m3u") {
15252
15567
  return parseM3u({ state });
15253
15568
  }
15254
- if (state.iterator.bytesRemaining() === 0) {
15255
- return Promise.reject(new Error("no bytes"));
15256
- }
15257
15569
  if (structure === null) {
15258
15570
  await initVideo({
15259
15571
  state
@@ -15554,6 +15866,82 @@ var aacState = () => {
15554
15866
  };
15555
15867
  };
15556
15868
 
15869
+ // src/containers/avc/max-buffer-size.ts
15870
+ var maxMacroblocksByLevel = {
15871
+ 10: 396,
15872
+ 11: 900,
15873
+ 12: 2376,
15874
+ 13: 2376,
15875
+ 20: 2376,
15876
+ 21: 4752,
15877
+ 22: 8100,
15878
+ 30: 8100,
15879
+ 31: 18000,
15880
+ 32: 20480,
15881
+ 40: 32768,
15882
+ 41: 32768,
15883
+ 42: 34816,
15884
+ 50: 110400,
15885
+ 51: 184320,
15886
+ 52: 184320,
15887
+ 60: 696320,
15888
+ 61: 696320,
15889
+ 62: 696320
15890
+ };
15891
+ var macroBlocksPerFrame = (sps) => {
15892
+ const { pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 } = sps;
15893
+ return (pic_width_in_mbs_minus1 + 1) * (pic_height_in_map_units_minus1 + 1);
15894
+ };
15895
+ var maxMacroblockBufferSize = (sps) => {
15896
+ const { level } = sps;
15897
+ const maxMacroblocks = maxMacroblocksByLevel[level];
15898
+ if (maxMacroblocks === undefined) {
15899
+ throw new Error(`Unsupported level: ${level.toString(16)}`);
15900
+ }
15901
+ return maxMacroblocks;
15902
+ };
15903
+
15904
+ // src/state/avc/avc-state.ts
15905
+ var avcState = () => {
15906
+ let prevPicOrderCntLsb = 0;
15907
+ let prevPicOrderCntMsb = 0;
15908
+ let sps = null;
15909
+ let maxFramesInBuffer = null;
15910
+ return {
15911
+ getPrevPicOrderCntLsb() {
15912
+ return prevPicOrderCntLsb;
15913
+ },
15914
+ getPrevPicOrderCntMsb() {
15915
+ return prevPicOrderCntMsb;
15916
+ },
15917
+ setPrevPicOrderCntLsb(value) {
15918
+ prevPicOrderCntLsb = value;
15919
+ },
15920
+ setPrevPicOrderCntMsb(value) {
15921
+ prevPicOrderCntMsb = value;
15922
+ },
15923
+ setSps(value) {
15924
+ const macroblockBufferSize = macroBlocksPerFrame(value);
15925
+ const maxBufferSize = maxMacroblockBufferSize(value);
15926
+ const maxFrames = Math.min(16, Math.floor(maxBufferSize / macroblockBufferSize));
15927
+ maxFramesInBuffer = maxFrames;
15928
+ sps = value;
15929
+ },
15930
+ getSps() {
15931
+ return sps;
15932
+ },
15933
+ getMaxFramesInBuffer() {
15934
+ return maxFramesInBuffer;
15935
+ },
15936
+ clear() {
15937
+ maxFramesInBuffer = null;
15938
+ sps = null;
15939
+ prevPicOrderCntLsb = 0;
15940
+ prevPicOrderCntMsb = 0;
15941
+ }
15942
+ };
15943
+ };
15944
+
15557
15945
  // src/state/current-reader.ts
15558
15946
  var currentReader = (initialReader) => {
15559
15947
  let current = initialReader;
@@ -15794,6 +16182,17 @@ var moovState = () => {
15794
16182
  };
15795
16183
  };
15796
16184
 
16185
+ // src/state/iso-base-media/timescale-state.ts
16186
+ var movieTimeScaleState = () => {
16187
+ let trackTimescale = null;
16188
+ return {
16189
+ getTrackTimescale: () => trackTimescale,
16190
+ setTrackTimescale: (timescale) => {
16191
+ trackTimescale = timescale;
16192
+ }
16193
+ };
16194
+ };
16195
+
15797
16196
  // src/state/iso-base-media/iso-state.ts
15798
16197
  var isoBaseMediaState = ({
15799
16198
  contentLength,
@@ -15815,7 +16214,8 @@ var isoBaseMediaState = ({
15815
16214
  prefetchCache
15816
16215
  }),
15817
16216
  moof: precomputedMoofState(),
15818
- tfra: precomputedTfraState()
16217
+ tfra: precomputedTfraState(),
16218
+ movieTimeScale: movieTimeScaleState()
15819
16219
  };
15820
16220
  };
15821
16221
 
@@ -16471,6 +16871,43 @@ var lazyIdx1Fetch = ({
16471
16871
  };
16472
16872
  };
16473
16873
 
16874
+ // src/state/riff/queued-frames.ts
16875
+ var queuedBFramesState = () => {
16876
+ const queuedFrames = [];
16877
+ const releasedFrames = [];
16878
+ const flush = () => {
16879
+ releasedFrames.push(...queuedFrames);
16880
+ queuedFrames.length = 0;
16881
+ };
16882
+ return {
16883
+ addFrame: (frame, maxFramesInBuffer) => {
16884
+ if (frame.type === "key") {
16885
+ flush();
16886
+ releasedFrames.push(frame);
16887
+ return;
16888
+ }
16889
+ queuedFrames.push(frame);
16890
+ if (queuedFrames.length > maxFramesInBuffer) {
16891
+ releasedFrames.push(queuedFrames.shift());
16892
+ }
16893
+ },
16894
+ flush,
16895
+ getReleasedFrame: () => {
16896
+ if (releasedFrames.length === 0) {
16897
+ return null;
16898
+ }
16899
+ return releasedFrames.shift();
16900
+ },
16901
+ hasReleasedFrames: () => {
16902
+ return releasedFrames.length > 0;
16903
+ },
16904
+ clear: () => {
16905
+ releasedFrames.length = 0;
16906
+ queuedFrames.length = 0;
16907
+ }
16908
+ };
16909
+ };
16910
+
16474
16911
  // src/state/riff/riff-keyframes.ts
16475
16912
  var riffKeyframesState = () => {
16476
16913
  const keyframes = [];
@@ -16479,6 +16916,7 @@ var riffKeyframesState = () => {
16479
16916
  return;
16480
16917
  }
16481
16918
  keyframes.push(keyframe);
16919
+ keyframes.sort((a, b) => a.positionInBytes - b.positionInBytes);
16482
16920
  };
16483
16921
  const getKeyframes2 = () => {
16484
16922
  return keyframes;
@@ -16498,6 +16936,7 @@ var riffKeyframesState = () => {
16498
16936
  // src/state/riff/sample-counter.ts
16499
16937
  var riffSampleCounter = () => {
16500
16938
  const samplesForTrack = {};
16939
+ const pocsAtKeyframeOffset = {};
16501
16940
  const riffKeys = riffKeyframesState();
16502
16941
  const onAudioSample = (trackId, audioSample) => {
16503
16942
  if (typeof samplesForTrack[trackId] === "undefined") {
@@ -16508,13 +16947,13 @@ var riffSampleCounter = () => {
16508
16947
  }
16509
16948
  samplesForTrack[trackId]++;
16510
16949
  };
16511
- const onVideoSample = (trackId, videoSample) => {
16512
- if (typeof samplesForTrack[trackId] === "undefined") {
16513
- samplesForTrack[trackId] = 0;
16950
+ const onVideoSample = (videoSample) => {
16951
+ if (typeof samplesForTrack[videoSample.trackId] === "undefined") {
16952
+ samplesForTrack[videoSample.trackId] = 0;
16514
16953
  }
16515
16954
  if (videoSample.type === "key") {
16516
16955
  riffKeys.addKeyframe({
16517
- trackId,
16956
+ trackId: videoSample.trackId,
16518
16957
  decodingTimeInSeconds: videoSample.dts / videoSample.timescale,
16519
16958
  positionInBytes: videoSample.offset,
16520
16959
  presentationTimeInSeconds: videoSample.cts / videoSample.timescale,
@@ -16523,10 +16962,10 @@ var riffSampleCounter = () => {
16523
16962
  });
16524
16963
  }
16525
16964
  if (videoSample.data.length > 0) {
16526
- samplesForTrack[trackId]++;
16965
+ samplesForTrack[videoSample.trackId]++;
16527
16966
  }
16528
16967
  };
16529
- const getSamplesForTrack = (trackId) => {
16968
+ const getSampleCountForTrack = ({ trackId }) => {
16530
16969
  return samplesForTrack[trackId] ?? 0;
16531
16970
  };
16532
16971
  const setSamplesFromSeek = (samples) => {
@@ -16534,12 +16973,39 @@ var riffSampleCounter = () => {
16534
16973
  samplesForTrack[trackId] = samples[trackId];
16535
16974
  }
16536
16975
  };
16976
+ const setPocAtKeyframeOffset = ({
16977
+ keyframeOffset,
16978
+ poc
16979
+ }) => {
16980
+ if (typeof pocsAtKeyframeOffset[keyframeOffset] === "undefined") {
16981
+ pocsAtKeyframeOffset[keyframeOffset] = [];
16982
+ }
16983
+ if (pocsAtKeyframeOffset[keyframeOffset].includes(poc)) {
16984
+ return;
16985
+ }
16986
+ pocsAtKeyframeOffset[keyframeOffset].push(poc);
16987
+ pocsAtKeyframeOffset[keyframeOffset].sort((a, b) => a - b);
16988
+ };
16989
+ const getPocAtKeyframeOffset = ({
16990
+ keyframeOffset
16991
+ }) => {
16992
+ return pocsAtKeyframeOffset[keyframeOffset];
16993
+ };
16994
+ const getKeyframeAtOffset = (sample) => {
16995
+ if (sample.type === "key") {
16996
+ return sample.offset;
16997
+ }
16998
+ return riffKeys.getKeyframes().findLast((k) => k.positionInBytes <= sample.offset)?.positionInBytes ?? null;
16999
+ };
16537
17000
  return {
16538
17001
  onAudioSample,
16539
17002
  onVideoSample,
16540
- getSamplesForTrack,
17003
+ getSampleCountForTrack,
16541
17004
  setSamplesFromSeek,
16542
- riffKeys
17005
+ riffKeys,
17006
+ setPocAtKeyframeOffset,
17007
+ getPocAtKeyframeOffset,
17008
+ getKeyframeAtOffset
16543
17009
  };
16544
17010
  };
16545
17011
 
@@ -16572,6 +17038,7 @@ var riffSpecificState = ({
16572
17038
  prefetchCache
16573
17039
  });
16574
17040
  const sampleCounter = riffSampleCounter();
17041
+ const queuedBFrames = queuedBFramesState();
16575
17042
  return {
16576
17043
  getAvcProfile: () => {
16577
17044
  return avcProfile;
@@ -16581,6 +17048,7 @@ var riffSpecificState = ({
16581
17048
  getNextTrackIndex: () => {
16582
17049
  return nextTrackIndex;
16583
17050
  },
17051
+ queuedBFrames,
16584
17052
  incrementNextTrackIndex: () => {
16585
17053
  nextTrackIndex++;
16586
17054
  },
@@ -16920,6 +17388,7 @@ var makeParserState = ({
16920
17388
  const timings = timingsState();
16921
17389
  const seekInfiniteLoop = seekInfiniteLoopDetectionState();
16922
17390
  const currentReaderState = currentReader(initialReaderInstance);
17391
+ const avc = avcState();
16923
17392
  const errored = null;
16924
17393
  const discardReadBytes = async (force) => {
16925
17394
  const { bytesRemoved, removedData } = iterator.removeBytesRead(force, mode);
@@ -17013,7 +17482,8 @@ var makeParserState = ({
17013
17482
  currentReader: currentReaderState,
17014
17483
  seekInfiniteLoop,
17015
17484
  makeSamplesStartAtZero,
17016
- prefetchCache
17485
+ prefetchCache,
17486
+ avc
17017
17487
  };
17018
17488
  };
17019
17489