@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
@@ -1927,6 +1927,41 @@ var makeFetchMoreData = (bytesNeeded) => ({
1927
1927
  bytesNeeded
1928
1928
  });
1929
1929
 
1930
+ // src/containers/iso-base-media/elst.ts
1931
+ var parseElst = ({
1932
+ iterator,
1933
+ size,
1934
+ offset
1935
+ }) => {
1936
+ const { expectNoMoreBytes } = iterator.startBox(size - 8);
1937
+ const version = iterator.getUint8();
1938
+ const flags = iterator.getUint24();
1939
+ const entryCount = iterator.getUint32();
1940
+ const entries = [];
1941
+ for (let i = 0;i < entryCount; i++) {
1942
+ const editDuration = iterator.getUint32();
1943
+ const mediaTime = iterator.getInt32();
1944
+ const mediaRateInteger = iterator.getUint16();
1945
+ const mediaRateFraction = iterator.getUint16();
1946
+ entries.push({
1947
+ editDuration,
1948
+ mediaTime,
1949
+ mediaRateInteger,
1950
+ mediaRateFraction
1951
+ });
1952
+ }
1953
+ expectNoMoreBytes();
1954
+ const result = {
1955
+ type: "elst-box",
1956
+ version,
1957
+ flags,
1958
+ entries,
1959
+ boxSize: size,
1960
+ offset
1961
+ };
1962
+ return result;
1963
+ };
1964
+
1930
1965
  // src/containers/iso-base-media/esds/decoder-specific-config.ts
1931
1966
  var parseDecoderSpecificConfig = (iterator) => {
1932
1967
  const layerTag = iterator.getUint8();
@@ -2273,6 +2308,35 @@ var getTrakBoxByTrackId = (moovBox, trackId) => {
2273
2308
  return tkhd.trackId === trackId;
2274
2309
  }) ?? null;
2275
2310
  };
2311
+ var getElstBox = (trakBox) => {
2312
+ const edtsBox = trakBox.children.find((s) => s.type === "regular-box" && s.boxType === "edts");
2313
+ if (!edtsBox || edtsBox.type !== "regular-box") {
2314
+ return null;
2315
+ }
2316
+ const elstBox = edtsBox.children.find((s) => s.type === "elst-box");
2317
+ return elstBox;
2318
+ };
2319
+
2320
+ // src/containers/iso-base-media/mdat/get-editlist.ts
2321
+ var findTrackStartTimeInSeconds = ({
2322
+ movieTimeScale,
2323
+ trakBox
2324
+ }) => {
2325
+ const elstBox = getElstBox(trakBox);
2326
+ if (!elstBox) {
2327
+ return 0;
2328
+ }
2329
+ const { entries } = elstBox;
2330
+ let dwellTime = 0;
2331
+ for (const entry of entries) {
2332
+ const { editDuration, mediaTime } = entry;
2333
+ if (mediaTime !== -1) {
2334
+ continue;
2335
+ }
2336
+ dwellTime += editDuration;
2337
+ }
2338
+ return dwellTime / movieTimeScale;
2339
+ };
2276
2340
 
2277
2341
  // src/containers/riff/timescale.ts
2278
2342
  var MEDIA_PARSER_RIFF_TIMESCALE = 1e6;
@@ -2327,7 +2391,8 @@ var makeAviAudioTrack = ({
2327
2391
  numberOfChannels: strf.numberOfChannels,
2328
2392
  sampleRate: strf.sampleRate,
2329
2393
  timescale: MEDIA_PARSER_RIFF_TIMESCALE,
2330
- trackId: index
2394
+ trackId: index,
2395
+ startInSeconds: 0
2331
2396
  };
2332
2397
  };
