@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
@@ -19,6 +19,10 @@ const checkIfDone = async (state) => {
19
19
  !state.m3u.getAllChunksProcessedOverall()) {
20
20
  return false;
21
21
  }
22
+ state.riff.queuedBFrames.flush();
23
+ if (state.riff.queuedBFrames.hasReleasedFrames()) {
24
+ return false;
25
+ }
22
26
  log_1.Log.verbose(state.logLevel, 'Reached end of file');
23
27
  await state.discardReadBytes(true);
24
28
  return true;
@@ -62,6 +62,7 @@ const parseAac = async (state) => {
62
62
  timescale: 1000000,
63
63
  trackId: 0,
64
64
  type: 'audio',
65
+ startInSeconds: 0,
65
66
  },
66
67
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
67
68
  tracks: state.callbacks.tracks,
@@ -1,2 +1,2 @@
1
1
  import type { AvcInfo } from './parse-avc';
2
- export declare const getKeyFrameOrDeltaFromAvcInfo: (infos: AvcInfo[]) => "key" | "delta";
2
+ export declare const getKeyFrameOrDeltaFromAvcInfo: (infos: AvcInfo[]) => "key" | "delta" | "bidirectional";
@@ -6,6 +6,10 @@ const getKeyFrameOrDeltaFromAvcInfo = (infos) => {
6
6
  if (!keyOrDelta) {
7
7
  throw new Error('expected avc to contain info about key or delta');
8
8
  }
9
- return keyOrDelta.type === 'keyframe' ? 'key' : 'delta';
9
+ return keyOrDelta.type === 'keyframe'
10
+ ? 'key'
11
+ : keyOrDelta.isBidirectionalFrame
12
+ ? 'bidirectional'
13
+ : 'delta';
10
14
  };
11
15
  exports.getKeyFrameOrDeltaFromAvcInfo = getKeyFrameOrDeltaFromAvcInfo;
