@remotion/media-parser 4.0.302 → 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(() => {});
@@ -970,6 +971,14 @@ var getTrakBoxByTrackId = (moovBox, trackId) => {
970
971
  return tkhd.trackId === trackId;
971
972
  }) ?? null;
972
973
  };
974
+ var getElstBox = (trakBox) => {
975
+ const edtsBox = trakBox.children.find((s) => s.type === "regular-box" && s.boxType === "edts");
976
+ if (!edtsBox || edtsBox.type !== "regular-box") {
977
+ return null;
978
+ }
979
+ const elstBox = edtsBox.children.find((s) => s.type === "elst-box");
980
+ return elstBox;
981
+ };
973
982
 
974
983
  // src/containers/riff/traversal.ts
975
984
  var isRiffAvi = (structure) => {
@@ -3228,7 +3237,7 @@ var getVideoCodecFromIsoTrak = (trakBox) => {
3228
3237
  };
3229
3238
 
3230
3239
  // src/containers/iso-base-media/make-track.ts
3231
- var makeBaseMediaTrack = (trakBox) => {
3240
+ var makeBaseMediaTrack = (trakBox, startTimeInSeconds) => {
3232
3241
  const tkhdBox = getTkhdBox(trakBox);
3233
3242
  const videoDescriptors = getVideoDescriptors(trakBox);
3234
3243
  const timescaleAndDuration = getTimescaleAndDuration(trakBox);
@@ -3265,7 +3274,8 @@ var makeBaseMediaTrack = (trakBox) => {
3265
3274
  sampleRate: actual.sampleRate,
3266
3275
  description: actual.codecPrivate?.data ?? undefined,
3267
3276
  codecData: actual.codecPrivate,
3268
- codecEnum
3277
+ codecEnum,
3278
+ startInSeconds: startTimeInSeconds
3269
3279
  };
3270
3280
  }
3271
3281
  if (!trakBoxContainsVideo(trakBox)) {
@@ -3273,7 +3283,8 @@ var makeBaseMediaTrack = (trakBox) => {
3273
3283
  type: "other",
3274
3284
  trackId: tkhdBox.trackId,
3275
3285
  timescale: timescaleAndDuration.timescale,
3276
- trakBox
3286
+ trakBox,
3287
+ startInSeconds: startTimeInSeconds
3277
3288
  };
3278
3289
  }
3279
3290
  const videoSample = getStsdVideoConfig(trakBox);
@@ -3320,11 +3331,33 @@ var makeBaseMediaTrack = (trakBox) => {
3320
3331
  colorSpace: mediaParserAdvancedColorToWebCodecsColor(advancedColor),
3321
3332
  advancedColor,
3322
3333
  codecEnum: getVideoCodecFromIsoTrak(trakBox),
3323
- fps: getFpsFromMp4TrakBox(trakBox)
3334
+ fps: getFpsFromMp4TrakBox(trakBox),
3335
+ startInSeconds: startTimeInSeconds
3324
3336
  };
3325
3337
  return track;
3326
3338
  };
3327
3339
 
3340
+ // src/containers/iso-base-media/mdat/get-editlist.ts
3341
+ var findTrackStartTimeInSeconds = ({
3342
+ movieTimeScale,
3343
+ trakBox
3344
+ }) => {
3345
+ const elstBox = getElstBox(trakBox);
3346
+ if (!elstBox) {
3347
+ return 0;
3348
+ }
3349
+ const { entries } = elstBox;
3350
+ let dwellTime = 0;
3351
+ for (const entry of entries) {
3352
+ const { editDuration, mediaTime } = entry;
3353
+ if (mediaTime !== -1) {
3354
+ continue;
3355
+ }
3356
+ dwellTime += editDuration;
3357
+ }
3358
+ return dwellTime / movieTimeScale;
3359
+ };
3360
+
3328
3361
  // src/containers/avc/codec-string.ts
3329
3362
  var getCodecStringFromSpsAndPps = (sps) => {
3330
3363
  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")}`;
@@ -3423,7 +3456,8 @@ var makeAviAudioTrack = ({
3423
3456
  numberOfChannels: strf.numberOfChannels,
3424
3457
  sampleRate: strf.sampleRate,
3425
3458
  timescale: MEDIA_PARSER_RIFF_TIMESCALE,
3426
- trackId: index
3459
+ trackId: index,
3460
+ startInSeconds: 0
3427
3461
  };
3428
3462
  };
3429
3463
  var makeAviVideoTrack = ({
@@ -3466,7 +3500,8 @@ var makeAviVideoTrack = ({
3466
3500
  numerator: 1,
3467
3501
  denominator: 1
3468
3502
  },
3469
- fps: strh.rate / strh.scale
3503
+ fps: strh.rate / strh.scale,
3504
+ startInSeconds: 0
3470
3505
  };
3471
3506
  };
3472
3507
  var getTracksFromAvi = (structure, state) => {
@@ -4119,7 +4154,8 @@ var getTrack = ({
4119
4154
  colorSpace: mediaParserAdvancedColorToWebCodecsColor(advancedColor),
4120
4155
  advancedColor,
4121
4156
  codecEnum,
4122
- fps: null
4157
+ fps: null,
4158
+ startInSeconds: 0
4123
4159
  };
4124
4160
  }
4125
4161
  if (trackTypeToString(trackType2.value.value) === "audio") {
@@ -4141,7 +4177,8 @@ var getTrack = ({
4141
4177
  codecData: codecPrivate2 ? codecString === "opus" ? { type: "ogg-identification", data: codecPrivate2 } : { type: "unknown-data", data: codecPrivate2 } : null,
4142
4178
  codecEnum: getMatroskaAudioCodecEnum({
4143
4179
  track
4144
- })
4180
+ }),
4181
+ startInSeconds: 0
4145
4182
  };
4146
4183
  }
4147
4184
  return null;
@@ -4262,7 +4299,15 @@ var getTracksFromMoovBox = (moovBox) => {
4262
4299
  const mediaParserTracks = [];
4263
4300
  const tracks2 = getTraks(moovBox);
4264
4301
  for (const trakBox of tracks2) {
4265
- const track = makeBaseMediaTrack(trakBox);
4302
+ const mvhdBox = getMvhdBox(moovBox);
4303
+ if (!mvhdBox) {
4304
+ throw new Error("Mvhd box is not found");
4305
+ }
4306
+ const startTime = findTrackStartTimeInSeconds({
4307
+ movieTimeScale: mvhdBox.timeScale,
4308
+ trakBox
4309
+ });
4310
+ const track = makeBaseMediaTrack(trakBox, startTime);
4266
4311
  if (!track) {
4267
4312
  continue;
4268
4313
  }
@@ -5724,13 +5769,14 @@ var findKeyframeBeforeTime = ({
5724
5769
  time,
5725
5770
  timescale,
5726
5771
  mediaSections,
5727
- logLevel
5772
+ logLevel,
5773
+ startInSeconds
5728
5774
  }) => {
5729
5775
  let videoByte = 0;
5730
5776
  let videoSample = null;
5731
5777
  for (const sample of samplePositions) {
5732
- const ctsInSeconds = sample.cts / timescale;
5733
- const dtsInSeconds = sample.dts / timescale;
5778
+ const ctsInSeconds = sample.cts / timescale + startInSeconds;
5779
+ const dtsInSeconds = sample.dts / timescale + startInSeconds;
5734
5780
  if (!sample.isKeyframe) {
5735
5781
  continue;
5736
5782
  }
@@ -5975,7 +6021,8 @@ var getSeekingByteFromFragmentedMp4 = async ({
5975
6021
  time,
5976
6022
  timescale: firstTrack.timescale,
5977
6023
  logLevel,
5978
- mediaSections: info.mediaSections
6024
+ mediaSections: info.mediaSections,
6025
+ startInSeconds: firstTrack.startInSeconds
5979
6026
  });
5980
6027
  if (kf) {
5981
6028
  return {
@@ -6077,7 +6124,8 @@ var getSeekingByteFromIsoBaseMedia = ({
6077
6124
  time,
6078
6125
  timescale: track.timescale,
6079
6126
  logLevel,
6080
- mediaSections: info.mediaSections
6127
+ mediaSections: info.mediaSections,
6128
+ startInSeconds: track.startInSeconds
6081
6129
  });
6082
6130
  if (keyframe) {
6083
6131
  return Promise.resolve({
@@ -6383,7 +6431,8 @@ function findLastKeyframe({
6383
6431
  var getSeekingByteForRiff = async ({
6384
6432
  info,
6385
6433
  time,
6386
- riffState
6434
+ riffState,
6435
+ avcState
6387
6436
  }) => {
6388
6437
  const idx1Entries = await (info.hasIndex ? riffState.lazyIdx1.waitForLoaded() : Promise.resolve(null));
6389
6438
  if (idx1Entries === null) {
@@ -6397,6 +6446,8 @@ var getSeekingByteForRiff = async ({
6397
6446
  };
6398
6447
  }
6399
6448
  riffState.sampleCounter.setSamplesFromSeek(lastKeyframe.sampleCounts);
6449
+ riffState.queuedBFrames.clear();
6450
+ avcState.clear();
6400
6451
  return {
6401
6452
  type: "do-seek",
6402
6453
  byte: lastKeyframe.positionInBytes
@@ -6426,6 +6477,8 @@ var getSeekingByteForRiff = async ({
6426
6477
  throw new Error("moviOffset is null");
6427
6478
  }
6428
6479
  riffState.sampleCounter.setSamplesFromSeek(bestEntry.sampleCounts);
6480
+ riffState.queuedBFrames.clear();
6481
+ avcState.clear();
6429
6482
  return {
6430
6483
  type: "do-seek",
6431
6484
  byte: bestEntry.offset + info.moviOffset - 4
@@ -6574,7 +6627,8 @@ var convertAudioOrVideoSampleToWebCodecsTimestamps = ({
6574
6627
  trackId: sample.trackId,
6575
6628
  type: sample.type,
6576
6629
  offset: sample.offset,
6577
- timescale: TARGET_TIMESCALE
6630
+ timescale: TARGET_TIMESCALE,
6631
+ ..."avc" in sample ? { avc: sample.avc } : {}
6578
6632
  };
6579
6633
  };
6580
6634
 
@@ -6687,11 +6741,38 @@ var getKeyFrameOrDeltaFromAvcInfo = (infos) => {
6687
6741
  if (!keyOrDelta) {
6688
6742
  throw new Error("expected avc to contain info about key or delta");
6689
6743
  }
6690
- return keyOrDelta.type === "keyframe" ? "key" : "delta";
6744
+ return keyOrDelta.type === "keyframe" ? "key" : keyOrDelta.isBidirectionalFrame ? "bidirectional" : "delta";
6691
6745
  };
6692
6746
 
6693
6747
  // src/containers/avc/parse-avc.ts
6694
6748
  var Extended_SAR = 255;
6749
+ var getPoc = (iterator, sps, avcState, isReferencePicture) => {
6750
+ const { pic_order_cnt_type, log2_max_pic_order_cnt_lsb_minus4 } = sps;
6751
+ if (pic_order_cnt_type !== 0) {
6752
+ return null;
6753
+ }
6754
+ const prevPicOrderCntLsb = avcState.getPrevPicOrderCntLsb();
6755
+ const prevPicOrderCntMsb = avcState.getPrevPicOrderCntMsb();
6756
+ if (log2_max_pic_order_cnt_lsb_minus4 === null) {
6757
+ throw new Error("log2_max_pic_order_cnt_lsb_minus4 is null");
6758
+ }
6759
+ const max_pic_order_cnt_lsb = 2 ** (log2_max_pic_order_cnt_lsb_minus4 + 4);
6760
+ const pic_order_cnt_lsb = iterator.getBits(log2_max_pic_order_cnt_lsb_minus4 + 4);
6761
+ let picOrderCntMsb;
6762
+ if (pic_order_cnt_lsb < prevPicOrderCntLsb && prevPicOrderCntLsb - pic_order_cnt_lsb >= max_pic_order_cnt_lsb / 2) {
6763
+ picOrderCntMsb = prevPicOrderCntMsb + max_pic_order_cnt_lsb;
6764
+ } else if (pic_order_cnt_lsb > prevPicOrderCntLsb && pic_order_cnt_lsb - prevPicOrderCntLsb > max_pic_order_cnt_lsb / 2) {
6765
+ picOrderCntMsb = prevPicOrderCntMsb - max_pic_order_cnt_lsb;
6766
+ } else {
6767
+ picOrderCntMsb = prevPicOrderCntMsb;
6768
+ }
6769
+ const poc = picOrderCntMsb + pic_order_cnt_lsb;
6770
+ if (isReferencePicture) {
6771
+ avcState.setPrevPicOrderCntLsb(pic_order_cnt_lsb);
6772
+ avcState.setPrevPicOrderCntMsb(picOrderCntMsb);
6773
+ }
6774
+ return poc;
6775
+ };
6695
6776
  var readVuiParameters = (iterator) => {
6696
6777
  let sar_width = null;
6697
6778
  let sar_height = null;
@@ -6837,7 +6918,8 @@ var readSps = (iterator) => {
6837
6918
  frame_crop_right_offset,
6838
6919
  frame_crop_top_offset,
6839
6920
  mb_adaptive_frame_field_flag,
6840
- vui_parameters
6921
+ vui_parameters,
6922
+ pic_order_cnt_type
6841
6923
  };
6842
6924
  };
6843
6925
  var findEnd = (buffer) => {
@@ -6855,17 +6937,23 @@ var findEnd = (buffer) => {
6855
6937
  }
6856
6938
  return null;
6857
6939
  };
6858
- var inspect = (buffer) => {
6940
+ var inspect = (buffer, avcState) => {
6859
6941
  const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
6860
6942
  iterator.startReadingBits();
6861
6943
  iterator.getBits(1);
6862
- iterator.getBits(2);
6944
+ const nal_ref_idc = iterator.getBits(2);
6945
+ const isReferencePicture = nal_ref_idc !== 0;
6863
6946
  const type = iterator.getBits(5);
6864
- iterator.stopReadingBits();
6865
6947
  if (type === 7) {
6948
+ iterator.stopReadingBits();
6866
6949
  const end = findEnd(buffer);
6867
6950
  const data = readSps(iterator);
6868
6951
  const sps = buffer.slice(0, end === null ? Infinity : end);
6952
+ avcState.setSps(data);
6953
+ if (isReferencePicture) {
6954
+ avcState.setPrevPicOrderCntLsb(0);
6955
+ avcState.setPrevPicOrderCntMsb(0);
6956
+ }
6869
6957
  return {
6870
6958
  spsData: data,
6871
6959
  sps,
@@ -6873,11 +6961,31 @@ var inspect = (buffer) => {
6873
6961
  };
6874
6962
  }
6875
6963
  if (type === 5) {
6964
+ avcState.setPrevPicOrderCntLsb(0);
6965
+ avcState.setPrevPicOrderCntMsb(0);
6966
+ iterator.readExpGolomb();
6967
+ iterator.readExpGolomb();
6968
+ iterator.readExpGolomb();
6969
+ const sps = avcState.getSps();
6970
+ if (!sps) {
6971
+ throw new Error("SPS not found");
6972
+ }
6973
+ const numberOfBitsForFrameNum = sps.log2_max_frame_num_minus4 + 4;
6974
+ iterator.getBits(numberOfBitsForFrameNum);
6975
+ iterator.readExpGolomb();
6976
+ const { pic_order_cnt_type } = sps;
6977
+ let poc = null;
6978
+ if (pic_order_cnt_type === 0) {
6979
+ poc = getPoc(iterator, sps, avcState, isReferencePicture);
6980
+ }
6981
+ iterator.stopReadingBits();
6876
6982
  return {
6877
- type: "keyframe"
6983
+ type: "keyframe",
6984
+ poc
6878
6985
  };
6879
6986
  }
6880
6987
  if (type === 8) {
6988
+ iterator.stopReadingBits();
6881
6989
  const end = findEnd(buffer);
6882
6990
  const pps = buffer.slice(0, end === null ? Infinity : end);
6883
6991
  return {
@@ -6886,14 +6994,32 @@ var inspect = (buffer) => {
6886
6994
  };
6887
6995
  }
6888
6996
  if (type === 1) {
6997
+ iterator.readExpGolomb();
6998
+ const slice_type = iterator.readExpGolomb();
6999
+ const isBidirectionalFrame = slice_type === 6;
7000
+ iterator.readExpGolomb();
7001
+ const sps = avcState.getSps();
7002
+ if (!sps) {
7003
+ throw new Error("SPS not found");
7004
+ }
7005
+ const numberOfBitsForFrameNum = sps.log2_max_frame_num_minus4 + 4;
7006
+ iterator.getBits(numberOfBitsForFrameNum);
7007
+ const { pic_order_cnt_type } = sps;
7008
+ let poc = null;
7009
+ if (pic_order_cnt_type === 0) {
7010
+ poc = getPoc(iterator, sps, avcState, isReferencePicture);
7011
+ }
7012
+ iterator.stopReadingBits();
6889
7013
  return {
6890
- type: "delta-frame"
7014
+ type: "delta-frame",
7015
+ isBidirectionalFrame,
7016
+ poc
6891
7017
  };
6892
7018
  }
6893
7019
  iterator.destroy();
6894
7020
  return null;
6895
7021
  };
6896
- var parseAvc = (buffer) => {
7022
+ var parseAvc = (buffer, avcState) => {
6897
7023
  let zeroesInARow = 0;
6898
7024
  const infos = [];
6899
7025
  for (let i = 0;i < buffer.length; i++) {
@@ -6904,7 +7030,7 @@ var parseAvc = (buffer) => {
6904
7030
  }
6905
7031
  if (zeroesInARow >= 2 && val === 1) {
6906
7032
  zeroesInARow = 0;
6907
- const info = inspect(buffer.slice(i + 1, i + 100));
7033
+ const info = inspect(buffer.slice(i + 1, i + 100), avcState);
6908
7034
  if (info) {
6909
7035
  infos.push(info);
6910
7036
  if (info.type === "keyframe" || info.type === "delta-frame") {
@@ -6939,9 +7065,10 @@ var handleAvcPacket = async ({
6939
7065
  logLevel,
6940
7066
  onVideoTrack,
6941
7067
  transportStream,
6942
- makeSamplesStartAtZero
7068
+ makeSamplesStartAtZero,
7069
+ avcState
6943
7070
  }) => {
6944
- const avc = parseAvc(streamBuffer.getBuffer());
7071
+ const avc = parseAvc(streamBuffer.getBuffer(), avcState);
6945
7072
  const isTrackRegistered = sampleCallbacks.tracks.getTracks().find((t) => {
6946
7073
  return t.trackId === programId;
6947
7074
  });
@@ -6978,7 +7105,8 @@ var handleAvcPacket = async ({
6978
7105
  numerator: sampleAspectRatio.width
6979
7106
  },
6980
7107
  colorSpace: mediaParserAdvancedColorToWebCodecsColor(advancedColor),
6981
- advancedColor
7108
+ advancedColor,
7109
+ startInSeconds: 0
6982
7110
  };
6983
7111
  await registerVideoTrack({
6984
7112
  track,
@@ -6997,7 +7125,7 @@ var handleAvcPacket = async ({
6997
7125
  duration: undefined,
6998
7126
  data: streamBuffer.getBuffer(),
6999
7127
  trackId: programId,
7000
- type,
7128
+ type: type === "bidirectional" ? "delta" : type,
7001
7129
  offset,
7002
7130
  timescale: MPEG_TIMESCALE
7003
7131
  };
@@ -7064,7 +7192,8 @@ var getSeekingByte = ({
7064
7192
  m3uPlaylistContext,
7065
7193
  structure,
7066
7194
  riffState,
7067
- m3uState
7195
+ m3uState,
7196
+ avcState
7068
7197
  }) => {
7069
7198
  if (info.type === "iso-base-media-seeking-hints") {
7070
7199
  return getSeekingByteFromIsoBaseMedia({
@@ -7124,7 +7253,8 @@ var getSeekingByte = ({
7124
7253
  return getSeekingByteForRiff({
7125
7254
  info,
7126
7255
  time,
7127
- riffState
7256
+ riffState,
7257
+ avcState
7128
7258
  });
7129
7259
  }
7130
7260
  if (info.type === "mp3-seeking-hints") {
@@ -7687,7 +7817,8 @@ var turnSeekIntoByte = async ({
7687
7817
  mp3State,
7688
7818
  contentLength,
7689
7819
  aacState,
7690
- m3uState
7820
+ m3uState,
7821
+ avcState
7691
7822
  }) => {
7692
7823
  const mediaSections = mediaSectionState2.getMediaSections();
7693
7824
  if (mediaSections.length === 0) {
@@ -7733,7 +7864,8 @@ var turnSeekIntoByte = async ({
7733
7864
  m3uPlaylistContext,
7734
7865
  structure: structureState,
7735
7866
  riffState,
7736
- m3uState
7867
+ m3uState,
7868
+ avcState
7737
7869
  });
7738
7870
  return seekingByte;
7739
7871
  };
@@ -7764,7 +7896,8 @@ var getWorkOnSeekRequestOptions = (state) => {
7764
7896
  mp3State: state.mp3,
7765
7897
  aacState: state.aac,
7766
7898
  m3uState: state.m3u,
7767
- prefetchCache: state.prefetchCache
7899
+ prefetchCache: state.prefetchCache,
7900
+ avcState: state.avc
7768
7901
  };
7769
7902
  };
7770
7903
  var workOnSeekRequest = async (options) => {
@@ -7794,7 +7927,8 @@ var workOnSeekRequest = async (options) => {
7794
7927
  mp3State,
7795
7928
  aacState,
7796
7929
  prefetchCache,
7797
- m3uState
7930
+ m3uState,
7931
+ avcState
7798
7932
  } = options;
7799
7933
  const seek2 = controller._internals.seekSignal.getSeek();
7800
7934
  if (seek2 === null) {
@@ -7819,7 +7953,8 @@ var workOnSeekRequest = async (options) => {
7819
7953
  mp3State,
7820
7954
  contentLength,
7821
7955
  aacState,
7822
- m3uState
7956
+ m3uState,
7957
+ avcState
7823
7958
  });
7824
7959
  Log.trace(logLevel, `Seek action: ${JSON.stringify(resolution)}`);
7825
7960
  if (resolution.type === "intermediary-seek") {
@@ -8398,6 +8533,10 @@ var checkIfDone = async (state) => {
8398
8533
  if (state.structure.getStructure().type === "m3u" && !state.m3u.getAllChunksProcessedOverall()) {
8399
8534
  return false;
8400
8535
  }
8536
+ state.riff.queuedBFrames.flush();
8537
+ if (state.riff.queuedBFrames.hasReleasedFrames()) {
8538
+ return false;
8539
+ }
8401
8540
  Log.verbose(state.logLevel, "Reached end of file");
8402
8541
  await state.discardReadBytes(true);
8403
8542
  return true;
@@ -8476,7 +8615,8 @@ var parseAac = async (state) => {
8476
8615
  sampleRate,
8477
8616
  timescale: 1e6,
8478
8617
  trackId: 0,
8479
- type: "audio"
8618
+ type: "audio",
8619
+ startInSeconds: 0
8480
8620
  },
8481
8621
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
8482
8622
  tracks: state.callbacks.tracks,
@@ -8877,7 +9017,8 @@ var parseStreamInfo = async ({
8877
9017
  numberOfChannels: channels2,
8878
9018
  sampleRate,
8879
9019
  timescale: 1e6,
8880
- trackId: 0
9020
+ trackId: 0,
9021
+ startInSeconds: 0
8881
9022
  },
8882
9023
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
8883
9024
  tracks: state.callbacks.tracks,
@@ -9195,6 +9336,41 @@ var structureState = () => {
9195
9336
  };
9196
9337
  };
9197
9338
 
9339
+ // src/containers/iso-base-media/elst.ts
9340
+ var parseElst = ({
9341
+ iterator,
9342
+ size,
9343
+ offset
9344
+ }) => {
9345
+ const { expectNoMoreBytes } = iterator.startBox(size - 8);
9346
+ const version = iterator.getUint8();
9347
+ const flags = iterator.getUint24();
9348
+ const entryCount = iterator.getUint32();
9349
+ const entries = [];
9350
+ for (let i = 0;i < entryCount; i++) {
9351
+ const editDuration = iterator.getUint32();
9352
+ const mediaTime = iterator.getInt32();
9353
+ const mediaRateInteger = iterator.getUint16();
9354
+ const mediaRateFraction = iterator.getUint16();
9355
+ entries.push({
9356
+ editDuration,
9357
+ mediaTime,
9358
+ mediaRateInteger,
9359
+ mediaRateFraction
9360
+ });
9361
+ }
9362
+ expectNoMoreBytes();
9363
+ const result = {
9364
+ type: "elst-box",
9365
+ version,
9366
+ flags,
9367
+ entries,
9368
+ boxSize: size,
9369
+ offset
9370
+ };
9371
+ return result;
9372
+ };
9373
+
9198
9374
  // src/containers/iso-base-media/esds/decoder-specific-config.ts
9199
9375
  var parseDecoderSpecificConfig = (iterator) => {
9200
9376
  const layerTag = iterator.getUint8();
@@ -10793,6 +10969,16 @@ var processBox = async ({
10793
10969
  box: parseFtyp({ iterator, size: boxSize, offset: fileOffset })
10794
10970
  };
10795
10971
  }
10972
+ if (boxType === "elst") {
10973
+ return {
10974
+ type: "box",
10975
+ box: parseElst({
10976
+ iterator,
10977
+ size: boxSize,
10978
+ offset: fileOffset
10979
+ })
10980
+ };
10981
+ }
10796
10982
  if (boxType === "colr") {
10797
10983
  return {
10798
10984
  type: "box",
@@ -10803,9 +10989,18 @@ var processBox = async ({
10803
10989
  };
10804
10990
  }
10805
10991
  if (boxType === "mvhd") {
10992
+ const mvhdBox = parseMvhd({
10993
+ iterator,
10994
+ offset: fileOffset,
10995
+ size: boxSize
10996
+ });
10997
+ if (!onlyIfMoovAtomExpected) {
10998
+ throw new Error("State is required");
10999
+ }
11000
+ onlyIfMoovAtomExpected.movieTimeScaleState.setTrackTimescale(mvhdBox.timeScale);
10806
11001
  return {
10807
11002
  type: "box",
10808
- box: parseMvhd({ iterator, offset: fileOffset, size: boxSize })
11003
+ box: mvhdBox
10809
11004
  };
10810
11005
  }
10811
11006
  if (boxType === "tkhd") {
@@ -10973,14 +11168,19 @@ var processBox = async ({
10973
11168
  throw new Error("State is required");
10974
11169
  }
10975
11170
  const { tracks: tracks2, onAudioTrack, onVideoTrack } = onlyIfMoovAtomExpected;
10976
- const box = await parseTrak({
11171
+ const trakBox = await parseTrak({
10977
11172
  size: boxSize,
10978
11173
  offsetAtStart: fileOffset,
10979
11174
  iterator,
10980
11175
  logLevel,
10981
11176
  contentLength
10982
11177
  });
10983
- const transformedTrack = makeBaseMediaTrack(box);
11178
+ const movieTimeScale = onlyIfMoovAtomExpected.movieTimeScaleState.getTrackTimescale();
11179
+ if (movieTimeScale === null) {
11180
+ throw new Error("Movie timescale is not set");
11181
+ }
11182
+ const editList = findTrackStartTimeInSeconds({ movieTimeScale, trakBox });
11183
+ const transformedTrack = makeBaseMediaTrack(trakBox, editList);
10984
11184
  if (transformedTrack && transformedTrack.type === "video") {
10985
11185
  await registerVideoTrack({
10986
11186
  track: transformedTrack,
@@ -11001,7 +11201,7 @@ var processBox = async ({
11001
11201
  onAudioTrack
11002
11202
  });
11003
11203
  }
11004
- return { type: "box", box };
11204
+ return { type: "box", box: trakBox };
11005
11205
  }
11006
11206
  if (boxType === "stts") {
11007
11207
  return {
@@ -11074,7 +11274,7 @@ var processBox = async ({
11074
11274
  if (boxType === "moof") {
11075
11275
  await onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
11076
11276
  }
11077
- if (boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "mfra" || boxType === "stsb") {
11277
+ 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") {
11078
11278
  const children = await getIsoBaseMediaChildren({
11079
11279
  iterator,
11080
11280
  size: boxSize - 8,
@@ -11175,6 +11375,7 @@ var getMoovAtom = async ({
11175
11375
  onlyIfMoovAtomExpected: {
11176
11376
  tracks: tracksState,
11177
11377
  isoState: null,
11378
+ movieTimeScaleState: state.iso.movieTimeScale,
11178
11379
  onAudioTrack,
11179
11380
  onVideoTrack,
11180
11381
  registerVideoSampleCallback: () => Promise.resolve(),
@@ -11415,7 +11616,18 @@ var parseMdatSection = async (state) => {
11415
11616
  if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
11416
11617
  return makeFetchMoreData(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
11417
11618
  }
11418
- const { cts, dts, duration: duration2, isKeyframe, offset, bigEndian, chunkSize } = samplesWithIndex.samplePosition;
11619
+ const {
11620
+ cts: rawCts,
11621
+ dts: rawDts,
11622
+ duration: duration2,
11623
+ isKeyframe,
11624
+ offset,
11625
+ bigEndian,
11626
+ chunkSize
11627
+ } = samplesWithIndex.samplePosition;
11628
+ const { timescale, startInSeconds } = samplesWithIndex.track;
11629
+ const cts = rawCts + startInSeconds * timescale;
11630
+ const dts = rawDts + startInSeconds * timescale;
11419
11631
  const bytes = postprocessBytes({
11420
11632
  bytes: iterator.getSlice(samplesWithIndex.samplePosition.size),
11421
11633
  bigEndian,
@@ -11432,9 +11644,9 @@ var parseMdatSection = async (state) => {
11432
11644
  trackId: samplesWithIndex.track.trackId,
11433
11645
  type: isKeyframe ? "key" : "delta",
11434
11646
  offset,
11435
- timescale: samplesWithIndex.track.timescale
11647
+ timescale
11436
11648
  },
11437
- timescale: samplesWithIndex.track.timescale
11649
+ timescale
11438
11650
  });
11439
11651
  await state.callbacks.onAudioSample(samplesWithIndex.track.trackId, audioSample);
11440
11652
  }
@@ -11455,9 +11667,9 @@ var parseMdatSection = async (state) => {
11455
11667
  trackId: samplesWithIndex.track.trackId,
11456
11668
  type: isKeyframe && !isRecoveryPoint ? "key" : "delta",
11457
11669
  offset,
11458
- timescale: samplesWithIndex.track.timescale
11670
+ timescale
11459
11671
  },
11460
- timescale: samplesWithIndex.track.timescale
11672
+ timescale
11461
11673
  });
11462
11674
  await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, videoSample);
11463
11675
  }
@@ -11482,6 +11694,7 @@ var parseIsoBaseMedia = async (state) => {
11482
11694
  onlyIfMoovAtomExpected: {
11483
11695
  tracks: state.callbacks.tracks,
11484
11696
  isoState: state.iso,
11697
+ movieTimeScaleState: state.iso.movieTimeScale,
11485
11698
  onAudioTrack: state.onAudioTrack,
11486
11699
  onVideoTrack: state.onVideoTrack,
11487
11700
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
@@ -12765,7 +12978,8 @@ var parseMpegHeader = async ({
12765
12978
  numberOfChannels,
12766
12979
  sampleRate,
12767
12980
  timescale: 1e6,
12768
- trackId: 0
12981
+ trackId: 0,
12982
+ startInSeconds: 0
12769
12983
  },
12770
12984
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
12771
12985
  tracks: state.callbacks.tracks,
@@ -12861,6 +13075,73 @@ var parseMp3 = async (state) => {
12861
13075
  throw new Error("Unknown MP3 header " + JSON.stringify(bytes));
12862
13076
  };
12863
13077
 
13078
+ // src/containers/riff/get-strh-for-index.ts
13079
+ var getStrhForIndex = (structure, trackId) => {
13080
+ const boxes = getStrlBoxes(structure);
13081
+ const box = boxes[trackId];
13082
+ if (!box) {
13083
+ throw new Error("Expected box");
13084
+ }
13085
+ const strh = getStrhBox(box.children);
13086
+ if (!strh) {
13087
+ throw new Error("strh");
13088
+ }
13089
+ return strh;
13090
+ };
13091
+
13092
+ // src/containers/riff/convert-queued-sample-to-mediaparser-sample.ts
13093
+ var getKeyFrameOffsetAndPocs = ({
13094
+ state,
13095
+ sample
13096
+ }) => {
13097
+ if (sample.type === "key") {
13098
+ const sampleOffset = state.riff.sampleCounter.getSampleCountForTrack({
13099
+ trackId: sample.trackId
13100
+ });
13101
+ return {
13102
+ sampleOffsetAtKeyframe: sampleOffset,
13103
+ pocsAtKeyframeOffset: [sample.avc?.poc ?? 0]
13104
+ };
13105
+ }
13106
+ const riffKeyframes = state.riff.sampleCounter.riffKeys.getKeyframes();
13107
+ const keyframeAtOffset = riffKeyframes.findLast((k) => k.positionInBytes <= sample.offset);
13108
+ if (!keyframeAtOffset) {
13109
+ throw new Error("no keyframe at offset");
13110
+ }
13111
+ const sampleOffsetAtKeyframe = keyframeAtOffset.sampleCounts[sample.trackId];
13112
+ const pocsAtKeyframeOffset = state.riff.sampleCounter.getPocAtKeyframeOffset({
13113
+ keyframeOffset: keyframeAtOffset.positionInBytes
13114
+ });
13115
+ return {
13116
+ sampleOffsetAtKeyframe,
13117
+ pocsAtKeyframeOffset
13118
+ };
13119
+ };
13120
+ var convertQueuedSampleToMediaParserSample = (sample, state) => {
13121
+ const strh = getStrhForIndex(state.structure.getRiffStructure(), sample.trackId);
13122
+ const samplesPerSecond = strh.rate / strh.scale;
13123
+ const { sampleOffsetAtKeyframe, pocsAtKeyframeOffset } = getKeyFrameOffsetAndPocs({
13124
+ sample,
13125
+ state
13126
+ });
13127
+ const indexOfPoc = pocsAtKeyframeOffset.findIndex((poc) => poc === sample.avc?.poc);
13128
+ if (indexOfPoc === -1) {
13129
+ throw new Error("poc not found");
13130
+ }
13131
+ const nthSample = indexOfPoc + sampleOffsetAtKeyframe;
13132
+ const timestamp = nthSample / samplesPerSecond;
13133
+ const videoSample = convertAudioOrVideoSampleToWebCodecsTimestamps({
13134
+ sample: {
13135
+ ...sample,
13136
+ timestamp,
13137
+ cts: timestamp,
13138
+ dts: timestamp
13139
+ },
13140
+ timescale: 1
13141
+ });
13142
+ return videoSample;
13143
+ };
13144
+
12864
13145
  // src/containers/riff/is-movi.ts
12865
13146
  var isMoviAtom = (iterator, ckId) => {
12866
13147
  if (ckId !== "LIST") {
@@ -13239,18 +13520,6 @@ var expectRiffBox = async ({
13239
13520
  };
13240
13521
 
13241
13522
  // src/containers/riff/parse-movi.ts
13242
- var getStrhForIndex = (structure, trackId) => {
13243
- const boxes = getStrlBoxes(structure);
13244
- const box = boxes[trackId];
13245
- if (!box) {
13246
- throw new Error("Expected box");
13247
- }
13248
- const strh = getStrhBox(box.children);
13249
- if (!strh) {
13250
- throw new Error("strh");
13251
- }
13252
- return strh;
13253
- };
13254
13523
  var handleChunk = async ({
13255
13524
  state,
13256
13525
  ckId,
@@ -13263,42 +13532,60 @@ var handleChunk = async ({
13263
13532
  const trackId = parseInt(videoChunk[1], 10);
13264
13533
  const strh = getStrhForIndex(state.structure.getRiffStructure(), trackId);
13265
13534
  const samplesPerSecond = strh.rate / strh.scale;
13266
- const nthSample = state.riff.sampleCounter.getSamplesForTrack(trackId);
13267
- const timeInSec = nthSample / samplesPerSecond;
13268
- const timestamp = timeInSec;
13269
13535
  const data = iterator.getSlice(ckSize);
13270
- const infos = parseAvc(data);
13536
+ const infos = parseAvc(data, state.avc);
13271
13537
  const keyOrDelta = getKeyFrameOrDeltaFromAvcInfo(infos);
13538
+ const info = infos.find((i) => i.type === "keyframe" || i.type === "delta-frame");
13272
13539
  const avcProfile = infos.find((i) => i.type === "avc-profile");
13273
13540
  const ppsProfile = infos.find((i) => i.type === "avc-pps");
13274
13541
  if (avcProfile && ppsProfile && !state.riff.getAvcProfile()) {
13275
13542
  await state.riff.onProfile({ pps: ppsProfile, sps: avcProfile });
13276
13543
  state.callbacks.tracks.setIsDone(state.logLevel);
13277
13544
  }
13278
- const videoSample = convertAudioOrVideoSampleToWebCodecsTimestamps({
13279
- sample: {
13280
- cts: timestamp,
13281
- dts: timestamp,
13282
- data,
13283
- duration: undefined,
13284
- timestamp,
13285
- trackId,
13286
- type: keyOrDelta,
13287
- offset,
13288
- timescale: samplesPerSecond
13289
- },
13290
- timescale: 1
13291
- });
13292
- state.riff.sampleCounter.onVideoSample(trackId, videoSample);
13545
+ const rawSample = {
13546
+ data,
13547
+ duration: 1 / samplesPerSecond,
13548
+ trackId,
13549
+ type: keyOrDelta === "bidirectional" ? "delta" : keyOrDelta,
13550
+ offset,
13551
+ timescale: samplesPerSecond,
13552
+ avc: info
13553
+ };
13554
+ const maxFramesInBuffer = state.avc.getMaxFramesInBuffer();
13555
+ if (maxFramesInBuffer === null) {
13556
+ throw new Error("maxFramesInBuffer is null");
13557
+ }
13558
+ if ((info?.poc ?? null) === null) {
13559
+ throw new Error("poc is null");
13560
+ }
13561
+ const keyframeOffset = state.riff.sampleCounter.getKeyframeAtOffset(rawSample);
13562
+ if (keyframeOffset !== null) {
13563
+ state.riff.sampleCounter.setPocAtKeyframeOffset({
13564
+ keyframeOffset,
13565
+ poc: info.poc
13566
+ });
13567
+ }
13568
+ state.riff.queuedBFrames.addFrame(rawSample, maxFramesInBuffer);
13569
+ const releasedFrame = state.riff.queuedBFrames.getReleasedFrame();
13570
+ if (!releasedFrame) {
13571
+ return;
13572
+ }
13573
+ const videoSample = convertQueuedSampleToMediaParserSample(releasedFrame, state);
13574
+ state.riff.sampleCounter.onVideoSample(videoSample);
13293
13575
  await state.callbacks.onVideoSample(trackId, videoSample);
13294
- return;
13295
13576
  }
13296
13577
  const audioChunk = ckId.match(/^([0-9]{2})wb$/);
13297
13578
  if (audioChunk) {
13298
13579
  const trackId = parseInt(audioChunk[1], 10);
13299
13580
  const strh = getStrhForIndex(state.structure.getRiffStructure(), trackId);
13300
- const samplesPerSecond = strh.rate / strh.scale;
13301
- const nthSample = state.riff.sampleCounter.getSamplesForTrack(trackId);
13581
+ const { strf } = strh;
13582
+ if (strf.type !== "strf-box-audio") {
13583
+ throw new Error("audio");
13584
+ }
13585
+ const samplesPerSecond = strh.rate / strh.scale * strf.numberOfChannels;
13586
+ const nthSample = state.riff.sampleCounter.getSampleCountForTrack({
13587
+ trackId
13588
+ });
13302
13589
  const timeInSec = nthSample / samplesPerSecond;
13303
13590
  const timestamp = timeInSec;
13304
13591
  const data = iterator.getSlice(ckSize);
@@ -13358,6 +13645,13 @@ var parseMediaSection = async (state) => {
13358
13645
 
13359
13646
  // src/containers/riff/parse-riff-body.ts
13360
13647
  var parseRiffBody = async (state) => {
13648
+ const releasedFrame = state.riff.queuedBFrames.getReleasedFrame();
13649
+ if (releasedFrame) {
13650
+ const converted = convertQueuedSampleToMediaParserSample(releasedFrame, state);
13651
+ state.riff.sampleCounter.onVideoSample(converted);
13652
+ await state.callbacks.onVideoSample(releasedFrame.trackId, converted);
13653
+ return null;
13654
+ }
13361
13655
  if (state.mediaSection.isCurrentByteInMediaSection(state.iterator) === "in-section") {
13362
13656
  if (maySkipVideoData({
13363
13657
  state
@@ -13738,7 +14032,8 @@ var handleAacPacket = async ({
13738
14032
  codec: mapAudioObjectTypeToCodecString(audioObjectType),
13739
14033
  description: codecPrivate2,
13740
14034
  numberOfChannels: channelConfiguration,
13741
- sampleRate
14035
+ sampleRate,
14036
+ startInSeconds: 0
13742
14037
  };
13743
14038
  await registerAudioTrack({
13744
14039
  track,
@@ -13825,7 +14120,8 @@ var processStreamBuffer = async ({
13825
14120
  onAudioTrack,
13826
14121
  onVideoTrack,
13827
14122
  transportStream,
13828
- makeSamplesStartAtZero
14123
+ makeSamplesStartAtZero,
14124
+ avcState
13829
14125
  }) => {
13830
14126
  const stream = getStreamForId(structure, programId);
13831
14127
  if (!stream) {
@@ -13843,7 +14139,8 @@ var processStreamBuffer = async ({
13843
14139
  onVideoTrack,
13844
14140
  offset: streamBuffer.offset,
13845
14141
  transportStream,
13846
- makeSamplesStartAtZero
14142
+ makeSamplesStartAtZero,
14143
+ avcState
13847
14144
  });
13848
14145
  } else if (stream.streamType === 15) {
13849
14146
  await handleAacPacket({
@@ -13872,7 +14169,8 @@ var processFinalStreamBuffers = async ({
13872
14169
  onAudioTrack,
13873
14170
  onVideoTrack,
13874
14171
  transportStream,
13875
- makeSamplesStartAtZero
14172
+ makeSamplesStartAtZero,
14173
+ avcState
13876
14174
  }) => {
13877
14175
  for (const [programId, buffer] of transportStream.streamBuffers) {
13878
14176
  if (buffer.getBuffer().byteLength > 0) {
@@ -13885,7 +14183,8 @@ var processFinalStreamBuffers = async ({
13885
14183
  onAudioTrack,
13886
14184
  onVideoTrack,
13887
14185
  transportStream,
13888
- makeSamplesStartAtZero
14186
+ makeSamplesStartAtZero,
14187
+ avcState
13889
14188
  });
13890
14189
  transportStream.streamBuffers.delete(programId);
13891
14190
  }
@@ -14012,7 +14311,8 @@ var processAudio = async ({
14012
14311
  onAudioTrack,
14013
14312
  onVideoTrack,
14014
14313
  transportStream,
14015
- makeSamplesStartAtZero
14314
+ makeSamplesStartAtZero,
14315
+ avcState
14016
14316
  }) => {
14017
14317
  const { streamBuffers, nextPesHeaderStore: nextPesHeader } = transportStream;
14018
14318
  const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
@@ -14039,7 +14339,8 @@ var processAudio = async ({
14039
14339
  onAudioTrack,
14040
14340
  onVideoTrack,
14041
14341
  transportStream,
14042
- makeSamplesStartAtZero
14342
+ makeSamplesStartAtZero,
14343
+ avcState
14043
14344
  });
14044
14345
  const rest = streamBuffer.getBuffer().slice(expectedLength);
14045
14346
  streamBuffers.set(transportStreamEntry.pid, makeTransportStreamPacketBuffer({
@@ -14068,7 +14369,8 @@ var processVideo = async ({
14068
14369
  onAudioTrack,
14069
14370
  onVideoTrack,
14070
14371
  transportStream,
14071
- makeSamplesStartAtZero
14372
+ makeSamplesStartAtZero,
14373
+ avcState
14072
14374
  }) => {
14073
14375
  const indexOfSeparator = streamBuffer.get2ndSubArrayIndex();
14074
14376
  if (indexOfSeparator === -1 || indexOfSeparator === 0) {
@@ -14090,7 +14392,8 @@ var processVideo = async ({
14090
14392
  onAudioTrack,
14091
14393
  onVideoTrack,
14092
14394
  transportStream,
14093
- makeSamplesStartAtZero
14395
+ makeSamplesStartAtZero,
14396
+ avcState
14094
14397
  });
14095
14398
  return rest;
14096
14399
  };
@@ -14118,7 +14421,8 @@ var processSampleIfPossible = async (state) => {
14118
14421
  onAudioTrack: state.onAudioTrack,
14119
14422
  onVideoTrack: state.onVideoTrack,
14120
14423
  transportStream: state.transportStream,
14121
- makeSamplesStartAtZero: state.makeSamplesStartAtZero
14424
+ makeSamplesStartAtZero: state.makeSamplesStartAtZero,
14425
+ avcState: state.avc
14122
14426
  });
14123
14427
  state.transportStream.streamBuffers.delete(stream.pid);
14124
14428
  state.transportStream.streamBuffers.set(stream.pid, makeTransportStreamPacketBuffer({
@@ -14141,7 +14445,8 @@ var processSampleIfPossible = async (state) => {
14141
14445
  onVideoTrack: state.onVideoTrack,
14142
14446
  transportStream: state.transportStream,
14143
14447
  makeSamplesStartAtZero: state.makeSamplesStartAtZero,
14144
- transportStreamEntry: stream
14448
+ transportStreamEntry: stream,
14449
+ avcState: state.avc
14145
14450
  });
14146
14451
  processed = true;
14147
14452
  break;
@@ -14178,7 +14483,8 @@ var parseTransportStream = async (state) => {
14178
14483
  logLevel: state.logLevel,
14179
14484
  onAudioTrack: state.onAudioTrack,
14180
14485
  onVideoTrack: state.onVideoTrack,
14181
- makeSamplesStartAtZero: state.makeSamplesStartAtZero
14486
+ makeSamplesStartAtZero: state.makeSamplesStartAtZero,
14487
+ avcState: state.avc
14182
14488
  });
14183
14489
  }
14184
14490
  return Promise.resolve(null);
@@ -14245,7 +14551,8 @@ var parseFmt = async ({
14245
14551
  numberOfChannels,
14246
14552
  sampleRate,
14247
14553
  timescale: 1e6,
14248
- trackId: 0
14554
+ trackId: 0,
14555
+ startInSeconds: 0
14249
14556
  },
14250
14557
  container: "wav",
14251
14558
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
@@ -14458,7 +14765,8 @@ var addAvcToTrackAndActivateTrackIfNecessary = async ({
14458
14765
  trackNumber: trackNumber2,
14459
14766
  logLevel,
14460
14767
  callbacks,
14461
- onVideoTrack
14768
+ onVideoTrack,
14769
+ avcState
14462
14770
  }) => {
14463
14771
  if (codec !== "V_MPEG4/ISO/AVC") {
14464
14772
  return;
@@ -14470,7 +14778,7 @@ var addAvcToTrackAndActivateTrackIfNecessary = async ({
14470
14778
  if (missingTracks.length === 0) {
14471
14779
  return;
14472
14780
  }
14473
- const parsed = parseAvc(partialVideoSample.data);
14781
+ const parsed = parseAvc(partialVideoSample.data, avcState);
14474
14782
  for (const parse of parsed) {
14475
14783
  if (parse.type === "avc-profile") {
14476
14784
  webmState.setAvcProfileForTrackNumber(trackNumber2, parse);
@@ -14504,7 +14812,8 @@ var getSampleFromBlock = async ({
14504
14812
  structureState: structureState2,
14505
14813
  callbacks,
14506
14814
  logLevel,
14507
- onVideoTrack
14815
+ onVideoTrack,
14816
+ avcState
14508
14817
  }) => {
14509
14818
  const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
14510
14819
  const trackNumber2 = iterator.getVint();
@@ -14551,7 +14860,8 @@ var getSampleFromBlock = async ({
14551
14860
  trackNumber: trackNumber2,
14552
14861
  callbacks,
14553
14862
  logLevel,
14554
- onVideoTrack
14863
+ onVideoTrack,
14864
+ avcState
14555
14865
  });
14556
14866
  const sample = {
14557
14867
  ...partialVideoSample,
@@ -14685,7 +14995,8 @@ var postprocessEbml = async ({
14685
14995
  logLevel,
14686
14996
  onAudioTrack,
14687
14997
  onVideoTrack,
14688
- structureState: structureState2
14998
+ structureState: structureState2,
14999
+ avcState
14689
15000
  }
14690
15001
  }) => {
14691
15002
  if (ebml.type === "TimestampScale") {
@@ -14734,7 +15045,8 @@ var postprocessEbml = async ({
14734
15045
  structureState: structureState2,
14735
15046
  callbacks,
14736
15047
  logLevel,
14737
- onVideoTrack
15048
+ onVideoTrack,
15049
+ avcState
14738
15050
  });
14739
15051
  if (sample.type === "video-sample") {
14740
15052
  await callbacks.onVideoSample(sample.videoSample.trackId, sample.videoSample);
@@ -14773,7 +15085,8 @@ var postprocessEbml = async ({
14773
15085
  structureState: structureState2,
14774
15086
  callbacks,
14775
15087
  logLevel,
14776
- onVideoTrack
15088
+ onVideoTrack,
15089
+ avcState
14777
15090
  });
14778
15091
  if (sample && sample.type === "partial-video-sample") {
14779
15092
  const completeFrame = {
@@ -14902,7 +15215,8 @@ var selectStatesForProcessing = ({
14902
15215
  onAudioTrack,
14903
15216
  onVideoTrack,
14904
15217
  structure,
14905
- webm
15218
+ webm,
15219
+ avc
14906
15220
  }) => {
14907
15221
  return {
14908
15222
  webmState: webm,
@@ -14910,7 +15224,8 @@ var selectStatesForProcessing = ({
14910
15224
  logLevel,
14911
15225
  onAudioTrack,
14912
15226
  onVideoTrack,
14913
- structureState: structure
15227
+ structureState: structure,
15228
+ avcState: avc
14914
15229
  };
14915
15230
  };
14916
15231
 
@@ -15120,9 +15435,6 @@ var runParseIteration = async ({
15120
15435
  if (structure && structure.type === "m3u") {
15121
15436
  return parseM3u({ state });
15122
15437
  }
15123
- if (state.iterator.bytesRemaining() === 0) {
15124
- return Promise.reject(new Error("no bytes"));
15125
- }
15126
15438
  if (structure === null) {
15127
15439
  await initVideo({
15128
15440
  state
@@ -15423,6 +15735,82 @@ var aacState = () => {
15423
15735
  };
15424
15736
  };
15425
15737
 
15738
+ // src/containers/avc/max-buffer-size.ts
15739
+ var maxMacroblocksByLevel = {
15740
+ 10: 396,
15741
+ 11: 900,
15742
+ 12: 2376,
15743
+ 13: 2376,
15744
+ 20: 2376,
15745
+ 21: 4752,
15746
+ 22: 8100,
15747
+ 30: 8100,
15748
+ 31: 18000,
15749
+ 32: 20480,
15750
+ 40: 32768,
15751
+ 41: 32768,
15752
+ 42: 34816,
15753
+ 50: 110400,
15754
+ 51: 184320,
15755
+ 52: 184320,
15756
+ 60: 696320,
15757
+ 61: 696320,
15758
+ 62: 696320
15759
+ };
15760
+ var macroBlocksPerFrame = (sps) => {
15761
+ const { pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 } = sps;
15762
+ return (pic_width_in_mbs_minus1 + 1) * (pic_height_in_map_units_minus1 + 1);
15763
+ };
15764
+ var maxMacroblockBufferSize = (sps) => {
15765
+ const { level } = sps;
15766
+ const maxMacroblocks = maxMacroblocksByLevel[level];
15767
+ if (maxMacroblocks === undefined) {
15768
+ throw new Error(`Unsupported level: ${level.toString(16)}`);
15769
+ }
15770
+ return maxMacroblocks;
15771
+ };
15772
+
15773
+ // src/state/avc/avc-state.ts
15774
+ var avcState = () => {
15775
+ let prevPicOrderCntLsb = 0;
15776
+ let prevPicOrderCntMsb = 0;
15777
+ let sps = null;
15778
+ let maxFramesInBuffer = null;
15779
+ return {
15780
+ getPrevPicOrderCntLsb() {
15781
+ return prevPicOrderCntLsb;
15782
+ },
15783
+ getPrevPicOrderCntMsb() {
15784
+ return prevPicOrderCntMsb;
15785
+ },
15786
+ setPrevPicOrderCntLsb(value) {
15787
+ prevPicOrderCntLsb = value;
15788
+ },
15789
+ setPrevPicOrderCntMsb(value) {
15790
+ prevPicOrderCntMsb = value;
15791
+ },
15792
+ setSps(value) {
15793
+ const macroblockBufferSize = macroBlocksPerFrame(value);
15794
+ const maxBufferSize = maxMacroblockBufferSize(value);
15795
+ const maxFrames = Math.min(16, Math.floor(maxBufferSize / macroblockBufferSize));
15796
+ maxFramesInBuffer = maxFrames;
15797
+ sps = value;
15798
+ },
15799
+ getSps() {
15800
+ return sps;
15801
+ },
15802
+ getMaxFramesInBuffer() {
15803
+ return maxFramesInBuffer;
15804
+ },
15805
+ clear() {
15806
+ maxFramesInBuffer = null;
15807
+ sps = null;
15808
+ prevPicOrderCntLsb = 0;
15809
+ prevPicOrderCntMsb = 0;
15810
+ }
15811
+ };
15812
+ };
15813
+
15426
15814
  // src/state/current-reader.ts
15427
15815
  var currentReader = (initialReader) => {
15428
15816
  let current = initialReader;
@@ -15663,6 +16051,17 @@ var moovState = () => {
15663
16051
  };
15664
16052
  };
15665
16053
 
16054
+ // src/state/iso-base-media/timescale-state.ts
16055
+ var movieTimeScaleState = () => {
16056
+ let trackTimescale = null;
16057
+ return {
16058
+ getTrackTimescale: () => trackTimescale,
16059
+ setTrackTimescale: (timescale) => {
16060
+ trackTimescale = timescale;
16061
+ }
16062
+ };
16063
+ };
16064
+
15666
16065
  // src/state/iso-base-media/iso-state.ts
15667
16066
  var isoBaseMediaState = ({
15668
16067
  contentLength,
@@ -15684,7 +16083,8 @@ var isoBaseMediaState = ({
15684
16083
  prefetchCache
15685
16084
  }),
15686
16085
  moof: precomputedMoofState(),
15687
- tfra: precomputedTfraState()
16086
+ tfra: precomputedTfraState(),
16087
+ movieTimeScale: movieTimeScaleState()
15688
16088
  };
15689
16089
  };
15690
16090
 
@@ -16340,6 +16740,43 @@ var lazyIdx1Fetch = ({
16340
16740
  };
16341
16741
  };
16342
16742
 
16743
+ // src/state/riff/queued-frames.ts
16744
+ var queuedBFramesState = () => {
16745
+ const queuedFrames = [];
16746
+ const releasedFrames = [];
16747
+ const flush = () => {
16748
+ releasedFrames.push(...queuedFrames);
16749
+ queuedFrames.length = 0;
16750
+ };
16751
+ return {
16752
+ addFrame: (frame, maxFramesInBuffer) => {
16753
+ if (frame.type === "key") {
16754
+ flush();
16755
+ releasedFrames.push(frame);
16756
+ return;
16757
+ }
16758
+ queuedFrames.push(frame);
16759
+ if (queuedFrames.length > maxFramesInBuffer) {
16760
+ releasedFrames.push(queuedFrames.shift());
16761
+ }
16762
+ },
16763
+ flush,
16764
+ getReleasedFrame: () => {
16765
+ if (releasedFrames.length === 0) {
16766
+ return null;
16767
+ }
16768
+ return releasedFrames.shift();
16769
+ },
16770
+ hasReleasedFrames: () => {
16771
+ return releasedFrames.length > 0;
16772
+ },
16773
+ clear: () => {
16774
+ releasedFrames.length = 0;
16775
+ queuedFrames.length = 0;
16776
+ }
16777
+ };
16778
+ };
16779
+
16343
16780
  // src/state/riff/riff-keyframes.ts
16344
16781
  var riffKeyframesState = () => {
16345
16782
  const keyframes = [];
@@ -16348,6 +16785,7 @@ var riffKeyframesState = () => {
16348
16785
  return;
16349
16786
  }
16350
16787
  keyframes.push(keyframe);
16788
+ keyframes.sort((a, b) => a.positionInBytes - b.positionInBytes);
16351
16789
  };
16352
16790
  const getKeyframes2 = () => {
16353
16791
  return keyframes;
@@ -16367,6 +16805,7 @@ var riffKeyframesState = () => {
16367
16805
  // src/state/riff/sample-counter.ts
16368
16806
  var riffSampleCounter = () => {
16369
16807
  const samplesForTrack = {};
16808
+ const pocsAtKeyframeOffset = {};
16370
16809
  const riffKeys = riffKeyframesState();
16371
16810
  const onAudioSample = (trackId, audioSample) => {
16372
16811
  if (typeof samplesForTrack[trackId] === "undefined") {
@@ -16377,13 +16816,13 @@ var riffSampleCounter = () => {
16377
16816
  }
16378
16817
  samplesForTrack[trackId]++;
16379
16818
  };
16380
- const onVideoSample = (trackId, videoSample) => {
16381
- if (typeof samplesForTrack[trackId] === "undefined") {
16382
- samplesForTrack[trackId] = 0;
16819
+ const onVideoSample = (videoSample) => {
16820
+ if (typeof samplesForTrack[videoSample.trackId] === "undefined") {
16821
+ samplesForTrack[videoSample.trackId] = 0;
16383
16822
  }
16384
16823
  if (videoSample.type === "key") {
16385
16824
  riffKeys.addKeyframe({
16386
- trackId,
16825
+ trackId: videoSample.trackId,
16387
16826
  decodingTimeInSeconds: videoSample.dts / videoSample.timescale,
16388
16827
  positionInBytes: videoSample.offset,
16389
16828
  presentationTimeInSeconds: videoSample.cts / videoSample.timescale,
@@ -16392,10 +16831,10 @@ var riffSampleCounter = () => {
16392
16831
  });
16393
16832
  }
16394
16833
  if (videoSample.data.length > 0) {
16395
- samplesForTrack[trackId]++;
16834
+ samplesForTrack[videoSample.trackId]++;
16396
16835
  }
16397
16836
  };
16398
- const getSamplesForTrack = (trackId) => {
16837
+ const getSampleCountForTrack = ({ trackId }) => {
16399
16838
  return samplesForTrack[trackId] ?? 0;
16400
16839
  };
16401
16840
  const setSamplesFromSeek = (samples) => {
@@ -16403,12 +16842,39 @@ var riffSampleCounter = () => {
16403
16842
  samplesForTrack[trackId] = samples[trackId];
16404
16843
  }
16405
16844
  };
16845
+ const setPocAtKeyframeOffset = ({
16846
+ keyframeOffset,
16847
+ poc
16848
+ }) => {
16849
+ if (typeof pocsAtKeyframeOffset[keyframeOffset] === "undefined") {
16850
+ pocsAtKeyframeOffset[keyframeOffset] = [];
16851
+ }
16852
+ if (pocsAtKeyframeOffset[keyframeOffset].includes(poc)) {
16853
+ return;
16854
+ }
16855
+ pocsAtKeyframeOffset[keyframeOffset].push(poc);
16856
+ pocsAtKeyframeOffset[keyframeOffset].sort((a, b) => a - b);
16857
+ };
16858
+ const getPocAtKeyframeOffset = ({
16859
+ keyframeOffset
16860
+ }) => {
16861
+ return pocsAtKeyframeOffset[keyframeOffset];
16862
+ };
16863
+ const getKeyframeAtOffset = (sample) => {
16864
+ if (sample.type === "key") {
16865
+ return sample.offset;
16866
+ }
16867
+ return riffKeys.getKeyframes().findLast((k) => k.positionInBytes <= sample.offset)?.positionInBytes ?? null;
16868
+ };
16406
16869
  return {
16407
16870
  onAudioSample,
16408
16871
  onVideoSample,
16409
- getSamplesForTrack,
16872
+ getSampleCountForTrack,
16410
16873
  setSamplesFromSeek,
16411
- riffKeys
16874
+ riffKeys,
16875
+ setPocAtKeyframeOffset,
16876
+ getPocAtKeyframeOffset,
16877
+ getKeyframeAtOffset
16412
16878
  };
16413
16879
  };
16414
16880
 
@@ -16441,6 +16907,7 @@ var riffSpecificState = ({
16441
16907
  prefetchCache
16442
16908
  });
16443
16909
  const sampleCounter = riffSampleCounter();
16910
+ const queuedBFrames = queuedBFramesState();
16444
16911
  return {
16445
16912
  getAvcProfile: () => {
16446
16913
  return avcProfile;
@@ -16450,6 +16917,7 @@ var riffSpecificState = ({
16450
16917
  getNextTrackIndex: () => {
16451
16918
  return nextTrackIndex;
16452
16919
  },
16920
+ queuedBFrames,
16453
16921
  incrementNextTrackIndex: () => {
16454
16922
  nextTrackIndex++;
16455
16923
  },
@@ -16789,6 +17257,7 @@ var makeParserState = ({
16789
17257
  const timings = timingsState();
16790
17258
  const seekInfiniteLoop = seekInfiniteLoopDetectionState();
16791
17259
  const currentReaderState = currentReader(initialReaderInstance);
17260
+ const avc = avcState();
16792
17261
  const errored = null;
16793
17262
  const discardReadBytes = async (force) => {
16794
17263
  const { bytesRemoved, removedData } = iterator.removeBytesRead(force, mode);
@@ -16882,7 +17351,8 @@ var makeParserState = ({
16882
17351
  currentReader: currentReaderState,
16883
17352
  seekInfiniteLoop,
16884
17353
  makeSamplesStartAtZero,
16885
- prefetchCache
17354
+ prefetchCache,
17355
+ avc
16886
17356
  };
16887
17357
  };
16888
17358