2333
2398
  var makeAviVideoTrack = ({
@@ -2370,7 +2435,8 @@ var makeAviVideoTrack = ({
2370
2435
  numerator: 1,
2371
2436
  denominator: 1
2372
2437
  },
2373
- fps: strh.rate / strh.scale
2438
+ fps: strh.rate / strh.scale,
2439
+ startInSeconds: 0
2374
2440
  };
2375
2441
  };
2376
2442
  var getTracksFromAvi = (structure, state) => {
@@ -3154,7 +3220,8 @@ var getTrack = ({
3154
3220
  colorSpace: mediaParserAdvancedColorToWebCodecsColor(advancedColor),
3155
3221
  advancedColor,
3156
3222
  codecEnum,
3157
- fps: null
3223
+ fps: null,
3224
+ startInSeconds: 0
3158
3225
  };
3159
3226
  }
3160
3227
  if (trackTypeToString(trackType2.value.value) === "audio") {
@@ -3176,7 +3243,8 @@ var getTrack = ({
3176
3243
  codecData: codecPrivate2 ? codecString === "opus" ? { type: "ogg-identification", data: codecPrivate2 } : { type: "unknown-data", data: codecPrivate2 } : null,
3177
3244
  codecEnum: getMatroskaAudioCodecEnum({
3178
3245
  track
3179
- })
3246
+ }),
3247
+ startInSeconds: 0
3180
3248
  };
3181
3249
  }
3182
3250
  return null;
@@ -3297,7 +3365,15 @@ var getTracksFromMoovBox = (moovBox) => {
3297
3365
  const mediaParserTracks = [];
3298
3366
  const tracks2 = getTraks(moovBox);
3299
3367
  for (const trakBox of tracks2) {
3300
- const track = makeBaseMediaTrack(trakBox);
3368
+ const mvhdBox = getMvhdBox(moovBox);
3369
+ if (!mvhdBox) {
3370
+ throw new Error("Mvhd box is not found");
3371
+ }
3372
+ const startTime = findTrackStartTimeInSeconds({
3373
+ movieTimeScale: mvhdBox.timeScale,
3374
+ trakBox
3375
+ });
3376
+ const track = makeBaseMediaTrack(trakBox, startTime);
3301
3377
  if (!track) {
3302
3378
  continue;
3303
3379
  }
@@ -4036,7 +4112,7 @@ var getVideoCodecFromIsoTrak = (trakBox) => {
4036
4112
  };
4037
4113
 
4038
4114
  // src/containers/iso-base-media/make-track.ts
4039
- var makeBaseMediaTrack = (trakBox) => {
4115
+ var makeBaseMediaTrack = (trakBox, startTimeInSeconds) => {
4040
4116
  const tkhdBox = getTkhdBox(trakBox);
4041
4117
  const videoDescriptors = getVideoDescriptors(trakBox);
4042
4118
  const timescaleAndDuration = getTimescaleAndDuration(trakBox);
@@ -4073,7 +4149,8 @@ var makeBaseMediaTrack = (trakBox) => {
4073
4149
  sampleRate: actual.sampleRate,
4074
4150
  description: actual.codecPrivate?.data ?? undefined,
4075
4151
  codecData: actual.codecPrivate,
4076
- codecEnum
4152
+ codecEnum,
4153
+ startInSeconds: startTimeInSeconds
4077
4154
  };
4078
4155
  }
4079
4156
  if (!trakBoxContainsVideo(trakBox)) {
@@ -4081,7 +4158,8 @@ var makeBaseMediaTrack = (trakBox) => {
4081
4158
  type: "other",
4082
4159
  trackId: tkhdBox.trackId,
4083
4160
  timescale: timescaleAndDuration.timescale,
4084
- trakBox
4161
+ trakBox,
4162
+ startInSeconds: startTimeInSeconds
4085
4163
  };
4086
4164
  }
4087
4165
  const videoSample = getStsdVideoConfig(trakBox);
@@ -4128,7 +4206,8 @@ var makeBaseMediaTrack = (trakBox) => {
4128
4206
  colorSpace: mediaParserAdvancedColorToWebCodecsColor(advancedColor),
4129
4207
  advancedColor,
4130
4208
  codecEnum: getVideoCodecFromIsoTrak(trakBox),
4131
- fps: getFpsFromMp4TrakBox(trakBox)
4209
+ fps: getFpsFromMp4TrakBox(trakBox),
4210
+ startInSeconds: startTimeInSeconds
4132
4211
  };
4133
4212
  return track;
4134
4213
  };
@@ -5192,6 +5271,16 @@ var processBox = async ({
5192
5271
  box: parseFtyp({ iterator, size: boxSize, offset: fileOffset })
5193
5272
  };
5194
5273
  }
5274
+ if (boxType === "elst") {
5275
+ return {
5276
+ type: "box",
5277
+ box: parseElst({
5278
+ iterator,
5279
+ size: boxSize,
5280
+ offset: fileOffset
5281
+ })
5282
+ };
5283
+ }
5195
5284
  if (boxType === "colr") {
5196
5285
  return {
5197
5286
  type: "box",
@@ -5202,9 +5291,18 @@ var processBox = async ({
5202
5291
  };
5203
5292
  }
5204
5293
  if (boxType === "mvhd") {
5294
+ const mvhdBox = parseMvhd({
5295
+ iterator,
5296
+ offset: fileOffset,
5297
+ size: boxSize
5298
+ });
5299
+ if (!onlyIfMoovAtomExpected) {
5300
+ throw new Error("State is required");
5301
+ }
5302
+ onlyIfMoovAtomExpected.movieTimeScaleState.setTrackTimescale(mvhdBox.timeScale);
5205
5303
  return {
5206
5304
  type: "box",
5207
- box: parseMvhd({ iterator, offset: fileOffset, size: boxSize })
5305
+ box: mvhdBox
5208
5306
  };
5209
5307
  }
5210
5308
  if (boxType === "tkhd") {
@@ -5372,14 +5470,19 @@ var processBox = async ({
5372
5470
  throw new Error("State is required");
5373
5471
  }
5374
5472
  const { tracks: tracks2, onAudioTrack, onVideoTrack } = onlyIfMoovAtomExpected;
5375
- const box = await parseTrak({
5473
+ const trakBox = await parseTrak({
5376
5474
  size: boxSize,
5377
5475
  offsetAtStart: fileOffset,
5378
5476
  iterator,
5379
5477
  logLevel,
5380
5478
  contentLength
5381
5479
  });
5382
- const transformedTrack = makeBaseMediaTrack(box);
5480
+ const movieTimeScale = onlyIfMoovAtomExpected.movieTimeScaleState.getTrackTimescale();
5481
+ if (movieTimeScale === null) {
5482
+ throw new Error("Movie timescale is not set");
5483
+ }
5484
+ const editList = findTrackStartTimeInSeconds({ movieTimeScale, trakBox });
5485
+ const transformedTrack = makeBaseMediaTrack(trakBox, editList);
5383
5486
  if (transformedTrack && transformedTrack.type === "video") {
5384
5487
  await registerVideoTrack({
5385
5488
  track: transformedTrack,
@@ -5400,7 +5503,7 @@ var processBox = async ({
5400
5503
  onAudioTrack
5401
5504
  });
5402
5505
  }
5403
- return { type: "box", box };
5506
+ return { type: "box", box: trakBox };
5404
5507
  }
5405
5508
  if (boxType === "stts") {
5406
5509
  return {
@@ -5473,7 +5576,7 @@ var processBox = async ({
5473
5576
  if (boxType === "moof") {
5474
5577
  await onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
5475
5578
  }
5476
- if (boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "mfra" || boxType === "stsb") {
5579
+ 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") {
5477
5580
  const children = await getIsoBaseMediaChildren({
5478
5581
  iterator,
5479
5582
  size: boxSize - 8,
@@ -5823,6 +5926,33 @@ var parseIsoFormatBoxes = async ({
5823
5926
 
5824
5927
  // src/containers/avc/parse-avc.ts
5825
5928
  var Extended_SAR = 255;
5929
+ var getPoc = (iterator, sps, avcState, isReferencePicture) => {
5930
+ const { pic_order_cnt_type, log2_max_pic_order_cnt_lsb_minus4 } = sps;
5931
+ if (pic_order_cnt_type !== 0) {
5932
+ return null;
5933
+ }
5934
+ const prevPicOrderCntLsb = avcState.getPrevPicOrderCntLsb();
5935
+ const prevPicOrderCntMsb = avcState.getPrevPicOrderCntMsb();
5936
+ if (log2_max_pic_order_cnt_lsb_minus4 === null) {
5937
+ throw new Error("log2_max_pic_order_cnt_lsb_minus4 is null");
5938
+ }
5939
+ const max_pic_order_cnt_lsb = 2 ** (log2_max_pic_order_cnt_lsb_minus4 + 4);
5940
+ const pic_order_cnt_lsb = iterator.getBits(log2_max_pic_order_cnt_lsb_minus4 + 4);
5941
+ let picOrderCntMsb;
5942
+ if (pic_order_cnt_lsb < prevPicOrderCntLsb && prevPicOrderCntLsb - pic_order_cnt_lsb >= max_pic_order_cnt_lsb / 2) {
5943
+ picOrderCntMsb = prevPicOrderCntMsb + max_pic_order_cnt_lsb;
5944
+ } else if (pic_order_cnt_lsb > prevPicOrderCntLsb && pic_order_cnt_lsb - prevPicOrderCntLsb > max_pic_order_cnt_lsb / 2) {
5945
+ picOrderCntMsb = prevPicOrderCntMsb - max_pic_order_cnt_lsb;
5946
+ } else {
5947
+ picOrderCntMsb = prevPicOrderCntMsb;
5948
+ }
5949
+ const poc = picOrderCntMsb + pic_order_cnt_lsb;
5950
+ if (isReferencePicture) {
5951
+ avcState.setPrevPicOrderCntLsb(pic_order_cnt_lsb);
5952
+ avcState.setPrevPicOrderCntMsb(picOrderCntMsb);
5953
+ }
5954
+ return poc;
5955
+ };
5826
5956
  var readVuiParameters = (iterator) => {
5827
5957
  let sar_width = null;
5828
5958
  let sar_height = null;
@@ -5968,7 +6098,8 @@ var readSps = (iterator) => {
5968
6098
  frame_crop_right_offset,
5969
6099
  frame_crop_top_offset,
5970
6100
  mb_adaptive_frame_field_flag,
5971
- vui_parameters
6101
+ vui_parameters,
6102
+ pic_order_cnt_type
5972
6103
  };
5973
6104
  };
5974
6105
  var findEnd = (buffer) => {
@@ -5986,17 +6117,23 @@ var findEnd = (buffer) => {
5986
6117
  }
5987
6118
  return null;
5988
6119
  };
5989
- var inspect = (buffer) => {
6120
+ var inspect = (buffer, avcState) => {
5990
6121
  const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
5991
6122
  iterator.startReadingBits();
5992
6123
  iterator.getBits(1);
5993
- iterator.getBits(2);
6124
+ const nal_ref_idc = iterator.getBits(2);
6125
+ const isReferencePicture = nal_ref_idc !== 0;
5994
6126
  const type = iterator.getBits(5);
5995
- iterator.stopReadingBits();
5996
6127
  if (type === 7) {
6128
+ iterator.stopReadingBits();
5997
6129
  const end = findEnd(buffer);
5998
6130
  const data = readSps(iterator);
5999
6131
  const sps = buffer.slice(0, end === null ? Infinity : end);
6132
+ avcState.setSps(data);
6133
+ if (isReferencePicture) {
6134
+ avcState.setPrevPicOrderCntLsb(0);
6135
+ avcState.setPrevPicOrderCntMsb(0);
6136
+ }
6000
6137
  return {
6001
6138
  spsData: data,
6002
6139
  sps,
@@ -6004,11 +6141,31 @@ var inspect = (buffer) => {
6004
6141
  };
6005
6142
  }
6006
6143
  if (type === 5) {
6144
+ avcState.setPrevPicOrderCntLsb(0);
6145
+ avcState.setPrevPicOrderCntMsb(0);
6146
+ iterator.readExpGolomb();
6147
+ iterator.readExpGolomb();
6148
+ iterator.readExpGolomb();
6149
+ const sps = avcState.getSps();
6150
+ if (!sps) {
6151
+ throw new Error("SPS not found");
6152
+ }
6153
+ const numberOfBitsForFrameNum = sps.log2_max_frame_num_minus4 + 4;
6154
+ iterator.getBits(numberOfBitsForFrameNum);
6155
+ iterator.readExpGolomb();
6156
+ const { pic_order_cnt_type } = sps;
6157
+ let poc = null;
6158
+ if (pic_order_cnt_type === 0) {
6159
+ poc = getPoc(iterator, sps, avcState, isReferencePicture);
6160
+ }
6161
+ iterator.stopReadingBits();
6007
6162
  return {
6008
- type: "keyframe"
6163
+ type: "keyframe",
6164
+ poc
6009
6165
  };
6010
6166
  }
6011
6167
  if (type === 8) {
6168
+ iterator.stopReadingBits();
6012
6169
  const end = findEnd(buffer);
6013
6170
  const pps = buffer.slice(0, end === null ? Infinity : end);
6014
6171
  return {
@@ -6017,14 +6174,32 @@ var inspect = (buffer) => {
6017
6174
  };
6018
6175
  }
6019
6176
  if (type === 1) {
6177
+ iterator.readExpGolomb();
6178
+ const slice_type = iterator.readExpGolomb();
6179
+ const isBidirectionalFrame = slice_type === 6;
6180
+ iterator.readExpGolomb();
6181
+ const sps = avcState.getSps();
6182
+ if (!sps) {
6183
+ throw new Error("SPS not found");
6184
+ }
6185
+ const numberOfBitsForFrameNum = sps.log2_max_frame_num_minus4 + 4;
6186
+ iterator.getBits(numberOfBitsForFrameNum);
6187
+ const { pic_order_cnt_type } = sps;
6188
+ let poc = null;
6189
+ if (pic_order_cnt_type === 0) {
6190
+ poc = getPoc(iterator, sps, avcState, isReferencePicture);
6191
+ }
6192
+ iterator.stopReadingBits();
6020
6193
  return {
6021
- type: "delta-frame"
6194
+ type: "delta-frame",
6195
+ isBidirectionalFrame,
6196
+ poc
6022
6197
  };
6023
6198
  }
6024
6199
  iterator.destroy();
6025
6200
  return null;
6026
6201
  };
6027
- var parseAvc = (buffer) => {
6202
+ var parseAvc = (buffer, avcState) => {
6028
6203
  let zeroesInARow = 0;
6029
6204
  const infos = [];
6030
6205
  for (let i = 0;i < buffer.length; i++) {
@@ -6035,7 +6210,7 @@ var parseAvc = (buffer) => {
6035
6210
  }
6036
6211
  if (zeroesInARow >= 2 && val === 1) {
6037
6212
  zeroesInARow = 0;
6038
- const info = inspect(buffer.slice(i + 1, i + 100));
6213
+ const info = inspect(buffer.slice(i + 1, i + 100), avcState);
6039
6214
  if (info) {
6040
6215
  infos.push(info);
6041
6216
  if (info.type === "keyframe" || info.type === "delta-frame") {
@@ -6091,7 +6266,8 @@ var addAvcToTrackAndActivateTrackIfNecessary = async ({
6091
6266
  trackNumber: trackNumber2,
6092
6267
  logLevel,
6093
6268
  callbacks,
6094
- onVideoTrack
6269
+ onVideoTrack,
6270
+ avcState
6095
6271
  }) => {
6096
6272
  if (codec !== "V_MPEG4/ISO/AVC") {
6097
6273
  return;
@@ -6103,7 +6279,7 @@ var addAvcToTrackAndActivateTrackIfNecessary = async ({
6103
6279
  if (missingTracks.length === 0) {
6104
6280
  return;
6105
6281
  }
6106
- const parsed = parseAvc(partialVideoSample.data);
6282
+ const parsed = parseAvc(partialVideoSample.data, avcState);
6107
6283
  for (const parse of parsed) {
6108
6284
  if (parse.type === "avc-profile") {
6109
6285
  webmState.setAvcProfileForTrackNumber(trackNumber2, parse);
@@ -6137,7 +6313,8 @@ var getSampleFromBlock = async ({
6137
6313
  structureState,
6138
6314
  callbacks,
6139
6315
  logLevel,
6140
- onVideoTrack
6316
+ onVideoTrack,
6317
+ avcState
6141
6318
  }) => {
6142
6319
  const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
6143
6320
  const trackNumber2 = iterator.getVint();
@@ -6184,7 +6361,8 @@ var getSampleFromBlock = async ({
6184
6361
  trackNumber: trackNumber2,
6185
6362
  callbacks,
6186
6363
  logLevel,
6187
- onVideoTrack
6364
+ onVideoTrack,
6365
+ avcState
6188
6366
  });
6189
6367
  const sample = {
6190
6368
  ...partialVideoSample,
@@ -6318,7 +6496,8 @@ var postprocessEbml = async ({
6318
6496
  logLevel,
6319
6497
  onAudioTrack,
6320
6498
  onVideoTrack,
6321
- structureState
6499
+ structureState,
6500
+ avcState
6322
6501
  }
6323
6502
  }) => {
6324
6503
  if (ebml.type === "TimestampScale") {
@@ -6367,7 +6546,8 @@ var postprocessEbml = async ({
6367
6546
  structureState,
6368
6547
  callbacks,
6369
6548
  logLevel,
6370
- onVideoTrack
6549
+ onVideoTrack,
6550
+ avcState
6371
6551
  });
6372
6552
  if (sample.type === "video-sample") {
6373
6553
  await callbacks.onVideoSample(sample.videoSample.trackId, sample.videoSample);
@@ -6406,7 +6586,8 @@ var postprocessEbml = async ({
6406
6586
  structureState,
6407
6587
  callbacks,
6408
6588
  logLevel,
6409
- onVideoTrack
6589
+ onVideoTrack,
6590
+ avcState
6410
6591
  });
6411
6592
  if (sample && sample.type === "partial-video-sample") {
6412
6593
  const completeFrame = {
@@ -7940,13 +8121,14 @@ var findKeyframeBeforeTime = ({
7940
8121
  time,
7941
8122
  timescale,
7942
8123
  mediaSections,
7943
- logLevel
8124
+ logLevel,
8125
+ startInSeconds
7944
8126
  }) => {
7945
8127
  let videoByte = 0;
7946
8128
  let videoSample = null;
7947
8129
  for (const sample of samplePositions) {
7948
- const ctsInSeconds = sample.cts / timescale;
7949
- const dtsInSeconds = sample.dts / timescale;
8130
+ const ctsInSeconds = sample.cts / timescale + startInSeconds;
8131
+ const dtsInSeconds = sample.dts / timescale + startInSeconds;
7950
8132
  if (!sample.isKeyframe) {
7951
8133
  continue;
7952
8134
  }
@@ -8191,7 +8373,8 @@ var getSeekingByteFromFragmentedMp4 = async ({
8191
8373
  time,
8192
8374
  timescale: firstTrack.timescale,
8193
8375
  logLevel,
8194
- mediaSections: info.mediaSections
8376
+ mediaSections: info.mediaSections,
8377
+ startInSeconds: firstTrack.startInSeconds
8195
8378
  });
8196
8379
  if (kf) {
8197
8380
  return {
@@ -8293,7 +8476,8 @@ var getSeekingByteFromIsoBaseMedia = ({
8293
8476
  time,
8294
8477
  timescale: track.timescale,
8295
8478
  logLevel,
8296
- mediaSections: info.mediaSections
8479
+ mediaSections: info.mediaSections,
8480
+ startInSeconds: track.startInSeconds
8297
8481
  });
8298
8482
  if (keyframe) {
8299
8483
  return Promise.resolve({
@@ -8599,7 +8783,8 @@ function findLastKeyframe({
8599
8783
  var getSeekingByteForRiff = async ({
8600
8784
  info,
8601
8785
  time,
8602
- riffState
8786
+ riffState,
8787
+ avcState
8603
8788
  }) => {
8604
8789
  const idx1Entries = await (info.hasIndex ? riffState.lazyIdx1.waitForLoaded() : Promise.resolve(null));
8605
8790
  if (idx1Entries === null) {
@@ -8613,6 +8798,8 @@ var getSeekingByteForRiff = async ({
8613
8798
  };
8614
8799
  }
8615
8800
  riffState.sampleCounter.setSamplesFromSeek(lastKeyframe.sampleCounts);
8801
+ riffState.queuedBFrames.clear();
8802
+ avcState.clear();
8616
8803
  return {
8617
8804
  type: "do-seek",
8618
8805
  byte: lastKeyframe.positionInBytes
@@ -8642,6 +8829,8 @@ var getSeekingByteForRiff = async ({
8642
8829
  throw new Error("moviOffset is null");
8643
8830
  }
8644
8831
  riffState.sampleCounter.setSamplesFromSeek(bestEntry.sampleCounts);
8832
+ riffState.queuedBFrames.clear();
8833
+ avcState.clear();
8645
8834
  return {
8646
8835
  type: "do-seek",
8647
8836
  byte: bestEntry.offset + info.moviOffset - 4
@@ -8790,7 +8979,8 @@ var convertAudioOrVideoSampleToWebCodecsTimestamps = ({
8790
8979
  trackId: sample.trackId,
8791
8980
  type: sample.type,
8792
8981
  offset: sample.offset,
8793
- timescale: TARGET_TIMESCALE
8982
+ timescale: TARGET_TIMESCALE,
8983
+ ..."avc" in sample ? { avc: sample.avc } : {}
8794
8984
  };
8795
8985
  };
8796
8986
 
@@ -8833,7 +9023,7 @@ var getKeyFrameOrDeltaFromAvcInfo = (infos) => {
8833
9023
  if (!keyOrDelta) {
8834
9024
  throw new Error("expected avc to contain info about key or delta");
8835
9025
  }
8836
- return keyOrDelta.type === "keyframe" ? "key" : "delta";
9026
+ return keyOrDelta.type === "keyframe" ? "key" : keyOrDelta.isBidirectionalFrame ? "bidirectional" : "delta";
8837
9027
  };
8838
9028
 
8839
9029
  // src/containers/avc/sps-and-pps.ts
@@ -8856,9 +9046,10 @@ var handleAvcPacket = async ({
8856
9046
  logLevel,
8857
9047
  onVideoTrack,
8858
9048
  transportStream,
8859
- makeSamplesStartAtZero
9049
+ makeSamplesStartAtZero,
9050
+ avcState
8860
9051
  }) => {
8861
- const avc = parseAvc(streamBuffer.getBuffer());
9052
+ const avc = parseAvc(streamBuffer.getBuffer(), avcState);
8862
9053
  const isTrackRegistered = sampleCallbacks.tracks.getTracks().find((t) => {
8863
9054
  return t.trackId === programId;
8864
9055
  });
@@ -8895,7 +9086,8 @@ var handleAvcPacket = async ({
8895
9086
  numerator: sampleAspectRatio.width
8896
9087
  },
8897
9088
  colorSpace: mediaParserAdvancedColorToWebCodecsColor(advancedColor),
8898
- advancedColor
9089
+ advancedColor,
9090
+ startInSeconds: 0
8899
9091
  };
8900
9092
  await registerVideoTrack({
8901
9093
  track,
@@ -8914,7 +9106,7 @@ var handleAvcPacket = async ({
8914
9106
  duration: undefined,
8915
9107
  data: streamBuffer.getBuffer(),
8916
9108
  trackId: programId,
8917
- type,
9109
+ type: type === "bidirectional" ? "delta" : type,
8918
9110
  offset,
8919
9111
  timescale: MPEG_TIMESCALE
8920
9112
  };
@@ -8981,7 +9173,8 @@ var getSeekingByte = ({
8981
9173
  m3uPlaylistContext,
8982
9174
  structure,
8983
9175
  riffState,
8984
- m3uState
9176
+ m3uState,
9177
+ avcState
8985
9178
  }) => {
8986
9179
  if (info.type === "iso-base-media-seeking-hints") {
8987
9180
  return getSeekingByteFromIsoBaseMedia({
@@ -9041,7 +9234,8 @@ var getSeekingByte = ({
9041
9234
  return getSeekingByteForRiff({
9042
9235
  info,
9043
9236
  time,
9044
- riffState
9237
+ riffState,
9238
+ avcState
9045
9239
  });
9046
9240
  }
9047
9241
  if (info.type === "mp3-seeking-hints") {
@@ -9604,7 +9798,8 @@ var turnSeekIntoByte = async ({
9604
9798
  mp3State,
9605
9799
  contentLength,
9606
9800
  aacState,
9607
- m3uState
9801
+ m3uState,
9802
+ avcState
9608
9803
  }) => {
9609
9804
  const mediaSections = mediaSectionState2.getMediaSections();
9610
9805
  if (mediaSections.length === 0) {
@@ -9650,7 +9845,8 @@ var turnSeekIntoByte = async ({
9650
9845
  m3uPlaylistContext,
9651
9846
  structure: structureState,
9652
9847
  riffState,
9653
- m3uState
9848
+ m3uState,
9849
+ avcState
9654
9850
  });
9655
9851
  return seekingByte;
9656
9852
  };
@@ -9681,7 +9877,8 @@ var getWorkOnSeekRequestOptions = (state) => {
9681
9877
  mp3State: state.mp3,
9682
9878
  aacState: state.aac,
9683
9879
  m3uState: state.m3u,
9684
- prefetchCache: state.prefetchCache
9880
+ prefetchCache: state.prefetchCache,
9881
+ avcState: state.avc
9685
9882
  };
9686
9883
  };
9687
9884
  var workOnSeekRequest = async (options) => {
@@ -9711,7 +9908,8 @@ var workOnSeekRequest = async (options) => {
9711
9908
  mp3State,
9712
9909
  aacState,
9713
9910
  prefetchCache,
9714
- m3uState
9911
+ m3uState,
9912
+ avcState
9715
9913
  } = options;
9716
9914
  const seek2 = controller._internals.seekSignal.getSeek();
9717
9915
  if (seek2 === null) {
@@ -9736,7 +9934,8 @@ var workOnSeekRequest = async (options) => {
9736
9934
  mp3State,
9737
9935
  contentLength,
9738
9936
  aacState,
9739
- m3uState
9937
+ m3uState,
9938
+ avcState
9740
9939
  });
9741
9940
  Log.trace(logLevel, `Seek action: ${JSON.stringify(resolution)}`);
9742
9941
  if (resolution.type === "intermediary-seek") {
@@ -10315,6 +10514,10 @@ var checkIfDone = async (state) => {
10315
10514
  if (state.structure.getStructure().type === "m3u" && !state.m3u.getAllChunksProcessedOverall()) {
10316
10515
  return false;
10317
10516
  }
10517
+ state.riff.queuedBFrames.flush();
10518
+ if (state.riff.queuedBFrames.hasReleasedFrames()) {
10519
+ return false;
10520
+ }
10318
10521
  Log.verbose(state.logLevel, "Reached end of file");
10319
10522
  await state.discardReadBytes(true);
10320
10523
  return true;
@@ -10393,7 +10596,8 @@ var parseAac = async (state) => {
10393
10596
  sampleRate,
10394
10597
  timescale: 1e6,
10395
10598
  trackId: 0,
10396
- type: "audio"
10599
+ type: "audio",
10600
+ startInSeconds: 0
10397
10601
  },
10398
10602
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
10399
10603
  tracks: state.callbacks.tracks,
@@ -10784,7 +10988,8 @@ var parseStreamInfo = async ({
10784
10988
  numberOfChannels: channels2,
10785
10989
  sampleRate,
10786
10990
  timescale: 1e6,
10787
- trackId: 0
10991
+ trackId: 0,
10992
+ startInSeconds: 0
10788
10993
  },
10789
10994
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
10790
10995
  tracks: state.callbacks.tracks,
@@ -11171,6 +11376,7 @@ var getMoovAtom = async ({
11171
11376
  onlyIfMoovAtomExpected: {
11172
11377
  tracks: tracksState,
11173
11378
  isoState: null,
11379
+ movieTimeScaleState: state.iso.movieTimeScale,
11174
11380
  onAudioTrack,
11175
11381
  onVideoTrack,
11176
11382
  registerVideoSampleCallback: () => Promise.resolve(),
@@ -11411,7 +11617,18 @@ var parseMdatSection = async (state) => {
11411
11617
  if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
11412
11618
  return makeFetchMoreData(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
11413
11619
  }
11414
- const { cts, dts, duration: duration2, isKeyframe, offset, bigEndian, chunkSize } = samplesWithIndex.samplePosition;
11620
+ const {
11621
+ cts: rawCts,
11622
+ dts: rawDts,
11623
+ duration: duration2,
11624
+ isKeyframe,
11625
+ offset,
11626
+ bigEndian,
11627
+ chunkSize
11628
+ } = samplesWithIndex.samplePosition;
11629
+ const { timescale, startInSeconds } = samplesWithIndex.track;
11630
+ const cts = rawCts + startInSeconds * timescale;
11631
+ const dts = rawDts + startInSeconds * timescale;
11415
11632
  const bytes = postprocessBytes({
11416
11633
  bytes: iterator.getSlice(samplesWithIndex.samplePosition.size),
11417
11634
  bigEndian,
@@ -11428,9 +11645,9 @@ var parseMdatSection = async (state) => {
11428
11645
  trackId: samplesWithIndex.track.trackId,
11429
11646
  type: isKeyframe ? "key" : "delta",
11430
11647
  offset,
11431
- timescale: samplesWithIndex.track.timescale
11648
+ timescale
11432
11649
  },
11433
- timescale: samplesWithIndex.track.timescale
11650
+ timescale
11434
11651
  });
11435
11652
  await state.callbacks.onAudioSample(samplesWithIndex.track.trackId, audioSample);
11436
11653
  }
@@ -11451,9 +11668,9 @@ var parseMdatSection = async (state) => {
11451
11668
  trackId: samplesWithIndex.track.trackId,
11452
11669
  type: isKeyframe && !isRecoveryPoint ? "key" : "delta",
11453
11670
  offset,
11454
- timescale: samplesWithIndex.track.timescale
11671
+ timescale
11455
11672
  },
11456
- timescale: samplesWithIndex.track.timescale
11673
+ timescale
11457
11674
  });
11458
11675
  await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, videoSample);
11459
11676
  }
@@ -11478,6 +11695,7 @@ var parseIsoBaseMedia = async (state) => {
11478
11695
  onlyIfMoovAtomExpected: {
11479
11696
  tracks: state.callbacks.tracks,
11480
11697
  isoState: state.iso,
11698
+ movieTimeScaleState: state.iso.movieTimeScale,
11481
11699
  onAudioTrack: state.onAudioTrack,
11482
11700
  onVideoTrack: state.onVideoTrack,
11483
11701
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
@@ -12076,14 +12294,7 @@ var fetchReadContent = async ({
12076
12294
  throw new Error("src must be a string when using `fetchReader`");
12077
12295
  }
12078
12296
  const fallbackName = src.toString().split("/").pop();
12079
- const {
12080
- reader,
12081
- contentLength,
12082
- needsContentRange,
12083
- name,
12084
- supportsContentRange,
12085
- contentType
12086
- } = await makeFetchRequestOrGetCached({
12297
+ const res = makeFetchRequestOrGetCached({
12087
12298
  range: range2,
12088
12299
  src,
12089
12300
  controller,
@@ -12092,6 +12303,14 @@ var fetchReadContent = async ({
12092
12303
  });
12093
12304
  const key = cacheKey({ src, range: range2 });
12094
12305
  prefetchCache.delete(key);
12306
+ const {
12307
+ reader,
12308
+ contentLength,
12309
+ needsContentRange,
12310
+ name,
12311
+ supportsContentRange,
12312
+ contentType
12313
+ } = await res;
12095
12314
  if (controller) {
12096
12315
  controller._internals.signal.addEventListener("abort", () => {
12097
12316
  reader.reader.cancel().catch(() => {});
@@ -13142,7 +13361,8 @@ var parseMpegHeader = async ({
13142
13361
  numberOfChannels,
13143
13362
  sampleRate,
13144
13363
  timescale: 1e6,
13145
- trackId: 0
13364
+ trackId: 0,
13365
+ startInSeconds: 0
13146
13366
  },
13147
13367
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
13148
13368
  tracks: state.callbacks.tracks,
@@ -13238,6 +13458,73 @@ var parseMp3 = async (state) => {
13238
13458
  throw new Error("Unknown MP3 header " + JSON.stringify(bytes));
13239
13459
  };
13240
13460
 
13461
+ // src/containers/riff/get-strh-for-index.ts
13462
+ var getStrhForIndex = (structure, trackId) => {
13463
+ const boxes = getStrlBoxes(structure);
13464
+ const box = boxes[trackId];
13465
+ if (!box) {
13466
+ throw new Error("Expected box");
13467
+ }
13468
+ const strh = getStrhBox(box.children);
13469
+ if (!strh) {
13470
+ throw new Error("strh");
13471
+ }
13472
+ return strh;
13473
+ };
13474
+
13475
+ // src/containers/riff/convert-queued-sample-to-mediaparser-sample.ts
13476
+ var getKeyFrameOffsetAndPocs = ({
13477
+ state,
13478
+ sample
13479
+ }) => {
13480
+ if (sample.type === "key") {
13481
+ const sampleOffset = state.riff.sampleCounter.getSampleCountForTrack({
13482
+ trackId: sample.trackId
13483
+ });
13484
+ return {
13485
+ sampleOffsetAtKeyframe: sampleOffset,
13486
+ pocsAtKeyframeOffset: [sample.avc?.poc ?? 0]
13487
+ };
13488
+ }
13489
+ const riffKeyframes = state.riff.sampleCounter.riffKeys.getKeyframes();
13490
+ const keyframeAtOffset = riffKeyframes.findLast((k) => k.positionInBytes <= sample.offset);
13491
+ if (!keyframeAtOffset) {
13492
+ throw new Error("no keyframe at offset");
13493
+ }
13494
+ const sampleOffsetAtKeyframe = keyframeAtOffset.sampleCounts[sample.trackId];
13495
+ const pocsAtKeyframeOffset = state.riff.sampleCounter.getPocAtKeyframeOffset({
13496
+ keyframeOffset: keyframeAtOffset.positionInBytes
13497
+ });
13498
+ return {
13499
+ sampleOffsetAtKeyframe,
13500
+ pocsAtKeyframeOffset
13501
+ };
13502
+ };
13503
+ var convertQueuedSampleToMediaParserSample = (sample, state) => {
13504
+ const strh = getStrhForIndex(state.structure.getRiffStructure(), sample.trackId);
13505
+ const samplesPerSecond = strh.rate / strh.scale;
13506
+ const { sampleOffsetAtKeyframe, pocsAtKeyframeOffset } = getKeyFrameOffsetAndPocs({
13507
+ sample,
13508
+ state
13509
+ });
13510
+ const indexOfPoc = pocsAtKeyframeOffset.findIndex((poc) => poc === sample.avc?.poc);
13511
+ if (indexOfPoc === -1) {
13512
+ throw new Error("poc not found");
13513
+ }
13514
+ const nthSample = indexOfPoc + sampleOffsetAtKeyframe;
13515
+ const timestamp = nthSample / samplesPerSecond;
13516
+ const videoSample = convertAudioOrVideoSampleToWebCodecsTimestamps({
13517
+ sample: {
13518
+ ...sample,
13519
+ timestamp,
13520
+ cts: timestamp,
13521
+ dts: timestamp
13522
+ },
13523
+ timescale: 1
13524
+ });
13525
+ return videoSample;
13526
+ };
13527
+
13241
13528
  // src/containers/riff/is-movi.ts
13242
13529
  var isMoviAtom = (iterator, ckId) => {
13243
13530
  if (ckId !== "LIST") {
@@ -13616,18 +13903,6 @@ var expectRiffBox = async ({
13616
13903
  };
13617
13904
 
13618
13905
  // src/containers/riff/parse-movi.ts
13619
- var getStrhForIndex = (structure, trackId) => {
13620
- const boxes = getStrlBoxes(structure);
13621
- const box = boxes[trackId];
13622
- if (!box) {
13623
- throw new Error("Expected box");
13624
- }
13625
- const strh = getStrhBox(box.children);
13626
- if (!strh) {
13627
- throw new Error("strh");
13628
- }
13629
- return strh;
13630
- };
13631
13906
  var handleChunk = async ({
13632
13907
  state,
13633
13908
  ckId,
@@ -13640,42 +13915,60 @@ var handleChunk = async ({
13640
13915
  const trackId = parseInt(videoChunk[1], 10);
13641
13916
  const strh = getStrhForIndex(state.structure.getRiffStructure(), trackId);
13642
13917
  const samplesPerSecond = strh.rate / strh.scale;
13643
- const nthSample = state.riff.sampleCounter.getSamplesForTrack(trackId);
13644
- const timeInSec = nthSample / samplesPerSecond;
13645
- const timestamp = timeInSec;
13646
13918
  const data = iterator.getSlice(ckSize);
13647
- const infos = parseAvc(data);
13919
+ const infos = parseAvc(data, state.avc);
13648
13920
  const keyOrDelta = getKeyFrameOrDeltaFromAvcInfo(infos);
13921
+ const info = infos.find((i) => i.type === "keyframe" || i.type === "delta-frame");
13649
13922
  const avcProfile = infos.find((i) => i.type === "avc-profile");
13650
13923
  const ppsProfile = infos.find((i) => i.type === "avc-pps");
13651
13924
  if (avcProfile && ppsProfile && !state.riff.getAvcProfile()) {
13652
13925
  await state.riff.onProfile({ pps: ppsProfile, sps: avcProfile });
13653
13926
  state.callbacks.tracks.setIsDone(state.logLevel);
13654
13927
  }
13655
- const videoSample = convertAudioOrVideoSampleToWebCodecsTimestamps({
13656
- sample: {
13657
- cts: timestamp,
13658
- dts: timestamp,
13659
- data,
13660
- duration: undefined,
13661
- timestamp,
13662
- trackId,
13663
- type: keyOrDelta,
13664
- offset,
13665
- timescale: samplesPerSecond
13666
- },
13667
- timescale: 1
13668
- });
13669
- state.riff.sampleCounter.onVideoSample(trackId, videoSample);
13928
+ const rawSample = {
13929
+ data,
13930
+ duration: 1 / samplesPerSecond,
13931
+ trackId,
13932
+ type: keyOrDelta === "bidirectional" ? "delta" : keyOrDelta,
13933
+ offset,
13934
+ timescale: samplesPerSecond,
13935
+ avc: info
13936
+ };
13937
+ const maxFramesInBuffer = state.avc.getMaxFramesInBuffer();
13938
+ if (maxFramesInBuffer === null) {
13939
+ throw new Error("maxFramesInBuffer is null");
13940
+ }
13941
+ if ((info?.poc ?? null) === null) {
13942
+ throw new Error("poc is null");
13943
+ }
13944
+ const keyframeOffset = state.riff.sampleCounter.getKeyframeAtOffset(rawSample);
13945
+ if (keyframeOffset !== null) {
13946
+ state.riff.sampleCounter.setPocAtKeyframeOffset({
13947
+ keyframeOffset,
13948
+ poc: info.poc
13949
+ });
13950
+ }
13951
+ state.riff.queuedBFrames.addFrame(rawSample, maxFramesInBuffer);
13952
+ const releasedFrame = state.riff.queuedBFrames.getReleasedFrame();
13953
+ if (!releasedFrame) {
13954
+ return;
13955
+ }
13956
+ const videoSample = convertQueuedSampleToMediaParserSample(releasedFrame, state);
13957
+ state.riff.sampleCounter.onVideoSample(videoSample);
13670
13958
  await state.callbacks.onVideoSample(trackId, videoSample);
13671
- return;
13672
13959
  }
13673
13960
  const audioChunk = ckId.match(/^([0-9]{2})wb$/);
13674
13961
  if (audioChunk) {
13675
13962
  const trackId = parseInt(audioChunk[1], 10);
13676
13963
  const strh = getStrhForIndex(state.structure.getRiffStructure(), trackId);
13677
- const samplesPerSecond = strh.rate / strh.scale;
13678
- const nthSample = state.riff.sampleCounter.getSamplesForTrack(trackId);
13964
+ const { strf } = strh;
13965
+ if (strf.type !== "strf-box-audio") {
13966
+ throw new Error("audio");
13967
+ }
13968
+ const samplesPerSecond = strh.rate / strh.scale * strf.numberOfChannels;
13969
+ const nthSample = state.riff.sampleCounter.getSampleCountForTrack({
13970
+ trackId
13971
+ });
13679
13972
  const timeInSec = nthSample / samplesPerSecond;
13680
13973
  const timestamp = timeInSec;
13681
13974
  const data = iterator.getSlice(ckSize);
@@ -13735,6 +14028,13 @@ var parseMediaSection = async (state) => {
13735
14028
 
13736
14029
  // src/containers/riff/parse-riff-body.ts
13737
14030
  var parseRiffBody = async (state) => {
14031
+ const releasedFrame = state.riff.queuedBFrames.getReleasedFrame();
14032
+ if (releasedFrame) {
14033
+ const converted = convertQueuedSampleToMediaParserSample(releasedFrame, state);
14034
+ state.riff.sampleCounter.onVideoSample(converted);
14035
+ await state.callbacks.onVideoSample(releasedFrame.trackId, converted);
14036
+ return null;
14037
+ }
13738
14038
  if (state.mediaSection.isCurrentByteInMediaSection(state.iterator) === "in-section") {
13739
14039
  if (maySkipVideoData({
13740
14040
  state
@@ -14115,7 +14415,8 @@ var handleAacPacket = async ({
14115
14415
  codec: mapAudioObjectTypeToCodecString(audioObjectType),
14116
14416
  description: codecPrivate2,
14117
14417
  numberOfChannels: channelConfiguration,
14118
- sampleRate
14418
+ sampleRate,
14419
+ startInSeconds: 0
14119
14420
  };
14120
14421
  await registerAudioTrack({
14121
14422
  track,
@@ -14202,7 +14503,8 @@ var processStreamBuffer = async ({
14202
14503
  onAudioTrack,
14203
14504
  onVideoTrack,
14204
14505
  transportStream,
14205
- makeSamplesStartAtZero
14506
+ makeSamplesStartAtZero,
14507
+ avcState
14206
14508
  }) => {
14207
14509
  const stream = getStreamForId(structure, programId);
14208
14510
  if (!stream) {
@@ -14220,7 +14522,8 @@ var processStreamBuffer = async ({
14220
14522
  onVideoTrack,
14221
14523
  offset: streamBuffer.offset,
14222
14524
  transportStream,
14223
- makeSamplesStartAtZero
14525
+ makeSamplesStartAtZero,
14526
+ avcState
14224
14527
  });
14225
14528
  } else if (stream.streamType === 15) {
14226
14529
  await handleAacPacket({
@@ -14249,7 +14552,8 @@ var processFinalStreamBuffers = async ({
14249
14552
  onAudioTrack,
14250
14553
  onVideoTrack,
14251
14554
  transportStream,
14252
- makeSamplesStartAtZero
14555
+ makeSamplesStartAtZero,
14556
+ avcState
14253
14557
  }) => {
14254
14558
  for (const [programId, buffer] of transportStream.streamBuffers) {
14255
14559
  if (buffer.getBuffer().byteLength > 0) {
@@ -14262,7 +14566,8 @@ var processFinalStreamBuffers = async ({
14262
14566
  onAudioTrack,
14263
14567
  onVideoTrack,
14264
14568
  transportStream,
14265
- makeSamplesStartAtZero
14569
+ makeSamplesStartAtZero,
14570
+ avcState
14266
14571
  });
14267
14572
  transportStream.streamBuffers.delete(programId);
14268
14573
  }
@@ -14389,7 +14694,8 @@ var processAudio = async ({
14389
14694
  onAudioTrack,
14390
14695
  onVideoTrack,
14391
14696
  transportStream,
14392
- makeSamplesStartAtZero
14697
+ makeSamplesStartAtZero,
14698
+ avcState
14393
14699
  }) => {
14394
14700
  const { streamBuffers, nextPesHeaderStore: nextPesHeader } = transportStream;
14395
14701
  const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
@@ -14416,7 +14722,8 @@ var processAudio = async ({
14416
14722
  onAudioTrack,
14417
14723
  onVideoTrack,
14418
14724
  transportStream,
14419
- makeSamplesStartAtZero
14725
+ makeSamplesStartAtZero,
14726
+ avcState
14420
14727
  });
14421
14728
  const rest = streamBuffer.getBuffer().slice(expectedLength);
14422
14729
  streamBuffers.set(transportStreamEntry.pid, makeTransportStreamPacketBuffer({
@@ -14445,7 +14752,8 @@ var processVideo = async ({
14445
14752
  onAudioTrack,
14446
14753
  onVideoTrack,
14447
14754
  transportStream,
14448
- makeSamplesStartAtZero
14755
+ makeSamplesStartAtZero,
14756
+ avcState
14449
14757
  }) => {
14450
14758
  const indexOfSeparator = streamBuffer.get2ndSubArrayIndex();
14451
14759
  if (indexOfSeparator === -1 || indexOfSeparator === 0) {
@@ -14467,7 +14775,8 @@ var processVideo = async ({
14467
14775
  onAudioTrack,
14468
14776
  onVideoTrack,
14469
14777
  transportStream,
14470
- makeSamplesStartAtZero
14778
+ makeSamplesStartAtZero,
14779
+ avcState
14471
14780
  });
14472
14781
  return rest;
14473
14782
  };
@@ -14495,7 +14804,8 @@ var processSampleIfPossible = async (state) => {
14495
14804
  onAudioTrack: state.onAudioTrack,
14496
14805
  onVideoTrack: state.onVideoTrack,
14497
14806
  transportStream: state.transportStream,
14498
- makeSamplesStartAtZero: state.makeSamplesStartAtZero
14807
+ makeSamplesStartAtZero: state.makeSamplesStartAtZero,
14808
+ avcState: state.avc
14499
14809
  });
14500
14810
  state.transportStream.streamBuffers.delete(stream.pid);
14501
14811
  state.transportStream.streamBuffers.set(stream.pid, makeTransportStreamPacketBuffer({
@@ -14518,7 +14828,8 @@ var processSampleIfPossible = async (state) => {
14518
14828
  onVideoTrack: state.onVideoTrack,
14519
14829
  transportStream: state.transportStream,
14520
14830
  makeSamplesStartAtZero: state.makeSamplesStartAtZero,
14521
- transportStreamEntry: stream
14831
+ transportStreamEntry: stream,
14832
+ avcState: state.avc
14522
14833
  });
14523
14834
  processed = true;
14524
14835
  break;
@@ -14555,7 +14866,8 @@ var parseTransportStream = async (state) => {
14555
14866
  logLevel: state.logLevel,
14556
14867
  onAudioTrack: state.onAudioTrack,
14557
14868
  onVideoTrack: state.onVideoTrack,
14558
- makeSamplesStartAtZero: state.makeSamplesStartAtZero
14869
+ makeSamplesStartAtZero: state.makeSamplesStartAtZero,
14870
+ avcState: state.avc
14559
14871
  });
14560
14872
  }
14561
14873
  return Promise.resolve(null);
@@ -14622,7 +14934,8 @@ var parseFmt = async ({
14622
14934
  numberOfChannels,
14623
14935
  sampleRate,
14624
14936
  timescale: 1e6,
14625
- trackId: 0
14937
+ trackId: 0,
14938
+ startInSeconds: 0
14626
14939
  },
14627
14940
  container: "wav",
14628
14941
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
@@ -14905,7 +15218,8 @@ var selectStatesForProcessing = ({
14905
15218
  onAudioTrack,
14906
15219
  onVideoTrack,
14907
15220
  structure,
14908
- webm
15221
+ webm,
15222
+ avc
14909
15223
  }) => {
14910
15224
  return {
14911
15225
  webmState: webm,
@@ -14913,7 +15227,8 @@ var selectStatesForProcessing = ({
14913
15227
  logLevel,
14914
15228
  onAudioTrack,
14915
15229
  onVideoTrack,
14916
- structureState: structure
15230
+ structureState: structure,
15231
+ avcState: avc
14917
15232
  };
14918
15233
  };
14919
15234
 
@@ -15123,9 +15438,6 @@ var runParseIteration = async ({
15123
15438
  if (structure && structure.type === "m3u") {
15124
15439
  return parseM3u({ state });
15125
15440
  }
15126
- if (state.iterator.bytesRemaining() === 0) {
15127
- return Promise.reject(new Error("no bytes"));
15128
- }
15129
15441
  if (structure === null) {
15130
15442
  await initVideo({
15131
15443
  state
@@ -15426,6 +15738,82 @@ var aacState = () => {
15426
15738
  };
15427
15739
  };
15428
15740
 
15741
+ // src/containers/avc/max-buffer-size.ts
15742
+ var maxMacroblocksByLevel = {
15743
+ 10: 396,
15744
+ 11: 900,
15745
+ 12: 2376,
15746
+ 13: 2376,
15747
+ 20: 2376,
15748
+ 21: 4752,
15749
+ 22: 8100,
15750
+ 30: 8100,
15751
+ 31: 18000,
15752
+ 32: 20480,
15753
+ 40: 32768,
15754
+ 41: 32768,
15755
+ 42: 34816,
15756
+ 50: 110400,
15757
+ 51: 184320,
15758
+ 52: 184320,
15759
+ 60: 696320,
15760
+ 61: 696320,
15761
+ 62: 696320
15762
+ };
15763
+ var macroBlocksPerFrame = (sps) => {
15764
+ const { pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 } = sps;
15765
+ return (pic_width_in_mbs_minus1 + 1) * (pic_height_in_map_units_minus1 + 1);
15766
+ };
15767
+ var maxMacroblockBufferSize = (sps) => {
15768
+ const { level } = sps;
15769
+ const maxMacroblocks = maxMacroblocksByLevel[level];
15770
+ if (maxMacroblocks === undefined) {
15771
+ throw new Error(`Unsupported level: ${level.toString(16)}`);
15772
+ }
15773
+ return maxMacroblocks;
15774
+ };
15775
+
15776
+ // src/state/avc/avc-state.ts
15777
+ var avcState = () => {
15778
+ let prevPicOrderCntLsb = 0;
15779
+ let prevPicOrderCntMsb = 0;
15780
+ let sps = null;
15781
+ let maxFramesInBuffer = null;
15782
+ return {
15783
+ getPrevPicOrderCntLsb() {
15784
+ return prevPicOrderCntLsb;
15785
+ },
15786
+ getPrevPicOrderCntMsb() {
15787
+ return prevPicOrderCntMsb;
15788
+ },
15789
+ setPrevPicOrderCntLsb(value) {
15790
+ prevPicOrderCntLsb = value;
15791
+ },
15792
+ setPrevPicOrderCntMsb(value) {
15793
+ prevPicOrderCntMsb = value;
15794
+ },
15795
+ setSps(value) {
15796
+ const macroblockBufferSize = macroBlocksPerFrame(value);
15797
+ const maxBufferSize = maxMacroblockBufferSize(value);
15798
+ const maxFrames = Math.min(16, Math.floor(maxBufferSize / macroblockBufferSize));
15799
+ maxFramesInBuffer = maxFrames;
15800
+ sps = value;
15801
+ },
15802
+ getSps() {
15803
+ return sps;
15804
+ },
15805
+ getMaxFramesInBuffer() {
15806
+ return maxFramesInBuffer;
15807
+ },
15808
+ clear() {
15809
+ maxFramesInBuffer = null;
15810
+ sps = null;
15811
+ prevPicOrderCntLsb = 0;
15812
+ prevPicOrderCntMsb = 0;
15813
+ }
15814
+ };
15815
+ };
15816
+
15429
15817
  // src/state/current-reader.ts
15430
15818
  var currentReader = (initialReader) => {
15431
15819
  let current = initialReader;
@@ -15666,6 +16054,17 @@ var moovState = () => {
15666
16054
  };
15667
16055
  };
15668
16056
 
16057
+ // src/state/iso-base-media/timescale-state.ts
16058
+ var movieTimeScaleState = () => {
16059
+ let trackTimescale = null;
16060
+ return {
16061
+ getTrackTimescale: () => trackTimescale,
16062
+ setTrackTimescale: (timescale) => {
16063
+ trackTimescale = timescale;
16064
+ }
16065
+ };
16066
+ };
16067
+
15669
16068
  // src/state/iso-base-media/iso-state.ts
15670
16069
  var isoBaseMediaState = ({
15671
16070
  contentLength,
@@ -15687,7 +16086,8 @@ var isoBaseMediaState = ({
15687
16086
  prefetchCache
15688
16087
  }),
15689
16088
  moof: precomputedMoofState(),
15690
- tfra: precomputedTfraState()
16089
+ tfra: precomputedTfraState(),
16090
+ movieTimeScale: movieTimeScaleState()
15691
16091
  };
15692
16092
  };
15693
16093
 
@@ -16343,6 +16743,43 @@ var lazyIdx1Fetch = ({
16343
16743
  };
16344
16744
  };
16345
16745
 
16746
+ // src/state/riff/queued-frames.ts
16747
+ var queuedBFramesState = () => {
16748
+ const queuedFrames = [];
16749
+ const releasedFrames = [];
16750
+ const flush = () => {
16751
+ releasedFrames.push(...queuedFrames);
16752
+ queuedFrames.length = 0;
16753
+ };
16754
+ return {
16755
+ addFrame: (frame, maxFramesInBuffer) => {
16756
+ if (frame.type === "key") {
16757
+ flush();
16758
+ releasedFrames.push(frame);
16759
+ return;
16760
+ }
16761
+ queuedFrames.push(frame);
16762
+ if (queuedFrames.length > maxFramesInBuffer) {
16763
+ releasedFrames.push(queuedFrames.shift());
16764
+ }
16765
+ },
16766
+ flush,
16767
+ getReleasedFrame: () => {
16768
+ if (releasedFrames.length === 0) {
16769
+ return null;
16770
+ }
16771
+ return releasedFrames.shift();
16772
+ },
16773
+ hasReleasedFrames: () => {
16774
+ return releasedFrames.length > 0;
16775
+ },
16776
+ clear: () => {
16777
+ releasedFrames.length = 0;
16778
+ queuedFrames.length = 0;
16779
+ }
16780
+ };
16781
+ };
16782
+
16346
16783
  // src/state/riff/riff-keyframes.ts
16347
16784
  var riffKeyframesState = () => {
16348
16785
  const keyframes = [];
@@ -16351,6 +16788,7 @@ var riffKeyframesState = () => {
16351
16788
  return;
16352
16789
  }
16353
16790
  keyframes.push(keyframe);
16791
+ keyframes.sort((a, b) => a.positionInBytes - b.positionInBytes);
16354
16792
  };
16355
16793
  const getKeyframes2 = () => {
16356
16794
  return keyframes;
@@ -16370,6 +16808,7 @@ var riffKeyframesState = () => {
16370
16808
  // src/state/riff/sample-counter.ts
16371
16809
  var riffSampleCounter = () => {
16372
16810
  const samplesForTrack = {};
16811
+ const pocsAtKeyframeOffset = {};
16373
16812
  const riffKeys = riffKeyframesState();
16374
16813
  const onAudioSample = (trackId, audioSample) => {
16375
16814
  if (typeof samplesForTrack[trackId] === "undefined") {
@@ -16380,13 +16819,13 @@ var riffSampleCounter = () => {
16380
16819
  }
16381
16820
  samplesForTrack[trackId]++;
16382
16821
  };
16383
- const onVideoSample = (trackId, videoSample) => {
16384
- if (typeof samplesForTrack[trackId] === "undefined") {
16385
- samplesForTrack[trackId] = 0;
16822
+ const onVideoSample = (videoSample) => {
16823
+ if (typeof samplesForTrack[videoSample.trackId] === "undefined") {
16824
+ samplesForTrack[videoSample.trackId] = 0;
16386
16825
  }
16387
16826
  if (videoSample.type === "key") {
16388
16827
  riffKeys.addKeyframe({
16389
- trackId,
16828
+ trackId: videoSample.trackId,
16390
16829
  decodingTimeInSeconds: videoSample.dts / videoSample.timescale,
16391
16830
  positionInBytes: videoSample.offset,
16392
16831
  presentationTimeInSeconds: videoSample.cts / videoSample.timescale,
@@ -16395,10 +16834,10 @@ var riffSampleCounter = () => {
16395
16834
  });
16396
16835
  }
16397
16836
  if (videoSample.data.length > 0) {
16398
- samplesForTrack[trackId]++;
16837
+ samplesForTrack[videoSample.trackId]++;
16399
16838
  }
16400
16839
  };
16401
- const getSamplesForTrack = (trackId) => {
16840
+ const getSampleCountForTrack = ({ trackId }) => {
16402
16841
  return samplesForTrack[trackId] ?? 0;
16403
16842
  };
16404
16843
  const setSamplesFromSeek = (samples) => {
@@ -16406,12 +16845,39 @@ var riffSampleCounter = () => {
16406
16845
  samplesForTrack[trackId] = samples[trackId];
16407
16846
  }
16408
16847
  };
16848
+ const setPocAtKeyframeOffset = ({
16849
+ keyframeOffset,
16850
+ poc
16851
+ }) => {
16852
+ if (typeof pocsAtKeyframeOffset[keyframeOffset] === "undefined") {
16853
+ pocsAtKeyframeOffset[keyframeOffset] = [];
16854
+ }
16855
+ if (pocsAtKeyframeOffset[keyframeOffset].includes(poc)) {
16856
+ return;
16857
+ }
16858
+ pocsAtKeyframeOffset[keyframeOffset].push(poc);
16859
+ pocsAtKeyframeOffset[keyframeOffset].sort((a, b) => a - b);
16860
+ };
16861
+ const getPocAtKeyframeOffset = ({
16862
+ keyframeOffset
16863
+ }) => {
16864
+ return pocsAtKeyframeOffset[keyframeOffset];
16865
+ };
16866
+ const getKeyframeAtOffset = (sample) => {
16867
+ if (sample.type === "key") {
16868
+ return sample.offset;
16869
+ }
16870
+ return riffKeys.getKeyframes().findLast((k) => k.positionInBytes <= sample.offset)?.positionInBytes ?? null;
16871
+ };
16409
16872
  return {
16410
16873
  onAudioSample,
16411
16874
  onVideoSample,
16412
- getSamplesForTrack,
16875
+ getSampleCountForTrack,
16413
16876
  setSamplesFromSeek,
16414
- riffKeys
16877
+ riffKeys,
16878
+ setPocAtKeyframeOffset,
16879
+ getPocAtKeyframeOffset,
16880
+ getKeyframeAtOffset
16415
16881
  };
16416
16882
  };
16417
16883
 
@@ -16444,6 +16910,7 @@ var riffSpecificState = ({
16444
16910
  prefetchCache
16445
16911
  });
16446
16912
  const sampleCounter = riffSampleCounter();
16913
+ const queuedBFrames = queuedBFramesState();
16447
16914
  return {
16448
16915
  getAvcProfile: () => {
16449
16916
  return avcProfile;
@@ -16453,6 +16920,7 @@ var riffSpecificState = ({
16453
16920
  getNextTrackIndex: () => {
16454
16921
  return nextTrackIndex;
16455
16922
  },
16923
+ queuedBFrames,
16456
16924
  incrementNextTrackIndex: () => {
16457
16925
  nextTrackIndex++;
16458
16926
  },
@@ -16792,6 +17260,7 @@ var makeParserState = ({
16792
17260
  const timings = timingsState();
16793
17261
  const seekInfiniteLoop = seekInfiniteLoopDetectionState();
16794
17262
  const currentReaderState = currentReader(initialReaderInstance);
17263
+ const avc = avcState();
16795
17264
  const errored = null;
16796
17265
  const discardReadBytes = async (force) => {
16797
17266
  const { bytesRemoved, removedData } = iterator.removeBytesRead(force, mode);
@@ -16885,7 +17354,8 @@ var makeParserState = ({
16885
17354
  currentReader: currentReaderState,
16886
17355
  seekInfiniteLoop,
16887
17356
  makeSamplesStartAtZero,
16888
- prefetchCache
17357
+ prefetchCache,
17358
+ avc
16889
17359
  };
16890
17360
  };
16891
17361
 
@@ -17140,7 +17610,7 @@ var downloadAndParseMedia = async (options) => {
17140
17610
  return returnValue;
17141
17611
  };
17142
17612
  // src/version.ts
17143
- var VERSION = "4.0.301";
17613
+ var VERSION = "4.0.303";
17144
17614
 
17145
17615
  // src/index.ts
17146
17616
  var MediaParserInternals = {