@remotion/media-parser 4.0.289 → 4.0.291

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 (167) hide show
  1. package/dist/containers/flac/get-channel-count.d.ts +1 -1
  2. package/dist/containers/iso-base-media/base-media-box.d.ts +0 -1
  3. package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.d.ts +4 -1
  4. package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.js +9 -5
  5. package/dist/containers/iso-base-media/find-keyframe-before-time.js +16 -11
  6. package/dist/containers/iso-base-media/find-track-to-seek.d.ts +14 -0
  7. package/dist/containers/iso-base-media/find-track-to-seek.js +39 -0
  8. package/dist/containers/iso-base-media/get-children.js +2 -2
  9. package/dist/containers/iso-base-media/get-keyframes.js +6 -1
  10. package/dist/containers/iso-base-media/get-mfra-seeking-box.d.ts +3 -1
  11. package/dist/containers/iso-base-media/get-mfra-seeking-box.js +5 -1
  12. package/dist/containers/iso-base-media/get-moov-atom.js +6 -3
  13. package/dist/containers/iso-base-media/get-sample-position-bounds.js +3 -1
  14. package/dist/containers/iso-base-media/get-sample-positions-from-track.js +1 -1
  15. package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.d.ts +14 -0
  16. package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.js +89 -0
  17. package/dist/containers/iso-base-media/get-seeking-byte.d.ts +3 -3
  18. package/dist/containers/iso-base-media/get-seeking-byte.js +32 -96
  19. package/dist/containers/iso-base-media/get-video-codec-from-iso-track.d.ts +1 -1
  20. package/dist/containers/iso-base-media/mdat/calculate-jump-marks.d.ts +6 -0
  21. package/dist/containers/iso-base-media/mdat/calculate-jump-marks.js +131 -0
  22. package/dist/containers/iso-base-media/mdat/mdat.d.ts +2 -2
  23. package/dist/containers/iso-base-media/mdat/mdat.js +18 -2
  24. package/dist/containers/iso-base-media/mfra/find-best-segment-from-tfra.d.ts +3 -3
  25. package/dist/containers/iso-base-media/mfra/find-best-segment-from-tfra.js +2 -2
  26. package/dist/containers/iso-base-media/mfra/get-mfra-atom.d.ts +5 -1
  27. package/dist/containers/iso-base-media/mfra/get-mfra-atom.js +3 -1
  28. package/dist/containers/iso-base-media/mfra/get-mfro-atom.d.ts +5 -1
  29. package/dist/containers/iso-base-media/mfra/get-mfro-atom.js +3 -1
  30. package/dist/containers/iso-base-media/parse-boxes.js +5 -2
  31. package/dist/containers/iso-base-media/process-box.d.ts +16 -5
  32. package/dist/containers/iso-base-media/process-box.js +206 -118
  33. package/dist/containers/iso-base-media/sample-positions.d.ts +25 -0
  34. package/dist/containers/iso-base-media/sample-positions.js +37 -0
  35. package/dist/containers/iso-base-media/seeking-hints.d.ts +1 -1
  36. package/dist/containers/iso-base-media/stsd/samples.js +1 -0
  37. package/dist/containers/iso-base-media/stsd/stsc.d.ts +1 -6
  38. package/dist/containers/iso-base-media/stsd/stsc.js +2 -5
  39. package/dist/containers/iso-base-media/stsd/stss.d.ts +1 -1
  40. package/dist/containers/iso-base-media/stsd/stss.js +2 -2
  41. package/dist/containers/iso-base-media/turn-sample-positions-into-array.d.ts +19 -0
  42. package/dist/containers/iso-base-media/turn-sample-positions-into-array.js +73 -0
  43. package/dist/containers/m3u/after-manifest-fetch.d.ts +5 -1
  44. package/dist/containers/m3u/after-manifest-fetch.js +3 -1
  45. package/dist/containers/m3u/first-sample-in-m3u-chunk.d.ts +13 -0
  46. package/dist/containers/m3u/first-sample-in-m3u-chunk.js +31 -0
  47. package/dist/containers/m3u/get-seeking-byte.d.ts +13 -0
  48. package/dist/containers/m3u/get-seeking-byte.js +32 -0
  49. package/dist/containers/m3u/get-streams.d.ts +1 -0
  50. package/dist/containers/m3u/get-streams.js +1 -0
  51. package/dist/containers/m3u/iterate-over-segment-files.d.ts +5 -3
  52. package/dist/containers/m3u/iterate-over-segment-files.js +11 -1
  53. package/dist/containers/m3u/parse-m3u-media-directive.js +1 -0
  54. package/dist/containers/m3u/parse-m3u.js +8 -0
  55. package/dist/containers/m3u/process-m3u-chunk.d.ts +12 -0
  56. package/dist/containers/m3u/process-m3u-chunk.js +274 -0
  57. package/dist/containers/m3u/run-over-m3u.js +7 -80
  58. package/dist/containers/m3u/sample-sorter.d.ts +1 -0
  59. package/dist/containers/m3u/sample-sorter.js +4 -1
  60. package/dist/containers/m3u/seek/get-chunk-to-seek-to.d.ts +5 -0
  61. package/dist/containers/m3u/seek/get-chunk-to-seek-to.js +14 -0
  62. package/dist/containers/m3u/seeking-hints.d.ts +2 -0
  63. package/dist/containers/m3u/seeking-hints.js +9 -0
  64. package/dist/containers/m3u/select-stream.d.ts +2 -1
  65. package/dist/containers/m3u/select-stream.js +7 -2
  66. package/dist/containers/m3u/types.d.ts +1 -0
  67. package/dist/containers/mp3/get-duration.d.ts +5 -0
  68. package/dist/containers/riff/seek/fetch-idx1.d.ts +3 -1
  69. package/dist/containers/riff/seek/fetch-idx1.js +3 -1
  70. package/dist/containers/transport-stream/handle-aac-packet.d.ts +2 -2
  71. package/dist/containers/transport-stream/handle-avc-packet.d.ts +2 -2
  72. package/dist/containers/transport-stream/process-audio.d.ts +2 -2
  73. package/dist/containers/transport-stream/process-stream-buffers.d.ts +3 -3
  74. package/dist/containers/transport-stream/process-video.d.ts +2 -2
  75. package/dist/containers/wav/get-duration-from-wav.d.ts +0 -1
  76. package/dist/containers/webm/get-sample-from-block.d.ts +12 -2
  77. package/dist/containers/webm/get-sample-from-block.js +40 -9
  78. package/dist/containers/webm/parse-ebml.js +28 -10
  79. package/dist/containers/webm/seek/fetch-web-cues.d.ts +3 -1
  80. package/dist/containers/webm/seek/fetch-web-cues.js +3 -1
  81. package/dist/containers/webm/state-for-processing.d.ts +2 -2
  82. package/dist/controller/media-parser-controller.d.ts +1 -1
  83. package/dist/controller/media-parser-controller.js +6 -2
  84. package/dist/controller/seek-signal.d.ts +1 -5
  85. package/dist/download-and-parse-media.js +1 -1
  86. package/dist/esm/index.mjs +1400 -611
  87. package/dist/esm/node.mjs +23 -3
  88. package/dist/esm/server-worker.mjs +8 -1
  89. package/dist/esm/universal.mjs +168 -15
  90. package/dist/esm/web.mjs +145 -13
  91. package/dist/esm/worker-server-entry.mjs +1467 -635
  92. package/dist/esm/worker-web-entry.mjs +1439 -634
  93. package/dist/esm/worker.mjs +8 -1
  94. package/dist/get-audio-codec.js +3 -0
  95. package/dist/get-duration.js +2 -1
  96. package/dist/get-fps.js +2 -1
  97. package/dist/get-sample-positions-from-mp4.js +10 -5
  98. package/dist/get-sample-positions.js +4 -4
  99. package/dist/get-seeking-byte.d.ts +5 -3
  100. package/dist/get-seeking-byte.js +19 -10
  101. package/dist/get-seeking-hints.d.ts +3 -3
  102. package/dist/get-seeking-hints.js +18 -13
  103. package/dist/get-tracks.d.ts +9 -1
  104. package/dist/get-tracks.js +13 -6
  105. package/dist/index.d.ts +21 -5
  106. package/dist/init-video.js +3 -2
  107. package/dist/internal-parse-media.js +13 -4
  108. package/dist/iterator/buffer-iterator.js +5 -3
  109. package/dist/metadata/metadata-from-iso.js +2 -1
  110. package/dist/options.d.ts +6 -1
  111. package/dist/parse-loop.js +22 -6
  112. package/dist/parse-media-on-worker-entry.js +1 -0
  113. package/dist/parse-media.js +1 -1
  114. package/dist/parse-result.d.ts +2 -2
  115. package/dist/perform-seek.d.ts +3 -1
  116. package/dist/perform-seek.js +3 -1
  117. package/dist/readers/fetch/get-body-and-reader.js +17 -2
  118. package/dist/readers/from-fetch.d.ts +17 -1
  119. package/dist/readers/from-fetch.js +68 -13
  120. package/dist/readers/from-node.js +24 -2
  121. package/dist/readers/from-web-file.js +3 -0
  122. package/dist/readers/reader.d.ts +19 -2
  123. package/dist/readers/universal.js +9 -0
  124. package/dist/readers/web.js +6 -0
  125. package/dist/register-track.d.ts +3 -3
  126. package/dist/seek-backwards.d.ts +3 -1
  127. package/dist/seek-backwards.js +4 -1
  128. package/dist/seek-forwards.d.ts +3 -1
  129. package/dist/seek-forwards.js +3 -1
  130. package/dist/seeking-hints.d.ts +4 -1
  131. package/dist/set-seeking-hints.js +4 -0
  132. package/dist/skip.d.ts +5 -0
  133. package/dist/skip.js +6 -1
  134. package/dist/state/can-skip-tracks.d.ts +1 -0
  135. package/dist/state/can-skip-tracks.js +10 -6
  136. package/dist/state/iso-base-media/cached-sample-positions.d.ts +15 -1
  137. package/dist/state/iso-base-media/cached-sample-positions.js +9 -4
  138. package/dist/state/iso-base-media/iso-state.d.ts +5 -1
  139. package/dist/state/iso-base-media/iso-state.js +2 -1
  140. package/dist/state/iso-base-media/lazy-mfra-load.d.ts +3 -1
  141. package/dist/state/iso-base-media/lazy-mfra-load.js +2 -1
  142. package/dist/state/keyframes.js +1 -0
  143. package/dist/state/m3u-state.d.ts +15 -4
  144. package/dist/state/m3u-state.js +20 -0
  145. package/dist/state/matroska/lazy-cues-fetch.d.ts +3 -1
  146. package/dist/state/matroska/lazy-cues-fetch.js +2 -1
  147. package/dist/state/matroska/webm.d.ts +3 -1
  148. package/dist/state/matroska/webm.js +2 -1
  149. package/dist/state/mp3.d.ts +16 -5
  150. package/dist/state/mp3.js +7 -5
  151. package/dist/state/parser-state.d.ts +31 -15
  152. package/dist/state/parser-state.js +19 -5
  153. package/dist/state/riff/lazy-idx1-fetch.d.ts +5 -3
  154. package/dist/state/riff/lazy-idx1-fetch.js +2 -1
  155. package/dist/state/riff.d.ts +5 -3
  156. package/dist/state/riff.js +2 -1
  157. package/dist/state/sample-callbacks.d.ts +3 -2
  158. package/dist/state/sample-callbacks.js +3 -3
  159. package/dist/version.d.ts +1 -1
  160. package/dist/version.js +1 -1
  161. package/dist/work-on-seek-request.d.ts +6 -3
  162. package/dist/work-on-seek-request.js +13 -13
  163. package/dist/worker/forward-controller-to-worker.js +1 -1
  164. package/dist/worker/serialize-error.js +26 -3
  165. package/dist/worker/worker-types.d.ts +7 -1
  166. package/dist/worker-server.js +2 -2
  167. package/package.json +3 -3
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.turnGroupIntoOld = exports.turnIntoOld = exports.turnSamplePositionsIntoArraySlow = void 0;
4
+ const turnSamplePositionsIntoArraySlow = ({ stcoBox, stszBox, stscBox, stssBox, sttsBox, cttsBox, onlyKeyframes, }) => {
5
+ var _a;
6
+ const sttsDeltas = [];
7
+ for (const distribution of sttsBox.sampleDistribution) {
8
+ for (let i = 0; i < distribution.sampleCount; i++) {
9
+ sttsDeltas.push(distribution.sampleDelta);
10
+ }
11
+ }
12
+ const cttsEntries = [];
13
+ for (const entry of (_a = cttsBox === null || cttsBox === void 0 ? void 0 : cttsBox.entries) !== null && _a !== void 0 ? _a : [
14
+ { sampleCount: sttsDeltas.length, sampleOffset: 0 },
15
+ ]) {
16
+ for (let i = 0; i < entry.sampleCount; i++) {
17
+ cttsEntries.push(entry.sampleOffset);
18
+ }
19
+ }
20
+ let dts = 0;
21
+ const samples = [];
22
+ let samplesPerChunk = 1;
23
+ for (let i = 0; i < stcoBox.entries.length; i++) {
24
+ const hasEntry = stscBox.entries.find((entry) => entry.firstChunk === i + 1);
25
+ if (hasEntry) {
26
+ samplesPerChunk = hasEntry.samplesPerChunk;
27
+ }
28
+ let offsetInThisChunk = 0;
29
+ for (let j = 0; j < samplesPerChunk; j++) {
30
+ const isKeyframe = stssBox
31
+ ? stssBox.sampleNumber.includes(samples.length + 1)
32
+ : true;
33
+ if (onlyKeyframes && !isKeyframe) {
34
+ continue;
35
+ }
36
+ const size = stszBox.countType === 'fixed'
37
+ ? stszBox.sampleSize
38
+ : stszBox.entries[samples.length];
39
+ const delta = sttsDeltas[samples.length];
40
+ const ctsOffset = cttsEntries[samples.length];
41
+ const cts = dts + ctsOffset;
42
+ samples.push({
43
+ offset: Number(stcoBox.entries[i]) + offsetInThisChunk,
44
+ size,
45
+ isKeyframe,
46
+ dts,
47
+ cts,
48
+ duration: delta,
49
+ chunk: i,
50
+ bigEndian: false,
51
+ chunkSize: null,
52
+ });
53
+ dts += delta;
54
+ offsetInThisChunk += size;
55
+ }
56
+ }
57
+ return samples;
58
+ };
59
+ exports.turnSamplePositionsIntoArraySlow = turnSamplePositionsIntoArraySlow;
60
+ const turnIntoOld = (samplePositions) => {
61
+ if (samplePositions.type === 'map') {
62
+ return (0, exports.turnSamplePositionsIntoArraySlow)({
63
+ ...samplePositions.boxes,
64
+ onlyKeyframes: false,
65
+ });
66
+ }
67
+ return samplePositions.boxes;
68
+ };
69
+ exports.turnIntoOld = turnIntoOld;
70
+ const turnGroupIntoOld = (samplePositions) => {
71
+ return samplePositions.map((s) => (0, exports.turnIntoOld)(s)).flat();
72
+ };
73
+ exports.turnGroupIntoOld = turnGroupIntoOld;
@@ -1,9 +1,11 @@
1
1
  import type { LogLevel } from '../../log';
