@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.
- package/dist/buffer-iterator.d.ts +1 -0
- package/dist/buffer-iterator.js +17 -0
- package/dist/containers/aac/parse-aac.js +1 -1
- package/dist/containers/avc/create-sps-pps-data.js +15 -1
- package/dist/containers/avc/interpret-sps.js +8 -2
- package/dist/containers/avc/parse-avc.js +23 -24
- package/dist/containers/flac/get-channel-count.d.ts +1 -1
- package/dist/containers/flac/m3u/after-manifest-fetch.d.ts +14 -0
- package/dist/containers/flac/m3u/after-manifest-fetch.js +53 -0
- package/dist/containers/flac/m3u/fetch-m3u8-stream.d.ts +3 -0
- package/dist/containers/flac/m3u/fetch-m3u8-stream.js +15 -0
- package/dist/containers/flac/m3u/get-chunks.d.ts +6 -0
- package/dist/containers/flac/m3u/get-chunks.js +20 -0
- package/dist/containers/flac/m3u/get-duration-from-m3u.d.ts +2 -0
- package/dist/containers/flac/m3u/get-duration-from-m3u.js +9 -0
- package/dist/containers/flac/m3u/get-playlist.d.ts +3 -0
- package/dist/containers/flac/m3u/get-playlist.js +19 -0
- package/dist/containers/flac/m3u/get-streams.d.ts +13 -0
- package/dist/containers/flac/m3u/get-streams.js +41 -0
- package/dist/containers/flac/m3u/parse-directive.d.ts +2 -0
- package/dist/containers/flac/m3u/parse-directive.js +64 -0
- package/dist/containers/flac/m3u/parse-m3u-manifest.d.ts +8 -0
- package/dist/containers/flac/m3u/parse-m3u-manifest.js +18 -0
- package/dist/containers/flac/m3u/parse-m3u.d.ts +4 -0
- package/dist/containers/flac/m3u/parse-m3u.js +35 -0
- package/dist/containers/flac/m3u/parse-m3u8-text.d.ts +2 -0
- package/dist/containers/flac/m3u/parse-m3u8-text.js +23 -0
- package/dist/containers/flac/m3u/parse-stream-inf.d.ts +3 -0
- package/dist/containers/flac/m3u/parse-stream-inf.js +61 -0
- package/dist/containers/flac/m3u/return-packets.d.ts +14 -0
- package/dist/containers/flac/m3u/return-packets.js +63 -0
- package/dist/containers/flac/m3u/select-stream.d.ts +10 -0
- package/dist/containers/flac/m3u/select-stream.js +15 -0
- package/dist/containers/flac/m3u/types.d.ts +48 -0
- package/dist/containers/flac/m3u/types.js +2 -0
- package/dist/containers/flac/parse-streaminfo.js +1 -1
- package/dist/containers/iso-base-media/get-moov-atom.js +3 -2
- package/dist/containers/iso-base-media/process-box.js +9 -2
- package/dist/containers/iso-base-media/trun.js +1 -1
- package/dist/containers/m3u/after-manifest-fetch.d.ts +14 -0
- package/dist/containers/m3u/after-manifest-fetch.js +67 -0
- package/dist/containers/m3u/fetch-m3u8-stream.d.ts +3 -0
- package/dist/containers/m3u/fetch-m3u8-stream.js +18 -0
- package/dist/containers/m3u/get-chunks.d.ts +6 -0
- package/dist/containers/m3u/get-chunks.js +20 -0
- package/dist/containers/m3u/get-duration-from-m3u.d.ts +2 -0
- package/dist/containers/m3u/get-duration-from-m3u.js +9 -0
- package/dist/containers/m3u/get-playlist.d.ts +3 -0
- package/dist/containers/m3u/get-playlist.js +27 -0
- package/dist/containers/m3u/get-streams.d.ts +14 -0
- package/dist/containers/m3u/get-streams.js +60 -0
- package/dist/containers/m3u/parse-directive.d.ts +2 -0
- package/dist/containers/m3u/parse-directive.js +64 -0
- package/dist/containers/m3u/parse-m3u-manifest.d.ts +8 -0
- package/dist/containers/m3u/parse-m3u-manifest.js +18 -0
- package/dist/containers/m3u/parse-m3u.d.ts +4 -0
- package/dist/containers/m3u/parse-m3u.js +35 -0
- package/dist/containers/m3u/parse-m3u8-text.d.ts +2 -0
- package/dist/containers/m3u/parse-m3u8-text.js +23 -0
- package/dist/containers/m3u/parse-stream-inf.d.ts +3 -0
- package/dist/containers/m3u/parse-stream-inf.js +61 -0
- package/dist/containers/m3u/return-packets.d.ts +16 -0
- package/dist/containers/m3u/return-packets.js +71 -0
- package/dist/containers/m3u/select-stream.d.ts +10 -0
- package/dist/containers/m3u/select-stream.js +19 -0
- package/dist/containers/m3u/types.d.ts +48 -0
- package/dist/containers/m3u/types.js +2 -0
- package/dist/containers/mp3/parse-mpeg-header.js +1 -1
- package/dist/containers/riff/expect-riff-box.js +1 -1
- package/dist/containers/transport-stream/boxes.d.ts +4 -1
- package/dist/containers/transport-stream/find-separator.d.ts +1 -2
- package/dist/containers/transport-stream/find-separator.js +7 -13
- package/dist/containers/transport-stream/handle-aac-packet.js +1 -1
- package/dist/containers/transport-stream/handle-avc-packet.js +1 -1
- package/dist/containers/transport-stream/parse-packet.js +7 -1
- package/dist/containers/transport-stream/parse-pat.d.ts +2 -1
- package/dist/containers/transport-stream/parse-pat.js +16 -1
- package/dist/containers/transport-stream/parse-stream-packet.js +86 -74
- package/dist/containers/wav/parse-fmt.js +1 -1
- package/dist/containers/webm/parse-ebml.js +9 -2
- package/dist/does-need-contentlength-contentrange.d.ts +2 -0
- package/dist/does-need-contentlength-contentrange.js +10 -0
- package/dist/download-and-parse-media.js +32 -29
- package/dist/emit-available-info.js +13 -1
- package/dist/emitter.d.ts +4 -0
- package/dist/emitter.js +4 -0
- package/dist/esm/from-fetch.mjs +65 -38
- package/dist/esm/from-node.mjs +2 -8
- package/dist/esm/from-web-file.mjs +2 -7
- package/dist/esm/index.mjs +1029 -289
- package/dist/file-types/detect-file-type.d.ts +5 -1
- package/dist/file-types/detect-file-type.js +5 -1
- package/dist/file-types/index.js +3 -0
- package/dist/forward-controller.d.ts +7 -0
- package/dist/forward-controller.js +25 -0
- package/dist/get-container.js +3 -0
- package/dist/get-duration.js +35 -2
- package/dist/get-fields-from-callbacks.js +1 -0
- package/dist/get-fps.js +7 -0
- package/dist/get-tracks.d.ts +2 -0
- package/dist/get-tracks.js +29 -4
- package/dist/has-all-info.js +4 -0
- package/dist/index.d.ts +46 -9
- package/dist/index.js +3 -1
- package/dist/init-video.js +8 -0
- package/dist/internal-parse-media.js +11 -4
- package/dist/is-audio-structure.js +3 -0
- package/dist/media-parser-controller.js +3 -1
- package/dist/metadata/get-metadata.js +26 -3
- package/dist/options.d.ts +9 -1
- package/dist/parse-media.js +11 -8
- package/dist/parse-result.d.ts +2 -1
- package/dist/readers/fetch/get-body-and-reader.d.ts +8 -0
- package/dist/readers/fetch/get-body-and-reader.js +41 -0
- package/dist/readers/fetch/resolve-url.d.ts +1 -0
- package/dist/readers/fetch/resolve-url.js +15 -0
- package/dist/readers/from-fetch.js +19 -40
- package/dist/readers/from-node.js +1 -7
- package/dist/readers/from-uintarray.d.ts +2 -0
- package/dist/readers/from-uintarray.js +27 -0
- package/dist/readers/from-web-file.js +1 -6
- package/dist/readers/reader.d.ts +1 -2
- package/dist/register-track.d.ts +8 -3
- package/dist/register-track.js +30 -17
- package/dist/run-parse-iteration.js +6 -1
- package/dist/state/can-skip-tracks.js +2 -1
- package/dist/state/emitted-fields.js +1 -0
- package/dist/state/m3u-state.d.ts +29 -0
- package/dist/state/m3u-state.js +48 -0
- package/dist/state/need-samples-for-fields.js +1 -0
- package/dist/state/parser-state.d.ts +36 -1
- package/dist/state/parser-state.js +4 -1
- package/dist/state/structure.d.ts +1 -0
- package/dist/state/structure.js +7 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/dist/parse-media.js
CHANGED
|
@@ -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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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,
|
package/dist/parse-result.d.ts
CHANGED
|
@@ -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 =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
!
|
|
58
|
-
|
|
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
|
|
70
|
-
|
|
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 =
|
|
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,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
|
};
|
package/dist/readers/reader.d.ts
CHANGED
|
@@ -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 {};
|
package/dist/register-track.d.ts
CHANGED
|
@@ -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
|
|
4
|
+
export declare const registerVideoTrack: ({ state, track, container, }: {
|
|
5
5
|
state: ParserState;
|
|
6
6
|
track: Track;
|
|
7
7
|
container: MediaParserContainer;
|
|
8
|
-
}) => Promise<
|
|
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;
|
package/dist/register-track.js
CHANGED
|
@@ -1,32 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerVideoTrackWhenProfileIsAvailable = exports.
|
|
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
|
|
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
|
|
12
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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.
|
|
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.
|
|
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' ||
|
|
@@ -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;
|