@remotion/media-parser 4.0.265 → 4.0.266

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 (137) hide show
  1. package/dist/buffer-iterator.d.ts +1 -0
  2. package/dist/buffer-iterator.js +17 -0
  3. package/dist/containers/aac/parse-aac.js +1 -1
  4. package/dist/containers/avc/create-sps-pps-data.js +15 -1
  5. package/dist/containers/avc/interpret-sps.js +8 -2
  6. package/dist/containers/avc/parse-avc.js +23 -24
  7. package/dist/containers/flac/get-channel-count.d.ts +1 -1
  8. package/dist/containers/flac/m3u/after-manifest-fetch.d.ts +14 -0
  9. package/dist/containers/flac/m3u/after-manifest-fetch.js +53 -0
  10. package/dist/containers/flac/m3u/fetch-m3u8-stream.d.ts +3 -0
  11. package/dist/containers/flac/m3u/fetch-m3u8-stream.js +15 -0
  12. package/dist/containers/flac/m3u/get-chunks.d.ts +6 -0
  13. package/dist/containers/flac/m3u/get-chunks.js +20 -0
  14. package/dist/containers/flac/m3u/get-duration-from-m3u.d.ts +2 -0
  15. package/dist/containers/flac/m3u/get-duration-from-m3u.js +9 -0
  16. package/dist/containers/flac/m3u/get-playlist.d.ts +3 -0
  17. package/dist/containers/flac/m3u/get-playlist.js +19 -0
  18. package/dist/containers/flac/m3u/get-streams.d.ts +13 -0
  19. package/dist/containers/flac/m3u/get-streams.js +41 -0
  20. package/dist/containers/flac/m3u/parse-directive.d.ts +2 -0
  21. package/dist/containers/flac/m3u/parse-directive.js +64 -0
  22. package/dist/containers/flac/m3u/parse-m3u-manifest.d.ts +8 -0
  23. package/dist/containers/flac/m3u/parse-m3u-manifest.js +18 -0
  24. package/dist/containers/flac/m3u/parse-m3u.d.ts +4 -0
  25. package/dist/containers/flac/m3u/parse-m3u.js +35 -0
  26. package/dist/containers/flac/m3u/parse-m3u8-text.d.ts +2 -0
  27. package/dist/containers/flac/m3u/parse-m3u8-text.js +23 -0
  28. package/dist/containers/flac/m3u/parse-stream-inf.d.ts +3 -0
  29. package/dist/containers/flac/m3u/parse-stream-inf.js +61 -0
  30. package/dist/containers/flac/m3u/return-packets.d.ts +14 -0
  31. package/dist/containers/flac/m3u/return-packets.js +63 -0
  32. package/dist/containers/flac/m3u/select-stream.d.ts +10 -0
  33. package/dist/containers/flac/m3u/select-stream.js +15 -0
  34. package/dist/containers/flac/m3u/types.d.ts +48 -0
  35. package/dist/containers/flac/m3u/types.js +2 -0
  36. package/dist/containers/flac/parse-streaminfo.js +1 -1
  37. package/dist/containers/iso-base-media/get-moov-atom.js +3 -2
  38. package/dist/containers/iso-base-media/process-box.js +9 -2
  39. package/dist/containers/iso-base-media/trun.js +1 -1
  40. package/dist/containers/m3u/after-manifest-fetch.d.ts +14 -0
  41. package/dist/containers/m3u/after-manifest-fetch.js +67 -0
  42. package/dist/containers/m3u/fetch-m3u8-stream.d.ts +3 -0
  43. package/dist/containers/m3u/fetch-m3u8-stream.js +18 -0
  44. package/dist/containers/m3u/get-chunks.d.ts +6 -0
  45. package/dist/containers/m3u/get-chunks.js +20 -0
  46. package/dist/containers/m3u/get-duration-from-m3u.d.ts +2 -0
  47. package/dist/containers/m3u/get-duration-from-m3u.js +9 -0
  48. package/dist/containers/m3u/get-playlist.d.ts +3 -0
  49. package/dist/containers/m3u/get-playlist.js +27 -0
  50. package/dist/containers/m3u/get-streams.d.ts +14 -0
  51. package/dist/containers/m3u/get-streams.js +60 -0
  52. package/dist/containers/m3u/parse-directive.d.ts +2 -0
  53. package/dist/containers/m3u/parse-directive.js +64 -0
  54. package/dist/containers/m3u/parse-m3u-manifest.d.ts +8 -0
  55. package/dist/containers/m3u/parse-m3u-manifest.js +18 -0
  56. package/dist/containers/m3u/parse-m3u.d.ts +4 -0
  57. package/dist/containers/m3u/parse-m3u.js +35 -0
  58. package/dist/containers/m3u/parse-m3u8-text.d.ts +2 -0
  59. package/dist/containers/m3u/parse-m3u8-text.js +23 -0
  60. package/dist/containers/m3u/parse-stream-inf.d.ts +3 -0
  61. package/dist/containers/m3u/parse-stream-inf.js +61 -0
  62. package/dist/containers/m3u/return-packets.d.ts +16 -0
  63. package/dist/containers/m3u/return-packets.js +71 -0
  64. package/dist/containers/m3u/select-stream.d.ts +10 -0
  65. package/dist/containers/m3u/select-stream.js +19 -0
  66. package/dist/containers/m3u/types.d.ts +48 -0
  67. package/dist/containers/m3u/types.js +2 -0
  68. package/dist/containers/mp3/parse-mpeg-header.js +1 -1
  69. package/dist/containers/riff/expect-riff-box.js +1 -1
  70. package/dist/containers/transport-stream/boxes.d.ts +4 -1
  71. package/dist/containers/transport-stream/find-separator.d.ts +1 -2
  72. package/dist/containers/transport-stream/find-separator.js +7 -13
  73. package/dist/containers/transport-stream/handle-aac-packet.js +1 -1
  74. package/dist/containers/transport-stream/handle-avc-packet.js +1 -1
  75. package/dist/containers/transport-stream/parse-packet.js +7 -1
  76. package/dist/containers/transport-stream/parse-pat.d.ts +2 -1
  77. package/dist/containers/transport-stream/parse-pat.js +16 -1
  78. package/dist/containers/transport-stream/parse-stream-packet.js +86 -74
  79. package/dist/containers/wav/parse-fmt.js +1 -1
  80. package/dist/containers/webm/parse-ebml.js +9 -2
  81. package/dist/does-need-contentlength-contentrange.d.ts +2 -0
  82. package/dist/does-need-contentlength-contentrange.js +10 -0
  83. package/dist/download-and-parse-media.js +32 -29
  84. package/dist/emit-available-info.js +13 -1
  85. package/dist/emitter.d.ts +4 -0
  86. package/dist/emitter.js +4 -0
  87. package/dist/esm/from-fetch.mjs +65 -38
  88. package/dist/esm/from-node.mjs +2 -8
  89. package/dist/esm/from-web-file.mjs +2 -7
  90. package/dist/esm/index.mjs +1029 -289
  91. package/dist/file-types/detect-file-type.d.ts +5 -1
  92. package/dist/file-types/detect-file-type.js +5 -1
  93. package/dist/file-types/index.js +3 -0
  94. package/dist/forward-controller.d.ts +7 -0
  95. package/dist/forward-controller.js +25 -0
  96. package/dist/get-container.js +3 -0
  97. package/dist/get-duration.js +35 -2
  98. package/dist/get-fields-from-callbacks.js +1 -0
  99. package/dist/get-fps.js +7 -0
  100. package/dist/get-tracks.d.ts +2 -0
  101. package/dist/get-tracks.js +29 -4
  102. package/dist/has-all-info.js +4 -0
  103. package/dist/index.d.ts +46 -9
  104. package/dist/index.js +3 -1
  105. package/dist/init-video.js +8 -0
  106. package/dist/internal-parse-media.js +11 -4
  107. package/dist/is-audio-structure.js +3 -0
  108. package/dist/media-parser-controller.js +3 -1
  109. package/dist/metadata/get-metadata.js +26 -3
  110. package/dist/options.d.ts +9 -1
  111. package/dist/parse-media.js +11 -8
  112. package/dist/parse-result.d.ts +2 -1
  113. package/dist/readers/fetch/get-body-and-reader.d.ts +8 -0
  114. package/dist/readers/fetch/get-body-and-reader.js +41 -0
  115. package/dist/readers/fetch/resolve-url.d.ts +1 -0
  116. package/dist/readers/fetch/resolve-url.js +15 -0
  117. package/dist/readers/from-fetch.js +19 -40
  118. package/dist/readers/from-node.js +1 -7
  119. package/dist/readers/from-uintarray.d.ts +2 -0
  120. package/dist/readers/from-uintarray.js +27 -0
  121. package/dist/readers/from-web-file.js +1 -6
  122. package/dist/readers/reader.d.ts +1 -2
  123. package/dist/register-track.d.ts +8 -3
  124. package/dist/register-track.js +30 -17
  125. package/dist/run-parse-iteration.js +6 -1
  126. package/dist/state/can-skip-tracks.js +2 -1
  127. package/dist/state/emitted-fields.js +1 -0
  128. package/dist/state/m3u-state.d.ts +29 -0
  129. package/dist/state/m3u-state.js +48 -0
  130. package/dist/state/need-samples-for-fields.js +1 -0
  131. package/dist/state/parser-state.d.ts +36 -1
  132. package/dist/state/parser-state.js +4 -1
  133. package/dist/state/structure.d.ts +1 -0
  134. package/dist/state/structure.js +7 -0
  135. package/dist/version.d.ts +1 -1
  136. package/dist/version.js +1 -1
  137. package/package.json +3 -3
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseMedia = void 0;
4
+ const select_stream_1 = require("./containers/m3u/select-stream");
4
5
  const internal_parse_media_1 = require("./internal-parse-media");