2
2
  import type { ReaderInterface } from '../../readers/reader';
3
+ import type { CanSkipTracksState } from '../../state/can-skip-tracks';
3
4
  import type { M3uState } from '../../state/m3u-state';
5
+ import type { OnAudioTrack } from '../../webcodec-sample-types';
4
6
  import type { SelectM3uAssociatedPlaylistsFn, SelectM3uStreamFn } from './select-stream';
5
7
  import type { M3uStructure } from './types';
6
- export declare const afterManifestFetch: ({ structure, m3uState, src, selectM3uStreamFn, logLevel, selectAssociatedPlaylistsFn, readerInterface, }: {
8
+ export declare const afterManifestFetch: ({ structure, m3uState, src, selectM3uStreamFn, logLevel, selectAssociatedPlaylistsFn, readerInterface, onAudioTrack, canSkipTracks, }: {
7
9
  structure: M3uStructure;
8
10
  m3uState: M3uState;
9
11
  src: string;
@@ -11,4 +13,6 @@ export declare const afterManifestFetch: ({ structure, m3uState, src, selectM3uS
11
13
  selectAssociatedPlaylistsFn: SelectM3uAssociatedPlaylistsFn;
12
14
  logLevel: LogLevel;
13
15
  readerInterface: ReaderInterface;
16
+ onAudioTrack: OnAudioTrack | null;
17
+ canSkipTracks: CanSkipTracksState;
14
18
  }) => Promise<void>;
@@ -5,7 +5,7 @@ const log_1 = require("../../log");
5
5
  const fetch_m3u8_stream_1 = require("./fetch-m3u8-stream");
6
6
  const get_streams_1 = require("./get-streams");
7
7
  const select_stream_1 = require("./select-stream");
8
- const afterManifestFetch = async ({ structure, m3uState, src, selectM3uStreamFn, logLevel, selectAssociatedPlaylistsFn, readerInterface, }) => {
8
+ const afterManifestFetch = async ({ structure, m3uState, src, selectM3uStreamFn, logLevel, selectAssociatedPlaylistsFn, readerInterface, onAudioTrack, canSkipTracks, }) => {
9
9
  const independentSegments = (0, get_streams_1.isIndependentSegments)(structure);
10
10
  if (!independentSegments) {
11
11
  if (!src) {
@@ -29,9 +29,11 @@ const afterManifestFetch = async ({ structure, m3uState, src, selectM3uStreamFn,
29
29
  type: 'selected-stream',
30
30
  stream: selectedPlaylist,
31
31
  });
32
+ const skipAudioTracks = onAudioTrack === null && canSkipTracks.doFieldsNeedTracks() === false;
32
33
  const associatedPlaylists = await (0, select_stream_1.selectAssociatedPlaylists)({
33
34
  playlists: selectedPlaylist.associatedPlaylists,
34
35
  fn: selectAssociatedPlaylistsFn,
36
+ skipAudioTracks,
35
37
  });
36
38
  m3uState.setAssociatedPlaylists(associatedPlaylists);
37
39
  const playlistUrls = [
@@ -0,0 +1,13 @@
1
+ import type { MediaParserController } from '../../controller/media-parser-controller';
2
+ import type { M3uState } from '../../state/m3u-state';
3
+ import type { AudioOrVideoSample } from '../../webcodec-sample-types';
4
+ export declare const considerSeekBasedOnChunk: ({ sample, parentController, childController, callback, m3uState, playlistUrl, subtractChunks, chunkIndex, }: {
5
+ sample: AudioOrVideoSample;
6
+ callback: (sample: AudioOrVideoSample) => void | Promise<void>;
7
+ parentController: MediaParserController;
8
+ childController: MediaParserController;
9
+ playlistUrl: string;
10
+ m3uState: M3uState;
11
+ subtractChunks: number;
12
+ chunkIndex: number | null;
13
+ }) => Promise<void>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.considerSeekBasedOnChunk = void 0;
4
+ const considerSeekBasedOnChunk = async ({ sample, parentController, childController, callback, m3uState, playlistUrl, subtractChunks, chunkIndex, }) => {
5
+ const pendingSeek = m3uState.getSeekToSecondsToProcess(playlistUrl);
6
+ // If there is not even a seek to consider, just call the callback
7
+ if (pendingSeek === null) {
8
+ await callback(sample);
9
+ return;
10
+ }
11
+ const timestamp = Math.min(sample.dts / sample.timescale, sample.cts / sample.timescale);
12
+ // Already too far, now we should go to the previous chunk
13
+ if (timestamp > pendingSeek.targetTime &&
14
+ chunkIndex !== null &&
15
+ chunkIndex > 0) {
16
+ m3uState.setNextSeekShouldSubtractChunks(playlistUrl, subtractChunks + 1);
17
+ parentController.seek({
18
+ type: 'keyframe-before-time',
19
+ timeInSeconds: pendingSeek.targetTime,
20
+ });
21
+ return;
22
+ }
23
+ // We are good, we have not gone too far! Don't emit sample and seek and clear pending seek
24
+ childController.seek({
25
+ type: 'keyframe-before-time',
26
+ timeInSeconds: pendingSeek.targetTime,
27
+ });
28
+ m3uState.setNextSeekShouldSubtractChunks(playlistUrl, 0);
29
+ m3uState.setSeekToSecondsToProcess(playlistUrl, null);
30
+ };
31
+ exports.considerSeekBasedOnChunk = considerSeekBasedOnChunk;
@@ -0,0 +1,13 @@
1
+ import type { LogLevel } from '../../log';
2
+ import type { M3uState } from '../../state/m3u-state';
3
+ import type { SeekResolution } from '../../work-on-seek-request';
4
+ export declare const clearM3uStateInPrepareForSeek: ({ m3uState, logLevel, }: {
5
+ m3uState: M3uState;
6
+ logLevel: LogLevel;
7
+ }) => void;
8
+ export declare const getSeekingByteForM3u8: ({ time, currentPosition, m3uState, logLevel, }: {
9
+ time: number;
10
+ currentPosition: number;
11
+ m3uState: M3uState;
12
+ logLevel: LogLevel;
13
+ }) => SeekResolution;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSeekingByteForM3u8 = exports.clearM3uStateInPrepareForSeek = void 0;
4
+ const log_1 = require("../../log");
5
+ const clearM3uStateInPrepareForSeek = ({ m3uState, logLevel, }) => {
6
+ const selectedPlaylists = m3uState.getSelectedPlaylists();
7
+ for (const playlistUrl of selectedPlaylists) {
8
+ const streamRun = m3uState.getM3uStreamRun(playlistUrl);
9
+ if (streamRun) {
10
+ streamRun.abort();
11
+ }
12
+ log_1.Log.trace(logLevel, 'Clearing M3U stream run for', playlistUrl);
13
+ m3uState.setM3uStreamRun(playlistUrl, null);
14
+ }
15
+ m3uState.clearAllChunksProcessed();
16
+ m3uState.sampleSorter.clearSamples();
17
+ };
18
+ exports.clearM3uStateInPrepareForSeek = clearM3uStateInPrepareForSeek;
19
+ const getSeekingByteForM3u8 = ({ time, currentPosition, m3uState, logLevel, }) => {
20
+ (0, exports.clearM3uStateInPrepareForSeek)({ m3uState, logLevel });
21
+ const selectedPlaylists = m3uState.getSelectedPlaylists();
22
+ for (const playlistUrl of selectedPlaylists) {
23
+ m3uState.setSeekToSecondsToProcess(playlistUrl, {
24
+ targetTime: time,
25
+ });
26
+ }
27
+ return {
28
+ type: 'do-seek',
29
+ byte: currentPosition,
30
+ };
31
+ };
32
+ exports.getSeekingByteForM3u8 = getSeekingByteForM3u8;
@@ -12,6 +12,7 @@ export type M3uAssociatedPlaylist = {
12
12
  channels: number | null;
13
13
  src: string;
14
14
  id: number;
15
+ isAudio: boolean;
15
16
  };
16
17
  export type M3uStream = {
17
18
  src: string;
@@ -35,6 +35,7 @@ const getM3uStreams = ({ structure, originalSrc, readerInterface, }) => {
35
35
  name: audioTrack.name,
36
36
  src: readerInterface.createAdjacentFileSource(audioTrack.uri, originalSrc),
37
37
  id: associatedPlaylists.length,
38
+ isAudio: true,
38
39
  });
39
40
  }
40
41
  }
@@ -1,11 +1,12 @@
1
1
  import type { MediaParserController } from '../../controller/media-parser-controller';
2
+ import type { PrefetchCache } from '../../fetch';
2
3
  import type { AudioTrack, VideoTrack } from '../../get-tracks';
3
4
  import type { LogLevel } from '../../log';
4
5
  import type { ReaderInterface } from '../../readers/reader';
5
- import type { ExistingM3uRun, M3uState } from '../../state/m3u-state';
6
+ import type { M3uRun, M3uState } from '../../state/m3u-state';
6
7
  import type { OnAudioSample, OnVideoSample } from '../../webcodec-sample-types';
7
8
  import type { M3uStructure } from './types';
8
- export declare const iteratorOverSegmentFiles: ({ structure, onVideoTrack, m3uState, onAudioTrack, onDoneWithTracks, playlistUrl, logLevel, parentController, onInitialProgress, readerInterface, }: {
9
+ export declare const iteratorOverSegmentFiles: ({ structure, onVideoTrack, m3uState, onAudioTrack, onDoneWithTracks, playlistUrl, logLevel, parentController, onInitialProgress, readerInterface, prefetchCache, }: {
9
10
  structure: M3uStructure;
10
11
  onVideoTrack: null | ((track: VideoTrack) => Promise<OnVideoSample | null>);
11
12
  onAudioTrack: null | ((track: AudioTrack) => Promise<OnAudioSample | null>);
@@ -14,6 +15,7 @@ export declare const iteratorOverSegmentFiles: ({ structure, onVideoTrack, m3uSt
14
15
  playlistUrl: string;
15
16
  logLevel: LogLevel;
16
17
  parentController: MediaParserController;
17
- onInitialProgress: (run: ExistingM3uRun | null) => void;
18
+ onInitialProgress: (run: M3uRun | null) => void;
18
19
  readerInterface: ReaderInterface;
20
+ prefetchCache: PrefetchCache;
19
21
  }) => Promise<void>;
@@ -7,7 +7,7 @@ const parse_media_1 = require("../../parse-media");
7
7
  const with_resolvers_1 = require("../../with-resolvers");
8
8
  const get_chunks_1 = require("./get-chunks");
9
9
  const get_playlist_1 = require("./get-playlist");
10
- const iteratorOverSegmentFiles = async ({ structure, onVideoTrack, m3uState, onAudioTrack, onDoneWithTracks, playlistUrl, logLevel, parentController, onInitialProgress, readerInterface, }) => {
10
+ const iteratorOverSegmentFiles = async ({ structure, onVideoTrack, m3uState, onAudioTrack, onDoneWithTracks, playlistUrl, logLevel, parentController, onInitialProgress, readerInterface, prefetchCache, }) => {
11
11
  const playlist = (0, get_playlist_1.getPlaylist)(structure, playlistUrl);
12
12
  const chunks = (0, get_chunks_1.getChunks)(playlist);
13
13
  let resolver = onInitialProgress;
@@ -22,6 +22,16 @@ const iteratorOverSegmentFiles = async ({ structure, onVideoTrack, m3uState, onA
22
22
  childController,
23
23
  parentController,
24
24
  });
25
+ const nextChunk = chunks[chunks.indexOf(chunk) + 1];
26
+ if (nextChunk) {
27
+ const nextChunkSource = readerInterface.createAdjacentFileSource(nextChunk.url, playlistUrl);
28
+ readerInterface.preload({
29
+ logLevel,
30
+ range: null,
31
+ src: nextChunkSource,
32
+ prefetchCache,
33
+ });
34
+ }
25
35
  const makeContinuationFn = () => {
26
36
  return {
27
37
  continue() {
@@ -31,6 +31,7 @@ const parseM3uMediaDirective = (str) => {
31
31
  language: map.LANGUAGE || null,
32
32
  name: map.NAME || null,
33
33
  uri: map.URI,
34
+ mediaType: map.TYPE || null,
34
35
  };
35
36
  };
36
37
  exports.parseM3uMediaDirective = parseM3uMediaDirective;
@@ -21,6 +21,12 @@ const parseM3u = async ({ state }) => {
21
21
  if (typeof state.src !== 'string' && !(state.src instanceof URL)) {
22
22
  throw new Error('Expected src to be a string');
23
23
  }
24
+ state.mediaSection.addMediaSection({
25
+ start: 0,
26
+ // We do a pseudo-seek when seeking m3u, which will be the same byte
27
+ // as we are currently in, which in most cases is the end of the file.
28
+ size: state.contentLength + 1,
29
+ });
24
30
  await (0, after_manifest_fetch_1.afterManifestFetch)({
25
31
  structure,
26
32
  m3uState: state.m3u,
@@ -29,6 +35,8 @@ const parseM3u = async ({ state }) => {
29
35
  logLevel: state.logLevel,
30
36
  selectAssociatedPlaylistsFn: state.selectM3uAssociatedPlaylistsFn,
31
37
  readerInterface: state.readerInterface,
38
+ onAudioTrack: state.onAudioTrack,
39
+ canSkipTracks: state.callbacks.canSkipTracksState,
32
40
  });
33
41
  return null;
34
42
  }
@@ -0,0 +1,12 @@
1
+ import type { ParserState } from '../../state/parser-state';
2
+ import type { M3uStructure } from './types';
3
+ export type PendingSeek = {
4
+ pending: number | null;
5
+ };
6
+ export declare const processM3uChunk: ({ playlistUrl, state, structure, audioDone, videoDone, }: {
7
+ playlistUrl: string;
8
+ state: ParserState;
9
+ structure: M3uStructure;
10
+ audioDone: boolean;
11
+ videoDone: boolean;
12
+ }) => Promise<void>;
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processM3uChunk = void 0;
4
+ const media_parser_controller_1 = require("../../controller/media-parser-controller");
5
+ const forward_controller_pause_resume_abort_1 = require("../../forward-controller-pause-resume-abort");
6
+ const parse_media_1 = require("../../parse-media");
7
+ const register_track_1 = require("../../register-track");
8
+ const with_resolvers_1 = require("../../with-resolvers");
9
+ const first_sample_in_m3u_chunk_1 = require("./first-sample-in-m3u-chunk");
10
+ const get_chunks_1 = require("./get-chunks");
11
+ const get_playlist_1 = require("./get-playlist");
12
+ const get_chunk_to_seek_to_1 = require("./seek/get-chunk-to-seek-to");
13
+ const processM3uChunk = ({ playlistUrl, state, structure, audioDone, videoDone, }) => {
14
+ const { promise, reject, resolve } = (0, with_resolvers_1.withResolvers)();
15
+ const onGlobalAudioTrack = audioDone
16
+ ? null
17
+ : async (track) => {
18
+ const existingTracks = state.callbacks.tracks.getTracks();
19
+ let { trackId } = track;
20
+ while (existingTracks.find((t) => t.trackId === trackId)) {
21
+ trackId++;
22
+ }
23
+ const onAudioSample = await (0, register_track_1.registerAudioTrack)({
24
+ container: 'm3u8',
25
+ track: {
26
+ ...track,
27
+ trackId,
28
+ },
29
+ registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
30
+ tracks: state.callbacks.tracks,
31
+ logLevel: state.logLevel,
32
+ onAudioTrack: state.onAudioTrack,
33
+ });
34
+ state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
35
+ if (onAudioSample === null) {
36
+ return null;
37
+ }
38
+ state.m3u.sampleSorter.addAudioStreamToConsider(playlistUrl, onAudioSample);
39
+ return async (sample) => {
40
+ await state.m3u.sampleSorter.addAudioSample(playlistUrl, sample);
41
+ };
42
+ };
43
+ const onGlobalVideoTrack = videoDone
44
+ ? null
45
+ : async (track) => {
46
+ const existingTracks = state.callbacks.tracks.getTracks();
47
+ let { trackId } = track;
48
+ while (existingTracks.find((t) => t.trackId === trackId)) {
49
+ trackId++;
50
+ }
51
+ const onVideoSample = await (0, register_track_1.registerVideoTrack)({
52
+ container: 'm3u8',
53
+ track: {
54
+ ...track,
55
+ trackId,
56
+ },
57
+ logLevel: state.logLevel,
58
+ onVideoTrack: state.onVideoTrack,
59
+ registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
60
+ tracks: state.callbacks.tracks,
61
+ });
62
+ state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
63
+ if (onVideoSample === null) {
64
+ return null;
65
+ }
66
+ state.m3u.sampleSorter.addVideoStreamToConsider(playlistUrl, onVideoSample);
67
+ return async (sample) => {
68
+ await state.m3u.sampleSorter.addVideoSample(playlistUrl, sample);
69
+ };
70
+ };
71
+ // This function will run through the whole playlist step by step, and pause itself
72
+ // On the next run it will continue
73
+ const pausableIterator = async () => {
74
+ const playlist = (0, get_playlist_1.getPlaylist)(structure, playlistUrl);
75
+ const chunks = (0, get_chunks_1.getChunks)(playlist);
76
+ const seekToSecondsToProcess = state.m3u.getSeekToSecondsToProcess(playlistUrl);
77
+ const chunksToSubtract = state.m3u.getNextSeekShouldSubtractChunks(playlistUrl);
78
+ let chunkIndex = null;
79
+ if (seekToSecondsToProcess !== null) {
80
+ chunkIndex = Math.max(0, (0, get_chunk_to_seek_to_1.getChunkToSeekTo)({
81
+ chunks,
82
+ seekToSecondsToProcess: seekToSecondsToProcess.targetTime,
83
+ }) - chunksToSubtract);
84
+ }
85
+ const currentPromise = {
86
+ resolver: (() => undefined),
87
+ rejector: reject,
88
+ };
89
+ const requiresHeaderToBeFetched = chunks[0].isHeader;
90
+ for (const chunk of chunks) {
91
+ const mp4HeaderSegment = state.m3u.getMp4HeaderSegment(playlistUrl);
92
+ if (requiresHeaderToBeFetched && mp4HeaderSegment && chunk.isHeader) {
93
+ continue;
94
+ }
95
+ if (chunkIndex !== null &&
96
+ chunks.indexOf(chunk) < chunkIndex &&
97
+ !chunk.isHeader) {
98
+ continue;
99
+ }
100
+ currentPromise.resolver = (newRun) => {
101
+ state.m3u.setM3uStreamRun(playlistUrl, newRun);
102
+ resolve();
103
+ };
104
+ currentPromise.rejector = reject;
105
+ const childController = (0, media_parser_controller_1.mediaParserController)();
106
+ const forwarded = (0, forward_controller_pause_resume_abort_1.forwardMediaParserControllerPauseResume)({
107
+ childController,
108
+ parentController: state.controller,
109
+ });
110
+ const nextChunk = chunks[chunks.indexOf(chunk) + 1];
111
+ if (nextChunk) {
112
+ const nextChunkSource = state.readerInterface.createAdjacentFileSource(nextChunk.url, playlistUrl);
113
+ state.readerInterface.preload({
114
+ logLevel: state.logLevel,
115
+ range: null,
116
+ src: nextChunkSource,
117
+ prefetchCache: state.prefetchCache,
118
+ });
119
+ }
120
+ const makeContinuationFn = () => {
121
+ return {
122
+ continue() {
123
+ const resolver = (0, with_resolvers_1.withResolvers)();
124
+ currentPromise.resolver = resolver.resolve;
125
+ currentPromise.rejector = resolver.reject;
126
+ childController.resume();
127
+ return resolver.promise;
128
+ },
129
+ abort() {
130
+ childController.abort();
131
+ },
132
+ };
133
+ };
134
+ const isLastChunk = chunk === chunks[chunks.length - 1];
135
+ await childController._internals.checkForAbortAndPause();
136
+ const src = state.readerInterface.createAdjacentFileSource(chunk.url, playlistUrl);
137
+ try {
138
+ const data = await (0, parse_media_1.parseMedia)({
139
+ src,
140
+ acknowledgeRemotionLicense: true,
141
+ logLevel: state.logLevel,
142
+ controller: childController,
143
+ progressIntervalInMs: 0,
144
+ onParseProgress: () => {
145
+ childController.pause();
146
+ currentPromise.resolver(makeContinuationFn());
147
+ },
148
+ fields: chunk.isHeader ? { structure: true } : undefined,
149
+ onTracks: () => {
150
+ if (!state.m3u.hasEmittedDoneWithTracks(playlistUrl)) {
151
+ state.m3u.setHasEmittedDoneWithTracks(playlistUrl);
152
+ const allDone = state.m3u.setTracksDone(playlistUrl);
153
+ if (allDone) {
154
+ state.callbacks.tracks.setIsDone(state.logLevel);
155
+ }
156
+ return null;
157
+ }
158
+ },
159
+ onAudioTrack: onGlobalAudioTrack === null
160
+ ? null
161
+ : async ({ track }) => {
162
+ const callbackOrFalse = state.m3u.hasEmittedAudioTrack(playlistUrl);
163
+ if (callbackOrFalse === false) {
164
+ const callback = await onGlobalAudioTrack(track);
165
+ if (!callback) {
166
+ state.m3u.setHasEmittedAudioTrack(playlistUrl, null);
167
+ return null;
168
+ }
169
+ state.m3u.setHasEmittedAudioTrack(playlistUrl, callback);
170
+ return async (sample) => {
171
+ await (0, first_sample_in_m3u_chunk_1.considerSeekBasedOnChunk)({
172
+ sample,
173
+ callback,
174
+ parentController: state.controller,
175
+ childController,
176
+ m3uState: state.m3u,
177
+ playlistUrl,
178
+ subtractChunks: chunksToSubtract,
179
+ chunkIndex,
180
+ });
181
+ };
182
+ }
183
+ if (callbackOrFalse === null) {
184
+ return null;
185
+ }
186
+ return async (sample) => {
187
+ await (0, first_sample_in_m3u_chunk_1.considerSeekBasedOnChunk)({
188
+ sample,
189
+ m3uState: state.m3u,
190
+ playlistUrl,
191
+ callback: callbackOrFalse,
192
+ parentController: state.controller,
193
+ childController,
194
+ subtractChunks: chunksToSubtract,
195
+ chunkIndex,
196
+ });
197
+ };
198
+ },
199
+ onVideoTrack: onGlobalVideoTrack === null
200
+ ? null
201
+ : async ({ track }) => {
202
+ const callbackOrFalse = state.m3u.hasEmittedVideoTrack(playlistUrl);
203
+ if (callbackOrFalse === false) {
204
+ const callback = await onGlobalVideoTrack({
205
+ ...track,
206
+ m3uStreamFormat: chunk.isHeader || mp4HeaderSegment ? 'mp4' : 'ts',
207
+ });
208
+ if (!callback) {
209
+ state.m3u.setHasEmittedVideoTrack(playlistUrl, null);
210
+ return null;
211
+ }
212
+ state.m3u.setHasEmittedVideoTrack(playlistUrl, callback);
213
+ return async (sample) => {
214
+ await (0, first_sample_in_m3u_chunk_1.considerSeekBasedOnChunk)({
215
+ sample,
216
+ m3uState: state.m3u,
217
+ playlistUrl,
218
+ callback,
219
+ parentController: state.controller,
220
+ childController,
221
+ subtractChunks: chunksToSubtract,
222
+ chunkIndex,
223
+ });
224
+ };
225
+ }
226
+ if (callbackOrFalse === null) {
227
+ return null;
228
+ }
229
+ return async (sample) => {
230
+ await (0, first_sample_in_m3u_chunk_1.considerSeekBasedOnChunk)({
231
+ sample,
232
+ m3uState: state.m3u,
233
+ playlistUrl,
234
+ callback: callbackOrFalse,
235
+ parentController: state.controller,
236
+ childController,
237
+ subtractChunks: chunksToSubtract,
238
+ chunkIndex,
239
+ });
240
+ };
241
+ },
242
+ reader: state.readerInterface,
243
+ makeSamplesStartAtZero: false,
244
+ m3uPlaylistContext: {
245
+ mp4HeaderSegment,
246
+ isLastChunkInPlaylist: isLastChunk,
247
+ },
248
+ });
249
+ if (chunk.isHeader) {
250
+ if (data.structure.type !== 'iso-base-media') {
251
+ throw new Error('Expected an mp4 file');
252
+ }
253
+ state.m3u.setMp4HeaderSegment(playlistUrl, data.structure);
254
+ }
255
+ }
256
+ catch (e) {
257
+ currentPromise.rejector(e);
258
+ throw e;
259
+ }
260
+ forwarded.cleanup();
261
+ if (!isLastChunk) {
262
+ childController.pause();
263
+ currentPromise.resolver(makeContinuationFn());
264
+ }
265
+ }
266
+ currentPromise.resolver(null);
267
+ };
268
+ const run = pausableIterator();
269
+ run.catch((err) => {
270
+ reject(err);
271
+ });
272
+ return promise;
273
+ };
274
+ exports.processM3uChunk = processM3uChunk;