@@ -0,0 +1,3 @@
1
+ import type { SpsInfo } from './parse-avc';
2
+ export declare const macroBlocksPerFrame: (sps: SpsInfo) => number;
3
+ export declare const maxMacroblockBufferSize: (sps: SpsInfo) => number;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.maxMacroblockBufferSize = exports.macroBlocksPerFrame = void 0;
4
+ // https://www.itu.int/rec/T-REC-H.264-202408-I
5
+ // Table A-1 – Level limits
6
+ const maxMacroblocksByLevel = {
7
+ 10: 396, // Level 1.0
8
+ 11: 900, // Level 1.1
9
+ 12: 2376, // Level 1.2
10
+ 13: 2376, // Level 1.3
11
+ 20: 2376, // Level 2.0
12
+ 21: 4752, // Level 2.1
13
+ 22: 8100, // Level 2.2
14
+ 30: 8100, // Level 3.0
15
+ 31: 18000, // Level 3.1
16
+ 32: 20480, // Level 3.2
17
+ 40: 32768, // Level 4.0
18
+ 41: 32768, // Level 4.1
19
+ 42: 34816, // Level 4.2
20
+ 50: 110400, // Level 5.0
21
+ 51: 184320, // Level 5.1
22
+ 52: 184320, // Level 5.2
23
+ 60: 696320, // Level 6.0
24
+ 61: 696320, // Level 6.1
25
+ 62: 696320, // Level 6.2
26
+ };
27
+ const macroBlocksPerFrame = (sps) => {
28
+ const { pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 } = sps;
29
+ return (pic_width_in_mbs_minus1 + 1) * (pic_height_in_map_units_minus1 + 1);
30
+ };
31
+ exports.macroBlocksPerFrame = macroBlocksPerFrame;
32
+ const maxMacroblockBufferSize = (sps) => {
33
+ const { level } = sps;
34
+ const maxMacroblocks = maxMacroblocksByLevel[level];
35
+ if (maxMacroblocks === undefined) {
36
+ throw new Error(`Unsupported level: ${level.toString(16)}`);
37
+ }
38
+ return maxMacroblocks;
39
+ };
40
+ exports.maxMacroblockBufferSize = maxMacroblockBufferSize;
@@ -1,3 +1,5 @@
1
+ import type { AvcState } from '../../state/avc/avc-state';
2
+ import type { MediaParserAvcDeltaFrameInfo, MediaParserAvcKeyframeInfo } from '../../webcodec-sample-types';
1
3
  type VuiParameters = {
2
4
  sar_width: number | null;
3
5
  sar_height: number | null;
@@ -19,7 +21,7 @@ export type SpsInfo = {
19
21
  bit_depth_luma_minus8: number | null;
20
22
  bit_depth_chroma_minus8: number | null;
21
23
  qpprime_y_zero_transform_bypass_flag: number | null;
22
- log2_max_frame_num_minus4: number | null;
24
+ log2_max_frame_num_minus4: number;
23
25
  log2_max_pic_order_cnt_lsb_minus4: number | null;
24
26
  max_num_ref_frames: number | null;
25
27
  gaps_in_frame_num_value_allowed_flag: number | null;
@@ -32,6 +34,7 @@ export type SpsInfo = {
32
34
  frame_crop_top_offset: number | null;
33
35
  frame_crop_bottom_offset: number | null;
34
36
  vui_parameters: VuiParameters | null;
37
+ pic_order_cnt_type: number;
35
38
  };
36
39
  export type AvcProfileInfo = {
37
40
  spsData: SpsInfo;
@@ -42,10 +45,6 @@ export type AvcPPs = {
42
45
  type: 'avc-pps';
43
46
  pps: Uint8Array;
44
47
  };
45
- export type AvcInfo = AvcProfileInfo | AvcPPs | {
46
- type: 'keyframe';
47
- } | {
48
- type: 'delta-frame';
49
- };
50
- export declare const parseAvc: (buffer: Uint8Array) => AvcInfo[];
48
+ export type AvcInfo = AvcProfileInfo | AvcPPs | MediaParserAvcKeyframeInfo | MediaParserAvcDeltaFrameInfo;
49
+ export declare const parseAvc: (buffer: Uint8Array, avcState: AvcState) => AvcInfo[];
51
50
  export {};
@@ -5,6 +5,37 @@ Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.parseAvc = void 0;
6
6
  const buffer_iterator_1 = require("../../iterator/buffer-iterator");
7
7
  const Extended_SAR = 255;
8
+ const getPoc = (iterator, sps, avcState, isReferencePicture) => {
9
+ const { pic_order_cnt_type, log2_max_pic_order_cnt_lsb_minus4 } = sps;
10
+ if (pic_order_cnt_type !== 0) {
11
+ return null;
12
+ }
13
+ const prevPicOrderCntLsb = avcState.getPrevPicOrderCntLsb();
14
+ const prevPicOrderCntMsb = avcState.getPrevPicOrderCntMsb();
15
+ if (log2_max_pic_order_cnt_lsb_minus4 === null) {
16
+ throw new Error('log2_max_pic_order_cnt_lsb_minus4 is null');
17
+ }
18
+ const max_pic_order_cnt_lsb = 2 ** (log2_max_pic_order_cnt_lsb_minus4 + 4);
19
+ const pic_order_cnt_lsb = iterator.getBits(log2_max_pic_order_cnt_lsb_minus4 + 4);
20
+ let picOrderCntMsb;
21
+ if (pic_order_cnt_lsb < prevPicOrderCntLsb &&
22
+ prevPicOrderCntLsb - pic_order_cnt_lsb >= max_pic_order_cnt_lsb / 2) {
23
+ picOrderCntMsb = prevPicOrderCntMsb + max_pic_order_cnt_lsb;
24
+ }
25
+ else if (pic_order_cnt_lsb > prevPicOrderCntLsb &&
26
+ pic_order_cnt_lsb - prevPicOrderCntLsb > max_pic_order_cnt_lsb / 2) {
27
+ picOrderCntMsb = prevPicOrderCntMsb - max_pic_order_cnt_lsb;
28
+ }
29
+ else {
30
+ picOrderCntMsb = prevPicOrderCntMsb;
31
+ }
32
+ const poc = picOrderCntMsb + pic_order_cnt_lsb;
33
+ if (isReferencePicture) {
34
+ avcState.setPrevPicOrderCntLsb(pic_order_cnt_lsb);
35
+ avcState.setPrevPicOrderCntMsb(picOrderCntMsb);
36
+ }
37
+ return poc;
38
+ };
8
39
  const readVuiParameters = (iterator) => {
9
40
  let sar_width = null;
10
41
  let sar_height = null;
@@ -168,6 +199,7 @@ const readSps = (iterator) => {
168
199
  frame_crop_top_offset,
169
200
  mb_adaptive_frame_field_flag,
170
201
  vui_parameters,
202
+ pic_order_cnt_type,
171
203
  };
172
204
  };
173
205
  const findEnd = (buffer) => {
@@ -185,17 +217,23 @@ const findEnd = (buffer) => {
185
217
  }
186
218
  return null;
187
219
  };
188
- const inspect = (buffer) => {
220
+ const inspect = (buffer, avcState) => {
189
221
  const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(buffer, buffer.byteLength);
190
222
  iterator.startReadingBits();
191
- iterator.getBits(1);
192
- iterator.getBits(2);
193
- const type = iterator.getBits(5);
194
- iterator.stopReadingBits();
223
+ iterator.getBits(1); // forbidden_zero_bit
224
+ const nal_ref_idc = iterator.getBits(2); // nal_ref_idc
225
+ const isReferencePicture = nal_ref_idc !== 0;
226
+ const type = iterator.getBits(5); // nal_unit_type
195
227
  if (type === 7) {
228
+ iterator.stopReadingBits();
196
229
  const end = findEnd(buffer);
197
230
  const data = readSps(iterator);
198
231
  const sps = buffer.slice(0, end === null ? Infinity : end);
232
+ avcState.setSps(data);
233
+ if (isReferencePicture) {
234
+ avcState.setPrevPicOrderCntLsb(0);
235
+ avcState.setPrevPicOrderCntMsb(0);
236
+ }
199
237
  return {
200
238
  spsData: data,
201
239
  sps,
@@ -203,11 +241,31 @@ const inspect = (buffer) => {
203
241
  };
204
242
  }
205
243
  if (type === 5) {
244
+ avcState.setPrevPicOrderCntLsb(0);
245
+ avcState.setPrevPicOrderCntMsb(0);
246
+ iterator.readExpGolomb(); // ignore first_mb_in_slice
247
+ iterator.readExpGolomb(); // slice_type
248
+ iterator.readExpGolomb(); // pic_parameter_set_id
249
+ const sps = avcState.getSps();
250
+ if (!sps) {
251
+ throw new Error('SPS not found');
252
+ }
253
+ const numberOfBitsForFrameNum = sps.log2_max_frame_num_minus4 + 4;
254
+ iterator.getBits(numberOfBitsForFrameNum); // frame_num
255
+ iterator.readExpGolomb(); // idr_pic_id
256
+ const { pic_order_cnt_type } = sps;
257
+ let poc = null;
258
+ if (pic_order_cnt_type === 0) {
259
+ poc = getPoc(iterator, sps, avcState, isReferencePicture);
260
+ }
261
+ iterator.stopReadingBits();
206
262
  return {
207
263
  type: 'keyframe',
264
+ poc,
208
265
  };
209
266
  }
210
267
  if (type === 8) {
268
+ iterator.stopReadingBits();
211
269
  const end = findEnd(buffer);
212
270
  const pps = buffer.slice(0, end === null ? Infinity : end);
213
271
  return {
@@ -216,15 +274,33 @@ const inspect = (buffer) => {
216
274
  };
217
275
  }
218
276
  if (type === 1) {
277
+ iterator.readExpGolomb(); // ignore first_mb_in_slice
278
+ const slice_type = iterator.readExpGolomb();
279
+ const isBidirectionalFrame = slice_type === 6;
280
+ iterator.readExpGolomb(); // pic_parameter_set_id
281
+ const sps = avcState.getSps();
282
+ if (!sps) {
283
+ throw new Error('SPS not found');
284
+ }
285
+ const numberOfBitsForFrameNum = sps.log2_max_frame_num_minus4 + 4;
286
+ iterator.getBits(numberOfBitsForFrameNum); // frame_num
287
+ const { pic_order_cnt_type } = sps;
288
+ let poc = null;
289
+ if (pic_order_cnt_type === 0) {
290
+ poc = getPoc(iterator, sps, avcState, isReferencePicture);
291
+ }
292
+ iterator.stopReadingBits();
219
293
  return {
220
294
  type: 'delta-frame',
295
+ isBidirectionalFrame,
296
+ poc,
221
297
  };
222
298
  }
223
299
  iterator.destroy();
224
300
  return null;
225
301
  };
226
302
  // https://stackoverflow.com/questions/24884827/possible-locations-for-sequence-picture-parameter-sets-for-h-264-stream
227
- const parseAvc = (buffer) => {
303
+ const parseAvc = (buffer, avcState) => {
228
304
  let zeroesInARow = 0;
229
305
  const infos = [];
230
306
  for (let i = 0; i < buffer.length; i++) {
@@ -235,7 +311,7 @@ const parseAvc = (buffer) => {
235
311
  }
236
312
  if (zeroesInARow >= 2 && val === 1) {
237
313
  zeroesInARow = 0;
238
- const info = inspect(buffer.slice(i + 1, i + 100));
314
+ const info = inspect(buffer.slice(i + 1, i + 100), avcState);
239
315
  if (info) {
240
316
  infos.push(info);
241
317
  if (info.type === 'keyframe' || info.type === 'delta-frame') {
@@ -43,6 +43,7 @@ const parseStreamInfo = async ({ iterator, state, }) => {
43
43
  sampleRate,
44
44
  timescale: 1000000,
45
45
  trackId: 0,
46
+ startInSeconds: 0,
46
47
  },
47
48
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
48
49
  tracks: state.callbacks.tracks,
@@ -1,4 +1,5 @@
1
1
  import type { BaseBox } from './base-type';
2
+ import type { ElstBox } from './elst';
2
3
  import type { EsdsBox } from './esds/esds';
3
4
  import type { FtypBox } from './ftyp';
4
5
  import type { MdhdBox } from './mdhd';
@@ -34,4 +35,4 @@ export interface RegularBox extends BaseBox {
34
35
  offset: number;
35
36
  type: 'regular-box';
36
37
  }
37
- export type IsoBaseMediaBox = RegularBox | FtypBox | MvhdBox | TkhdBox | StsdBox | MebxBox | KeysBox | MoovBox | TrakBox | SttsBox | MdhdBox | IlstBox | EsdsBox | StszBox | StcoBox | StscBox | AvccBox | HvccBox | VoidBox | StssBox | PaspBox | CttsBox | Av1CBox | TrunBox | HdlrBox | ColorParameterBox | TfdtBox | TfhdBox | TfraBox;
38
+ export type IsoBaseMediaBox = RegularBox | FtypBox | MvhdBox | TkhdBox | StsdBox | ElstBox | MebxBox | KeysBox | MoovBox | TrakBox | SttsBox | MdhdBox | IlstBox | EsdsBox | StszBox | StcoBox | StscBox | AvccBox | HvccBox | VoidBox | StssBox | PaspBox | CttsBox | Av1CBox | TrunBox | HdlrBox | ColorParameterBox | TfdtBox | TfhdBox | TfraBox;
@@ -0,0 +1,19 @@
1
+ import type { BufferIterator } from '../../iterator/buffer-iterator';
2
+ import type { BaseBox } from './base-type';
3
+ export interface ElstBox extends BaseBox {
4
+ type: 'elst-box';
5
+ version: number;
6
+ flags: number;
7
+ entries: ElstEntry[];
8
+ }
9
+ export type ElstEntry = {
10
+ editDuration: number;
11
+ mediaTime: number;
12
+ mediaRateInteger: number;
13
+ mediaRateFraction: number;
14
+ };
15
+ export declare const parseElst: ({ iterator, size, offset, }: {
16
+ iterator: BufferIterator;
17
+ size: number;
18
+ offset: number;
19
+ }) => ElstBox;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseElst = void 0;
4
+ const parseElst = ({ iterator, size, offset, }) => {
5
+ const { expectNoMoreBytes } = iterator.startBox(size - 8);
6
+ const version = iterator.getUint8();
7
+ const flags = iterator.getUint24();
8
+ const entryCount = iterator.getUint32();
9
+ const entries = [];
10
+ for (let i = 0; i < entryCount; i++) {
11
+ const editDuration = iterator.getUint32();
12
+ const mediaTime = iterator.getInt32();
13
+ const mediaRateInteger = iterator.getUint16();
14
+ const mediaRateFraction = iterator.getUint16();
15
+ entries.push({
16
+ editDuration,
17
+ mediaTime,
18
+ mediaRateInteger,
19
+ mediaRateFraction,
20
+ });
21
+ }
22
+ expectNoMoreBytes();
23
+ const result = {
24
+ type: 'elst-box',
25
+ version,
26
+ flags,
27
+ entries,
28
+ boxSize: size,
29
+ offset,
30
+ };
31
+ return result;
32
+ };
33
+ exports.parseElst = parseElst;
@@ -1,10 +1,11 @@
1
1
  import type { SamplePosition } from '../../get-sample-positions';
2
2
  import type { MediaParserLogLevel } from '../../log';
3
3
  import type { MediaSection } from '../../state/video-section';
4
- export declare const findKeyframeBeforeTime: ({ samplePositions, time, timescale, mediaSections, logLevel, }: {
4
+ export declare const findKeyframeBeforeTime: ({ samplePositions, time, timescale, mediaSections, logLevel, startInSeconds, }: {
5
5
  samplePositions: SamplePosition[];
6
6
  time: number;
7
7
  timescale: number;
8
8
  mediaSections: MediaSection[];
9
9
  logLevel: MediaParserLogLevel;
10
+ startInSeconds: number;
10
11
  }) => number | null;
@@ -2,12 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.findKeyframeBeforeTime = void 0;
4
4
  const log_1 = require("../../log");
5
- const findKeyframeBeforeTime = ({ samplePositions, time, timescale, mediaSections, logLevel, }) => {
5
+ const findKeyframeBeforeTime = ({ samplePositions, time, timescale, mediaSections, logLevel, startInSeconds, }) => {
6
6
  let videoByte = 0;
7
7
  let videoSample = null;
8
8
  for (const sample of samplePositions) {
9
- const ctsInSeconds = sample.cts / timescale;
10
- const dtsInSeconds = sample.dts / timescale;
9
+ const ctsInSeconds = sample.cts / timescale + startInSeconds;
10
+ const dtsInSeconds = sample.dts / timescale + startInSeconds;
11
11
  if (!sample.isKeyframe) {
12
12
  continue;
13
13
  }
@@ -79,6 +79,7 @@ const getMoovAtom = async ({ endOfMdat, state, }) => {
79
79
  onlyIfMoovAtomExpected: {
80
80
  tracks: tracksState,
81
81
  isoState: null,
82
+ movieTimeScaleState: state.iso.movieTimeScale,
82
83
  onAudioTrack,
83
84
  onVideoTrack,
84
85
  registerVideoSampleCallback: () => Promise.resolve(),
@@ -54,6 +54,7 @@ const getSeekingByteFromFragmentedMp4 = async ({ info, time, logLevel, currentPo
54
54
  timescale: firstTrack.timescale,
55
55
  logLevel,
56
56
  mediaSections: info.mediaSections,
57
+ startInSeconds: firstTrack.startInSeconds,
57
58
  });
58
59
  if (kf) {
59
60
  return {
@@ -53,6 +53,7 @@ const getSeekingByteFromIsoBaseMedia = ({ info, time, logLevel, currentPosition,
53
53
  timescale: track.timescale,
54
54
  logLevel,
55
55
  mediaSections: info.mediaSections,
56
+ startInSeconds: track.startInSeconds,
56
57
  });
57
58
  if (keyframe) {
58
59
  return Promise.resolve({
@@ -1,3 +1,3 @@
1
1
  import type { MediaParserAudioTrack, MediaParserOtherTrack, MediaParserVideoTrack } from '../../get-tracks';
2
2
  import type { TrakBox } from './trak/trak';
3
- export declare const makeBaseMediaTrack: (trakBox: TrakBox) => MediaParserVideoTrack | MediaParserAudioTrack | MediaParserOtherTrack | null;
3
+ export declare const makeBaseMediaTrack: (trakBox: TrakBox, startTimeInSeconds: number) => MediaParserVideoTrack | MediaParserAudioTrack | MediaParserOtherTrack | null;
@@ -9,7 +9,7 @@ const color_to_webcodecs_colors_1 = require("./color-to-webcodecs-colors");
9
9
  const get_actual_number_of_channels_1 = require("./get-actual-number-of-channels");
10
10
  const get_video_codec_from_iso_track_1 = require("./get-video-codec-from-iso-track");
11
11
  const traversal_1 = require("./traversal");
12
- const makeBaseMediaTrack = (trakBox) => {
12
+ const makeBaseMediaTrack = (trakBox, startTimeInSeconds) => {
13
13
  var _a, _b, _c, _d, _e;
14
14
  const tkhdBox = (0, traversal_1.getTkhdBox)(trakBox);
15
15
  const videoDescriptors = (0, traversal_1.getVideoDescriptors)(trakBox);
@@ -48,6 +48,7 @@ const makeBaseMediaTrack = (trakBox) => {
48
48
  description: (_d = (_c = actual.codecPrivate) === null || _c === void 0 ? void 0 : _c.data) !== null && _d !== void 0 ? _d : undefined,
49
49
  codecData: actual.codecPrivate,
50
50
  codecEnum,
51
+ startInSeconds: startTimeInSeconds,
51
52
  };
52
53
  }
53
54
  if (!(0, get_fps_1.trakBoxContainsVideo)(trakBox)) {
@@ -56,6 +57,7 @@ const makeBaseMediaTrack = (trakBox) => {
56
57
  trackId: tkhdBox.trackId,
57
58
  timescale: timescaleAndDuration.timescale,
58
59
  trakBox,
60
+ startInSeconds: startTimeInSeconds,
59
61
  };
60
62
  }
61
63
  const videoSample = (0, get_sample_aspect_ratio_1.getStsdVideoConfig)(trakBox);
@@ -104,6 +106,7 @@ const makeBaseMediaTrack = (trakBox) => {
104
106
  advancedColor,
105
107
  codecEnum: (0, get_video_codec_from_iso_track_1.getVideoCodecFromIsoTrak)(trakBox),
106
108
  fps: (0, get_fps_1.getFpsFromMp4TrakBox)(trakBox),
109
+ startInSeconds: startTimeInSeconds,
107
110
  };
108
111
  return track;
109
112
  };
@@ -0,0 +1,5 @@
1
+ import type { TrakBox } from '../trak/trak';
2
+ export declare const findTrackStartTimeInSeconds: ({ movieTimeScale, trakBox, }: {
3
+ movieTimeScale: number;
4
+ trakBox: TrakBox;
5
+ }) => number;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findTrackStartTimeInSeconds = void 0;
4
+ const traversal_1 = require("../traversal");
5
+ const findTrackStartTimeInSeconds = ({ movieTimeScale, trakBox, }) => {
6
+ const elstBox = (0, traversal_1.getElstBox)(trakBox);
7
+ if (!elstBox) {
8
+ return 0;
9
+ }
10
+ const { entries } = elstBox;
11
+ let dwellTime = 0;
12
+ for (const entry of entries) {
13
+ const { editDuration, mediaTime } = entry;
14
+ if (mediaTime !== -1) {
15
+ continue;
16
+ }
17
+ dwellTime += editDuration;
18
+ }
19
+ return dwellTime / movieTimeScale;
20
+ };
21
+ exports.findTrackStartTimeInSeconds = findTrackStartTimeInSeconds;
@@ -107,7 +107,10 @@ const parseMdatSection = async (state) => {
107
107
  if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
108
108
  return (0, skip_1.makeFetchMoreData)(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
109
109
  }
110
- const { cts, dts, duration, isKeyframe, offset, bigEndian, chunkSize } = samplesWithIndex.samplePosition;
110
+ const { cts: rawCts, dts: rawDts, duration, isKeyframe, offset, bigEndian, chunkSize, } = samplesWithIndex.samplePosition;
111
+ const { timescale, startInSeconds } = samplesWithIndex.track;
112
+ const cts = rawCts + startInSeconds * timescale;
113
+ const dts = rawDts + startInSeconds * timescale;
111
114
  const bytes = (0, postprocess_bytes_1.postprocessBytes)({
112
115
  bytes: iterator.getSlice(samplesWithIndex.samplePosition.size),
113
116
  bigEndian,
@@ -124,9 +127,9 @@ const parseMdatSection = async (state) => {
124
127
  trackId: samplesWithIndex.track.trackId,
125
128
  type: isKeyframe ? 'key' : 'delta',
126
129
  offset,
127
- timescale: samplesWithIndex.track.timescale,
130
+ timescale,
128
131
  },
129
- timescale: samplesWithIndex.track.timescale,
132
+ timescale,
130
133
  });
131
134
  await state.callbacks.onAudioSample(samplesWithIndex.track.trackId, audioSample);
132
135
  }
@@ -153,9 +156,9 @@ const parseMdatSection = async (state) => {
153
156
  trackId: samplesWithIndex.track.trackId,
154
157
  type: isKeyframe && !isRecoveryPoint ? 'key' : 'delta',
155
158
  offset,
156
- timescale: samplesWithIndex.track.timescale,
159
+ timescale,
157
160
  },
158
- timescale: samplesWithIndex.track.timescale,
161
+ timescale,
159
162
  });
160
163
  await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, videoSample);
161
164
  }
@@ -15,6 +15,7 @@ const parseIsoBaseMedia = async (state) => {
15
15
  onlyIfMoovAtomExpected: {
16
16
  tracks: state.callbacks.tracks,
17
17
  isoState: state.iso,
18
+ movieTimeScaleState: state.iso.movieTimeScale,
18
19
  onAudioTrack: state.onAudioTrack,
19
20
  onVideoTrack: state.onVideoTrack,
20
21
  registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
@@ -3,6 +3,7 @@ import type { MediaParserLogLevel } from '../../log';
3
3
  import type { FetchMoreData } from '../../skip';
4
4
  import type { TracksState } from '../../state/has-tracks-section';
5
5
  import type { IsoBaseMediaState } from '../../state/iso-base-media/iso-state';
6
+ import type { MovieTimeScaleState } from '../../state/iso-base-media/timescale-state';
6
7
  import type { CallbacksState } from '../../state/sample-callbacks';
7
8
  import type { MediaSectionState } from '../../state/video-section';
8
9
  import type { MediaParserOnAudioTrack, MediaParserOnVideoTrack } from '../../webcodec-sample-types';
@@ -10,6 +11,7 @@ import type { IsoBaseMediaBox } from './base-media-box';
10
11
  export type OnlyIfMoovAtomExpected = {
11
12
  tracks: TracksState;
12
13
  isoState: IsoBaseMediaState | null;
14
+ movieTimeScaleState: MovieTimeScaleState;
13
15
  onVideoTrack: MediaParserOnVideoTrack | null;
14
16
  onAudioTrack: MediaParserOnAudioTrack | null;
15
17
  registerVideoSampleCallback: CallbacksState['registerVideoSampleCallback'];
@@ -4,10 +4,12 @@ exports.processBox = void 0;
4
4
  const log_1 = require("../../log");
5
5
  const register_track_1 = require("../../register-track");
6
6
  const skip_1 = require("../../skip");
7
+ const elst_1 = require("./elst");
7
8
  const esds_1 = require("./esds/esds");
8
9
  const ftyp_1 = require("./ftyp");
9
10
  const get_children_1 = require("./get-children");
10
11
  const make_track_1 = require("./make-track");
12
+ const get_editlist_1 = require("./mdat/get-editlist");
11
13
  const mdhd_1 = require("./mdhd");
12
14
  const hdlr_1 = require("./meta/hdlr");
13
15
  const ilst_1 = require("./meta/ilst");
@@ -84,6 +86,16 @@ const processBox = async ({ iterator, logLevel, onlyIfMoovAtomExpected, onlyIfMd
84
86
  box: (0, ftyp_1.parseFtyp)({ iterator, size: boxSize, offset: fileOffset }),
85
87
  };
86
88
  }
89
+ if (boxType === 'elst') {
90
+ return {
91
+ type: 'box',
92
+ box: (0, elst_1.parseElst)({
93
+ iterator,
94
+ size: boxSize,
95
+ offset: fileOffset,
96
+ }),
97
+ };
98
+ }
87
99
  if (boxType === 'colr') {
88
100
  return {
89
101
  type: 'box',
@@ -94,9 +106,18 @@ const processBox = async ({ iterator, logLevel, onlyIfMoovAtomExpected, onlyIfMd
94
106
  };
95
107
  }
96
108
  if (boxType === 'mvhd') {
109
+ const mvhdBox = (0, mvhd_1.parseMvhd)({
110
+ iterator,
111
+ offset: fileOffset,
112
+ size: boxSize,
113
+ });
114
+ if (!onlyIfMoovAtomExpected) {
115
+ throw new Error('State is required');
116
+ }
117
+ onlyIfMoovAtomExpected.movieTimeScaleState.setTrackTimescale(mvhdBox.timeScale);
97
118
  return {
98
119
  type: 'box',
99
- box: (0, mvhd_1.parseMvhd)({ iterator, offset: fileOffset, size: boxSize }),
120
+ box: mvhdBox,
100
121
  };
101
122
  }
102
123
  if (boxType === 'tkhd') {
@@ -266,14 +287,19 @@ const processBox = async ({ iterator, logLevel, onlyIfMoovAtomExpected, onlyIfMd
266
287
  throw new Error('State is required');
267
288
  }
268
289
  const { tracks, onAudioTrack, onVideoTrack } = onlyIfMoovAtomExpected;
269
- const box = await (0, trak_1.parseTrak)({
290
+ const trakBox = await (0, trak_1.parseTrak)({
270
291
  size: boxSize,
271
292
  offsetAtStart: fileOffset,
272
293
  iterator,
273
294
  logLevel,
274
295
  contentLength,
275
296
  });
276
- const transformedTrack = (0, make_track_1.makeBaseMediaTrack)(box);
297
+ const movieTimeScale = onlyIfMoovAtomExpected.movieTimeScaleState.getTrackTimescale();
298
+ if (movieTimeScale === null) {
299
+ throw new Error('Movie timescale is not set');
300
+ }
301
+ const editList = (0, get_editlist_1.findTrackStartTimeInSeconds)({ movieTimeScale, trakBox });
302
+ const transformedTrack = (0, make_track_1.makeBaseMediaTrack)(trakBox, editList);
277
303
  if (transformedTrack && transformedTrack.type === 'video') {
278
304
  await (0, register_track_1.registerVideoTrack)({
279
305
  track: transformedTrack,
@@ -294,7 +320,7 @@ const processBox = async ({ iterator, logLevel, onlyIfMoovAtomExpected, onlyIfMd
294
320
  onAudioTrack,
295
321
  });
296
322
  }
297
- return { type: 'box', box };
323
+ return { type: 'box', box: trakBox };
298
324
  }
299
325
  if (boxType === 'stts') {
300
326
  return {
@@ -377,6 +403,7 @@ const processBox = async ({ iterator, logLevel, onlyIfMoovAtomExpected, onlyIfMd
377
403
  boxType === 'wave' ||
378
404
  boxType === 'traf' ||
379
405
  boxType === 'mfra' ||
406
+ boxType === 'edts' ||
380
407
  boxType === 'stsb') {
381
408
  const children = await (0, get_children_1.getIsoBaseMediaChildren)({
382
409
  iterator,
@@ -3,6 +3,7 @@ import type { IsoBaseMediaState } from '../../state/iso-base-media/iso-state';
3
3
  import type { MoofBox } from '../../state/iso-base-media/precomputed-moof';
4
4
  import type { StructureState } from '../../state/structure';
5
5
  import type { IsoBaseMediaBox, RegularBox } from './base-media-box';
6
+ import type { ElstBox } from './elst';
6
7
  import type { FtypBox } from './ftyp';
7
8
  import type { MdhdBox } from './mdhd';
8
9
  import type { TfraBox } from './mfra/tfra';
@@ -49,3 +50,4 @@ export declare const getTrunBoxes: (segment: IsoBaseMediaBox) => TrunBox[];
49
50
  export declare const getTfraBoxesFromMfraBoxChildren: (mfraBoxChildren: IsoBaseMediaBox[]) => TfraBox[];
50
51
  export declare const getTfraBoxes: (structure: IsoBaseMediaBox[]) => TfraBox[];
51
52
  export declare const getTrakBoxByTrackId: (moovBox: MoovBox, trackId: number) => TrakBox | null;
53
+ export declare const getElstBox: (trakBox: TrakBox) => ElstBox | null;