@remotion/media-parser 4.0.311 → 4.0.313

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 (57) hide show
  1. package/dist/containers/aac/get-seeking-byte.js +5 -1
  2. package/dist/containers/flac/get-seeking-byte.d.ts +2 -1
  3. package/dist/containers/flac/get-seeking-byte.js +1 -1
  4. package/dist/containers/iso-base-media/base-media-box.d.ts +3 -2
  5. package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.d.ts +3 -1
  6. package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.js +2 -1
  7. package/dist/containers/iso-base-media/find-keyframe-before-time.d.ts +1 -1
  8. package/dist/containers/iso-base-media/find-keyframe-before-time.js +1 -1
  9. package/dist/containers/iso-base-media/find-track-to-seek.js +2 -0
  10. package/dist/containers/iso-base-media/get-keyframes.js +1 -0
  11. package/dist/containers/iso-base-media/get-sample-positions-from-track.d.ts +3 -1
  12. package/dist/containers/iso-base-media/get-sample-positions-from-track.js +2 -1
  13. package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.js +4 -1
  14. package/dist/containers/iso-base-media/get-seeking-byte.js +3 -1
  15. package/dist/containers/iso-base-media/moov/mvhd.d.ts +30 -0
  16. package/dist/containers/iso-base-media/moov/mvhd.js +65 -0
  17. package/dist/containers/iso-base-media/moov/trex.d.ts +16 -0
  18. package/dist/containers/iso-base-media/moov/trex.js +27 -0
  19. package/dist/containers/iso-base-media/process-box.js +10 -1
  20. package/dist/containers/iso-base-media/tkhd.d.ts +1 -1
  21. package/dist/containers/iso-base-media/traversal.d.ts +4 -1
  22. package/dist/containers/iso-base-media/traversal.js +18 -1
  23. package/dist/containers/m3u/get-seeking-byte.js +2 -0
  24. package/dist/containers/mp3/get-seeking-byte.js +4 -1
  25. package/dist/containers/riff/get-seeking-byte.js +3 -0
  26. package/dist/containers/wav/get-seeking-byte.js +1 -0
  27. package/dist/containers/wav/parse-list.js +4 -3
  28. package/dist/containers/webm/seek/get-seeking-byte.js +21 -6
  29. package/dist/controller/media-parser-controller.d.ts +3 -0
  30. package/dist/controller/media-parser-controller.js +15 -0
  31. package/dist/esm/index.mjs +327 -156
  32. package/dist/esm/server-worker.mjs +17 -0
  33. package/dist/esm/worker-server-entry.mjs +341 -155
  34. package/dist/esm/worker-web-entry.mjs +341 -155
  35. package/dist/esm/worker.mjs +28 -0
  36. package/dist/get-duration.js +1 -0
  37. package/dist/get-seeking-byte.js +13 -2
  38. package/dist/index.cjs +54 -0
  39. package/dist/index.d.ts +3 -2
  40. package/dist/index.js +1 -1
  41. package/dist/internal-parse-media.js +25 -0
  42. package/dist/iterator/buffer-iterator.d.ts +1 -1
  43. package/dist/iterator/buffer-manager.d.ts +1 -1
  44. package/dist/iterator/buffer-manager.js +19 -5
  45. package/dist/parse-media-on-worker-entry.js +17 -0
  46. package/dist/samples-from-moof.d.ts +3 -1
  47. package/dist/samples-from-moof.js +15 -12
  48. package/dist/state/iso-base-media/cached-sample-positions.js +1 -0
  49. package/dist/state/iso-base-media/lazy-mfra-load.js +1 -1
  50. package/dist/version.d.ts +1 -1
  51. package/dist/version.js +1 -1
  52. package/dist/webcodec-sample-types.d.ts +2 -2
  53. package/dist/work-on-seek-request.d.ts +22 -0
  54. package/dist/work-on-seek-request.js +3 -2
  55. package/dist/worker/forward-controller-to-worker.js +18 -0
  56. package/dist/worker/worker-types.d.ts +13 -2
  57. package/package.json +3 -3
@@ -23,7 +23,11 @@ const getSeekingByteForAac = ({ time, seekingHints, }) => {
23
23
  }
24
24
  }
25
25
  if (bestAudioSample) {
26
- return { type: 'do-seek', byte: bestAudioSample.offset };
26
+ return {
27
+ type: 'do-seek',
28
+ byte: bestAudioSample.offset,
29
+ timeInSeconds: bestAudioSample.timeInSeconds,
30
+ };
27
31
  }
28
32
  return { type: 'valid-but-must-wait' };
29
33
  };
@@ -1,5 +1,6 @@
1
+ import type { AudioSampleOffset } from '../../state/audio-sample-map';
1
2
  import type { FlacSeekingHints } from './seeking-hints';