5
6
  const from_fetch_1 = require("./readers/from-fetch");
6
7
  const parseMedia = (options) => {
7
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10;
8
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12;
8
9
  return (0, internal_parse_media_1.internalParseMedia)({
9
10
  fields: (_a = options.fields) !== null && _a !== void 0 ? _a : null,
10
11
  logLevel: (_b = options.logLevel) !== null && _b !== void 0 ? _b : 'info',
@@ -34,13 +35,15 @@ const parseMedia = (options) => {
34
35
  onSlowNumberOfFrames: (_1 = options.onSlowNumberOfFrames) !== null && _1 !== void 0 ? _1 : null,
35
36
  onSlowVideoBitrate: (_2 = options.onSlowVideoBitrate) !== null && _2 !== void 0 ? _2 : null,
36
37
  onStructure: (_3 = options.onStructure) !== null && _3 !== void 0 ? _3 : null,
37
- onTracks: (_4 = options.onTracks) !== null && _4 !== void 0 ? _4 : null,
38
- onUnrotatedDimensions: (_5 = options.onUnrotatedDimensions) !== null && _5 !== void 0 ? _5 : null,
39
- onVideoCodec: (_6 = options.onVideoCodec) !== null && _6 !== void 0 ? _6 : null,
40
- onVideoTrack: (_7 = options.onVideoTrack) !== null && _7 !== void 0 ? _7 : null,
41
- progressIntervalInMs: (_8 = options.progressIntervalInMs) !== null && _8 !== void 0 ? _8 : null,
42
- reader: (_9 = options.reader) !== null && _9 !== void 0 ? _9 : from_fetch_1.fetchReader,
43
- controller: (_10 = options.controller) !== null && _10 !== void 0 ? _10 : undefined,
38
+ onM3uStreams: (_4 = options.onM3uStreams) !== null && _4 !== void 0 ? _4 : null,
39
+ onTracks: (_5 = options.onTracks) !== null && _5 !== void 0 ? _5 : null,
40
+ onUnrotatedDimensions: (_6 = options.onUnrotatedDimensions) !== null && _6 !== void 0 ? _6 : null,
41
+ onVideoCodec: (_7 = options.onVideoCodec) !== null && _7 !== void 0 ? _7 : null,
42
+ onVideoTrack: (_8 = options.onVideoTrack) !== null && _8 !== void 0 ? _8 : null,
43
+ progressIntervalInMs: (_9 = options.progressIntervalInMs) !== null && _9 !== void 0 ? _9 : null,
44
+ reader: (_10 = options.reader) !== null && _10 !== void 0 ? _10 : from_fetch_1.fetchReader,
45
+ controller: (_11 = options.controller) !== null && _11 !== void 0 ? _11 : undefined,
46
+ selectM3uStream: (_12 = options.selectM3uStream) !== null && _12 !== void 0 ? _12 : select_stream_1.defaultSelectM3uStreamFn,
44
47
  src: options.src,
45
48
  mode: 'query',
46
49
  onDiscardedData: null,
@@ -1,6 +1,7 @@
1
1
  import type { AacStructure } from './containers/aac/types';
2
2
  import type { FlacStructure } from './containers/flac/types';
3
3
  import type { IsoBaseMediaBox } from './containers/iso-base-media/base-media-box';
4
+ import type { M3uStructure } from './containers/m3u/types';
4
5
  import type { RiffBox, RiffStructure } from './containers/riff/riff-box';
5
6
  import type { TransportStreamBox } from './containers/transport-stream/boxes';
6
7
  import type { WavStructure } from './containers/wav/types';
@@ -33,6 +34,6 @@ export type Mp3Structure = {
33
34
  type: 'mp3';
34
35
  boxes: Mp3Box[];
35
36
  };
36
- export type Structure = IsoBaseMediaStructure | RiffStructure | MatroskaStructure | TransportStreamStructure | Mp3Structure | AacStructure | WavStructure | FlacStructure;
37
+ export type Structure = IsoBaseMediaStructure | RiffStructure | MatroskaStructure | TransportStreamStructure | Mp3Structure | AacStructure | WavStructure | M3uStructure | FlacStructure;
37
38
  export type ParseResult = Skip | null;
38
39
  export {};
@@ -0,0 +1,8 @@
1
+ import type { Reader } from '../reader';
2
+ type ReturnType = {
3
+ reader: Reader;
4
+ contentLength: number | null;
5
+ needsContentRange: boolean;
6
+ };
7
+ export declare const getLengthAndReader: (endsWithM3u8: boolean, res: Response, ownController: AbortController) => Promise<ReturnType>;
8
+ export {};
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getLengthAndReader = void 0;
4
+ const getLengthAndReader = async (endsWithM3u8, res, ownController) => {
5
+ if (endsWithM3u8) {
6
+ const text = await res.text();
7
+ const stream = new ReadableStream({
8
+ start(controller) {
9
+ controller.enqueue(new TextEncoder().encode(text));
10
+ controller.close();
11
+ },
12
+ });
13
+ return {
14
+ contentLength: text.length,
15
+ reader: {
16
+ reader: stream.getReader(),
17
+ abort() {
18
+ ownController.abort();
19
+ },
20
+ },
21
+ needsContentRange: false,
22
+ };
23
+ }
24
+ const length = res.headers.get('content-length');
25
+ const contentLength = length === null ? null : parseInt(length, 10);
26
+ if (!res.body) {
27
+ throw new Error('No body');
28
+ }
29
+ const reader = res.body.getReader();
30
+ return {
31
+ reader: {
32
+ reader,
33
+ abort: () => {
34
+ ownController.abort();
35
+ },
36
+ },
37
+ contentLength,
38
+ needsContentRange: true,
39
+ };
40
+ };
41
+ exports.getLengthAndReader = getLengthAndReader;
@@ -0,0 +1 @@
1
+ export declare const resolveUrl: (src: string) => string | URL;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveUrl = void 0;
4
+ const resolveUrl = (src) => {
5
+ try {
6
+ const resolvedUrl = typeof window !== 'undefined' && typeof window.location !== 'undefined'
7
+ ? new URL(src, window.location.origin)
8
+ : new URL(src);
9
+ return resolvedUrl;
10
+ }
11
+ catch (_a) {
12
+ return src;
13
+ }
14
+ };
15
+ exports.resolveUrl = resolveUrl;
@@ -5,6 +5,8 @@ exports.parseContentRange = parseContentRange;
5
5
  /* eslint-disable eqeqeq */
6
6
  /* eslint-disable no-eq-null */
7
7
  const errors_1 = require("../errors");
8
+ const get_body_and_reader_1 = require("./fetch/get-body-and-reader");
9
+ const resolve_url_1 = require("./fetch/resolve-url");
8
10
  /**
9
11
  * Parse Content-Range header.
10
12
  * From: https://github.com/gregberge/content-range/blob/main/src/index.ts
@@ -50,14 +52,12 @@ exports.fetchReader = {
50
52
  if (typeof src !== 'string') {
51
53
  throw new Error('src must be a string when using `fetchReader`');
52
54
  }
53
- const resolvedUrl = typeof window !== 'undefined' && typeof window.location !== 'undefined'
54
- ? new URL(src, window.location.origin).toString()
55
- : src;
56
- if (!resolvedUrl.startsWith('https://') &&
57
- !resolvedUrl.startsWith('blob:') &&
58
- !resolvedUrl.startsWith('http://')) {
59
- return Promise.reject(new Error(resolvedUrl +
60
- ' is not a URL - needs to start with http:// or https:// or blob:. If you want to read a local file, pass `reader: nodeReader` to parseMedia().'));
55
+ const resolvedUrl = (0, resolve_url_1.resolveUrl)(src);
56
+ const resolvedUrlString = resolvedUrl.toString();
57
+ if (!resolvedUrlString.startsWith('https://') &&
58
+ !resolvedUrlString.startsWith('blob:') &&
59
+ !resolvedUrlString.startsWith('http://')) {
60
+ return Promise.reject(new Error(`${resolvedUrlString} is not a URL - needs to start with http:// or https:// or blob:. If you want to read a local file, pass \`reader: nodeReader\` to parseMedia().`));
61
61
  }
62
62
  const ownController = new AbortController();
63
63
  const cache = typeof navigator !== 'undefined' &&
@@ -66,14 +66,18 @@ exports.fetchReader = {
66
66
  : // Disable Next.js caching
67
67
  'no-store';
68
68
  const actualRange = range === null ? 0 : range;
69
- const res = await fetch(resolvedUrl, {
70
- headers: typeof actualRange === 'number'
69
+ const endsWithM3u8 = (typeof resolvedUrl === 'string' ? resolvedUrl : resolvedUrl.pathname).endsWith('.m3u8');
70
+ const headers = actualRange === 0 && endsWithM3u8
71
+ ? {}
72
+ : typeof actualRange === 'number'
71
73
  ? {
72
74
  Range: `bytes=${actualRange}-`,
73
75
  }
74
76
  : {
75
77
  Range: `bytes=${`${actualRange[0]}-${actualRange[1]}`}`,
76
- },
78
+ };
79
+ const res = await fetch(resolvedUrl, {
80
+ headers,
77
81
  signal: ownController.signal,
78
82
  cache,
79
83
  });
@@ -89,49 +93,24 @@ exports.fetchReader = {
89
93
  res.status.toString().startsWith('5')) {
90
94
  throw new Error(`Server returned status code ${res.status} for ${src} and range ${actualRange}`);
91
95
  }
92
- if (!res.body) {
93
- throw new Error('No body');
94
- }
95
- const length = res.headers.get('content-length');
96
- const contentLength = length === null ? null : parseInt(length, 10);
97
96
  const contentDisposition = res.headers.get('content-disposition');
98
97
  const name = (_a = contentDisposition === null || contentDisposition === void 0 ? void 0 : contentDisposition.match(/filename="([^"]+)"/)) === null || _a === void 0 ? void 0 : _a[1];
99
98
  const fallbackName = src.split('/').pop();
100
- const reader = res.body.getReader();
99
+ const { contentLength, needsContentRange, reader } = await (0, get_body_and_reader_1.getLengthAndReader)(endsWithM3u8, res, ownController);
101
100
  if (controller) {
102
101
  controller._internals.signal.addEventListener('abort', () => {
103
- reader.cancel().catch(() => {
102
+ reader.reader.cancel().catch(() => {
104
103
  // Prevent unhandled rejection in Firefox
105
104
  });
106
105
  }, { once: true });
107
106
  }
108
107
  return {
109
- reader: {
110
- reader,
111
- abort: () => {
112
- ownController.abort();
113
- },
114
- },
108
+ reader,
115
109
  contentLength,
116
110
  contentType: res.headers.get('content-type'),
117
111
  name: name !== null && name !== void 0 ? name : fallbackName,
118
112
  supportsContentRange,
113
+ needsContentRange,
119
114
  };
120
115
  },
121
- getLength: async (src) => {
122
- if (typeof src !== 'string') {
123
- throw new Error('src must be a string when using `fetchReader`');
124
- }
125
- const res = await fetch(src, {
126
- method: 'HEAD',
127
- });
128
- if (!res.body) {
129
- throw new Error('No body');
130
- }
131
- const length = res.headers.get('content-length');
132
- if (!length) {
133
- throw new Error('No content-length');
134
- }
135
- return parseInt(length, 10);
136
- },
137
116
  };
@@ -40,13 +40,7 @@ exports.nodeReader = {
40
40
  contentType: null,
41
41
  name: src.split(path_1.sep).pop(),
42
42
  supportsContentRange: true,
43
+ needsContentRange: true,
43
44
  });
44
45
  },
45
- getLength: (src) => {
46
- if (typeof src !== 'string') {
47
- throw new Error('src must be a string when using `nodeReader`');
48
- }
49
- const stats = (0, fs_1.statSync)(src);
50
- return Promise.resolve(stats.size);
51
- },
52
46
  };
@@ -0,0 +1,2 @@
1
+ import { ReaderInterface } from "./reader";
2
+ export declare const uintArrayReader: ReaderInterface;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uintArrayReader = void 0;
4
+ exports.uintArrayReader = {
5
+ read: ({ src, range, controller }) => {
6
+ if (!(src instanceof Uint8Array)) {
7
+ throw new Error('`uintArrayReader` only supports `Uint8Array` objects');
8
+ }
9
+ const part = range === null
10
+ ? src
11
+ : typeof range === 'number'
12
+ ? src.slice(range)
13
+ : src.slice(range[0], range[1]);
14
+ return Promise.resolve({
15
+ reader: {
16
+ reader: part.(),
17
+ abort() {
18
+ // no-op
19
+ },
20
+ },
21
+ contentLength: src.length,
22
+ contentType: 'application/octet-stream',
23
+ name: 'uintArray',
24
+ supportsContentRange: true,
25
+ });
26
+ }
27
+ };
@@ -40,6 +40,7 @@ exports.webFileReader = {
40
40
  name: src.name,
41
41
  supportsContentRange: true,
42
42
  contentType: src.type,
43
+ needsContentRange: true,
43
44
  });
44
45
  };
45
46
  reader.onerror = (error) => {
@@ -47,10 +48,4 @@ exports.webFileReader = {
47
48
  };
48
49
  });
49
50
  },
50
- getLength: (src) => {
51
- if (typeof src === 'string') {
52
- throw new Error('`inputTypeFileReader` only supports `File` objects');
53
- }
54
- return Promise.resolve(src.size);
55
- },
56
51
  };
@@ -10,15 +10,14 @@ type ReadResult = {
10
10
  contentType: string | null;
11
11
  name: string;
12
12
  supportsContentRange: boolean;
13
+ needsContentRange: boolean;
13
14
  };
14
15
  type ReadContent = (options: {
15
16
  src: ParseMediaSrc;
16
17
  range: [number, number] | number | null;
17
18
  controller: MediaParserController;
18
19
  }) => Promise<ReadResult>;
19
- type GetLength = (src: ParseMediaSrc) => Promise<number>;
20
20
  export type ReaderInterface = {
21
21
  read: ReadContent;
22
- getLength: GetLength;
23
22
  };
24
23
  export {};
@@ -1,11 +1,16 @@
1
- import type { Track, VideoTrack } from './get-tracks';
1
+ import type { AudioTrack, Track, VideoTrack } from './get-tracks';
2
2
  import type { MediaParserContainer } from './options';
3
3
  import type { ParserState } from './state/parser-state';
4
- export declare const registerTrack: ({ state, track, container, }: {
4
+ export declare const registerVideoTrack: ({ state, track, container, }: {
5
5
  state: ParserState;
6
6
  track: Track;
7
7
  container: MediaParserContainer;
8
- }) => Promise<void>;
8
+ }) => Promise<import("./webcodec-sample-types").OnVideoSample | null>;
9
+ export declare const registerAudioTrack: ({ state, track, container, }: {
10
+ state: ParserState;
11
+ track: AudioTrack;
12
+ container: MediaParserContainer;
13
+ }) => Promise<import("./webcodec-sample-types").OnAudioSample | null>;
9
14
  export declare const registerVideoTrackWhenProfileIsAvailable: ({ state, track, container, }: {
10
15
  state: ParserState;
11
16
  track: VideoTrack;
@@ -1,32 +1,45 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerVideoTrackWhenProfileIsAvailable = exports.registerTrack = void 0;
3
+ exports.registerVideoTrackWhenProfileIsAvailable = exports.registerAudioTrack = exports.registerVideoTrack = void 0;
4
4
  const add_avc_profile_to_track_1 = require("./add-avc-profile-to-track");
5
5
  const log_1 = require("./log");
6
- const registerTrack = async ({ state, track, container, }) => {
6
+ const registerVideoTrack = async ({ state, track, container, }) => {
7
7
  if (state.callbacks.tracks.getTracks().find((t) => t.trackId === track.trackId)) {
8
8
  log_1.Log.trace(state.logLevel, `Track ${track.trackId} already registered, skipping`);
9
- return;
9
+ return null;
10
10
  }
11
- if (track.type === 'video') {
12
- state.callbacks.tracks.addTrack(track);
13
- if (state.onVideoTrack) {
14
- const callback = await state.onVideoTrack({ track, container });
15
- await state.callbacks.registerVideoSampleCallback(track.trackId, callback !== null && callback !== void 0 ? callback : null);
16
- }
11
+ if (track.type !== 'video') {
12
+ throw new Error('Expected video track');
17
13
  }
18
- if (track.type === 'audio') {
19
- state.callbacks.tracks.addTrack(track);
20
- if (state.onAudioTrack) {
21
- const callback = await state.onAudioTrack({ track, container });
22
- await state.callbacks.registerAudioSampleCallback(track.trackId, callback !== null && callback !== void 0 ? callback : null);
23
- }
14
+ state.callbacks.tracks.addTrack(track);
15
+ if (!state.onVideoTrack) {
16
+ return null;
24
17
  }
18
+ const callback = await state.onVideoTrack({ track, container });
19
+ await state.callbacks.registerVideoSampleCallback(track.trackId, callback !== null && callback !== void 0 ? callback : null);
20
+ return callback;
25
21
  };
26
- exports.registerTrack = registerTrack;
22
+ exports.registerVideoTrack = registerVideoTrack;
23
+ const registerAudioTrack = async ({ state, track, container, }) => {
24
+ if (state.callbacks.tracks.getTracks().find((t) => t.trackId === track.trackId)) {
25
+ log_1.Log.trace(state.logLevel, `Track ${track.trackId} already registered, skipping`);
26
+ return null;
27
+ }
28
+ if (track.type !== 'audio') {
29
+ throw new Error('Expected audio track');
30
+ }
31
+ state.callbacks.tracks.addTrack(track);
32
+ if (!state.onAudioTrack) {
33
+ return null;
34
+ }
35
+ const callback = await state.onAudioTrack({ track, container });
36
+ await state.callbacks.registerAudioSampleCallback(track.trackId, callback !== null && callback !== void 0 ? callback : null);
37
+ return callback;
38
+ };
39
+ exports.registerAudioTrack = registerAudioTrack;
27
40
  const registerVideoTrackWhenProfileIsAvailable = ({ state, track, container, }) => {
28
41
  state.riff.registerOnAvcProfileCallback(async (profile) => {
29
- await (0, exports.registerTrack)({
42
+ await (0, exports.registerVideoTrack)({
30
43
  state,
31
44
  track: (0, add_avc_profile_to_track_1.addAvcProfileToTrack)(track, profile),
32
45
  container,
@@ -4,6 +4,7 @@ exports.runParseIteration = void 0;
4
4
  const parse_aac_1 = require("./containers/aac/parse-aac");
5
5
  const parse_flac_1 = require("./containers/flac/parse-flac");
6
6
  const parse_boxes_1 = require("./containers/iso-base-media/parse-boxes");
7
+ const parse_m3u_1 = require("./containers/m3u/parse-m3u");
7
8
  const parse_mp3_1 = require("./containers/mp3/parse-mp3");
8
9
  const parse_riff_1 = require("./containers/riff/parse-riff");
9
10
  const parse_transport_stream_1 = require("./containers/transport-stream/parse-transport-stream");
@@ -11,10 +12,14 @@ const parse_wav_1 = require("./containers/wav/parse-wav");
11
12
  const parse_webm_header_1 = require("./containers/webm/parse-webm-header");
12
13
  const init_video_1 = require("./init-video");
13
14
  const runParseIteration = async ({ state, mimeType, contentLength, name, }) => {
15
+ const structure = state.getStructureOrNull();
16
+ // m3u8 is busy parsing the chunks once the manifest has been read
17
+ if (structure && structure.type === 'm3u') {
18
+ return (0, parse_m3u_1.parseM3u)({ state });
19
+ }
14
20
  if (state.iterator.bytesRemaining() === 0) {
15
21
  return Promise.reject(new Error('no bytes'));
16
22
  }
17
- const structure = state.getStructureOrNull();
18
23
  if (structure === null) {
19
24
  await (0, init_video_1.initVideo)({ state, mimeType, name, contentLength });
20
25
  return null;
@@ -28,7 +28,8 @@ const needsTracksForField = ({ field, structure, }) => {
28
28
  field === 'sampleRate' ||
29
29
  field === 'numberOfAudioChannels' ||
30
30
  field === 'slowAudioBitrate' ||
31
- field === 'slowVideoBitrate') {
31
+ field === 'slowVideoBitrate' ||
32
+ field === 'm3uStreams') {
32
33
  return true;
33
34
  }
34
35
  if (field === 'container' ||
@@ -30,6 +30,7 @@ const emittedState = () => {
30
30
  sampleRate: false,
31
31
  slowAudioBitrate: false,
32
32
  slowVideoBitrate: false,
33
+ m3uStreams: false,
33
34
  };
34
35
  return emittedFields;
35
36
  };
@@ -0,0 +1,29 @@
1
+ import type { M3uStream } from '../containers/m3u/get-streams';
2
+ import type { OnAudioSample, OnVideoSample } from '../webcodec-sample-types';
3
+ type M3uStreamOrInitialUrl = {
4
+ type: 'selected-stream';
5
+ stream: M3uStream;
6
+ } | {
7
+ type: 'initial-url';
8
+ url: string;
9
+ };
10
+ export declare const m3uState: () => {
11
+ setSelectedStream: (stream: M3uStreamOrInitialUrl) => void;
12
+ getSelectedStream: () => M3uStreamOrInitialUrl | null;
13
+ setHasEmittedVideoTrack: (callback: OnVideoSample | null) => void;
14
+ hasEmittedVideoTrack: () => false | OnVideoSample | null;
15
+ setHasEmittedAudioTrack: (callback: OnAudioSample | null) => void;
16
+ hasEmittedAudioTrack: () => false | OnAudioSample | null;
17
+ setHasEmittedDoneWithTracks: () => void;
18
+ hasEmittedDoneWithTracks: () => boolean;
19
+ setReadyToIterateOverM3u: () => void;
20
+ isReadyToIterateOverM3u: () => boolean;
21
+ setLastChunkProcessed: (chunk: number) => void;
22
+ getLastChunkProcessed: () => number;
23
+ getAllChunksProcessed: () => boolean;
24
+ setAllChunksProcessed: () => void;
25
+ setHasFinishedManifest: () => void;
26
+ hasFinishedManifest: () => boolean;
27
+ };
28
+ export type M3uState = ReturnType<typeof m3uState>;
29
+ export {};
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.m3uState = void 0;
4
+ const m3uState = () => {
5
+ let selectedStream = null;
6
+ let hasEmittedVideoTrack = false;
7
+ let hasEmittedAudioTrack = false;
8
+ let hasEmittedDoneWithTracks = false;
9
+ let hasFinishedManifest = false;
10
+ let readyToIterateOverM3u = false;
11
+ let lastChunkProcessed = -1;
12
+ let allChunksProcessed = false;
13
+ return {
14
+ setSelectedStream: (stream) => {
15
+ selectedStream = stream;
16
+ },
17
+ getSelectedStream: () => selectedStream,
18
+ setHasEmittedVideoTrack: (callback) => {
19
+ hasEmittedVideoTrack = callback;
20
+ },
21
+ hasEmittedVideoTrack: () => hasEmittedVideoTrack,
22
+ setHasEmittedAudioTrack: (callback) => {
23
+ hasEmittedAudioTrack = callback;
24
+ },
25
+ hasEmittedAudioTrack: () => hasEmittedAudioTrack,
26
+ setHasEmittedDoneWithTracks: () => {
27
+ hasEmittedDoneWithTracks = true;
28
+ },
29
+ hasEmittedDoneWithTracks: () => hasEmittedDoneWithTracks,
30
+ setReadyToIterateOverM3u: () => {
31
+ readyToIterateOverM3u = true;
32
+ },
33
+ isReadyToIterateOverM3u: () => readyToIterateOverM3u,
34
+ setLastChunkProcessed: (chunk) => {
35
+ lastChunkProcessed = chunk;
36
+ },
37
+ getLastChunkProcessed: () => lastChunkProcessed,
38
+ getAllChunksProcessed: () => allChunksProcessed,
39
+ setAllChunksProcessed: () => {
40
+ allChunksProcessed = true;
41
+ },
42
+ setHasFinishedManifest: () => {
43
+ hasFinishedManifest = true;
44
+ },
45
+ hasFinishedManifest: () => hasFinishedManifest,
46
+ };
47
+ };
48
+ exports.m3uState = m3uState;
@@ -29,6 +29,7 @@ const needsSamples = {
29
29
  sampleRate: false,
30
30
  slowAudioBitrate: true,
31
31
  slowVideoBitrate: true,
32
+ m3uStreams: false,
32
33
  };
33
34
  const needsToIterateOverSamples = ({ fields, emittedFields, }) => {
34
35
  const keys = Object.keys(fields !== null && fields !== void 0 ? fields : {});
@@ -1,5 +1,6 @@
1
1
  import { type BufferIterator } from '../buffer-iterator';
2
2
  import type { AvcPPs, AvcProfileInfo } from '../containers/avc/parse-avc';
3
+ import type { SelectM3uStreamFn } from '../containers/m3u/select-stream';
3
4
  import { type LogLevel } from '../log';
4
5
  import type { MediaParserController } from '../media-parser-controller';
5
6
  import type { OnDiscardedData, Options, ParseMediaFields, ParseMediaMode, ParseMediaSrc } from '../options';
@@ -13,7 +14,7 @@ export type SpsAndPps = {
13
14
  sps: AvcProfileInfo;
14
15
  pps: AvcPPs;
15
16
  };
16
- export declare const makeParserState: ({ hasAudioTrackHandlers, hasVideoTrackHandlers, controller, fields, onAudioTrack, onVideoTrack, contentLength, logLevel, mode, src, readerInterface, onDiscardedData, }: {
17
+ export declare const makeParserState: ({ hasAudioTrackHandlers, hasVideoTrackHandlers, controller, fields, onAudioTrack, onVideoTrack, contentLength, logLevel, mode, src, readerInterface, onDiscardedData, selectM3uStreamFn, }: {
17
18
  hasAudioTrackHandlers: boolean;
18
19
  hasVideoTrackHandlers: boolean;
19
20
  controller: MediaParserController;
@@ -26,6 +27,7 @@ export declare const makeParserState: ({ hasAudioTrackHandlers, hasVideoTrackHan
26
27
  src: ParseMediaSrc;
27
28
  readerInterface: ReaderInterface;
28
29
  onDiscardedData: OnDiscardedData | null;
30
+ selectM3uStreamFn: SelectM3uStreamFn;
29
31
  }) => {
30
32
  onAudioTrack: OnAudioTrack | null;
31
33
  onVideoTrack: OnVideoTrack | null;
@@ -117,6 +119,7 @@ export declare const makeParserState: ({ hasAudioTrackHandlers, hasVideoTrackHan
117
119
  returnToCheckpoint: () => void;
118
120
  };
119
121
  getFlacCodecNumber: () => number;
122
+ readUntilLineEnd: () => string | null;
120
123
  getSyncSafeInt32: () => number;
121
124
  };
122
125
  controller: MediaParserController;
@@ -127,12 +130,14 @@ export declare const makeParserState: ({ hasAudioTrackHandlers, hasVideoTrackHan
127
130
  src: ParseMediaSrc;
128
131
  readerInterface: ReaderInterface;
129
132
  discardReadBytes: (force: boolean) => Promise<void>;
133
+ selectM3uStreamFn: SelectM3uStreamFn;
130
134
  getStructureOrNull: () => import("../parse-result").Structure | null;
131
135
  getStructure: () => import("../parse-result").Structure;
132
136
  setStructure: (value: import("../parse-result").Structure) => void;
133
137
  getFlacStructure: () => import("../containers/flac/types").FlacStructure;
134
138
  getIsoStructure: () => import("../parse-result").IsoBaseMediaStructure;
135
139
  getMp3Structure: () => import("../parse-result").Mp3Structure;
140
+ getM3uStructure: () => import("../containers/m3u/types").M3uStructure;
136
141
  getRiffStructure: () => import("../containers/riff/riff-box").RiffStructure;
137
142
  getTsStructure: () => import("../parse-result").TransportStreamStructure;
138
143
  getWavStructure: () => import("../containers/wav/types").WavStructure;
@@ -197,6 +202,36 @@ export declare const makeParserState: ({ hasAudioTrackHandlers, hasVideoTrackHan
197
202
  setBlockingBitStrategy: (strategy: number) => void;
198
203
  getBlockingBitStrategy: () => number | undefined;
199
204
  };
205
+ m3u: {
206
+ setSelectedStream: (stream: {
207
+ type: "selected-stream";
208
+ stream: import("../containers/m3u/get-streams").M3uStream;
209
+ } | {
210
+ type: "initial-url";
211
+ url: string;
212
+ }) => void;
213
+ getSelectedStream: () => ({
214
+ type: "selected-stream";
215
+ stream: import("../containers/m3u/get-streams").M3uStream;
216
+ } | {
217
+ type: "initial-url";
218
+ url: string;
219
+ }) | null;
220
+ setHasEmittedVideoTrack: (callback: import("../webcodec-sample-types").OnVideoSample | null) => void;
221
+ hasEmittedVideoTrack: () => false | import("../webcodec-sample-types").OnVideoSample | null;
222
+ setHasEmittedAudioTrack: (callback: import("../webcodec-sample-types").OnAudioSample | null) => void;
223
+ hasEmittedAudioTrack: () => false | import("../webcodec-sample-types").OnAudioSample | null;
224
+ setHasEmittedDoneWithTracks: () => void;
225
+ hasEmittedDoneWithTracks: () => boolean;
226
+ setReadyToIterateOverM3u: () => void;
227
+ isReadyToIterateOverM3u: () => boolean;
228
+ setLastChunkProcessed: (chunk: number) => void;
229
+ getLastChunkProcessed: () => number;
230
+ getAllChunksProcessed: () => boolean;
231
+ setAllChunksProcessed: () => void;
232
+ setHasFinishedManifest: () => void;
233
+ hasFinishedManifest: () => boolean;
234
+ };
200
235
  callbacks: {
201
236
  registerVideoSampleCallback: (id: number, callback: import("../webcodec-sample-types").OnVideoSample | null) => Promise<void>;
202
237
  onAudioSample: (trackId: number, audioSample: import("../webcodec-sample-types").AudioOrVideoSample) => Promise<void>;
@@ -10,6 +10,7 @@ const images_1 = require("./images");
10
10
  const iso_state_1 = require("./iso-base-media/iso-state");
11
11
  const keyframes_1 = require("./keyframes");
12
12
  const last_eventloop_break_1 = require("./last-eventloop-break");
13
+ const m3u_state_1 = require("./m3u-state");
13
14
  const mp3_1 = require("./mp3");
14
15
  const riff_1 = require("./riff");
15
16
  const sample_callbacks_1 = require("./sample-callbacks");
@@ -18,7 +19,7 @@ const structure_1 = require("./structure");
18
19
  const transport_stream_1 = require("./transport-stream");
19
20
  const video_section_1 = require("./video-section");
20
21
  const webm_1 = require("./webm");
21
- const makeParserState = ({ hasAudioTrackHandlers, hasVideoTrackHandlers, controller, fields, onAudioTrack, onVideoTrack, contentLength, logLevel, mode, src, readerInterface, onDiscardedData, }) => {
22
+ const makeParserState = ({ hasAudioTrackHandlers, hasVideoTrackHandlers, controller, fields, onAudioTrack, onVideoTrack, contentLength, logLevel, mode, src, readerInterface, onDiscardedData, selectM3uStreamFn, }) => {
22
23
  let skippedBytes = 0;
23
24
  const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(new Uint8Array([]), contentLength);
24
25
  const increaseSkippedBytes = (bytes) => {
@@ -47,6 +48,7 @@ const makeParserState = ({ hasAudioTrackHandlers, hasVideoTrackHandlers, control
47
48
  mp3Info,
48
49
  aac: (0, aac_state_1.aacState)(),
49
50
  flac: (0, flac_state_1.flacState)(),
51
+ m3u: (0, m3u_state_1.m3uState)(),
50
52
  callbacks: (0, sample_callbacks_1.sampleCallback)({
51
53
  controller,
52
54
  hasAudioTrackHandlers,
@@ -84,6 +86,7 @@ const makeParserState = ({ hasAudioTrackHandlers, hasVideoTrackHandlers, control
84
86
  src,
85
87
  readerInterface,
86
88
  discardReadBytes,
89
+ selectM3uStreamFn,
87
90
  };
88
91
  };
89
92
  exports.makeParserState = makeParserState;