2
3
  export declare const getSeekingByteForFlac: ({ time, seekingHints, }: {
3
4
  time: number;
4
5
  seekingHints: FlacSeekingHints;
5
- }) => number | null;
6
+ }) => AudioSampleOffset | null;
@@ -23,7 +23,7 @@ const getSeekingByteForFlac = ({ time, seekingHints, }) => {
23
23
  }
24
24
  }
25
25
  if (bestAudioSample) {
26
- return bestAudioSample.offset;
26
+ return bestAudioSample;
27
27
  }
28
28
  return null;
29
29
  };
@@ -7,7 +7,8 @@ import type { HdlrBox } from './meta/hdlr';
7
7
  import type { IlstBox } from './meta/ilst';
8
8
  import type { TfraBox } from './mfra/tfra';
9
9
  import type { MoovBox } from './moov/moov';
10
- import type { MvhdBox } from './mvhd';
10
+ import type { MvhdBox } from './moov/mvhd';
11
+ import type { TrexBox } from './moov/trex';
11
12
  import type { Av1CBox } from './stsd/av1c';
12
13
  import type { AvccBox } from './stsd/avcc';
13
14
  import type { ColorParameterBox } from './stsd/colr';
@@ -35,4 +36,4 @@ export interface RegularBox extends BaseBox {
35
36
  offset: number;
36
37
  type: 'regular-box';
37
38
  }
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;
39
+ 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 | TrexBox;
@@ -1,9 +1,11 @@
1
1
  import type { MoofBox } from '../../state/iso-base-media/precomputed-moof';
2
+ import type { TrexBox } from './moov/trex';
2
3
  import type { TkhdBox } from './tkhd';
3
- export declare const collectSamplePositionsFromMoofBoxes: ({ moofBoxes, tkhdBox, isComplete, }: {
4
+ export declare const collectSamplePositionsFromMoofBoxes: ({ moofBoxes, tkhdBox, isComplete, trexBoxes, }: {
4
5
  moofBoxes: MoofBox[];
5
6
  tkhdBox: TkhdBox;
6
7
  isComplete: boolean;
8
+ trexBoxes: TrexBox[];
7
9
  }) => {
8
10
  samplePositions: {
9
11
  isLastFragment: boolean;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.collectSamplePositionsFromMoofBoxes = void 0;
4
4
  const samples_from_moof_1 = require("../../samples-from-moof");
5
- const collectSamplePositionsFromMoofBoxes = ({ moofBoxes, tkhdBox, isComplete, }) => {
5
+ const collectSamplePositionsFromMoofBoxes = ({ moofBoxes, tkhdBox, isComplete, trexBoxes, }) => {
6
6
  const samplePositions = moofBoxes.map((m, index) => {
7
7
  const isLastFragment = index === moofBoxes.length - 1 && isComplete;
8
8
  return {
@@ -10,6 +10,7 @@ const collectSamplePositionsFromMoofBoxes = ({ moofBoxes, tkhdBox, isComplete, }
10
10
  samples: (0, samples_from_moof_1.getSamplesFromMoof)({
11
11
  moofBox: m,
12
12
  trackId: tkhdBox.trackId,
13
+ trexBoxes,
13
14
  }),
14
15
  };
15
16
  });
@@ -8,4 +8,4 @@ export declare const findKeyframeBeforeTime: ({ samplePositions, time, timescale
8
8
  mediaSections: MediaSection[];
9
9
  logLevel: MediaParserLogLevel;
10
10
  startInSeconds: number;
11
- }) => number | null;
11
+ }) => SamplePosition | null;
@@ -28,6 +28,6 @@ const findKeyframeBeforeTime = ({ samplePositions, time, timescale, mediaSection
28
28
  log_1.Log.trace(logLevel, 'Found a sample, but the offset has not yet been marked as a video section yet. Not yet able to seek, but probably once we have started reading the next box.', videoSample);
29
29
  return null;
30
30
  }
31
- return videoSample.offset;
31
+ return videoSample;
32
32
  };
33
33
  exports.findKeyframeBeforeTime = findKeyframeBeforeTime;
@@ -22,6 +22,7 @@ const findAnyTrackWithSamplePositions = (allTracks, struc) => {
22
22
  moofBoxes: (0, traversal_1.getMoofBoxes)(struc.boxes),
23
23
  tfraBoxes: (0, traversal_1.getTfraBoxes)(struc.boxes),
24
24
  }),
25
+ trexBoxes: (0, traversal_1.getTrexBoxes)(moov),
25
26
  });
26
27
  if (samplePositions.length === 0) {
27
28
  continue;
@@ -53,6 +54,7 @@ const findTrackToSeek = (allTracks, structure) => {
53
54
  moofBoxes: (0, traversal_1.getMoofBoxes)(struc.boxes),
54
55
  tfraBoxes: (0, traversal_1.getTfraBoxes)(struc.boxes),
55
56
  }),
57
+ trexBoxes: (0, traversal_1.getTrexBoxes)(moov),
56
58
  });
57
59
  if (samplePositions.length === 0) {
58
60
  return (0, exports.findAnyTrackWithSamplePositions)(allTracks, struc);
@@ -33,6 +33,7 @@ const getKeyframesFromIsoBaseMedia = (state) => {
33
33
  moofBoxes,
34
34
  tfraBoxes,
35
35
  }),
36
+ trexBoxes: (0, traversal_1.getTrexBoxes)(moov),
36
37
  });
37
38
  if (!isComplete) {
38
39
  return [];
@@ -1,10 +1,12 @@
1
1
  import type { SamplePosition } from '../../get-sample-positions';
2
2
  import type { MoofBox } from '../../state/iso-base-media/precomputed-moof';
3
+ import type { TrexBox } from './moov/trex';
3
4
  import type { TrakBox } from './trak/trak';
4
- export declare const getSamplePositionsFromTrack: ({ trakBox, moofBoxes, moofComplete, }: {
5
+ export declare const getSamplePositionsFromTrack: ({ trakBox, moofBoxes, moofComplete, trexBoxes, }: {
5
6
  trakBox: TrakBox;
6
7
  moofBoxes: MoofBox[];
7
8
  moofComplete: boolean;
9
+ trexBoxes: TrexBox[];
8
10
  }) => {
9
11
  samplePositions: SamplePosition[];
10
12
  isComplete: boolean;
@@ -4,7 +4,7 @@ exports.getSamplePositionsFromTrack = void 0;
4
4
  const collect_sample_positions_from_moof_boxes_1 = require("./collect-sample-positions-from-moof-boxes");
5
5
  const collect_sample_positions_from_trak_1 = require("./collect-sample-positions-from-trak");
6
6
  const traversal_1 = require("./traversal");
7
- const getSamplePositionsFromTrack = ({ trakBox, moofBoxes, moofComplete, }) => {
7
+ const getSamplePositionsFromTrack = ({ trakBox, moofBoxes, moofComplete, trexBoxes, }) => {
8
8
  const tkhdBox = (0, traversal_1.getTkhdBox)(trakBox);
9
9
  if (!tkhdBox) {
10
10
  throw new Error('Expected tkhd box in trak box');
@@ -14,6 +14,7 @@ const getSamplePositionsFromTrack = ({ trakBox, moofBoxes, moofComplete, }) => {
14
14
  moofBoxes,
15
15
  tkhdBox,
16
16
  isComplete: moofComplete,
17
+ trexBoxes,
17
18
  });
18
19
  return {
19
20
  samplePositions: samplePositions.map((s) => s.samples).flat(1),
@@ -41,6 +41,7 @@ const getSeekingByteFromFragmentedMp4 = async ({ info, time, logLevel, currentPo
41
41
  moofBoxes: info.moofBoxes,
42
42
  tkhdBox,
43
43
  isComplete,
44
+ trexBoxes: (0, traversal_1.getTrexBoxes)(moov),
44
45
  });
45
46
  log_1.Log.trace(logLevel, 'Fragmented MP4 - Checking if we have seeking info for this time range');
46
47
  for (const positions of samplePositionsArray) {
@@ -59,7 +60,9 @@ const getSeekingByteFromFragmentedMp4 = async ({ info, time, logLevel, currentPo
59
60
  if (kf) {
60
61
  return {
61
62
  type: 'do-seek',
62
- byte: kf,
63
+ byte: kf.offset,
64
+ timeInSeconds: Math.min(kf.decodingTimestamp, kf.timestamp) /
65
+ firstTrack.originalTimescale,
63
66
  };
64
67
  }
65
68
  }
@@ -58,7 +58,9 @@ const getSeekingByteFromIsoBaseMedia = ({ info, time, logLevel, currentPosition,
58
58
  if (keyframe) {
59
59
  return Promise.resolve({
60
60
  type: 'do-seek',
61
- byte: keyframe,
61
+ byte: keyframe.offset,
62
+ timeInSeconds: Math.min(keyframe.decodingTimestamp, keyframe.timestamp) /
63
+ track.originalTimescale,
62
64
  });
63
65
  }
64
66
  return Promise.resolve({
@@ -0,0 +1,30 @@
1
+ import type { BufferIterator } from '../../../iterator/buffer-iterator';
2
+ import type { BaseBox } from '../base-type';
3
+ export type ThreeDMatrix = [
4
+ number,
5
+ number,
6
+ number,
7
+ number,
8
+ number,
9
+ number,
10
+ number,
11
+ number,
12
+ number
13
+ ];
14
+ export interface MvhdBox extends BaseBox {
15
+ durationInUnits: number;
16
+ durationInSeconds: number;
17
+ creationTime: number | null;
18
+ modificationTime: number | null;
19
+ timeScale: number;
20
+ rate: number;
21
+ volume: number;
22
+ matrix: ThreeDMatrix;
23
+ nextTrackId: number;
24
+ type: 'mvhd-box';
25
+ }
26
+ export declare const parseMvhd: ({ iterator, offset, size, }: {
27
+ iterator: BufferIterator;
28
+ offset: number;
29
+ size: number;
30
+ }) => MvhdBox;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseMvhd = void 0;
4
+ const buffer_iterator_1 = require("../../../iterator/buffer-iterator");
5
+ const to_date_1 = require("../to-date");
6
+ const parseMvhd = ({ iterator, offset, size, }) => {
7
+ const version = iterator.getUint8();
8
+ // Flags, we discard them
9
+ iterator.discard(3);
10
+ const creationTime = version === 1 ? iterator.getUint64() : iterator.getUint32();
11
+ const modificationTime = version === 1 ? iterator.getUint64() : iterator.getUint32();
12
+ const timeScale = iterator.getUint32();
13
+ const durationInUnits = version === 1 ? iterator.getUint64() : iterator.getUint32();
14
+ const durationInSeconds = Number(durationInUnits) / timeScale;
15
+ const rateArray = iterator.getSlice(4);
16
+ const rateView = (0, buffer_iterator_1.getArrayBufferIterator)(rateArray, rateArray.length);
17
+ const rate = rateView.getInt8() * 10 +
18
+ rateView.getInt8() +
19
+ rateView.getInt8() * 0.1 +
20
+ rateView.getInt8() * 0.01;
21
+ const volumeArray = iterator.getSlice(2);
22
+ const volumeView = (0, buffer_iterator_1.getArrayBufferIterator)(volumeArray, volumeArray.length);
23
+ const volume = volumeView.getInt8() + volumeView.getInt8() * 0.1;
24
+ // reserved 16bit
25
+ iterator.discard(2);
26
+ // reserved 32bit x2
27
+ iterator.discard(4);
28
+ iterator.discard(4);
29
+ // matrix
30
+ const matrix = [
31
+ iterator.getFixedPointSigned1616Number(),
32
+ iterator.getFixedPointSigned1616Number(),
33
+ iterator.getFixedPointSigned230Number(),
34
+ iterator.getFixedPointSigned1616Number(),
35
+ iterator.getFixedPointSigned1616Number(),
36
+ iterator.getFixedPointSigned230Number(),
37
+ iterator.getFixedPointSigned1616Number(),
38
+ iterator.getFixedPointSigned1616Number(),
39
+ iterator.getFixedPointSigned230Number(),
40
+ ];
41
+ // pre-defined
42
+ iterator.discard(4 * 6);
43
+ // next track id
44
+ const nextTrackId = iterator.getUint32();
45
+ volumeView.destroy();
46
+ const bytesRemaining = size - (iterator.counter.getOffset() - offset);
47
+ if (bytesRemaining !== 0) {
48
+ throw new Error('expected 0 bytes ' + bytesRemaining);
49
+ }
50
+ return {
51
+ creationTime: (0, to_date_1.toUnixTimestamp)(Number(creationTime)),
52
+ modificationTime: (0, to_date_1.toUnixTimestamp)(Number(modificationTime)),
53
+ timeScale,
54
+ durationInUnits: Number(durationInUnits),
55
+ durationInSeconds,
56
+ rate,
57
+ volume,
58
+ matrix: matrix,
59
+ nextTrackId,
60
+ type: 'mvhd-box',
61
+ boxSize: size,
62
+ offset,
63
+ };
64
+ };
65
+ exports.parseMvhd = parseMvhd;
@@ -0,0 +1,16 @@
1
+ import type { BufferIterator } from '../../../iterator/buffer-iterator';
2
+ import type { BaseBox } from '../base-type';
3
+ export interface TrexBox extends BaseBox {
4
+ type: 'trex-box';
5
+ version: number;
6
+ trackId: number;
7
+ defaultSampleDescriptionIndex: number;
8
+ defaultSampleDuration: number;
9
+ defaultSampleSize: number;
10
+ defaultSampleFlags: number;
11
+ }
12
+ export declare const parseTrex: ({ iterator, offset, size, }: {
13
+ iterator: BufferIterator;
14
+ offset: number;
15
+ size: number;
16
+ }) => TrexBox;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseTrex = void 0;
4
+ const parseTrex = ({ iterator, offset, size, }) => {
5
+ const box = iterator.startBox(size - 8);
6
+ const version = iterator.getUint8();
7
+ // Flags, we discard them
8
+ iterator.discard(3);
9
+ const trackId = iterator.getUint32();
10
+ const defaultSampleDescriptionIndex = iterator.getUint32();
11
+ const defaultSampleDuration = iterator.getUint32();
12
+ const defaultSampleSize = iterator.getUint32();
13
+ const defaultSampleFlags = iterator.getUint32();
14
+ box.expectNoMoreBytes();
15
+ return {
16
+ type: 'trex-box',
17
+ boxSize: size,
18
+ offset,
19
+ trackId,
20
+ version,
21
+ defaultSampleDescriptionIndex,
22
+ defaultSampleDuration,
23
+ defaultSampleSize,
24
+ defaultSampleFlags,
25
+ };
26
+ };
27
+ exports.parseTrex = parseTrex;
@@ -15,7 +15,8 @@ const hdlr_1 = require("./meta/hdlr");
15
15
  const ilst_1 = require("./meta/ilst");
16
16
  const tfra_1 = require("./mfra/tfra");
17
17
  const moov_1 = require("./moov/moov");
18
- const mvhd_1 = require("./mvhd");
18
+ const mvhd_1 = require("./moov/mvhd");
19
+ const trex_1 = require("./moov/trex");
19
20
  const av1c_1 = require("./stsd/av1c");
20
21
  const avcc_1 = require("./stsd/avcc");
21
22
  const colr_1 = require("./stsd/colr");
@@ -390,6 +391,12 @@ const processBox = async ({ iterator, logLevel, onlyIfMoovAtomExpected, onlyIfMd
390
391
  }),
391
392
  };
392
393
  }
394
+ if (boxType === 'trex') {
395
+ return {
396
+ type: 'box',
397
+ box: await (0, trex_1.parseTrex)({ iterator, offset: fileOffset, size: boxSize }),
398
+ };
399
+ }
393
400
  if (boxType === 'moof') {
394
401
  await ((_b = onlyIfMoovAtomExpected === null || onlyIfMoovAtomExpected === void 0 ? void 0 : onlyIfMoovAtomExpected.isoState) === null || _b === void 0 ? void 0 : _b.mfra.triggerLoad());
395
402
  }
@@ -404,6 +411,7 @@ const processBox = async ({ iterator, logLevel, onlyIfMoovAtomExpected, onlyIfMd
404
411
  boxType === 'traf' ||
405
412
  boxType === 'mfra' ||
406
413
  boxType === 'edts' ||
414
+ boxType === 'mvex' ||
407
415
  boxType === 'stsb') {
408
416
  const children = await (0, get_children_1.getIsoBaseMediaChildren)({
409
417
  iterator,
@@ -424,6 +432,7 @@ const processBox = async ({ iterator, logLevel, onlyIfMoovAtomExpected, onlyIfMd
424
432
  };
425
433
  }
426
434
  iterator.discard(boxSize - 8);
435
+ log_1.Log.verbose(logLevel, 'Unknown ISO Base Media Box:', boxType);
427
436
  return {
428
437
  type: 'box',
429
438
  box: {
@@ -1,6 +1,6 @@
1
1
  import type { BufferIterator } from '../../iterator/buffer-iterator';
2
2
  import type { BaseBox } from './base-type';
3
- import type { ThreeDMatrix } from './mvhd';
3
+ import type { ThreeDMatrix } from './moov/mvhd';
4
4
  export interface TkhdBox extends BaseBox {
5
5
  type: 'tkhd-box';
6
6
  alternateGroup: number;
@@ -8,7 +8,8 @@ import type { FtypBox } from './ftyp';
8
8
  import type { MdhdBox } from './mdhd';
9
9
  import type { TfraBox } from './mfra/tfra';
10
10
  import type { MoovBox } from './moov/moov';
11
- import type { MvhdBox } from './mvhd';
11
+ import type { MvhdBox } from './moov/mvhd';
12
+ import type { TrexBox } from './moov/trex';
12
13
  import type { CttsBox } from './stsd/ctts';
13
14
  import type { StcoBox } from './stsd/stco';
14
15
  import type { StscBox } from './stsd/stsc';
@@ -47,6 +48,8 @@ export declare const getStssBox: (trakBox: TrakBox) => StssBox | null;
47
48
  export declare const getTfdtBox: (segment: IsoBaseMediaBox) => TfdtBox | null;
48
49
  export declare const getTfhdBox: (segment: IsoBaseMediaBox) => TfhdBox | null;
49
50
  export declare const getTrunBoxes: (segment: IsoBaseMediaBox) => TrunBox[];
51
+ export declare const getMvexBox: (moovAtom: MoovBox) => RegularBox | null;
52
+ export declare const getTrexBoxes: (moovAtom: MoovBox) => TrexBox[];
50
53
  export declare const getTfraBoxesFromMfraBoxChildren: (mfraBoxChildren: IsoBaseMediaBox[]) => TfraBox[];
51
54
  export declare const getTfraBoxes: (structure: IsoBaseMediaBox[]) => TfraBox[];
52
55
  export declare const getTrakBoxByTrackId: (moovBox: MoovBox, trackId: number) => TrakBox | null;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getElstBox = exports.getTrakBoxByTrackId = exports.getTfraBoxes = exports.getTfraBoxesFromMfraBoxChildren = exports.getTrunBoxes = exports.getTfhdBox = exports.getTfdtBox = exports.getStssBox = exports.getStscBox = exports.getStszBox = exports.getCttsBox = exports.getSttsBox = exports.getStcoBox = exports.getVideoDescriptors = exports.getStsdBox = exports.getStblBox = exports.getMdhdBox = exports.getMdiaBox = exports.getTkhdBox = exports.getTraks = exports.getMvhdBox = exports.getMoofBoxes = exports.getMoovBoxFromState = exports.getMoovFromFromIsoStructure = exports.getFtypBox = void 0;
3
+ exports.getElstBox = exports.getTrakBoxByTrackId = exports.getTfraBoxes = exports.getTfraBoxesFromMfraBoxChildren = exports.getTrexBoxes = exports.getMvexBox = exports.getTrunBoxes = exports.getTfhdBox = exports.getTfdtBox = exports.getStssBox = exports.getStscBox = exports.getStszBox = exports.getCttsBox = exports.getSttsBox = exports.getStcoBox = exports.getVideoDescriptors = exports.getStsdBox = exports.getStblBox = exports.getMdhdBox = exports.getMdiaBox = exports.getTkhdBox = exports.getTraks = exports.getMvhdBox = exports.getMoofBoxes = exports.getMoovBoxFromState = exports.getMoovFromFromIsoStructure = exports.getFtypBox = void 0;
4
4
  const precomputed_moof_1 = require("../../state/iso-base-media/precomputed-moof");
5
5
  const getFtypBox = (segments) => {
6
6
  const ftypBox = segments.find((s) => s.type === 'ftyp-box');
@@ -198,6 +198,23 @@ const getTrunBoxes = (segment) => {
198
198
  return trunBoxes;
199
199
  };
200
200
  exports.getTrunBoxes = getTrunBoxes;
201
+ const getMvexBox = (moovAtom) => {
202
+ const mvexBox = moovAtom.children.find((s) => s.type === 'regular-box' && s.boxType === 'mvex');
203
+ if (!mvexBox || mvexBox.type !== 'regular-box') {
204
+ return null;
205
+ }
206
+ return mvexBox;
207
+ };
208
+ exports.getMvexBox = getMvexBox;
209
+ const getTrexBoxes = (moovAtom) => {
210
+ const mvexBox = (0, exports.getMvexBox)(moovAtom);
211
+ if (!mvexBox) {
212
+ return [];
213
+ }
214
+ const trexBoxes = mvexBox.children.filter((c) => c.type === 'trex-box');
215
+ return trexBoxes;
216
+ };
217
+ exports.getTrexBoxes = getTrexBoxes;
201
218
  const getTfraBoxesFromMfraBoxChildren = (mfraBoxChildren) => {
202
219
  const tfraBoxes = mfraBoxChildren.filter((b) => b.type === 'tfra-box');
203
220
  return tfraBoxes;
@@ -27,6 +27,8 @@ const getSeekingByteForM3u8 = ({ time, currentPosition, m3uState, logLevel, }) =
27
27
  return {
28
28
  type: 'do-seek',
29
29
  byte: currentPosition,
30
+ // TODO: This will be imperfect when seeking in playMedia()
31
+ timeInSeconds: time,
30
32
  };
31
33
  };
32
34
  exports.getSeekingByteForM3u8 = getSeekingByteForM3u8;
@@ -41,9 +41,12 @@ const getSeekingByteForMp3 = ({ time, info, }) => {
41
41
  type: 'valid-but-must-wait',
42
42
  };
43
43
  }
44
+ const byte = Math.max(...candidates);
45
+ const timeInSeconds = byte === (bestAudioSample === null || bestAudioSample === void 0 ? void 0 : bestAudioSample.offset) ? bestAudioSample.timeInSeconds : time;
44
46
  return {
45
47
  type: 'do-seek',
46
- byte: Math.max(...candidates),
48
+ byte,
49
+ timeInSeconds,
47
50
  };
48
51
  };
49
52
  exports.getSeekingByteForMp3 = getSeekingByteForMp3;
@@ -22,6 +22,7 @@ const getSeekingByteForRiff = async ({ info, time, riffState, avcState, }) => {
22
22
  return {
23
23
  type: 'do-seek',
24
24
  byte: lastKeyframe.positionInBytes,
25
+ timeInSeconds: Math.min(lastKeyframe.decodingTimeInSeconds, lastKeyframe.presentationTimeInSeconds),
25
26
  };
26
27
  }
27
28
  if (idx1Entries.videoTrackIndex === null) {
@@ -55,6 +56,8 @@ const getSeekingByteForRiff = async ({ info, time, riffState, avcState, }) => {
55
56
  return {
56
57
  type: 'do-seek',
57
58
  byte: bestEntry.offset + info.moviOffset - 4,
59
+ timeInSeconds: bestEntry.sampleCounts[idx1Entries.videoTrackIndex] /
60
+ info.samplesPerSecond,
58
61
  };
59
62
  };
60
63
  exports.getSeekingByteForRiff = getSeekingByteForRiff;
@@ -10,6 +10,7 @@ const getSeekingByteFromWav = ({ info, time, }) => {
10
10
  return Promise.resolve({
11
11
  type: 'do-seek',
12
12
  byte: byteOffset + info.mediaSection.start,
13
+ timeInSeconds: timeRoundedDown,
13
14
  });
14
15
  };
15
16
  exports.getSeekingByteFromWav = getSeekingByteFromWav;
@@ -16,10 +16,11 @@ const parseList = ({ state, }) => {
16
16
  // Padding
17
17
  // https://discord.com/channels/809501355504959528/1308803317480292482/1343979547246333983
18
18
  // Indie_Hacker_Podcast (2).wav
19
- if (remainingBytes() < 4) {
20
- iterator.discard(remainingBytes());
21
- break;
19
+ const byte = iterator.getUint8();
20
+ if (byte === 0) {
21
+ continue;
22
22
  }
23
+ iterator.counter.decrement(1);
23
24
  const key = iterator.getByteString(4, false);
24
25
  const size = iterator.getUint32Le();
25
26
  const value = iterator.getByteString(size, true);
@@ -19,7 +19,6 @@ const findBiggestCueBeforeTime = ({ cues, time, track, }) => {
19
19
  return biggestCueBeforeTime;
20
20
  };
21
21
  const findKeyframeBeforeTime = ({ keyframes, time, }) => {
22
- var _a;
23
22
  let keyframeBeforeTime;
24
23
  for (const keyframe of keyframes) {
25
24
  if (keyframe.decodingTimeInSeconds < time &&
@@ -29,7 +28,7 @@ const findKeyframeBeforeTime = ({ keyframes, time, }) => {
29
28
  keyframeBeforeTime = keyframe;
30
29
  }
31
30
  }
32
- return (_a = keyframeBeforeTime === null || keyframeBeforeTime === void 0 ? void 0 : keyframeBeforeTime.positionInBytes) !== null && _a !== void 0 ? _a : null;
31
+ return keyframeBeforeTime !== null && keyframeBeforeTime !== void 0 ? keyframeBeforeTime : null;
33
32
  };
34
33
  const getByteFromCues = ({ cuesResponse, time, info, logLevel, }) => {
35
34
  if (!cuesResponse) {
@@ -46,10 +45,13 @@ const getByteFromCues = ({ cuesResponse, time, info, logLevel, }) => {
46
45
  if (!biggestCueBeforeTime) {
47
46
  return null;
48
47
  }
49
- return biggestCueBeforeTime.clusterPositionInSegment + segmentOffset;
48
+ return {
49
+ byte: biggestCueBeforeTime.clusterPositionInSegment + segmentOffset,
50
+ timeInSeconds: toSeconds(biggestCueBeforeTime.timeInTimescale, info.track),
51
+ };
50
52
  };
51
53
  const getSeekingByteFromMatroska = async ({ time, webmState, info, logLevel, mediaSection, }) => {
52
- var _a, _b, _c;
54
+ var _a, _b, _c, _d, _e;
53
55
  if (!info.track) {
54
56
  log_1.Log.trace(logLevel, 'No video track found, cannot seek yet');
55
57
  return {
@@ -74,8 +76,8 @@ const getSeekingByteFromMatroska = async ({ time, webmState, info, logLevel, med
74
76
  // Optimization possibility for later:
75
77
  // Don't seek back, if the last seen time is smaller than the time we want to seek to
76
78
  const seekPossibilities = [
77
- byteFromCues,
78
- byteFromObservedKeyframe,
79
+ (_d = byteFromCues === null || byteFromCues === void 0 ? void 0 : byteFromCues.byte) !== null && _d !== void 0 ? _d : null,
80
+ (_e = byteFromObservedKeyframe === null || byteFromObservedKeyframe === void 0 ? void 0 : byteFromObservedKeyframe.positionInBytes) !== null && _e !== void 0 ? _e : null,
79
81
  byteFromFirstMediaSection,
80
82
  ].filter((n) => n !== null);
81
83
  const byteToSeekTo = seekPossibilities.length === 0 ? null : Math.max(...seekPossibilities);
@@ -92,9 +94,22 @@ const getSeekingByteFromMatroska = async ({ time, webmState, info, logLevel, med
92
94
  start: byteToSeekTo,
93
95
  size: 1,
94
96
  });
97
+ const timeInSeconds = (() => {
98
+ if (byteToSeekTo === (byteFromObservedKeyframe === null || byteFromObservedKeyframe === void 0 ? void 0 : byteFromObservedKeyframe.positionInBytes)) {
99
+ return Math.min(byteFromObservedKeyframe.decodingTimeInSeconds, byteFromObservedKeyframe.presentationTimeInSeconds);
100
+ }
101
+ if (byteToSeekTo === (byteFromCues === null || byteFromCues === void 0 ? void 0 : byteFromCues.byte)) {
102
+ return byteFromCues.timeInSeconds;
103
+ }
104
+ if (byteToSeekTo === byteFromFirstMediaSection) {
105
+ return 0;
106
+ }
107
+ throw new Error('Should not happen');
108
+ })();
95
109
  return {
96
110
  type: 'do-seek',
97
111
  byte: byteToSeekTo,
112
+ timeInSeconds,
98
113
  };
99
114
  };
100
115
  exports.getSeekingByteFromMatroska = getSeekingByteFromMatroska;
@@ -1,4 +1,5 @@
1
1
  import type { SeekingHints } from '../seeking-hints';
2
+ import type { SeekResolution } from '../work-on-seek-request';
2
3
  import { MediaParserEmitter } from './emitter';
3
4
  import type { PauseSignal } from './pause-signal';
4
5
  import type { PerformedSeeksSignal } from './performed-seeks-stats';
@@ -8,6 +9,7 @@ export type MediaParserController = {
8
9
  pause: PauseSignal['pause'];
9
10
  resume: PauseSignal['resume'];
10
11
  seek: SeekSignal['seek'];
12
+ simulateSeek: (seekInSeconds: number) => Promise<SeekResolution>;
11
13
  addEventListener: MediaParserEmitter['addEventListener'];
12
14
  removeEventListener: MediaParserEmitter['removeEventListener'];
13
15
  getSeekingHints: () => Promise<SeekingHints | null>;
@@ -21,6 +23,7 @@ export type MediaParserController = {
21
23
  markAsReadyToEmitEvents: () => void;
22
24
  performedSeeksSignal: PerformedSeeksSignal;
23
25
  attachSeekingHintResolution: (callback: () => Promise<SeekingHints | null>) => void;
26
+ attachSimulateSeekResolution: (callback: (seekInSeconds: number) => Promise<SeekResolution>) => void;
24
27
  };
25
28
  };
26
29
  export declare const mediaParserController: () => MediaParserController;
@@ -23,18 +23,31 @@ const mediaParserController = () => {
23
23
  await pauseSignal.waitUntilResume();
24
24
  };
25
25
  let seekingHintResolution = null;
26
+ let simulateSeekResolution = null;
26
27
  const getSeekingHints = () => {
27
28
  if (!seekingHintResolution) {
28
29
  throw new Error('The mediaParserController() was not yet used in a parseMedia() call');
29
30
  }
30
31
  return seekingHintResolution();
31
32
  };
33
+ const simulateSeek = (seekInSeconds) => {
34
+ if (!simulateSeekResolution) {
35
+ throw new Error('The mediaParserController() was not yet used in a parseMedia() call');
36
+ }
37
+ return simulateSeekResolution(seekInSeconds);
38
+ };
32
39
  const attachSeekingHintResolution = (callback) => {
33
40
  if (seekingHintResolution) {
34
41
  throw new Error('The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.');
35
42
  }
36
43
  seekingHintResolution = callback;
37
44
  };
45
+ const attachSimulateSeekResolution = (callback) => {
46
+ if (simulateSeekResolution) {
47
+ throw new Error('The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.');
48
+ }
49
+ simulateSeekResolution = callback;
50
+ };
38
51
  return {
39
52
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
53
  abort: (reason) => {
@@ -42,6 +55,7 @@ const mediaParserController = () => {
42
55
  emitter.dispatchAbort(reason);
43
56
  },
44
57
  seek: seekSignal.seek,
58
+ simulateSeek,
45
59
  pause: pauseSignal.pause,
46
60
  resume: pauseSignal.resume,
47
61
  addEventListener: emitter.addEventListener,
@@ -54,6 +68,7 @@ const mediaParserController = () => {
54
68
  markAsReadyToEmitEvents: emitter.markAsReady,
55
69
  performedSeeksSignal,
56
70
  attachSeekingHintResolution,
71
+ attachSimulateSeekResolution,
57
72
  },
58
73
  };
59
74
  };