@remotion/media-parser 4.0.290 → 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.
- package/dist/containers/iso-base-media/base-media-box.d.ts +0 -1
- package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.d.ts +4 -1
- package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.js +9 -5
- package/dist/containers/iso-base-media/find-keyframe-before-time.js +16 -11
- package/dist/containers/iso-base-media/find-track-to-seek.d.ts +14 -0
- package/dist/containers/iso-base-media/find-track-to-seek.js +39 -0
- package/dist/containers/iso-base-media/get-children.js +2 -2
- package/dist/containers/iso-base-media/get-keyframes.js +6 -1
- package/dist/containers/iso-base-media/get-mfra-seeking-box.d.ts +3 -1
- package/dist/containers/iso-base-media/get-mfra-seeking-box.js +5 -1
- package/dist/containers/iso-base-media/get-moov-atom.js +6 -3
- package/dist/containers/iso-base-media/get-sample-position-bounds.js +3 -1
- package/dist/containers/iso-base-media/get-sample-positions-from-track.js +1 -1
- package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.d.ts +14 -0
- package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.js +89 -0
- package/dist/containers/iso-base-media/get-seeking-byte.d.ts +3 -3
- package/dist/containers/iso-base-media/get-seeking-byte.js +32 -96
- package/dist/containers/iso-base-media/mdat/calculate-jump-marks.d.ts +6 -0
- package/dist/containers/iso-base-media/mdat/calculate-jump-marks.js +131 -0
- package/dist/containers/iso-base-media/mdat/mdat.d.ts +2 -2
- package/dist/containers/iso-base-media/mdat/mdat.js +18 -2
- package/dist/containers/iso-base-media/mfra/find-best-segment-from-tfra.d.ts +3 -3
- package/dist/containers/iso-base-media/mfra/find-best-segment-from-tfra.js +2 -2
- package/dist/containers/iso-base-media/mfra/get-mfra-atom.d.ts +5 -1
- package/dist/containers/iso-base-media/mfra/get-mfra-atom.js +3 -1
- package/dist/containers/iso-base-media/mfra/get-mfro-atom.d.ts +5 -1
- package/dist/containers/iso-base-media/mfra/get-mfro-atom.js +3 -1
- package/dist/containers/iso-base-media/parse-boxes.js +5 -2
- package/dist/containers/iso-base-media/process-box.d.ts +16 -5
- package/dist/containers/iso-base-media/process-box.js +206 -118
- package/dist/containers/iso-base-media/sample-positions.d.ts +25 -0
- package/dist/containers/iso-base-media/sample-positions.js +37 -0
- package/dist/containers/iso-base-media/stsd/samples.js +1 -0
- package/dist/containers/iso-base-media/stsd/stsc.d.ts +1 -6
- package/dist/containers/iso-base-media/stsd/stsc.js +2 -5
- package/dist/containers/iso-base-media/stsd/stss.d.ts +1 -1
- package/dist/containers/iso-base-media/stsd/stss.js +2 -2
- package/dist/containers/iso-base-media/turn-sample-positions-into-array.d.ts +19 -0
- package/dist/containers/iso-base-media/turn-sample-positions-into-array.js +73 -0
- package/dist/containers/m3u/after-manifest-fetch.d.ts +5 -1
- package/dist/containers/m3u/after-manifest-fetch.js +3 -1
- package/dist/containers/m3u/first-sample-in-m3u-chunk.d.ts +13 -0
- package/dist/containers/m3u/first-sample-in-m3u-chunk.js +31 -0
- package/dist/containers/m3u/get-seeking-byte.d.ts +13 -0
- package/dist/containers/m3u/get-seeking-byte.js +32 -0
- package/dist/containers/m3u/get-streams.d.ts +1 -0
- package/dist/containers/m3u/get-streams.js +1 -0
- package/dist/containers/m3u/iterate-over-segment-files.d.ts +5 -3
- package/dist/containers/m3u/iterate-over-segment-files.js +11 -1
- package/dist/containers/m3u/parse-m3u-media-directive.js +1 -0
- package/dist/containers/m3u/parse-m3u.js +8 -0
- package/dist/containers/m3u/process-m3u-chunk.d.ts +12 -0
- package/dist/containers/m3u/process-m3u-chunk.js +274 -0
- package/dist/containers/m3u/run-over-m3u.js +7 -80
- package/dist/containers/m3u/sample-sorter.d.ts +1 -0
- package/dist/containers/m3u/sample-sorter.js +4 -1
- package/dist/containers/m3u/seek/get-chunk-to-seek-to.d.ts +5 -0
- package/dist/containers/m3u/seek/get-chunk-to-seek-to.js +14 -0
- package/dist/containers/m3u/seeking-hints.d.ts +2 -0
- package/dist/containers/m3u/seeking-hints.js +9 -0
- package/dist/containers/m3u/select-stream.d.ts +2 -1
- package/dist/containers/m3u/select-stream.js +7 -2
- package/dist/containers/m3u/types.d.ts +1 -0
- package/dist/containers/riff/seek/fetch-idx1.d.ts +3 -1
- package/dist/containers/riff/seek/fetch-idx1.js +3 -1
- package/dist/containers/transport-stream/handle-aac-packet.d.ts +2 -2
- package/dist/containers/transport-stream/handle-avc-packet.d.ts +2 -2
- package/dist/containers/transport-stream/process-audio.d.ts +2 -2
- package/dist/containers/transport-stream/process-stream-buffers.d.ts +3 -3
- package/dist/containers/transport-stream/process-video.d.ts +2 -2
- package/dist/containers/webm/get-sample-from-block.d.ts +12 -2
- package/dist/containers/webm/get-sample-from-block.js +40 -9
- package/dist/containers/webm/parse-ebml.js +28 -10
- package/dist/containers/webm/seek/fetch-web-cues.d.ts +3 -1
- package/dist/containers/webm/seek/fetch-web-cues.js +3 -1
- package/dist/containers/webm/state-for-processing.d.ts +2 -2
- package/dist/controller/media-parser-controller.d.ts +1 -1
- package/dist/controller/media-parser-controller.js +6 -2
- package/dist/controller/seek-signal.d.ts +1 -5
- package/dist/download-and-parse-media.js +1 -1
- package/dist/esm/index.mjs +1400 -611
- package/dist/esm/node.mjs +23 -3
- package/dist/esm/server-worker.mjs +8 -1
- package/dist/esm/universal.mjs +168 -15
- package/dist/esm/web.mjs +145 -13
- package/dist/esm/worker-server-entry.mjs +1467 -635
- package/dist/esm/worker-web-entry.mjs +1439 -634
- package/dist/esm/worker.mjs +8 -1
- package/dist/get-audio-codec.js +3 -0
- package/dist/get-duration.js +2 -1
- package/dist/get-fps.js +2 -1
- package/dist/get-sample-positions-from-mp4.js +10 -5
- package/dist/get-sample-positions.js +4 -4
- package/dist/get-seeking-byte.d.ts +5 -3
- package/dist/get-seeking-byte.js +19 -10
- package/dist/get-seeking-hints.d.ts +3 -3
- package/dist/get-seeking-hints.js +18 -13
- package/dist/get-tracks.d.ts +9 -1
- package/dist/get-tracks.js +13 -6
- package/dist/index.d.ts +21 -5
- package/dist/init-video.js +3 -2
- package/dist/internal-parse-media.js +13 -4
- package/dist/iterator/buffer-iterator.js +5 -3
- package/dist/metadata/metadata-from-iso.js +2 -1
- package/dist/options.d.ts +6 -1
- package/dist/parse-loop.js +22 -6
- package/dist/parse-media-on-worker-entry.js +1 -0
- package/dist/parse-media.js +1 -1
- package/dist/parse-result.d.ts +2 -2
- package/dist/perform-seek.d.ts +3 -1
- package/dist/perform-seek.js +3 -1
- package/dist/readers/fetch/get-body-and-reader.js +17 -2
- package/dist/readers/from-fetch.d.ts +17 -1
- package/dist/readers/from-fetch.js +68 -13
- package/dist/readers/from-node.js +24 -2
- package/dist/readers/from-web-file.js +3 -0
- package/dist/readers/reader.d.ts +19 -2
- package/dist/readers/universal.js +9 -0
- package/dist/readers/web.js +6 -0
- package/dist/register-track.d.ts +3 -3
- package/dist/seek-backwards.d.ts +3 -1
- package/dist/seek-backwards.js +4 -1
- package/dist/seek-forwards.d.ts +3 -1
- package/dist/seek-forwards.js +3 -1
- package/dist/seeking-hints.d.ts +4 -1
- package/dist/set-seeking-hints.js +4 -0
- package/dist/skip.d.ts +5 -0
- package/dist/skip.js +6 -1
- package/dist/state/can-skip-tracks.d.ts +1 -0
- package/dist/state/can-skip-tracks.js +10 -6
- package/dist/state/iso-base-media/cached-sample-positions.d.ts +15 -1
- package/dist/state/iso-base-media/cached-sample-positions.js +9 -4
- package/dist/state/iso-base-media/iso-state.d.ts +5 -1
- package/dist/state/iso-base-media/iso-state.js +2 -1
- package/dist/state/iso-base-media/lazy-mfra-load.d.ts +3 -1
- package/dist/state/iso-base-media/lazy-mfra-load.js +2 -1
- package/dist/state/keyframes.js +1 -0
- package/dist/state/m3u-state.d.ts +15 -4
- package/dist/state/m3u-state.js +20 -0
- package/dist/state/matroska/lazy-cues-fetch.d.ts +3 -1
- package/dist/state/matroska/lazy-cues-fetch.js +2 -1
- package/dist/state/matroska/webm.d.ts +3 -1
- package/dist/state/matroska/webm.js +2 -1
- package/dist/state/parser-state.d.ts +29 -13
- package/dist/state/parser-state.js +19 -5
- package/dist/state/riff/lazy-idx1-fetch.d.ts +3 -1
- package/dist/state/riff/lazy-idx1-fetch.js +2 -1
- package/dist/state/riff.d.ts +3 -1
- package/dist/state/riff.js +2 -1
- package/dist/state/sample-callbacks.d.ts +3 -2
- package/dist/state/sample-callbacks.js +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/work-on-seek-request.d.ts +6 -3
- package/dist/work-on-seek-request.js +13 -13
- package/dist/worker/forward-controller-to-worker.js +1 -1
- package/dist/worker/serialize-error.js +26 -3
- package/dist/worker/worker-types.d.ts +7 -1
- package/dist/worker-server.js +2 -2
- package/package.json +3 -3
|
@@ -98,6 +98,40 @@ class MediaParserAbortError extends Error {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
// src/log.ts
|
|
102
|
+
var logLevels = ["trace", "verbose", "info", "warn", "error"];
|
|
103
|
+
var getNumberForLogLevel = (level) => {
|
|
104
|
+
return logLevels.indexOf(level);
|
|
105
|
+
};
|
|
106
|
+
var isEqualOrBelowLogLevel = (currentLevel, level) => {
|
|
107
|
+
return getNumberForLogLevel(currentLevel) <= getNumberForLogLevel(level);
|
|
108
|
+
};
|
|
109
|
+
var Log = {
|
|
110
|
+
trace: (logLevel, ...args) => {
|
|
111
|
+
if (isEqualOrBelowLogLevel(logLevel, "trace")) {
|
|
112
|
+
return console.log(...args);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
verbose: (logLevel, ...args) => {
|
|
116
|
+
if (isEqualOrBelowLogLevel(logLevel, "verbose")) {
|
|
117
|
+
return console.log(...args);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
info: (logLevel, ...args) => {
|
|
121
|
+
if (isEqualOrBelowLogLevel(logLevel, "info")) {
|
|
122
|
+
return console.log(...args);
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
warn: (logLevel, ...args) => {
|
|
126
|
+
if (isEqualOrBelowLogLevel(logLevel, "warn")) {
|
|
127
|
+
return console.warn(...args);
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
error: (...args) => {
|
|
131
|
+
return console.error(...args);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
101
135
|
// src/readers/fetch/get-body-and-reader.ts
|
|
102
136
|
var getLengthAndReader = async ({
|
|
103
137
|
canLiveWithoutContentLength,
|
|
@@ -110,10 +144,22 @@ var getLengthAndReader = async ({
|
|
|
110
144
|
if (requestedWithoutRange || canLiveWithoutContentLength && contentLength === null) {
|
|
111
145
|
const buffer = await res.arrayBuffer();
|
|
112
146
|
const encoded = new Uint8Array(buffer);
|
|
147
|
+
let streamCancelled = false;
|
|
113
148
|
const stream = new ReadableStream({
|
|
114
149
|
start(controller) {
|
|
115
|
-
|
|
116
|
-
|
|
150
|
+
if (ownController.signal.aborted) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (streamCancelled) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
controller.enqueue(encoded);
|
|
158
|
+
controller.close();
|
|
159
|
+
} catch {}
|
|
160
|
+
},
|
|
161
|
+
cancel() {
|
|
162
|
+
streamCancelled = true;
|
|
117
163
|
}
|
|
118
164
|
});
|
|
119
165
|
return {
|
|
@@ -189,14 +235,11 @@ var validateContentRangeAndDetectIfSupported = ({
|
|
|
189
235
|
}
|
|
190
236
|
return { supportsContentRange: true };
|
|
191
237
|
};
|
|
192
|
-
var
|
|
193
|
-
src,
|
|
238
|
+
var makeFetchRequest = async ({
|
|
194
239
|
range,
|
|
240
|
+
src,
|
|
195
241
|
controller
|
|
196
242
|
}) => {
|
|
197
|
-
if (typeof src !== "string" && src instanceof URL === false) {
|
|
198
|
-
throw new Error("src must be a string when using `fetchReader`");
|
|
199
|
-
}
|
|
200
243
|
const resolvedUrl = resolveUrl(src);
|
|
201
244
|
const resolvedUrlString = resolvedUrl.toString();
|
|
202
245
|
if (!resolvedUrlString.startsWith("https://") && !resolvedUrlString.startsWith("blob:") && !resolvedUrlString.startsWith("http://")) {
|
|
@@ -225,21 +268,83 @@ var fetchReadContent = async ({
|
|
|
225
268
|
parsedContentRange,
|
|
226
269
|
statusCode: res.status
|
|
227
270
|
});
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
271
|
+
if (controller) {
|
|
272
|
+
controller._internals.signal.addEventListener("abort", () => {
|
|
273
|
+
ownController.abort(new MediaParserAbortError("Aborted by user"));
|
|
274
|
+
}, { once: true });
|
|
275
|
+
}
|
|
231
276
|
if (res.status.toString().startsWith("4") || res.status.toString().startsWith("5")) {
|
|
232
|
-
throw new Error(`Server returned status code ${res.status} for ${
|
|
277
|
+
throw new Error(`Server returned status code ${res.status} for ${resolvedUrl} and range ${requestedRange}`);
|
|
233
278
|
}
|
|
234
279
|
const contentDisposition = res.headers.get("content-disposition");
|
|
235
280
|
const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1];
|
|
236
|
-
const fallbackName = src.toString().split("/").pop();
|
|
237
281
|
const { contentLength, needsContentRange, reader } = await getLengthAndReader({
|
|
238
282
|
canLiveWithoutContentLength,
|
|
239
283
|
res,
|
|
240
284
|
ownController,
|
|
241
285
|
requestedWithoutRange: requestWithoutRange
|
|
242
286
|
});
|
|
287
|
+
const contentType = res.headers.get("content-type");
|
|
288
|
+
return {
|
|
289
|
+
contentLength,
|
|
290
|
+
needsContentRange,
|
|
291
|
+
reader,
|
|
292
|
+
name,
|
|
293
|
+
contentType,
|
|
294
|
+
supportsContentRange
|
|
295
|
+
};
|
|
296
|
+
};
|
|
297
|
+
var cacheKey = ({
|
|
298
|
+
src,
|
|
299
|
+
range
|
|
300
|
+
}) => {
|
|
301
|
+
return `${src}-${JSON.stringify(range)}`;
|
|
302
|
+
};
|
|
303
|
+
var makeFetchRequestOrGetCached = ({
|
|
304
|
+
range,
|
|
305
|
+
src,
|
|
306
|
+
controller,
|
|
307
|
+
logLevel,
|
|
308
|
+
prefetchCache
|
|
309
|
+
}) => {
|
|
310
|
+
const key = cacheKey({ src, range });
|
|
311
|
+
const cached = prefetchCache.get(key);
|
|
312
|
+
if (cached) {
|
|
313
|
+
Log.verbose(logLevel, `Reading from preload cache for ${key}`);
|
|
314
|
+
return cached;
|
|
315
|
+
}
|
|
316
|
+
Log.verbose(logLevel, `Fetching ${key}`);
|
|
317
|
+
const result = makeFetchRequest({ range, src, controller });
|
|
318
|
+
prefetchCache.set(key, result);
|
|
319
|
+
return result;
|
|
320
|
+
};
|
|
321
|
+
var fetchReadContent = async ({
|
|
322
|
+
src,
|
|
323
|
+
range,
|
|
324
|
+
controller,
|
|
325
|
+
logLevel,
|
|
326
|
+
prefetchCache
|
|
327
|
+
}) => {
|
|
328
|
+
if (typeof src !== "string" && src instanceof URL === false) {
|
|
329
|
+
throw new Error("src must be a string when using `fetchReader`");
|
|
330
|
+
}
|
|
331
|
+
const fallbackName = src.toString().split("/").pop();
|
|
332
|
+
const {
|
|
333
|
+
reader,
|
|
334
|
+
contentLength,
|
|
335
|
+
needsContentRange,
|
|
336
|
+
name,
|
|
337
|
+
supportsContentRange,
|
|
338
|
+
contentType
|
|
339
|
+
} = await makeFetchRequestOrGetCached({
|
|
340
|
+
range,
|
|
341
|
+
src,
|
|
342
|
+
controller,
|
|
343
|
+
logLevel,
|
|
344
|
+
prefetchCache
|
|
345
|
+
});
|
|
346
|
+
const key = cacheKey({ src, range });
|
|
347
|
+
prefetchCache.delete(key);
|
|
243
348
|
if (controller) {
|
|
244
349
|
controller._internals.signal.addEventListener("abort", () => {
|
|
245
350
|
reader.reader.cancel().catch(() => {});
|
|
@@ -248,12 +353,33 @@ var fetchReadContent = async ({
|
|
|
248
353
|
return {
|
|
249
354
|
reader,
|
|
250
355
|
contentLength,
|
|
251
|
-
contentType
|
|
356
|
+
contentType,
|
|
252
357
|
name: name ?? fallbackName,
|
|
253
358
|
supportsContentRange,
|
|
254
359
|
needsContentRange
|
|
255
360
|
};
|
|
256
361
|
};
|
|
362
|
+
var fetchPreload = ({
|
|
363
|
+
src,
|
|
364
|
+
range,
|
|
365
|
+
logLevel,
|
|
366
|
+
prefetchCache
|
|
367
|
+
}) => {
|
|
368
|
+
if (typeof src !== "string" && src instanceof URL === false) {
|
|
369
|
+
throw new Error("src must be a string when using `fetchReader`");
|
|
370
|
+
}
|
|
371
|
+
const key = cacheKey({ src, range });
|
|
372
|
+
if (prefetchCache.has(key)) {
|
|
373
|
+
return prefetchCache.get(key);
|
|
374
|
+
}
|
|
375
|
+
makeFetchRequestOrGetCached({
|
|
376
|
+
range,
|
|
377
|
+
src,
|
|
378
|
+
controller: null,
|
|
379
|
+
logLevel,
|
|
380
|
+
prefetchCache
|
|
381
|
+
});
|
|
382
|
+
};
|
|
257
383
|
var fetchReadWholeAsText = async (src) => {
|
|
258
384
|
if (typeof src !== "string" && src instanceof URL === false) {
|
|
259
385
|
throw new Error("src must be a string when using `fetchReader`");
|
|
@@ -274,7 +400,6 @@ var fetchCreateAdjacentFileSource = (relativePath, src) => {
|
|
|
274
400
|
// src/readers/from-node.ts
|
|
275
401
|
import { createReadStream, promises, statSync } from "fs";
|
|
276
402
|
import { dirname, join, relative, sep } from "path";
|
|
277
|
-
import { Readable } from "stream";
|
|
278
403
|
var nodeReadContent = ({ src, range, controller }) => {
|
|
279
404
|
if (typeof src !== "string") {
|
|
280
405
|
throw new Error("src must be a string when using `nodeReader`");
|
|
@@ -289,7 +414,27 @@ var nodeReadContent = ({ src, range, controller }) => {
|
|
|
289
414
|
ownController.abort();
|
|
290
415
|
}, { once: true });
|
|
291
416
|
const stats = statSync(src);
|
|
292
|
-
|
|
417
|
+
let readerCancelled = false;
|
|
418
|
+
const reader = new ReadableStream({
|
|
419
|
+
start(c) {
|
|
420
|
+
if (readerCancelled) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
stream.on("data", (chunk) => {
|
|
424
|
+
c.enqueue(chunk);
|
|
425
|
+
});
|
|
426
|
+
stream.on("end", () => {
|
|
427
|
+
c.close();
|
|
428
|
+
});
|
|
429
|
+
stream.on("error", (err) => {
|
|
430
|
+
c.error(err);
|
|
431
|
+
});
|
|
432
|
+
},
|
|
433
|
+
cancel() {
|
|
434
|
+
readerCancelled = true;
|
|
435
|
+
stream.destroy();
|
|
436
|
+
}
|
|
437
|
+
}).getReader();
|
|
293
438
|
if (controller) {
|
|
294
439
|
controller._internals.signal.addEventListener("abort", () => {
|
|
295
440
|
reader.cancel().catch(() => {});
|
|
@@ -405,12 +550,21 @@ var universalReader = {
|
|
|
405
550
|
return fetchCreateAdjacentFileSource(relativePath, src);
|
|
406
551
|
}
|
|
407
552
|
return nodeCreateAdjacentFileSource(relativePath, src);
|
|
553
|
+
},
|
|
554
|
+
preload: ({ src, range, logLevel, prefetchCache }) => {
|
|
555
|
+
if (src instanceof Blob) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
if (src.toString().startsWith("http") || src.toString().startsWith("blob:")) {
|
|
559
|
+
return fetchPreload({ range, src, logLevel, prefetchCache });
|
|
560
|
+
}
|
|
408
561
|
}
|
|
409
562
|
};
|
|
410
563
|
// src/containers/m3u/select-stream.ts
|
|
411
564
|
var selectAssociatedPlaylists = async ({
|
|
412
565
|
playlists,
|
|
413
|
-
fn
|
|
566
|
+
fn,
|
|
567
|
+
skipAudioTracks
|
|
414
568
|
}) => {
|
|
415
569
|
if (playlists.length < 1) {
|
|
416
570
|
return Promise.resolve([]);
|
|
@@ -419,12 +573,17 @@ var selectAssociatedPlaylists = async ({
|
|
|
419
573
|
if (!Array.isArray(streams)) {
|
|
420
574
|
throw new Error("Expected an array of associated playlists");
|
|
421
575
|
}
|
|
576
|
+
const selectedStreams = [];
|
|
422
577
|
for (const stream of streams) {
|
|
578
|
+
if (stream.isAudio && skipAudioTracks) {
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
423
581
|
if (!playlists.find((playlist) => playlist.src === stream.src)) {
|
|
424
582
|
throw new Error(`The associated playlist ${JSON.stringify(streams)} cannot be selected because it was not in the list of selectable playlists`);
|
|
425
583
|
}
|
|
584
|
+
selectedStreams.push(stream);
|
|
426
585
|
}
|
|
427
|
-
return
|
|
586
|
+
return selectedStreams;
|
|
428
587
|
};
|
|
429
588
|
var defaultSelectM3uAssociatedPlaylists = ({ associatedPlaylists }) => {
|
|
430
589
|
if (associatedPlaylists.length === 1) {
|
|
@@ -596,7 +755,11 @@ var mediaParserController = () => {
|
|
|
596
755
|
const performedSeeksSignal = performedSeeksStats();
|
|
597
756
|
const checkForAbortAndPause = async () => {
|
|
598
757
|
if (abortController.signal.aborted) {
|
|
599
|
-
|
|
758
|
+
const err = new MediaParserAbortError("Aborted");
|
|
759
|
+
if (abortController.signal.reason) {
|
|
760
|
+
err.cause = abortController.signal.reason;
|
|
761
|
+
}
|
|
762
|
+
throw err;
|
|
600
763
|
}
|
|
601
764
|
await pauseSignal.waitUntilResume();
|
|
602
765
|
};
|
|
@@ -618,7 +781,7 @@ var mediaParserController = () => {
|
|
|
618
781
|
abortController.abort(reason);
|
|
619
782
|
emitter.dispatchAbort(reason);
|
|
620
783
|
},
|
|
621
|
-
|
|
784
|
+
seek: seekSignal.seek,
|
|
622
785
|
pause: pauseSignal.pause,
|
|
623
786
|
resume: pauseSignal.resume,
|
|
624
787
|
addEventListener: emitter.addEventListener,
|
|
@@ -672,7 +835,8 @@ var getM3uStreams = ({
|
|
|
672
835
|
language: audioTrack.language,
|
|
673
836
|
name: audioTrack.name,
|
|
674
837
|
src: readerInterface.createAdjacentFileSource(audioTrack.uri, originalSrc),
|
|
675
|
-
id: associatedPlaylists.length
|
|
838
|
+
id: associatedPlaylists.length,
|
|
839
|
+
isAudio: true
|
|
676
840
|
});
|
|
677
841
|
}
|
|
678
842
|
}
|
|
@@ -1033,7 +1197,7 @@ var getFpsFromIsoMaseMedia = (state) => {
|
|
|
1033
1197
|
const moovBox = getMoovBoxFromState({
|
|
1034
1198
|
structureState: state.structure,
|
|
1035
1199
|
isoState: state.iso,
|
|
1036
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
1200
|
+
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
1037
1201
|
mayUsePrecomputed: true
|
|
1038
1202
|
});
|
|
1039
1203
|
if (!moovBox) {
|
|
@@ -2192,40 +2356,6 @@ var detectFileType = (data) => {
|
|
|
2192
2356
|
return { type: "unknown" };
|
|
2193
2357
|
};
|
|
2194
2358
|
|
|
2195
|
-
// src/log.ts
|
|
2196
|
-
var logLevels = ["trace", "verbose", "info", "warn", "error"];
|
|
2197
|
-
var getNumberForLogLevel = (level) => {
|
|
2198
|
-
return logLevels.indexOf(level);
|
|
2199
|
-
};
|
|
2200
|
-
var isEqualOrBelowLogLevel = (currentLevel, level) => {
|
|
2201
|
-
return getNumberForLogLevel(currentLevel) <= getNumberForLogLevel(level);
|
|
2202
|
-
};
|
|
2203
|
-
var Log = {
|
|
2204
|
-
trace: (logLevel, ...args) => {
|
|
2205
|
-
if (isEqualOrBelowLogLevel(logLevel, "trace")) {
|
|
2206
|
-
return console.log(...args);
|
|
2207
|
-
}
|
|
2208
|
-
},
|
|
2209
|
-
verbose: (logLevel, ...args) => {
|
|
2210
|
-
if (isEqualOrBelowLogLevel(logLevel, "verbose")) {
|
|
2211
|
-
return console.log(...args);
|
|
2212
|
-
}
|
|
2213
|
-
},
|
|
2214
|
-
info: (logLevel, ...args) => {
|
|
2215
|
-
if (isEqualOrBelowLogLevel(logLevel, "info")) {
|
|
2216
|
-
return console.log(...args);
|
|
2217
|
-
}
|
|
2218
|
-
},
|
|
2219
|
-
warn: (logLevel, ...args) => {
|
|
2220
|
-
if (isEqualOrBelowLogLevel(logLevel, "warn")) {
|
|
2221
|
-
return console.warn(...args);
|
|
2222
|
-
}
|
|
2223
|
-
},
|
|
2224
|
-
error: (...args) => {
|
|
2225
|
-
return console.error(...args);
|
|
2226
|
-
}
|
|
2227
|
-
};
|
|
2228
|
-
|
|
2229
2359
|
// src/iterator/buffer-manager.ts
|
|
2230
2360
|
var bufferManager = ({
|
|
2231
2361
|
initialData,
|
|
@@ -2403,7 +2533,7 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
2403
2533
|
const six = getUint8();
|
|
2404
2534
|
const seven = getUint8();
|
|
2405
2535
|
const eight = getUint8();
|
|
2406
|
-
return eight << 56 | seven << 48 | six << 40 | five << 32 | four << 24 | three << 16 | two << 8 | one;
|
|
2536
|
+
return (eight << 56 | seven << 48 | six << 40 | five << 32 | four << 24 | three << 16 | two << 8 | one) >>> 0;
|
|
2407
2537
|
}
|
|
2408
2538
|
function byteArrayToBigInt(byteArray) {
|
|
2409
2539
|
let result = BigInt(0);
|
|
@@ -2425,7 +2555,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
2425
2555
|
return Number(bigInt);
|
|
2426
2556
|
};
|
|
2427
2557
|
const getFourByteNumber = () => {
|
|
2428
|
-
|
|
2558
|
+
const unsigned = getUint8() << 24 | getUint8() << 16 | getUint8() << 8 | getUint8();
|
|
2559
|
+
return unsigned >>> 0;
|
|
2429
2560
|
};
|
|
2430
2561
|
const getPaddedFourByteNumber = () => {
|
|
2431
2562
|
let lastInt = 128;
|
|
@@ -4091,7 +4222,7 @@ var isoBaseMediaHasTracks = (state, mayUsePrecomputed) => {
|
|
|
4091
4222
|
return Boolean(getMoovBoxFromState({
|
|
4092
4223
|
structureState: state.structure,
|
|
4093
4224
|
isoState: state.iso,
|
|
4094
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
4225
|
+
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
4095
4226
|
mayUsePrecomputed
|
|
4096
4227
|
}));
|
|
4097
4228
|
};
|
|
@@ -4176,11 +4307,16 @@ var getTracksFromMoovBox = (moovBox) => {
|
|
|
4176
4307
|
otherTracks
|
|
4177
4308
|
};
|
|
4178
4309
|
};
|
|
4179
|
-
var getTracksFromIsoBaseMedia = (
|
|
4310
|
+
var getTracksFromIsoBaseMedia = ({
|
|
4311
|
+
mayUsePrecomputed,
|
|
4312
|
+
structure,
|
|
4313
|
+
isoState,
|
|
4314
|
+
m3uPlaylistContext
|
|
4315
|
+
}) => {
|
|
4180
4316
|
const moovBox = getMoovBoxFromState({
|
|
4181
|
-
structureState:
|
|
4182
|
-
isoState
|
|
4183
|
-
mp4HeaderSegment:
|
|
4317
|
+
structureState: structure,
|
|
4318
|
+
isoState,
|
|
4319
|
+
mp4HeaderSegment: m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
4184
4320
|
mayUsePrecomputed
|
|
4185
4321
|
});
|
|
4186
4322
|
if (!moovBox) {
|
|
@@ -4209,7 +4345,12 @@ var getTracks = (state, mayUsePrecomputed) => {
|
|
|
4209
4345
|
return getCategorizedTracksFromMatroska(state);
|
|
4210
4346
|
}
|
|
4211
4347
|
if (structure.type === "iso-base-media") {
|
|
4212
|
-
return getTracksFromIsoBaseMedia(
|
|
4348
|
+
return getTracksFromIsoBaseMedia({
|
|
4349
|
+
isoState: state.iso,
|
|
4350
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
4351
|
+
structure: state.structure,
|
|
4352
|
+
mayUsePrecomputed
|
|
4353
|
+
});
|
|
4213
4354
|
}
|
|
4214
4355
|
if (structure.type === "riff") {
|
|
4215
4356
|
return getTracksFromAvi(structure, state);
|
|
@@ -4415,6 +4556,9 @@ var getAudioCodecFromAudioCodecInfo = (codec) => {
|
|
|
4415
4556
|
if (codec.format === "ac-3") {
|
|
4416
4557
|
return "ac3";
|
|
4417
4558
|
}
|
|
4559
|
+
if (codec.format === "Opus") {
|
|
4560
|
+
return "opus";
|
|
4561
|
+
}
|
|
4418
4562
|
if (codec.format === "mp4a") {
|
|
4419
4563
|
if (codec.primarySpecificator === 64) {
|
|
4420
4564
|
return "aac";
|
|
@@ -4597,11 +4741,15 @@ var collectSamplePositionsFromMoofBoxes = ({
|
|
|
4597
4741
|
tkhdBox
|
|
4598
4742
|
}) => {
|
|
4599
4743
|
const isComplete = tfraBoxes.length > 0 && tfraBoxes.every((t) => t.entries.length === moofBoxes.length);
|
|
4600
|
-
const samplePositions = moofBoxes.map((m) => {
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4744
|
+
const samplePositions = moofBoxes.map((m, index) => {
|
|
4745
|
+
const isLastFragment = index === moofBoxes.length - 1 && isComplete;
|
|
4746
|
+
return {
|
|
4747
|
+
isLastFragment,
|
|
4748
|
+
samples: getSamplesFromMoof({
|
|
4749
|
+
moofBox: m,
|
|
4750
|
+
trackId: tkhdBox.trackId
|
|
4751
|
+
})
|
|
4752
|
+
};
|
|
4605
4753
|
});
|
|
4606
4754
|
return { samplePositions, isComplete };
|
|
4607
4755
|
};
|
|
@@ -4634,14 +4782,14 @@ var getSamplePositions = ({
|
|
|
4634
4782
|
const samples = [];
|
|
4635
4783
|
let samplesPerChunk = 1;
|
|
4636
4784
|
for (let i = 0;i < chunks.length; i++) {
|
|
4637
|
-
const hasEntry = stscBox.entries.
|
|
4638
|
-
if (hasEntry) {
|
|
4639
|
-
samplesPerChunk = hasEntry
|
|
4785
|
+
const hasEntry = stscBox.entries.get(i + 1);
|
|
4786
|
+
if (hasEntry !== undefined) {
|
|
4787
|
+
samplesPerChunk = hasEntry;
|
|
4640
4788
|
}
|
|
4641
4789
|
let offsetInThisChunk = 0;
|
|
4642
4790
|
for (let j = 0;j < samplesPerChunk; j++) {
|
|
4643
4791
|
const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
|
|
4644
|
-
const isKeyframe = stssBox ? stssBox.sampleNumber.
|
|
4792
|
+
const isKeyframe = stssBox ? stssBox.sampleNumber.has(samples.length + 1) : true;
|
|
4645
4793
|
const delta = sttsDeltas[samples.length];
|
|
4646
4794
|
const ctsOffset = cttsEntries[samples.length];
|
|
4647
4795
|
const cts = dts + ctsOffset;
|
|
@@ -4685,11 +4833,16 @@ var getGroupedSamplesPositionsFromMp4 = ({
|
|
|
4685
4833
|
}
|
|
4686
4834
|
const samples = [];
|
|
4687
4835
|
let timestamp = 0;
|
|
4836
|
+
const stscKeys = Array.from(stscBox.entries.keys());
|
|
4688
4837
|
for (let i = 0;i < stcoBox.entries.length; i++) {
|
|
4689
4838
|
const entry = stcoBox.entries[i];
|
|
4690
4839
|
const chunk = i + 1;
|
|
4691
|
-
const stscEntry =
|
|
4692
|
-
if (
|
|
4840
|
+
const stscEntry = stscKeys.findLast((e) => e <= chunk);
|
|
4841
|
+
if (stscEntry === undefined) {
|
|
4842
|
+
throw new Error("should not be");
|
|
4843
|
+
}
|
|
4844
|
+
const samplesPerChunk = stscBox.entries.get(stscEntry);
|
|
4845
|
+
if (samplesPerChunk === undefined) {
|
|
4693
4846
|
throw new Error("should not be");
|
|
4694
4847
|
}
|
|
4695
4848
|
samples.push({
|
|
@@ -4697,13 +4850,13 @@ var getGroupedSamplesPositionsFromMp4 = ({
|
|
|
4697
4850
|
cts: timestamp,
|
|
4698
4851
|
dts: timestamp,
|
|
4699
4852
|
offset: Number(entry),
|
|
4700
|
-
size: stszBox.sampleSize *
|
|
4701
|
-
duration:
|
|
4853
|
+
size: stszBox.sampleSize * samplesPerChunk,
|
|
4854
|
+
duration: samplesPerChunk,
|
|
4702
4855
|
isKeyframe: true,
|
|
4703
4856
|
bigEndian,
|
|
4704
4857
|
chunkSize: stszBox.sampleSize
|
|
4705
4858
|
});
|
|
4706
|
-
timestamp +=
|
|
4859
|
+
timestamp += samplesPerChunk;
|
|
4707
4860
|
}
|
|
4708
4861
|
return samples;
|
|
4709
4862
|
};
|
|
@@ -4780,7 +4933,7 @@ var getSamplePositionsFromTrack = ({
|
|
|
4780
4933
|
tkhdBox
|
|
4781
4934
|
});
|
|
4782
4935
|
return {
|
|
4783
|
-
samplePositions: samplePositions.flat(1),
|
|
4936
|
+
samplePositions: samplePositions.map((s) => s.samples).flat(1),
|
|
4784
4937
|
isComplete
|
|
4785
4938
|
};
|
|
4786
4939
|
}
|
|
@@ -5014,7 +5167,7 @@ var getDurationFromIsoBaseMedia = (parserState) => {
|
|
|
5014
5167
|
const moovBox = getMoovBoxFromState({
|
|
5015
5168
|
structureState: parserState.structure,
|
|
5016
5169
|
isoState: parserState.iso,
|
|
5017
|
-
mp4HeaderSegment: parserState.mp4HeaderSegment,
|
|
5170
|
+
mp4HeaderSegment: parserState.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
5018
5171
|
mayUsePrecomputed: true
|
|
5019
5172
|
});
|
|
5020
5173
|
if (!moovBox) {
|
|
@@ -5120,7 +5273,12 @@ var hasHdr = (state) => {
|
|
|
5120
5273
|
|
|
5121
5274
|
// src/containers/iso-base-media/get-keyframes.ts
|
|
5122
5275
|
var getKeyframesFromIsoBaseMedia = (state) => {
|
|
5123
|
-
const { videoTracks } = getTracksFromIsoBaseMedia(
|
|
5276
|
+
const { videoTracks } = getTracksFromIsoBaseMedia({
|
|
5277
|
+
isoState: state.iso,
|
|
5278
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
5279
|
+
structure: state.structure,
|
|
5280
|
+
mayUsePrecomputed: true
|
|
5281
|
+
});
|
|
5124
5282
|
const structure = state.structure.getIsoStructure();
|
|
5125
5283
|
const moofBoxes = getMoofBoxes(structure.boxes);
|
|
5126
5284
|
const tfraBoxes = getTfraBoxes(structure);
|
|
@@ -5274,7 +5432,7 @@ var getMetadataFromIsoBase = (state) => {
|
|
|
5274
5432
|
const moov = getMoovBoxFromState({
|
|
5275
5433
|
structureState: state.structure,
|
|
5276
5434
|
isoState: state.iso,
|
|
5277
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
5435
|
+
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
5278
5436
|
mayUsePrecomputed: true
|
|
5279
5437
|
});
|
|
5280
5438
|
if (!moov) {
|
|
@@ -5540,6 +5698,75 @@ var getSeekingByteForFlac = ({
|
|
|
5540
5698
|
return null;
|
|
5541
5699
|
};
|
|
5542
5700
|
|
|
5701
|
+
// src/containers/iso-base-media/find-keyframe-before-time.ts
|
|
5702
|
+
var findKeyframeBeforeTime = ({
|
|
5703
|
+
samplePositions,
|
|
5704
|
+
time,
|
|
5705
|
+
timescale,
|
|
5706
|
+
mediaSections,
|
|
5707
|
+
logLevel
|
|
5708
|
+
}) => {
|
|
5709
|
+
let videoByte = 0;
|
|
5710
|
+
let videoSample = null;
|
|
5711
|
+
for (const sample of samplePositions) {
|
|
5712
|
+
const ctsInSeconds = sample.cts / timescale;
|
|
5713
|
+
const dtsInSeconds = sample.dts / timescale;
|
|
5714
|
+
if (!sample.isKeyframe) {
|
|
5715
|
+
continue;
|
|
5716
|
+
}
|
|
5717
|
+
if (!(ctsInSeconds <= time || dtsInSeconds <= time)) {
|
|
5718
|
+
continue;
|
|
5719
|
+
}
|
|
5720
|
+
if (videoByte <= sample.offset) {
|
|
5721
|
+
videoByte = sample.offset;
|
|
5722
|
+
videoSample = sample;
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
if (!videoSample) {
|
|
5726
|
+
throw new Error("No sample found");
|
|
5727
|
+
}
|
|
5728
|
+
const mediaSection = mediaSections.find((section) => videoSample.offset >= section.start && videoSample.offset < section.start + section.size);
|
|
5729
|
+
if (!mediaSection) {
|
|
5730
|
+
Log.trace(logLevel, "Found a sample, but the offset has not yet been marked as a video section yet. Not yet able to seek, but probably once we have started reading the next box.", videoSample);
|
|
5731
|
+
return null;
|
|
5732
|
+
}
|
|
5733
|
+
return videoSample.offset;
|
|
5734
|
+
};
|
|
5735
|
+
|
|
5736
|
+
// src/containers/iso-base-media/find-track-to-seek.ts
|
|
5737
|
+
var findAnyTrackWithSamplePositions = (allTracks, struc) => {
|
|
5738
|
+
for (const track of allTracks) {
|
|
5739
|
+
if (track.type === "video" || track.type === "audio") {
|
|
5740
|
+
const { samplePositions } = getSamplePositionsFromTrack({
|
|
5741
|
+
trakBox: track.trakBox,
|
|
5742
|
+
moofBoxes: getMoofBoxes(struc.boxes),
|
|
5743
|
+
tfraBoxes: getTfraBoxes(struc)
|
|
5744
|
+
});
|
|
5745
|
+
if (samplePositions.length === 0) {
|
|
5746
|
+
continue;
|
|
5747
|
+
}
|
|
5748
|
+
return { track, samplePositions };
|
|
5749
|
+
}
|
|
5750
|
+
}
|
|
5751
|
+
return null;
|
|
5752
|
+
};
|
|
5753
|
+
var findTrackToSeek = (allTracks, structure) => {
|
|
5754
|
+
const firstVideoTrack = allTracks.find((t) => t.type === "video");
|
|
5755
|
+
const struc = structure.getIsoStructure();
|
|
5756
|
+
if (!firstVideoTrack) {
|
|
5757
|
+
return findAnyTrackWithSamplePositions(allTracks, struc);
|
|
5758
|
+
}
|
|
5759
|
+
const { samplePositions } = getSamplePositionsFromTrack({
|
|
5760
|
+
trakBox: firstVideoTrack.trakBox,
|
|
5761
|
+
moofBoxes: getMoofBoxes(struc.boxes),
|
|
5762
|
+
tfraBoxes: getTfraBoxes(struc)
|
|
5763
|
+
});
|
|
5764
|
+
if (samplePositions.length === 0) {
|
|
5765
|
+
return findAnyTrackWithSamplePositions(allTracks, struc);
|
|
5766
|
+
}
|
|
5767
|
+
return { track: firstVideoTrack, samplePositions };
|
|
5768
|
+
};
|
|
5769
|
+
|
|
5543
5770
|
// src/state/video-section.ts
|
|
5544
5771
|
var isByteInMediaSection = ({
|
|
5545
5772
|
position,
|
|
@@ -5608,42 +5835,13 @@ var mediaSectionState = () => {
|
|
|
5608
5835
|
};
|
|
5609
5836
|
};
|
|
5610
5837
|
|
|
5611
|
-
// src/containers/iso-base-media/find-keyframe-before-time.ts
|
|
5612
|
-
var findKeyframeBeforeTime = ({
|
|
5613
|
-
samplePositions,
|
|
5614
|
-
time,
|
|
5615
|
-
timescale,
|
|
5616
|
-
mediaSections,
|
|
5617
|
-
logLevel
|
|
5618
|
-
}) => {
|
|
5619
|
-
let byte = 0;
|
|
5620
|
-
let sam = null;
|
|
5621
|
-
for (const sample of samplePositions) {
|
|
5622
|
-
const ctsInSeconds = sample.cts / timescale;
|
|
5623
|
-
const dtsInSeconds = sample.dts / timescale;
|
|
5624
|
-
if ((ctsInSeconds <= time || dtsInSeconds <= time) && byte <= sample.offset && sample.isKeyframe) {
|
|
5625
|
-
byte = sample.offset;
|
|
5626
|
-
sam = sample;
|
|
5627
|
-
}
|
|
5628
|
-
}
|
|
5629
|
-
if (!sam) {
|
|
5630
|
-
throw new Error("No sample found");
|
|
5631
|
-
}
|
|
5632
|
-
const mediaSection = mediaSections.find((section) => sam.offset >= section.start && sam.offset < section.start + section.size);
|
|
5633
|
-
if (!mediaSection) {
|
|
5634
|
-
Log.trace(logLevel, "Found a sample, but the offset has not yet been marked as a video section yet. Not yet able to seek, but probably once we have started reading the next box.", sam);
|
|
5635
|
-
return null;
|
|
5636
|
-
}
|
|
5637
|
-
return sam.offset;
|
|
5638
|
-
};
|
|
5639
|
-
|
|
5640
5838
|
// src/containers/iso-base-media/get-sample-position-bounds.ts
|
|
5641
5839
|
var getSamplePositionBounds = (samplePositions, timescale) => {
|
|
5642
5840
|
let min = Infinity;
|
|
5643
5841
|
let max = -Infinity;
|
|
5644
5842
|
for (const samplePosition of samplePositions) {
|
|
5645
5843
|
const timestampMin = Math.min(samplePosition.cts, samplePosition.dts);
|
|
5646
|
-
const timestampMax = Math.max(samplePosition.cts, samplePosition.dts);
|
|
5844
|
+
const timestampMax = Math.max(samplePosition.cts, samplePosition.dts) + (samplePosition.duration ?? 0);
|
|
5647
5845
|
if (timestampMin < min) {
|
|
5648
5846
|
min = timestampMin;
|
|
5649
5847
|
}
|
|
@@ -5658,10 +5856,10 @@ var getSamplePositionBounds = (samplePositions, timescale) => {
|
|
|
5658
5856
|
var findBestSegmentFromTfra = ({
|
|
5659
5857
|
mfra,
|
|
5660
5858
|
time,
|
|
5661
|
-
|
|
5859
|
+
firstTrack,
|
|
5662
5860
|
timescale
|
|
5663
5861
|
}) => {
|
|
5664
|
-
const tfra = mfra.find((b) => b.type === "tfra-box" && b.trackId ===
|
|
5862
|
+
const tfra = mfra.find((b) => b.type === "tfra-box" && b.trackId === firstTrack.trackId);
|
|
5665
5863
|
if (!tfra) {
|
|
5666
5864
|
return null;
|
|
5667
5865
|
}
|
|
@@ -5682,130 +5880,191 @@ var findBestSegmentFromTfra = ({
|
|
|
5682
5880
|
};
|
|
5683
5881
|
};
|
|
5684
5882
|
|
|
5685
|
-
// src/containers/iso-base-media/get-seeking-byte.ts
|
|
5686
|
-
var
|
|
5883
|
+
// src/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.ts
|
|
5884
|
+
var getSeekingByteFromFragmentedMp4 = async ({
|
|
5687
5885
|
info,
|
|
5688
5886
|
time,
|
|
5689
5887
|
logLevel,
|
|
5690
5888
|
currentPosition,
|
|
5691
5889
|
isoState,
|
|
5692
|
-
|
|
5693
|
-
|
|
5890
|
+
allTracks,
|
|
5891
|
+
isLastChunkInPlaylist
|
|
5694
5892
|
}) => {
|
|
5695
|
-
const tracks2 = getTracksFromMoovBox(info.moovBox);
|
|
5696
|
-
const allTracks = [
|
|
5697
|
-
...tracks2.videoTracks,
|
|
5698
|
-
...tracks2.audioTracks,
|
|
5699
|
-
...tracks2.otherTracks
|
|
5700
|
-
];
|
|
5701
|
-
const hasMoov = Boolean(getMoovBoxFromState({
|
|
5702
|
-
mp4HeaderSegment,
|
|
5703
|
-
structureState: structure,
|
|
5704
|
-
isoState,
|
|
5705
|
-
mayUsePrecomputed: false
|
|
5706
|
-
}));
|
|
5707
|
-
if (!hasMoov) {
|
|
5708
|
-
Log.trace(logLevel, "No moov box found, must wait");
|
|
5709
|
-
return {
|
|
5710
|
-
type: "valid-but-must-wait"
|
|
5711
|
-
};
|
|
5712
|
-
}
|
|
5713
5893
|
const firstVideoTrack = allTracks.find((t) => t.type === "video");
|
|
5714
|
-
|
|
5715
|
-
|
|
5894
|
+
const firstTrack = firstVideoTrack ?? allTracks.find((t) => t.type === "audio");
|
|
5895
|
+
if (!firstTrack) {
|
|
5896
|
+
throw new Error("no video and no audio tracks");
|
|
5716
5897
|
}
|
|
5717
|
-
const
|
|
5718
|
-
if (
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
const kf = findKeyframeBeforeTime({
|
|
5734
|
-
samplePositions: positions,
|
|
5735
|
-
time,
|
|
5736
|
-
timescale,
|
|
5737
|
-
logLevel,
|
|
5738
|
-
mediaSections: info.mediaSections
|
|
5739
|
-
});
|
|
5740
|
-
if (kf) {
|
|
5741
|
-
return {
|
|
5742
|
-
type: "do-seek",
|
|
5743
|
-
byte: kf
|
|
5744
|
-
};
|
|
5745
|
-
}
|
|
5746
|
-
}
|
|
5747
|
-
}
|
|
5748
|
-
const atom = await (info.mfraAlreadyLoaded ? Promise.resolve(info.mfraAlreadyLoaded) : isoState.mfra.triggerLoad());
|
|
5749
|
-
if (atom) {
|
|
5750
|
-
const moofOffset = findBestSegmentFromTfra({
|
|
5751
|
-
mfra: atom,
|
|
5898
|
+
const tkhdBox = getTkhdBox(firstTrack.trakBox);
|
|
5899
|
+
if (!tkhdBox) {
|
|
5900
|
+
throw new Error("Expected tkhd box in trak box");
|
|
5901
|
+
}
|
|
5902
|
+
const { samplePositions: samplePositionsArray } = collectSamplePositionsFromMoofBoxes({
|
|
5903
|
+
moofBoxes: info.moofBoxes,
|
|
5904
|
+
tfraBoxes: info.tfraBoxes,
|
|
5905
|
+
tkhdBox
|
|
5906
|
+
});
|
|
5907
|
+
Log.trace(logLevel, "Fragmented MP4 - Checking if we have seeking info for this time range");
|
|
5908
|
+
for (const positions of samplePositionsArray) {
|
|
5909
|
+
const { min, max } = getSamplePositionBounds(positions.samples, firstTrack.timescale);
|
|
5910
|
+
if (min <= time && (positions.isLastFragment || isLastChunkInPlaylist || time <= max)) {
|
|
5911
|
+
Log.trace(logLevel, `Fragmented MP4 - Found that we have seeking info for this time range: ${min} <= ${time} <= ${max}`);
|
|
5912
|
+
const kf = findKeyframeBeforeTime({
|
|
5913
|
+
samplePositions: positions.samples,
|
|
5752
5914
|
time,
|
|
5753
|
-
|
|
5754
|
-
|
|
5915
|
+
timescale: firstTrack.timescale,
|
|
5916
|
+
logLevel,
|
|
5917
|
+
mediaSections: info.mediaSections
|
|
5755
5918
|
});
|
|
5756
|
-
if (
|
|
5757
|
-
Log.verbose(logLevel, `Fragmented MP4 - Found based on mfra information that we should seek to: ${moofOffset.start} ${moofOffset.end}`);
|
|
5919
|
+
if (kf) {
|
|
5758
5920
|
return {
|
|
5759
|
-
type: "
|
|
5760
|
-
byte:
|
|
5921
|
+
type: "do-seek",
|
|
5922
|
+
byte: kf
|
|
5761
5923
|
};
|
|
5762
5924
|
}
|
|
5763
5925
|
}
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5926
|
+
}
|
|
5927
|
+
const atom = await (info.mfraAlreadyLoaded ? Promise.resolve(info.mfraAlreadyLoaded) : isoState.mfra.triggerLoad());
|
|
5928
|
+
if (atom) {
|
|
5929
|
+
const moofOffset = findBestSegmentFromTfra({
|
|
5930
|
+
mfra: atom,
|
|
5931
|
+
time,
|
|
5932
|
+
firstTrack,
|
|
5933
|
+
timescale: firstTrack.timescale
|
|
5934
|
+
});
|
|
5935
|
+
if (moofOffset !== null && !(moofOffset.start <= currentPosition && currentPosition < moofOffset.end)) {
|
|
5936
|
+
Log.verbose(logLevel, `Fragmented MP4 - Found based on mfra information that we should seek to: ${moofOffset.start} ${moofOffset.end}`);
|
|
5769
5937
|
return {
|
|
5770
|
-
type: "
|
|
5938
|
+
type: "intermediary-seek",
|
|
5939
|
+
byte: moofOffset.start
|
|
5771
5940
|
};
|
|
5772
5941
|
}
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
throw new Error("No video section defined");
|
|
5780
|
-
}
|
|
5942
|
+
}
|
|
5943
|
+
Log.trace(logLevel, "Fragmented MP4 - No seeking info found for this time range.");
|
|
5944
|
+
if (isByteInMediaSection({
|
|
5945
|
+
position: currentPosition,
|
|
5946
|
+
mediaSections: info.mediaSections
|
|
5947
|
+
}) !== "in-section") {
|
|
5781
5948
|
return {
|
|
5782
|
-
type: "
|
|
5783
|
-
byte: mediaSection.start + mediaSection.size
|
|
5949
|
+
type: "valid-but-must-wait"
|
|
5784
5950
|
};
|
|
5785
5951
|
}
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5952
|
+
Log.trace(logLevel, "Fragmented MP4 - Inside the wrong video section, skipping to the end of the section");
|
|
5953
|
+
const mediaSection = getCurrentMediaSection({
|
|
5954
|
+
offset: currentPosition,
|
|
5955
|
+
mediaSections: info.mediaSections
|
|
5790
5956
|
});
|
|
5791
|
-
if (!
|
|
5792
|
-
throw new Error("
|
|
5957
|
+
if (!mediaSection) {
|
|
5958
|
+
throw new Error("No video section defined");
|
|
5793
5959
|
}
|
|
5960
|
+
return {
|
|
5961
|
+
type: "intermediary-seek",
|
|
5962
|
+
byte: mediaSection.start + mediaSection.size
|
|
5963
|
+
};
|
|
5964
|
+
};
|
|
5965
|
+
|
|
5966
|
+
// src/containers/iso-base-media/get-seeking-byte.ts
|
|
5967
|
+
var getSeekingByteFromIsoBaseMedia = ({
|
|
5968
|
+
info,
|
|
5969
|
+
time,
|
|
5970
|
+
logLevel,
|
|
5971
|
+
currentPosition,
|
|
5972
|
+
isoState,
|
|
5973
|
+
m3uPlaylistContext,
|
|
5974
|
+
structure
|
|
5975
|
+
}) => {
|
|
5976
|
+
const tracks2 = getTracksFromIsoBaseMedia({
|
|
5977
|
+
isoState,
|
|
5978
|
+
m3uPlaylistContext,
|
|
5979
|
+
structure,
|
|
5980
|
+
mayUsePrecomputed: false
|
|
5981
|
+
});
|
|
5982
|
+
const allTracks = [
|
|
5983
|
+
...tracks2.videoTracks,
|
|
5984
|
+
...tracks2.audioTracks,
|
|
5985
|
+
...tracks2.otherTracks
|
|
5986
|
+
];
|
|
5987
|
+
const hasMoov = Boolean(getMoovBoxFromState({
|
|
5988
|
+
structureState: structure,
|
|
5989
|
+
isoState,
|
|
5990
|
+
mayUsePrecomputed: false,
|
|
5991
|
+
mp4HeaderSegment: m3uPlaylistContext?.mp4HeaderSegment ?? null
|
|
5992
|
+
}));
|
|
5993
|
+
if (!hasMoov) {
|
|
5994
|
+
Log.trace(logLevel, "No moov box found, must wait");
|
|
5995
|
+
return Promise.resolve({
|
|
5996
|
+
type: "valid-but-must-wait"
|
|
5997
|
+
});
|
|
5998
|
+
}
|
|
5999
|
+
if (info.moofBoxes.length > 0) {
|
|
6000
|
+
return getSeekingByteFromFragmentedMp4({
|
|
6001
|
+
info,
|
|
6002
|
+
time,
|
|
6003
|
+
logLevel,
|
|
6004
|
+
currentPosition,
|
|
6005
|
+
isoState,
|
|
6006
|
+
allTracks,
|
|
6007
|
+
isLastChunkInPlaylist: m3uPlaylistContext?.isLastChunkInPlaylist ?? false
|
|
6008
|
+
});
|
|
6009
|
+
}
|
|
6010
|
+
const trackWithSamplePositions = findTrackToSeek(allTracks, structure);
|
|
6011
|
+
if (!trackWithSamplePositions) {
|
|
6012
|
+
return Promise.resolve({
|
|
6013
|
+
type: "valid-but-must-wait"
|
|
6014
|
+
});
|
|
6015
|
+
}
|
|
6016
|
+
const { track, samplePositions } = trackWithSamplePositions;
|
|
5794
6017
|
const keyframe = findKeyframeBeforeTime({
|
|
5795
6018
|
samplePositions,
|
|
5796
6019
|
time,
|
|
5797
|
-
timescale,
|
|
6020
|
+
timescale: track.timescale,
|
|
5798
6021
|
logLevel,
|
|
5799
6022
|
mediaSections: info.mediaSections
|
|
5800
6023
|
});
|
|
5801
6024
|
if (keyframe) {
|
|
5802
|
-
return {
|
|
6025
|
+
return Promise.resolve({
|
|
5803
6026
|
type: "do-seek",
|
|
5804
6027
|
byte: keyframe
|
|
5805
|
-
};
|
|
6028
|
+
});
|
|
5806
6029
|
}
|
|
5807
|
-
return {
|
|
6030
|
+
return Promise.resolve({
|
|
5808
6031
|
type: "invalid"
|
|
6032
|
+
});
|
|
6033
|
+
};
|
|
6034
|
+
|
|
6035
|
+
// src/containers/m3u/get-seeking-byte.ts
|
|
6036
|
+
var clearM3uStateInPrepareForSeek = ({
|
|
6037
|
+
m3uState,
|
|
6038
|
+
logLevel
|
|
6039
|
+
}) => {
|
|
6040
|
+
const selectedPlaylists = m3uState.getSelectedPlaylists();
|
|
6041
|
+
for (const playlistUrl of selectedPlaylists) {
|
|
6042
|
+
const streamRun = m3uState.getM3uStreamRun(playlistUrl);
|
|
6043
|
+
if (streamRun) {
|
|
6044
|
+
streamRun.abort();
|
|
6045
|
+
}
|
|
6046
|
+
Log.trace(logLevel, "Clearing M3U stream run for", playlistUrl);
|
|
6047
|
+
m3uState.setM3uStreamRun(playlistUrl, null);
|
|
6048
|
+
}
|
|
6049
|
+
m3uState.clearAllChunksProcessed();
|
|
6050
|
+
m3uState.sampleSorter.clearSamples();
|
|
6051
|
+
};
|
|
6052
|
+
var getSeekingByteForM3u8 = ({
|
|
6053
|
+
time,
|
|
6054
|
+
currentPosition,
|
|
6055
|
+
m3uState,
|
|
6056
|
+
logLevel
|
|
6057
|
+
}) => {
|
|
6058
|
+
clearM3uStateInPrepareForSeek({ m3uState, logLevel });
|
|
6059
|
+
const selectedPlaylists = m3uState.getSelectedPlaylists();
|
|
6060
|
+
for (const playlistUrl of selectedPlaylists) {
|
|
6061
|
+
m3uState.setSeekToSecondsToProcess(playlistUrl, {
|
|
6062
|
+
targetTime: time
|
|
6063
|
+
});
|
|
6064
|
+
}
|
|
6065
|
+
return {
|
|
6066
|
+
type: "do-seek",
|
|
6067
|
+
byte: currentPosition
|
|
5809
6068
|
};
|
|
5810
6069
|
};
|
|
5811
6070
|
|
|
@@ -6742,9 +7001,10 @@ var getSeekingByte = ({
|
|
|
6742
7001
|
transportStream,
|
|
6743
7002
|
webmState,
|
|
6744
7003
|
mediaSection,
|
|
6745
|
-
|
|
7004
|
+
m3uPlaylistContext,
|
|
6746
7005
|
structure,
|
|
6747
|
-
riffState
|
|
7006
|
+
riffState,
|
|
7007
|
+
m3uState
|
|
6748
7008
|
}) => {
|
|
6749
7009
|
if (info.type === "iso-base-media-seeking-hints") {
|
|
6750
7010
|
return getSeekingByteFromIsoBaseMedia({
|
|
@@ -6753,8 +7013,8 @@ var getSeekingByte = ({
|
|
|
6753
7013
|
logLevel,
|
|
6754
7014
|
currentPosition,
|
|
6755
7015
|
isoState,
|
|
6756
|
-
|
|
6757
|
-
|
|
7016
|
+
structure,
|
|
7017
|
+
m3uPlaylistContext
|
|
6758
7018
|
});
|
|
6759
7019
|
}
|
|
6760
7020
|
if (info.type === "wav-seeking-hints") {
|
|
@@ -6819,6 +7079,14 @@ var getSeekingByte = ({
|
|
|
6819
7079
|
seekingHints: info
|
|
6820
7080
|
}));
|
|
6821
7081
|
}
|
|
7082
|
+
if (info.type === "m3u8-seeking-hints") {
|
|
7083
|
+
return Promise.resolve(getSeekingByteForM3u8({
|
|
7084
|
+
time,
|
|
7085
|
+
currentPosition,
|
|
7086
|
+
m3uState,
|
|
7087
|
+
logLevel
|
|
7088
|
+
}));
|
|
7089
|
+
}
|
|
6822
7090
|
throw new Error(`Unknown seeking info type: ${info}`);
|
|
6823
7091
|
};
|
|
6824
7092
|
|
|
@@ -6907,6 +7175,13 @@ var getSeekingHintsFromMp4 = ({
|
|
|
6907
7175
|
};
|
|
6908
7176
|
var setSeekingHintsForMp4 = ({}) => {};
|
|
6909
7177
|
|
|
7178
|
+
// src/containers/m3u/seeking-hints.ts
|
|
7179
|
+
var getSeekingHintsForM3u = () => {
|
|
7180
|
+
return {
|
|
7181
|
+
type: "m3u8-seeking-hints"
|
|
7182
|
+
};
|
|
7183
|
+
};
|
|
7184
|
+
|
|
6910
7185
|
// src/containers/mp3/seeking-hints.ts
|
|
6911
7186
|
var getSeekingHintsForMp3 = ({
|
|
6912
7187
|
mp3State,
|
|
@@ -7053,7 +7328,7 @@ var setSeekingHintsForWebm = ({
|
|
|
7053
7328
|
// src/get-seeking-hints.ts
|
|
7054
7329
|
var getSeekingHints = ({
|
|
7055
7330
|
structureState,
|
|
7056
|
-
|
|
7331
|
+
m3uPlaylistContext,
|
|
7057
7332
|
mediaSectionState: mediaSectionState2,
|
|
7058
7333
|
isoState,
|
|
7059
7334
|
transportStream,
|
|
@@ -7075,7 +7350,7 @@ var getSeekingHints = ({
|
|
|
7075
7350
|
return getSeekingHintsFromMp4({
|
|
7076
7351
|
structureState,
|
|
7077
7352
|
isoState,
|
|
7078
|
-
mp4HeaderSegment,
|
|
7353
|
+
mp4HeaderSegment: m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
7079
7354
|
mediaSectionState: mediaSectionState2
|
|
7080
7355
|
});
|
|
7081
7356
|
}
|
|
@@ -7118,7 +7393,10 @@ var getSeekingHints = ({
|
|
|
7118
7393
|
samplesObserved
|
|
7119
7394
|
});
|
|
7120
7395
|
}
|
|
7121
|
-
|
|
7396
|
+
if (structure.type === "m3u") {
|
|
7397
|
+
return getSeekingHintsForM3u();
|
|
7398
|
+
}
|
|
7399
|
+
throw new Error(`Seeking is not supported for this format: ${structure}`);
|
|
7122
7400
|
};
|
|
7123
7401
|
|
|
7124
7402
|
// src/seek-backwards.ts
|
|
@@ -7129,10 +7407,12 @@ var seekBackwards = async ({
|
|
|
7129
7407
|
src,
|
|
7130
7408
|
controller,
|
|
7131
7409
|
logLevel,
|
|
7132
|
-
currentReader
|
|
7410
|
+
currentReader,
|
|
7411
|
+
prefetchCache
|
|
7133
7412
|
}) => {
|
|
7134
7413
|
const howManyBytesWeCanGoBack = iterator.counter.getDiscardedOffset();
|
|
7135
7414
|
if (iterator.counter.getOffset() - howManyBytesWeCanGoBack <= seekTo) {
|
|
7415
|
+
Log.verbose(logLevel, `Seeking back to ${seekTo}`);
|
|
7136
7416
|
iterator.skipTo(seekTo);
|
|
7137
7417
|
return;
|
|
7138
7418
|
}
|
|
@@ -7141,7 +7421,9 @@ var seekBackwards = async ({
|
|
|
7141
7421
|
const { reader: newReader } = await readerInterface.read({
|
|
7142
7422
|
src,
|
|
7143
7423
|
range: seekTo,
|
|
7144
|
-
controller
|
|
7424
|
+
controller,
|
|
7425
|
+
logLevel,
|
|
7426
|
+
prefetchCache
|
|
7145
7427
|
});
|
|
7146
7428
|
iterator.replaceData(new Uint8Array([]), seekTo);
|
|
7147
7429
|
Log.verbose(logLevel, `Re-reading took ${Date.now() - time}ms. New position: ${iterator.counter.getOffset()}`);
|
|
@@ -7211,7 +7493,8 @@ var seekForward = async ({
|
|
|
7211
7493
|
readerInterface,
|
|
7212
7494
|
src,
|
|
7213
7495
|
controller,
|
|
7214
|
-
discardReadBytes
|
|
7496
|
+
discardReadBytes,
|
|
7497
|
+
prefetchCache
|
|
7215
7498
|
}) => {
|
|
7216
7499
|
if (userInitiated) {
|
|
7217
7500
|
disallowForwardSeekIfSamplesAreNeeded({
|
|
@@ -7232,7 +7515,9 @@ var seekForward = async ({
|
|
|
7232
7515
|
const { reader: newReader } = await readerInterface.read({
|
|
7233
7516
|
src,
|
|
7234
7517
|
range: seekTo,
|
|
7235
|
-
controller
|
|
7518
|
+
controller,
|
|
7519
|
+
logLevel,
|
|
7520
|
+
prefetchCache
|
|
7236
7521
|
});
|
|
7237
7522
|
iterator.skipTo(seekTo);
|
|
7238
7523
|
await discardReadBytes(true);
|
|
@@ -7255,7 +7540,8 @@ var performSeek = async ({
|
|
|
7255
7540
|
readerInterface,
|
|
7256
7541
|
src,
|
|
7257
7542
|
discardReadBytes,
|
|
7258
|
-
fields
|
|
7543
|
+
fields,
|
|
7544
|
+
prefetchCache
|
|
7259
7545
|
}) => {
|
|
7260
7546
|
const byteInMediaSection = isByteInMediaSection({
|
|
7261
7547
|
position: seekTo,
|
|
@@ -7304,7 +7590,8 @@ var performSeek = async ({
|
|
|
7304
7590
|
readerInterface,
|
|
7305
7591
|
src,
|
|
7306
7592
|
controller,
|
|
7307
|
-
discardReadBytes
|
|
7593
|
+
discardReadBytes,
|
|
7594
|
+
prefetchCache
|
|
7308
7595
|
});
|
|
7309
7596
|
} else {
|
|
7310
7597
|
await seekBackwards({
|
|
@@ -7314,7 +7601,8 @@ var performSeek = async ({
|
|
|
7314
7601
|
logLevel,
|
|
7315
7602
|
currentReader,
|
|
7316
7603
|
readerInterface,
|
|
7317
|
-
src
|
|
7604
|
+
src,
|
|
7605
|
+
prefetchCache
|
|
7318
7606
|
});
|
|
7319
7607
|
}
|
|
7320
7608
|
await controller._internals.checkForAbortAndPause();
|
|
@@ -7327,7 +7615,7 @@ var turnSeekIntoByte = async ({
|
|
|
7327
7615
|
logLevel,
|
|
7328
7616
|
iterator,
|
|
7329
7617
|
structureState,
|
|
7330
|
-
|
|
7618
|
+
m3uPlaylistContext,
|
|
7331
7619
|
isoState,
|
|
7332
7620
|
transportStream,
|
|
7333
7621
|
tracksState,
|
|
@@ -7338,7 +7626,8 @@ var turnSeekIntoByte = async ({
|
|
|
7338
7626
|
riffState,
|
|
7339
7627
|
mp3State,
|
|
7340
7628
|
contentLength,
|
|
7341
|
-
aacState
|
|
7629
|
+
aacState,
|
|
7630
|
+
m3uState
|
|
7342
7631
|
}) => {
|
|
7343
7632
|
const mediaSections = mediaSectionState2.getMediaSections();
|
|
7344
7633
|
if (mediaSections.length === 0) {
|
|
@@ -7355,7 +7644,6 @@ var turnSeekIntoByte = async ({
|
|
|
7355
7644
|
riffState,
|
|
7356
7645
|
samplesObserved,
|
|
7357
7646
|
structureState,
|
|
7358
|
-
mp4HeaderSegment,
|
|
7359
7647
|
mediaSectionState: mediaSectionState2,
|
|
7360
7648
|
isoState,
|
|
7361
7649
|
transportStream,
|
|
@@ -7365,7 +7653,8 @@ var turnSeekIntoByte = async ({
|
|
|
7365
7653
|
flacState,
|
|
7366
7654
|
mp3State,
|
|
7367
7655
|
contentLength,
|
|
7368
|
-
aacState
|
|
7656
|
+
aacState,
|
|
7657
|
+
m3uPlaylistContext
|
|
7369
7658
|
});
|
|
7370
7659
|
if (!seekingHints) {
|
|
7371
7660
|
Log.trace(logLevel, "No seeking info, cannot seek yet");
|
|
@@ -7382,18 +7671,13 @@ var turnSeekIntoByte = async ({
|
|
|
7382
7671
|
transportStream,
|
|
7383
7672
|
webmState,
|
|
7384
7673
|
mediaSection: mediaSectionState2,
|
|
7385
|
-
|
|
7674
|
+
m3uPlaylistContext,
|
|
7386
7675
|
structure: structureState,
|
|
7387
|
-
riffState
|
|
7676
|
+
riffState,
|
|
7677
|
+
m3uState
|
|
7388
7678
|
});
|
|
7389
7679
|
return seekingByte;
|
|
7390
7680
|
}
|
|
7391
|
-
if (seek2.type === "byte") {
|
|
7392
|
-
return {
|
|
7393
|
-
type: "do-seek",
|
|
7394
|
-
byte: seek2.byte
|
|
7395
|
-
};
|
|
7396
|
-
}
|
|
7397
7681
|
throw new Error(`Cannot process seek request for ${seek2}: ${JSON.stringify(seek2)}`);
|
|
7398
7682
|
};
|
|
7399
7683
|
var getWorkOnSeekRequestOptions = (state) => {
|
|
@@ -7407,7 +7691,7 @@ var getWorkOnSeekRequestOptions = (state) => {
|
|
|
7407
7691
|
contentLength: state.contentLength,
|
|
7408
7692
|
readerInterface: state.readerInterface,
|
|
7409
7693
|
mediaSection: state.mediaSection,
|
|
7410
|
-
|
|
7694
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
7411
7695
|
mode: state.mode,
|
|
7412
7696
|
seekInfiniteLoop: state.seekInfiniteLoop,
|
|
7413
7697
|
currentReader: state.currentReader,
|
|
@@ -7421,7 +7705,9 @@ var getWorkOnSeekRequestOptions = (state) => {
|
|
|
7421
7705
|
samplesObserved: state.samplesObserved,
|
|
7422
7706
|
riffState: state.riff,
|
|
7423
7707
|
mp3State: state.mp3,
|
|
7424
|
-
aacState: state.aac
|
|
7708
|
+
aacState: state.aac,
|
|
7709
|
+
m3uState: state.m3u,
|
|
7710
|
+
prefetchCache: state.prefetchCache
|
|
7425
7711
|
};
|
|
7426
7712
|
};
|
|
7427
7713
|
var workOnSeekRequest = async (options) => {
|
|
@@ -7429,7 +7715,7 @@ var workOnSeekRequest = async (options) => {
|
|
|
7429
7715
|
logLevel,
|
|
7430
7716
|
controller,
|
|
7431
7717
|
mediaSection,
|
|
7432
|
-
|
|
7718
|
+
m3uPlaylistContext,
|
|
7433
7719
|
isoState,
|
|
7434
7720
|
iterator,
|
|
7435
7721
|
structureState,
|
|
@@ -7449,20 +7735,22 @@ var workOnSeekRequest = async (options) => {
|
|
|
7449
7735
|
samplesObserved,
|
|
7450
7736
|
riffState,
|
|
7451
7737
|
mp3State,
|
|
7452
|
-
aacState
|
|
7738
|
+
aacState,
|
|
7739
|
+
prefetchCache,
|
|
7740
|
+
m3uState
|
|
7453
7741
|
} = options;
|
|
7454
7742
|
const seek2 = controller._internals.seekSignal.getSeek();
|
|
7455
7743
|
if (!seek2) {
|
|
7456
7744
|
return;
|
|
7457
7745
|
}
|
|
7458
|
-
Log.trace(logLevel, `Has seek request: ${JSON.stringify(seek2)}`);
|
|
7746
|
+
Log.trace(logLevel, `Has seek request for ${src}: ${JSON.stringify(seek2)}`);
|
|
7459
7747
|
const resolution = await turnSeekIntoByte({
|
|
7460
7748
|
seek: seek2,
|
|
7461
7749
|
mediaSectionState: mediaSection,
|
|
7462
7750
|
logLevel,
|
|
7463
7751
|
iterator,
|
|
7464
7752
|
structureState,
|
|
7465
|
-
|
|
7753
|
+
m3uPlaylistContext,
|
|
7466
7754
|
isoState,
|
|
7467
7755
|
transportStream,
|
|
7468
7756
|
tracksState,
|
|
@@ -7473,7 +7761,8 @@ var workOnSeekRequest = async (options) => {
|
|
|
7473
7761
|
riffState,
|
|
7474
7762
|
mp3State,
|
|
7475
7763
|
contentLength,
|
|
7476
|
-
aacState
|
|
7764
|
+
aacState,
|
|
7765
|
+
m3uState
|
|
7477
7766
|
});
|
|
7478
7767
|
Log.trace(logLevel, `Seek action: ${JSON.stringify(resolution)}`);
|
|
7479
7768
|
if (resolution.type === "intermediary-seek") {
|
|
@@ -7491,7 +7780,8 @@ var workOnSeekRequest = async (options) => {
|
|
|
7491
7780
|
readerInterface,
|
|
7492
7781
|
src,
|
|
7493
7782
|
discardReadBytes,
|
|
7494
|
-
fields
|
|
7783
|
+
fields,
|
|
7784
|
+
prefetchCache
|
|
7495
7785
|
});
|
|
7496
7786
|
return;
|
|
7497
7787
|
}
|
|
@@ -7510,7 +7800,8 @@ var workOnSeekRequest = async (options) => {
|
|
|
7510
7800
|
readerInterface,
|
|
7511
7801
|
src,
|
|
7512
7802
|
discardReadBytes,
|
|
7513
|
-
fields
|
|
7803
|
+
fields,
|
|
7804
|
+
prefetchCache
|
|
7514
7805
|
});
|
|
7515
7806
|
const { hasChanged } = controller._internals.seekSignal.clearSeekIfStillSame(seek2);
|
|
7516
7807
|
if (hasChanged) {
|
|
@@ -8136,6 +8427,10 @@ var makeSkip = (skipTo) => ({
|
|
|
8136
8427
|
action: "skip",
|
|
8137
8428
|
skipTo
|
|
8138
8429
|
});
|
|
8430
|
+
var makeFetchMoreData = (bytesNeeded) => ({
|
|
8431
|
+
action: "fetch-more-data",
|
|
8432
|
+
bytesNeeded
|
|
8433
|
+
});
|
|
8139
8434
|
|
|
8140
8435
|
// src/containers/flac/get-block-size.ts
|
|
8141
8436
|
var getBlockSize = (iterator) => {
|
|
@@ -8590,11 +8885,12 @@ var calculateFlatSamples = (state) => {
|
|
|
8590
8885
|
samplePosition
|
|
8591
8886
|
};
|
|
8592
8887
|
});
|
|
8593
|
-
})
|
|
8888
|
+
});
|
|
8594
8889
|
return flatSamples;
|
|
8595
8890
|
};
|
|
8596
8891
|
var cachedSamplePositionsState = () => {
|
|
8597
8892
|
const cachedForMdatStart = {};
|
|
8893
|
+
const jumpMarksForMdatStart = {};
|
|
8598
8894
|
return {
|
|
8599
8895
|
getSamples: (mdatStart) => {
|
|
8600
8896
|
if (cachedForMdatStart[mdatStart]) {
|
|
@@ -8604,6 +8900,12 @@ var cachedSamplePositionsState = () => {
|
|
|
8604
8900
|
},
|
|
8605
8901
|
setSamples: (mdatStart, samples) => {
|
|
8606
8902
|
cachedForMdatStart[mdatStart] = samples;
|
|
8903
|
+
},
|
|
8904
|
+
setJumpMarks: (mdatStart, marks) => {
|
|
8905
|
+
jumpMarksForMdatStart[mdatStart] = marks;
|
|
8906
|
+
},
|
|
8907
|
+
getJumpMarks: (mdatStart) => {
|
|
8908
|
+
return jumpMarksForMdatStart[mdatStart];
|
|
8607
8909
|
}
|
|
8608
8910
|
};
|
|
8609
8911
|
};
|
|
@@ -8633,17 +8935,21 @@ var makeCanSkipTracksState = ({
|
|
|
8633
8935
|
hasVideoTrackHandlers,
|
|
8634
8936
|
structure
|
|
8635
8937
|
}) => {
|
|
8938
|
+
const doFieldsNeedTracks = () => {
|
|
8939
|
+
const keys = Object.keys(fields ?? {});
|
|
8940
|
+
const selectedKeys = keys.filter((k) => fields[k]);
|
|
8941
|
+
return selectedKeys.some((k) => needsTracksForField({
|
|
8942
|
+
field: k,
|
|
8943
|
+
structure: structure.getStructureOrNull()
|
|
8944
|
+
}));
|
|
8945
|
+
};
|
|
8636
8946
|
return {
|
|
8947
|
+
doFieldsNeedTracks,
|
|
8637
8948
|
canSkipTracks: () => {
|
|
8638
8949
|
if (hasAudioTrackHandlers || hasVideoTrackHandlers) {
|
|
8639
8950
|
return false;
|
|
8640
8951
|
}
|
|
8641
|
-
|
|
8642
|
-
const selectedKeys = keys.filter((k) => fields[k]);
|
|
8643
|
-
return !selectedKeys.some((k) => needsTracksForField({
|
|
8644
|
-
field: k,
|
|
8645
|
-
structure: structure.getStructureOrNull()
|
|
8646
|
-
}));
|
|
8952
|
+
return !doFieldsNeedTracks();
|
|
8647
8953
|
}
|
|
8648
8954
|
};
|
|
8649
8955
|
};
|
|
@@ -8934,10 +9240,10 @@ var getIsoBaseMediaChildren = async ({
|
|
|
8934
9240
|
onlyIfMdatAtomExpected: null,
|
|
8935
9241
|
contentLength
|
|
8936
9242
|
});
|
|
8937
|
-
if (
|
|
9243
|
+
if (parsed.type !== "box") {
|
|
8938
9244
|
throw new Error("Expected box");
|
|
8939
9245
|
}
|
|
8940
|
-
boxes.push(parsed);
|
|
9246
|
+
boxes.push(parsed.box);
|
|
8941
9247
|
}
|
|
8942
9248
|
if (iterator.counter.getOffset() > size + initial) {
|
|
8943
9249
|
throw new Error(`read too many bytes - size: ${size}, read: ${iterator.counter.getOffset() - initial}. initial offset: ${initial}`);
|
|
@@ -9637,7 +9943,7 @@ var parseStsc = ({
|
|
|
9637
9943
|
}
|
|
9638
9944
|
const flags = iterator.getSlice(3);
|
|
9639
9945
|
const entryCount = iterator.getUint32();
|
|
9640
|
-
const entries =
|
|
9946
|
+
const entries = new Map;
|
|
9641
9947
|
for (let i = 0;i < entryCount; i++) {
|
|
9642
9948
|
const firstChunk = iterator.getUint32();
|
|
9643
9949
|
const samplesPerChunk = iterator.getUint32();
|
|
@@ -9645,10 +9951,7 @@ var parseStsc = ({
|
|
|
9645
9951
|
if (sampleDescriptionIndex !== 1) {
|
|
9646
9952
|
throw new Error(`Expected sampleDescriptionIndex to be 1, but got ${sampleDescriptionIndex}`);
|
|
9647
9953
|
}
|
|
9648
|
-
entries.
|
|
9649
|
-
firstChunk,
|
|
9650
|
-
samplesPerChunk
|
|
9651
|
-
});
|
|
9954
|
+
entries.set(firstChunk, samplesPerChunk);
|
|
9652
9955
|
}
|
|
9653
9956
|
return {
|
|
9654
9957
|
type: "stsc-box",
|
|
@@ -9719,7 +10022,8 @@ var audioTags = [
|
|
|
9719
10022
|
1836253269,
|
|
9720
10023
|
".mp3",
|
|
9721
10024
|
"mp4a",
|
|
9722
|
-
"ac-3"
|
|
10025
|
+
"ac-3",
|
|
10026
|
+
"Opus"
|
|
9723
10027
|
];
|
|
9724
10028
|
var processIsoFormatBox = async ({
|
|
9725
10029
|
iterator,
|
|
@@ -9992,9 +10296,9 @@ var parseStss = ({
|
|
|
9992
10296
|
}
|
|
9993
10297
|
const flags = iterator.getSlice(3);
|
|
9994
10298
|
const sampleCount = iterator.getUint32();
|
|
9995
|
-
const sampleNumber =
|
|
10299
|
+
const sampleNumber = new Set;
|
|
9996
10300
|
for (let i = 0;i < sampleCount; i++) {
|
|
9997
|
-
sampleNumber.
|
|
10301
|
+
sampleNumber.add(iterator.getUint32());
|
|
9998
10302
|
}
|
|
9999
10303
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - offset);
|
|
10000
10304
|
if (bytesRemainingInBox > 0) {
|
|
@@ -10310,8 +10614,11 @@ var processBox = async ({
|
|
|
10310
10614
|
const boxSizeRaw = iterator.getFourByteNumber();
|
|
10311
10615
|
if (boxSizeRaw === 0) {
|
|
10312
10616
|
return {
|
|
10313
|
-
type: "
|
|
10314
|
-
|
|
10617
|
+
type: "box",
|
|
10618
|
+
box: {
|
|
10619
|
+
type: "void-box",
|
|
10620
|
+
boxSize: 0
|
|
10621
|
+
}
|
|
10315
10622
|
};
|
|
10316
10623
|
}
|
|
10317
10624
|
if (boxSizeRaw === 1 && iterator.bytesRemaining() < 12 || iterator.bytesRemaining() < 4) {
|
|
@@ -10325,120 +10632,177 @@ var processBox = async ({
|
|
|
10325
10632
|
const headerLength = iterator.counter.getOffset() - startOff;
|
|
10326
10633
|
if (boxType === "mdat") {
|
|
10327
10634
|
if (!onlyIfMdatAtomExpected) {
|
|
10328
|
-
return
|
|
10635
|
+
return { type: "nothing" };
|
|
10329
10636
|
}
|
|
10330
10637
|
const { mediaSectionState: mediaSectionState2 } = onlyIfMdatAtomExpected;
|
|
10331
10638
|
mediaSectionState2.addMediaSection({
|
|
10332
10639
|
size: boxSize - headerLength,
|
|
10333
10640
|
start: iterator.counter.getOffset()
|
|
10334
10641
|
});
|
|
10335
|
-
return
|
|
10642
|
+
return { type: "nothing" };
|
|
10336
10643
|
}
|
|
10337
10644
|
if (bytesRemaining < boxSize) {
|
|
10338
10645
|
returnToCheckpoint();
|
|
10339
|
-
return
|
|
10646
|
+
return {
|
|
10647
|
+
type: "fetch-more-data",
|
|
10648
|
+
bytesNeeded: makeFetchMoreData(boxSize - bytesRemaining)
|
|
10649
|
+
};
|
|
10340
10650
|
}
|
|
10341
10651
|
if (boxType === "ftyp") {
|
|
10342
|
-
return
|
|
10652
|
+
return {
|
|
10653
|
+
type: "box",
|
|
10654
|
+
box: await parseFtyp({ iterator, size: boxSize, offset: fileOffset })
|
|
10655
|
+
};
|
|
10343
10656
|
}
|
|
10344
10657
|
if (boxType === "colr") {
|
|
10345
|
-
return
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10658
|
+
return {
|
|
10659
|
+
type: "box",
|
|
10660
|
+
box: await parseColorParameterBox({
|
|
10661
|
+
iterator,
|
|
10662
|
+
size: boxSize
|
|
10663
|
+
})
|
|
10664
|
+
};
|
|
10349
10665
|
}
|
|
10350
10666
|
if (boxType === "mvhd") {
|
|
10351
|
-
return
|
|
10667
|
+
return {
|
|
10668
|
+
type: "box",
|
|
10669
|
+
box: await parseMvhd({ iterator, offset: fileOffset, size: boxSize })
|
|
10670
|
+
};
|
|
10352
10671
|
}
|
|
10353
10672
|
if (boxType === "tkhd") {
|
|
10354
|
-
return
|
|
10673
|
+
return {
|
|
10674
|
+
type: "box",
|
|
10675
|
+
box: await parseTkhd({ iterator, offset: fileOffset, size: boxSize })
|
|
10676
|
+
};
|
|
10355
10677
|
}
|
|
10356
10678
|
if (boxType === "trun") {
|
|
10357
|
-
return
|
|
10679
|
+
return {
|
|
10680
|
+
type: "box",
|
|
10681
|
+
box: await parseTrun({ iterator, offset: fileOffset, size: boxSize })
|
|
10682
|
+
};
|
|
10358
10683
|
}
|
|
10359
10684
|
if (boxType === "tfdt") {
|
|
10360
|
-
return
|
|
10685
|
+
return {
|
|
10686
|
+
type: "box",
|
|
10687
|
+
box: await parseTfdt({ iterator, size: boxSize, offset: fileOffset })
|
|
10688
|
+
};
|
|
10361
10689
|
}
|
|
10362
10690
|
if (boxType === "stsd") {
|
|
10363
|
-
return
|
|
10364
|
-
|
|
10365
|
-
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10691
|
+
return {
|
|
10692
|
+
type: "box",
|
|
10693
|
+
box: await parseStsd({
|
|
10694
|
+
offset: fileOffset,
|
|
10695
|
+
size: boxSize,
|
|
10696
|
+
iterator,
|
|
10697
|
+
logLevel,
|
|
10698
|
+
contentLength
|
|
10699
|
+
})
|
|
10700
|
+
};
|
|
10370
10701
|
}
|
|
10371
10702
|
if (boxType === "stsz") {
|
|
10372
|
-
return
|
|
10373
|
-
|
|
10374
|
-
|
|
10375
|
-
|
|
10376
|
-
|
|
10703
|
+
return {
|
|
10704
|
+
type: "box",
|
|
10705
|
+
box: await parseStsz({
|
|
10706
|
+
iterator,
|
|
10707
|
+
offset: fileOffset,
|
|
10708
|
+
size: boxSize
|
|
10709
|
+
})
|
|
10710
|
+
};
|
|
10377
10711
|
}
|
|
10378
10712
|
if (boxType === "stco" || boxType === "co64") {
|
|
10379
|
-
return
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10713
|
+
return {
|
|
10714
|
+
type: "box",
|
|
10715
|
+
box: await parseStco({
|
|
10716
|
+
iterator,
|
|
10717
|
+
offset: fileOffset,
|
|
10718
|
+
size: boxSize,
|
|
10719
|
+
mode64Bit: boxType === "co64"
|
|
10720
|
+
})
|
|
10721
|
+
};
|
|
10385
10722
|
}
|
|
10386
10723
|
if (boxType === "pasp") {
|
|
10387
|
-
return
|
|
10388
|
-
|
|
10389
|
-
|
|
10390
|
-
|
|
10391
|
-
|
|
10724
|
+
return {
|
|
10725
|
+
type: "box",
|
|
10726
|
+
box: await parsePasp({
|
|
10727
|
+
iterator,
|
|
10728
|
+
offset: fileOffset,
|
|
10729
|
+
size: boxSize
|
|
10730
|
+
})
|
|
10731
|
+
};
|
|
10392
10732
|
}
|
|
10393
10733
|
if (boxType === "stss") {
|
|
10394
|
-
return
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
|
|
10398
|
-
|
|
10734
|
+
return {
|
|
10735
|
+
type: "box",
|
|
10736
|
+
box: await parseStss({
|
|
10737
|
+
iterator,
|
|
10738
|
+
offset: fileOffset,
|
|
10739
|
+
boxSize
|
|
10740
|
+
})
|
|
10741
|
+
};
|
|
10399
10742
|
}
|
|
10400
10743
|
if (boxType === "ctts") {
|
|
10401
|
-
return
|
|
10402
|
-
|
|
10403
|
-
|
|
10404
|
-
|
|
10405
|
-
|
|
10744
|
+
return {
|
|
10745
|
+
type: "box",
|
|
10746
|
+
box: await parseCtts({
|
|
10747
|
+
iterator,
|
|
10748
|
+
offset: fileOffset,
|
|
10749
|
+
size: boxSize
|
|
10750
|
+
})
|
|
10751
|
+
};
|
|
10406
10752
|
}
|
|
10407
10753
|
if (boxType === "stsc") {
|
|
10408
|
-
return
|
|
10409
|
-
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
|
|
10754
|
+
return {
|
|
10755
|
+
type: "box",
|
|
10756
|
+
box: await parseStsc({
|
|
10757
|
+
iterator,
|
|
10758
|
+
offset: fileOffset,
|
|
10759
|
+
size: boxSize
|
|
10760
|
+
})
|
|
10761
|
+
};
|
|
10413
10762
|
}
|
|
10414
10763
|
if (boxType === "mebx") {
|
|
10415
|
-
return
|
|
10416
|
-
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10420
|
-
|
|
10421
|
-
|
|
10764
|
+
return {
|
|
10765
|
+
type: "box",
|
|
10766
|
+
box: await parseMebx({
|
|
10767
|
+
offset: fileOffset,
|
|
10768
|
+
size: boxSize,
|
|
10769
|
+
iterator,
|
|
10770
|
+
logLevel,
|
|
10771
|
+
contentLength
|
|
10772
|
+
})
|
|
10773
|
+
};
|
|
10422
10774
|
}
|
|
10423
10775
|
if (boxType === "hdlr") {
|
|
10424
|
-
return
|
|
10776
|
+
return {
|
|
10777
|
+
type: "box",
|
|
10778
|
+
box: await parseHdlr({ iterator, size: boxSize, offset: fileOffset })
|
|
10779
|
+
};
|
|
10425
10780
|
}
|
|
10426
10781
|
if (boxType === "keys") {
|
|
10427
|
-
return
|
|
10782
|
+
return {
|
|
10783
|
+
type: "box",
|
|
10784
|
+
box: await parseKeys({ iterator, size: boxSize, offset: fileOffset })
|
|
10785
|
+
};
|
|
10428
10786
|
}
|
|
10429
10787
|
if (boxType === "ilst") {
|
|
10430
|
-
return
|
|
10431
|
-
|
|
10432
|
-
|
|
10433
|
-
|
|
10434
|
-
|
|
10788
|
+
return {
|
|
10789
|
+
type: "box",
|
|
10790
|
+
box: await parseIlstBox({
|
|
10791
|
+
iterator,
|
|
10792
|
+
offset: fileOffset,
|
|
10793
|
+
size: boxSize
|
|
10794
|
+
})
|
|
10795
|
+
};
|
|
10435
10796
|
}
|
|
10436
10797
|
if (boxType === "tfra") {
|
|
10437
|
-
return
|
|
10438
|
-
|
|
10439
|
-
|
|
10440
|
-
|
|
10441
|
-
|
|
10798
|
+
return {
|
|
10799
|
+
type: "box",
|
|
10800
|
+
box: await parseTfraBox({
|
|
10801
|
+
iterator,
|
|
10802
|
+
offset: fileOffset,
|
|
10803
|
+
size: boxSize
|
|
10804
|
+
})
|
|
10805
|
+
};
|
|
10442
10806
|
}
|
|
10443
10807
|
if (boxType === "moov") {
|
|
10444
10808
|
if (!onlyIfMoovAtomExpected) {
|
|
@@ -10447,12 +10811,12 @@ var processBox = async ({
|
|
|
10447
10811
|
const { tracks: tracks2, isoState } = onlyIfMoovAtomExpected;
|
|
10448
10812
|
if (tracks2.hasAllTracks()) {
|
|
10449
10813
|
iterator.discard(boxSize - 8);
|
|
10450
|
-
return
|
|
10814
|
+
return { type: "nothing" };
|
|
10451
10815
|
}
|
|
10452
10816
|
if (isoState && isoState.moov.getMoovBoxAndPrecomputed() && !isoState.moov.getMoovBoxAndPrecomputed()?.precomputed) {
|
|
10453
10817
|
Log.verbose(logLevel, "Moov box already parsed, skipping");
|
|
10454
10818
|
iterator.discard(boxSize - 8);
|
|
10455
|
-
return
|
|
10819
|
+
return { type: "nothing" };
|
|
10456
10820
|
}
|
|
10457
10821
|
const box = await parseMoov({
|
|
10458
10822
|
offset: fileOffset,
|
|
@@ -10463,7 +10827,7 @@ var processBox = async ({
|
|
|
10463
10827
|
contentLength
|
|
10464
10828
|
});
|
|
10465
10829
|
tracks2.setIsDone(logLevel);
|
|
10466
|
-
return box;
|
|
10830
|
+
return { type: "box", box };
|
|
10467
10831
|
}
|
|
10468
10832
|
if (boxType === "trak") {
|
|
10469
10833
|
if (!onlyIfMoovAtomExpected) {
|
|
@@ -10498,54 +10862,75 @@ var processBox = async ({
|
|
|
10498
10862
|
onAudioTrack
|
|
10499
10863
|
});
|
|
10500
10864
|
}
|
|
10501
|
-
return box;
|
|
10865
|
+
return { type: "box", box };
|
|
10502
10866
|
}
|
|
10503
10867
|
if (boxType === "stts") {
|
|
10504
|
-
return
|
|
10505
|
-
|
|
10506
|
-
|
|
10507
|
-
|
|
10508
|
-
|
|
10868
|
+
return {
|
|
10869
|
+
type: "box",
|
|
10870
|
+
box: await parseStts({
|
|
10871
|
+
data: iterator,
|
|
10872
|
+
size: boxSize,
|
|
10873
|
+
fileOffset
|
|
10874
|
+
})
|
|
10875
|
+
};
|
|
10509
10876
|
}
|
|
10510
10877
|
if (boxType === "avcC") {
|
|
10511
|
-
return
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10878
|
+
return {
|
|
10879
|
+
type: "box",
|
|
10880
|
+
box: await parseAvcc({
|
|
10881
|
+
data: iterator,
|
|
10882
|
+
size: boxSize
|
|
10883
|
+
})
|
|
10884
|
+
};
|
|
10515
10885
|
}
|
|
10516
10886
|
if (boxType === "av1C") {
|
|
10517
|
-
return
|
|
10518
|
-
|
|
10519
|
-
|
|
10520
|
-
|
|
10887
|
+
return {
|
|
10888
|
+
type: "box",
|
|
10889
|
+
box: await parseAv1C({
|
|
10890
|
+
data: iterator,
|
|
10891
|
+
size: boxSize
|
|
10892
|
+
})
|
|
10893
|
+
};
|
|
10521
10894
|
}
|
|
10522
10895
|
if (boxType === "hvcC") {
|
|
10523
|
-
return
|
|
10524
|
-
|
|
10525
|
-
|
|
10526
|
-
|
|
10527
|
-
|
|
10896
|
+
return {
|
|
10897
|
+
type: "box",
|
|
10898
|
+
box: await parseHvcc({
|
|
10899
|
+
data: iterator,
|
|
10900
|
+
size: boxSize,
|
|
10901
|
+
offset: fileOffset
|
|
10902
|
+
})
|
|
10903
|
+
};
|
|
10528
10904
|
}
|
|
10529
10905
|
if (boxType === "tfhd") {
|
|
10530
|
-
return
|
|
10531
|
-
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10906
|
+
return {
|
|
10907
|
+
type: "box",
|
|
10908
|
+
box: await getTfhd({
|
|
10909
|
+
iterator,
|
|
10910
|
+
offset: fileOffset,
|
|
10911
|
+
size: boxSize
|
|
10912
|
+
})
|
|
10913
|
+
};
|
|
10535
10914
|
}
|
|
10536
10915
|
if (boxType === "mdhd") {
|
|
10537
|
-
return
|
|
10538
|
-
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10916
|
+
return {
|
|
10917
|
+
type: "box",
|
|
10918
|
+
box: await parseMdhd({
|
|
10919
|
+
data: iterator,
|
|
10920
|
+
size: boxSize,
|
|
10921
|
+
fileOffset
|
|
10922
|
+
})
|
|
10923
|
+
};
|
|
10542
10924
|
}
|
|
10543
10925
|
if (boxType === "esds") {
|
|
10544
|
-
return
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
|
|
10926
|
+
return {
|
|
10927
|
+
type: "box",
|
|
10928
|
+
box: await parseEsds({
|
|
10929
|
+
data: iterator,
|
|
10930
|
+
size: boxSize,
|
|
10931
|
+
fileOffset
|
|
10932
|
+
})
|
|
10933
|
+
};
|
|
10549
10934
|
}
|
|
10550
10935
|
if (boxType === "moof") {
|
|
10551
10936
|
onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
|
|
@@ -10559,20 +10944,26 @@ var processBox = async ({
|
|
|
10559
10944
|
contentLength
|
|
10560
10945
|
});
|
|
10561
10946
|
return {
|
|
10562
|
-
type: "
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10947
|
+
type: "box",
|
|
10948
|
+
box: {
|
|
10949
|
+
type: "regular-box",
|
|
10950
|
+
boxType,
|
|
10951
|
+
boxSize,
|
|
10952
|
+
children,
|
|
10953
|
+
offset: fileOffset
|
|
10954
|
+
}
|
|
10567
10955
|
};
|
|
10568
10956
|
}
|
|
10569
10957
|
iterator.discard(boxSize - 8);
|
|
10570
10958
|
return {
|
|
10571
|
-
type: "
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10959
|
+
type: "box",
|
|
10960
|
+
box: {
|
|
10961
|
+
type: "regular-box",
|
|
10962
|
+
boxType,
|
|
10963
|
+
boxSize,
|
|
10964
|
+
children: [],
|
|
10965
|
+
offset: fileOffset
|
|
10966
|
+
}
|
|
10576
10967
|
};
|
|
10577
10968
|
};
|
|
10578
10969
|
|
|
@@ -10581,7 +10972,7 @@ var getMoovAtom = async ({
|
|
|
10581
10972
|
endOfMdat,
|
|
10582
10973
|
state
|
|
10583
10974
|
}) => {
|
|
10584
|
-
const headerSegment = state.mp4HeaderSegment;
|
|
10975
|
+
const headerSegment = state.m3uPlaylistContext?.mp4HeaderSegment;
|
|
10585
10976
|
if (headerSegment) {
|
|
10586
10977
|
const segment = getMoovFromFromIsoStructure(headerSegment);
|
|
10587
10978
|
if (!segment) {
|
|
@@ -10594,7 +10985,9 @@ var getMoovAtom = async ({
|
|
|
10594
10985
|
const { reader } = await state.readerInterface.read({
|
|
10595
10986
|
src: state.src,
|
|
10596
10987
|
range: endOfMdat,
|
|
10597
|
-
controller: state.controller
|
|
10988
|
+
controller: state.controller,
|
|
10989
|
+
logLevel: state.logLevel,
|
|
10990
|
+
prefetchCache: state.prefetchCache
|
|
10598
10991
|
});
|
|
10599
10992
|
const onAudioTrack = state.onAudioTrack ? async ({ track, container }) => {
|
|
10600
10993
|
await registerAudioTrack({
|
|
@@ -10651,8 +11044,8 @@ var getMoovAtom = async ({
|
|
|
10651
11044
|
onlyIfMdatAtomExpected: null,
|
|
10652
11045
|
contentLength: state.contentLength - endOfMdat
|
|
10653
11046
|
});
|
|
10654
|
-
if (box) {
|
|
10655
|
-
boxes.push(box);
|
|
11047
|
+
if (box.type === "box") {
|
|
11048
|
+
boxes.push(box.box);
|
|
10656
11049
|
}
|
|
10657
11050
|
if (iterator.counter.getOffset() + endOfMdat > state.contentLength) {
|
|
10658
11051
|
throw new Error("Read past end of file");
|
|
@@ -10669,6 +11062,121 @@ var getMoovAtom = async ({
|
|
|
10669
11062
|
return moov;
|
|
10670
11063
|
};
|
|
10671
11064
|
|
|
11065
|
+
// src/containers/iso-base-media/mdat/calculate-jump-marks.ts
|
|
11066
|
+
var MAX_SPREAD_IN_SECONDS = 8;
|
|
11067
|
+
var getKey = (samplePositionTrack) => {
|
|
11068
|
+
return `${samplePositionTrack.track.trackId}-${samplePositionTrack.samplePosition.dts}`;
|
|
11069
|
+
};
|
|
11070
|
+
var findBestJump = ({
|
|
11071
|
+
allSamplesSortedByOffset,
|
|
11072
|
+
visited,
|
|
11073
|
+
progresses
|
|
11074
|
+
}) => {
|
|
11075
|
+
const minProgress = Math.min(...Object.values(progresses));
|
|
11076
|
+
const trackNumberWithLowestProgress = Object.entries(progresses).find(([, progress]) => progress === minProgress)?.[0];
|
|
11077
|
+
const firstSampleAboveMinProgress = allSamplesSortedByOffset.findIndex((sample) => sample.track.trackId === Number(trackNumberWithLowestProgress) && !visited.has(getKey(sample)));
|
|
11078
|
+
return firstSampleAboveMinProgress;
|
|
11079
|
+
};
|
|
11080
|
+
var calculateJumpMarks = (samplePositionTracks, endOfMdat) => {
|
|
11081
|
+
const progresses = {};
|
|
11082
|
+
for (const track of samplePositionTracks) {
|
|
11083
|
+
progresses[track[0].track.trackId] = 0;
|
|
11084
|
+
}
|
|
11085
|
+
const jumpMarks = [];
|
|
11086
|
+
const allSamplesSortedByOffset = samplePositionTracks.flat(1).sort((a, b) => a.samplePosition.offset - b.samplePosition.offset);
|
|
11087
|
+
let indexToVisit = 0;
|
|
11088
|
+
const visited = new Set;
|
|
11089
|
+
let rollOverToProcess = false;
|
|
11090
|
+
const increaseIndex = () => {
|
|
11091
|
+
indexToVisit++;
|
|
11092
|
+
if (indexToVisit >= allSamplesSortedByOffset.length) {
|
|
11093
|
+
rollOverToProcess = true;
|
|
11094
|
+
indexToVisit = 0;
|
|
11095
|
+
}
|
|
11096
|
+
};
|
|
11097
|
+
let lastVisitedSample = null;
|
|
11098
|
+
const addJumpMark = ({
|
|
11099
|
+
firstSampleAboveMinProgress
|
|
11100
|
+
}) => {
|
|
11101
|
+
if (!lastVisitedSample) {
|
|
11102
|
+
throw new Error("no last visited sample");
|
|
11103
|
+
}
|
|
11104
|
+
const jumpMark = {
|
|
11105
|
+
afterSampleWithOffset: lastVisitedSample.samplePosition.offset,
|
|
11106
|
+
jumpToOffset: allSamplesSortedByOffset[firstSampleAboveMinProgress].samplePosition.offset
|
|
11107
|
+
};
|
|
11108
|
+
indexToVisit = firstSampleAboveMinProgress;
|
|
11109
|
+
jumpMarks.push(jumpMark);
|
|
11110
|
+
};
|
|
11111
|
+
const addFinalJumpIfNecessary = () => {
|
|
11112
|
+
if (indexToVisit === allSamplesSortedByOffset.length - 1) {
|
|
11113
|
+
return;
|
|
11114
|
+
}
|
|
11115
|
+
jumpMarks.push({
|
|
11116
|
+
afterSampleWithOffset: allSamplesSortedByOffset[indexToVisit].samplePosition.offset,
|
|
11117
|
+
jumpToOffset: endOfMdat
|
|
11118
|
+
});
|
|
11119
|
+
};
|
|
11120
|
+
const considerJump = () => {
|
|
11121
|
+
const firstSampleAboveMinProgress = findBestJump({
|
|
11122
|
+
allSamplesSortedByOffset,
|
|
11123
|
+
visited,
|
|
11124
|
+
progresses
|
|
11125
|
+
});
|
|
11126
|
+
if (firstSampleAboveMinProgress > -1 && firstSampleAboveMinProgress !== indexToVisit + 1) {
|
|
11127
|
+
addJumpMark({ firstSampleAboveMinProgress });
|
|
11128
|
+
indexToVisit = firstSampleAboveMinProgress;
|
|
11129
|
+
} else {
|
|
11130
|
+
while (true) {
|
|
11131
|
+
increaseIndex();
|
|
11132
|
+
if (!visited.has(getKey(allSamplesSortedByOffset[indexToVisit]))) {
|
|
11133
|
+
break;
|
|
11134
|
+
}
|
|
11135
|
+
}
|
|
11136
|
+
}
|
|
11137
|
+
};
|
|
11138
|
+
while (true) {
|
|
11139
|
+
const currentSamplePosition = allSamplesSortedByOffset[indexToVisit];
|
|
11140
|
+
const sampleKey = getKey(currentSamplePosition);
|
|
11141
|
+
if (visited.has(sampleKey)) {
|
|
11142
|
+
considerJump();
|
|
11143
|
+
continue;
|
|
11144
|
+
}
|
|
11145
|
+
visited.add(sampleKey);
|
|
11146
|
+
if (rollOverToProcess) {
|
|
11147
|
+
if (!lastVisitedSample) {
|
|
11148
|
+
throw new Error("no last visited sample");
|
|
11149
|
+
}
|
|
11150
|
+
jumpMarks.push({
|
|
11151
|
+
afterSampleWithOffset: lastVisitedSample.samplePosition.offset,
|
|
11152
|
+
jumpToOffset: currentSamplePosition.samplePosition.offset
|
|
11153
|
+
});
|
|
11154
|
+
rollOverToProcess = false;
|
|
11155
|
+
}
|
|
11156
|
+
lastVisitedSample = currentSamplePosition;
|
|
11157
|
+
if (visited.size === allSamplesSortedByOffset.length) {
|
|
11158
|
+
addFinalJumpIfNecessary();
|
|
11159
|
+
break;
|
|
11160
|
+
}
|
|
11161
|
+
const timestamp = currentSamplePosition.samplePosition.dts / currentSamplePosition.track.timescale;
|
|
11162
|
+
progresses[currentSamplePosition.track.trackId] = timestamp;
|
|
11163
|
+
const progressValues = Object.values(progresses);
|
|
11164
|
+
const maxProgress = Math.max(...progressValues);
|
|
11165
|
+
const minProgress = Math.min(...progressValues);
|
|
11166
|
+
const spread = maxProgress - minProgress;
|
|
11167
|
+
if (visited.size === allSamplesSortedByOffset.length) {
|
|
11168
|
+
addFinalJumpIfNecessary();
|
|
11169
|
+
break;
|
|
11170
|
+
}
|
|
11171
|
+
if (spread > MAX_SPREAD_IN_SECONDS) {
|
|
11172
|
+
considerJump();
|
|
11173
|
+
} else {
|
|
11174
|
+
increaseIndex();
|
|
11175
|
+
}
|
|
11176
|
+
}
|
|
11177
|
+
return jumpMarks;
|
|
11178
|
+
};
|
|
11179
|
+
|
|
10672
11180
|
// src/containers/iso-base-media/mdat/postprocess-bytes.ts
|
|
10673
11181
|
var postprocessBytes = ({
|
|
10674
11182
|
bytes,
|
|
@@ -10718,9 +11226,13 @@ var parseMdatSection = async (state) => {
|
|
|
10718
11226
|
return parseMdatSection(state);
|
|
10719
11227
|
}
|
|
10720
11228
|
if (!state.iso.flatSamples.getSamples(mediaSection.start)) {
|
|
10721
|
-
|
|
11229
|
+
const flattedSamples = calculateFlatSamples(state);
|
|
11230
|
+
const calcedJumpMarks = calculateJumpMarks(flattedSamples, endOfMdat);
|
|
11231
|
+
state.iso.flatSamples.setJumpMarks(mediaSection.start, calcedJumpMarks);
|
|
11232
|
+
state.iso.flatSamples.setSamples(mediaSection.start, flattedSamples.flat(1));
|
|
10722
11233
|
}
|
|
10723
11234
|
const flatSamples = state.iso.flatSamples.getSamples(mediaSection.start);
|
|
11235
|
+
const jumpMarks = state.iso.flatSamples.getJumpMarks(mediaSection.start);
|
|
10724
11236
|
const { iterator } = state;
|
|
10725
11237
|
const samplesWithIndex = flatSamples.find((sample) => {
|
|
10726
11238
|
return sample.samplePosition.offset === iterator.counter.getOffset();
|
|
@@ -10733,8 +11245,11 @@ var parseMdatSection = async (state) => {
|
|
|
10733
11245
|
}
|
|
10734
11246
|
return makeSkip(endOfMdat);
|
|
10735
11247
|
}
|
|
11248
|
+
if (samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size > state.contentLength) {
|
|
11249
|
+
return makeSkip(endOfMdat);
|
|
11250
|
+
}
|
|
10736
11251
|
if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
|
|
10737
|
-
return
|
|
11252
|
+
return makeFetchMoreData(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
|
|
10738
11253
|
}
|
|
10739
11254
|
const { cts, dts, duration: duration2, isKeyframe, offset, bigEndian, chunkSize } = samplesWithIndex.samplePosition;
|
|
10740
11255
|
const bytes = postprocessBytes({
|
|
@@ -10782,6 +11297,10 @@ var parseMdatSection = async (state) => {
|
|
|
10782
11297
|
});
|
|
10783
11298
|
await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, videoSample);
|
|
10784
11299
|
}
|
|
11300
|
+
const jump = jumpMarks.find((j) => j.afterSampleWithOffset === offset);
|
|
11301
|
+
if (jump) {
|
|
11302
|
+
return makeSkip(jump.jumpToOffset);
|
|
11303
|
+
}
|
|
10785
11304
|
return null;
|
|
10786
11305
|
};
|
|
10787
11306
|
|
|
@@ -10808,8 +11327,11 @@ var parseIsoBaseMedia = async (state) => {
|
|
|
10808
11327
|
},
|
|
10809
11328
|
contentLength: state.contentLength
|
|
10810
11329
|
});
|
|
10811
|
-
if (result) {
|
|
10812
|
-
|
|
11330
|
+
if (result.type === "fetch-more-data") {
|
|
11331
|
+
return result.bytesNeeded;
|
|
11332
|
+
}
|
|
11333
|
+
if (result.type === "box") {
|
|
11334
|
+
state.structure.getIsoStructure().boxes.push(result.box);
|
|
10813
11335
|
}
|
|
10814
11336
|
return null;
|
|
10815
11337
|
};
|
|
@@ -10888,7 +11410,8 @@ var parseM3uMediaDirective = (str) => {
|
|
|
10888
11410
|
groupId: map["GROUP-ID"],
|
|
10889
11411
|
language: map.LANGUAGE || null,
|
|
10890
11412
|
name: map.NAME || null,
|
|
10891
|
-
uri: map.URI
|
|
11413
|
+
uri: map.URI,
|
|
11414
|
+
mediaType: map.TYPE || null
|
|
10892
11415
|
};
|
|
10893
11416
|
};
|
|
10894
11417
|
|
|
@@ -11048,7 +11571,9 @@ var afterManifestFetch = async ({
|
|
|
11048
11571
|
selectM3uStreamFn,
|
|
11049
11572
|
logLevel,
|
|
11050
11573
|
selectAssociatedPlaylistsFn,
|
|
11051
|
-
readerInterface
|
|
11574
|
+
readerInterface,
|
|
11575
|
+
onAudioTrack,
|
|
11576
|
+
canSkipTracks
|
|
11052
11577
|
}) => {
|
|
11053
11578
|
const independentSegments = isIndependentSegments(structure);
|
|
11054
11579
|
if (!independentSegments) {
|
|
@@ -11073,9 +11598,11 @@ var afterManifestFetch = async ({
|
|
|
11073
11598
|
type: "selected-stream",
|
|
11074
11599
|
stream: selectedPlaylist
|
|
11075
11600
|
});
|
|
11601
|
+
const skipAudioTracks = onAudioTrack === null && canSkipTracks.doFieldsNeedTracks() === false;
|
|
11076
11602
|
const associatedPlaylists = await selectAssociatedPlaylists({
|
|
11077
11603
|
playlists: selectedPlaylist.associatedPlaylists,
|
|
11078
|
-
fn: selectAssociatedPlaylistsFn
|
|
11604
|
+
fn: selectAssociatedPlaylistsFn,
|
|
11605
|
+
skipAudioTracks
|
|
11079
11606
|
});
|
|
11080
11607
|
m3uState.setAssociatedPlaylists(associatedPlaylists);
|
|
11081
11608
|
const playlistUrls = [
|
|
@@ -11159,6 +11686,12 @@ var webReader = {
|
|
|
11159
11686
|
return webFileReadWholeAsText(src);
|
|
11160
11687
|
}
|
|
11161
11688
|
return fetchReadWholeAsText(src);
|
|
11689
|
+
},
|
|
11690
|
+
preload: ({ range: range2, src, logLevel, prefetchCache }) => {
|
|
11691
|
+
if (src instanceof Blob) {
|
|
11692
|
+
return;
|
|
11693
|
+
}
|
|
11694
|
+
return fetchPreload({ range: range2, src, logLevel, prefetchCache });
|
|
11162
11695
|
}
|
|
11163
11696
|
};
|
|
11164
11697
|
// src/parse-media.ts
|
|
@@ -11202,7 +11735,7 @@ var parseMedia = (options) => {
|
|
|
11202
11735
|
controller: options.controller ?? undefined,
|
|
11203
11736
|
selectM3uStream: options.selectM3uStream ?? defaultSelectM3uStreamFn,
|
|
11204
11737
|
selectM3uAssociatedPlaylists: options.selectM3uAssociatedPlaylists ?? defaultSelectM3uAssociatedPlaylists,
|
|
11205
|
-
|
|
11738
|
+
m3uPlaylistContext: options.m3uPlaylistContext ?? null,
|
|
11206
11739
|
src: options.src,
|
|
11207
11740
|
mode: "query",
|
|
11208
11741
|
onDiscardedData: null,
|
|
@@ -11214,6 +11747,39 @@ var parseMedia = (options) => {
|
|
|
11214
11747
|
});
|
|
11215
11748
|
};
|
|
11216
11749
|
|
|
11750
|
+
// src/containers/m3u/first-sample-in-m3u-chunk.ts
|
|
11751
|
+
var considerSeekBasedOnChunk = async ({
|
|
11752
|
+
sample,
|
|
11753
|
+
parentController,
|
|
11754
|
+
childController,
|
|
11755
|
+
callback,
|
|
11756
|
+
m3uState,
|
|
11757
|
+
playlistUrl,
|
|
11758
|
+
subtractChunks,
|
|
11759
|
+
chunkIndex
|
|
11760
|
+
}) => {
|
|
11761
|
+
const pendingSeek = m3uState.getSeekToSecondsToProcess(playlistUrl);
|
|
11762
|
+
if (pendingSeek === null) {
|
|
11763
|
+
await callback(sample);
|
|
11764
|
+
return;
|
|
11765
|
+
}
|
|
11766
|
+
const timestamp = Math.min(sample.dts / sample.timescale, sample.cts / sample.timescale);
|
|
11767
|
+
if (timestamp > pendingSeek.targetTime && chunkIndex !== null && chunkIndex > 0) {
|
|
11768
|
+
m3uState.setNextSeekShouldSubtractChunks(playlistUrl, subtractChunks + 1);
|
|
11769
|
+
parentController.seek({
|
|
11770
|
+
type: "keyframe-before-time",
|
|
11771
|
+
timeInSeconds: pendingSeek.targetTime
|
|
11772
|
+
});
|
|
11773
|
+
return;
|
|
11774
|
+
}
|
|
11775
|
+
childController.seek({
|
|
11776
|
+
type: "keyframe-before-time",
|
|
11777
|
+
timeInSeconds: pendingSeek.targetTime
|
|
11778
|
+
});
|
|
11779
|
+
m3uState.setNextSeekShouldSubtractChunks(playlistUrl, 0);
|
|
11780
|
+
m3uState.setSeekToSecondsToProcess(playlistUrl, null);
|
|
11781
|
+
};
|
|
11782
|
+
|
|
11217
11783
|
// src/containers/m3u/get-chunks.ts
|
|
11218
11784
|
var getChunks = (playlist) => {
|
|
11219
11785
|
const chunks = [];
|
|
@@ -11231,127 +11797,282 @@ var getChunks = (playlist) => {
|
|
|
11231
11797
|
}
|
|
11232
11798
|
chunks.push({ duration: box.value, url: nextBox.value, isHeader: false });
|
|
11233
11799
|
}
|
|
11234
|
-
continue;
|
|
11800
|
+
continue;
|
|
11801
|
+
}
|
|
11802
|
+
return chunks;
|
|
11803
|
+
};
|
|
11804
|
+
|
|
11805
|
+
// src/containers/m3u/seek/get-chunk-to-seek-to.ts
|
|
11806
|
+
var getChunkToSeekTo = ({
|
|
11807
|
+
chunks,
|
|
11808
|
+
seekToSecondsToProcess
|
|
11809
|
+
}) => {
|
|
11810
|
+
let duration2 = 0;
|
|
11811
|
+
for (let i = 0;i < chunks.length; i++) {
|
|
11812
|
+
if (duration2 >= seekToSecondsToProcess) {
|
|
11813
|
+
return Math.max(0, i - 1);
|
|
11814
|
+
}
|
|
11815
|
+
duration2 += chunks[i].duration;
|
|
11235
11816
|
}
|
|
11236
|
-
return chunks;
|
|
11817
|
+
return Math.max(0, chunks.length - 1);
|
|
11237
11818
|
};
|
|
11238
11819
|
|
|
11239
|
-
// src/containers/m3u/
|
|
11240
|
-
var
|
|
11241
|
-
structure,
|
|
11242
|
-
onVideoTrack,
|
|
11243
|
-
m3uState,
|
|
11244
|
-
onAudioTrack,
|
|
11245
|
-
onDoneWithTracks,
|
|
11820
|
+
// src/containers/m3u/process-m3u-chunk.ts
|
|
11821
|
+
var processM3uChunk = ({
|
|
11246
11822
|
playlistUrl,
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11823
|
+
state,
|
|
11824
|
+
structure,
|
|
11825
|
+
audioDone,
|
|
11826
|
+
videoDone
|
|
11251
11827
|
}) => {
|
|
11252
|
-
const
|
|
11253
|
-
const
|
|
11254
|
-
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
const
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11828
|
+
const { promise, reject, resolve } = withResolvers();
|
|
11829
|
+
const onGlobalAudioTrack = audioDone ? null : async (track) => {
|
|
11830
|
+
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11831
|
+
let { trackId } = track;
|
|
11832
|
+
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11833
|
+
trackId++;
|
|
11834
|
+
}
|
|
11835
|
+
const onAudioSample = await registerAudioTrack({
|
|
11836
|
+
container: "m3u8",
|
|
11837
|
+
track: {
|
|
11838
|
+
...track,
|
|
11839
|
+
trackId
|
|
11840
|
+
},
|
|
11841
|
+
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
11842
|
+
tracks: state.callbacks.tracks,
|
|
11843
|
+
logLevel: state.logLevel,
|
|
11844
|
+
onAudioTrack: state.onAudioTrack
|
|
11263
11845
|
});
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
return promise;
|
|
11272
|
-
},
|
|
11273
|
-
abort() {
|
|
11274
|
-
childController.abort();
|
|
11275
|
-
}
|
|
11276
|
-
};
|
|
11846
|
+
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11847
|
+
if (onAudioSample === null) {
|
|
11848
|
+
return null;
|
|
11849
|
+
}
|
|
11850
|
+
state.m3u.sampleSorter.addAudioStreamToConsider(playlistUrl, onAudioSample);
|
|
11851
|
+
return async (sample) => {
|
|
11852
|
+
await state.m3u.sampleSorter.addAudioSample(playlistUrl, sample);
|
|
11277
11853
|
};
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
const
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11854
|
+
};
|
|
11855
|
+
const onGlobalVideoTrack = videoDone ? null : async (track) => {
|
|
11856
|
+
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11857
|
+
let { trackId } = track;
|
|
11858
|
+
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11859
|
+
trackId++;
|
|
11860
|
+
}
|
|
11861
|
+
const onVideoSample = await registerVideoTrack({
|
|
11862
|
+
container: "m3u8",
|
|
11863
|
+
track: {
|
|
11864
|
+
...track,
|
|
11865
|
+
trackId
|
|
11866
|
+
},
|
|
11867
|
+
logLevel: state.logLevel,
|
|
11868
|
+
onVideoTrack: state.onVideoTrack,
|
|
11869
|
+
registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
|
|
11870
|
+
tracks: state.callbacks.tracks
|
|
11871
|
+
});
|
|
11872
|
+
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11873
|
+
if (onVideoSample === null) {
|
|
11874
|
+
return null;
|
|
11875
|
+
}
|
|
11876
|
+
state.m3u.sampleSorter.addVideoStreamToConsider(playlistUrl, onVideoSample);
|
|
11877
|
+
return async (sample) => {
|
|
11878
|
+
await state.m3u.sampleSorter.addVideoSample(playlistUrl, sample);
|
|
11879
|
+
};
|
|
11880
|
+
};
|
|
11881
|
+
const pausableIterator = async () => {
|
|
11882
|
+
const playlist = getPlaylist(structure, playlistUrl);
|
|
11883
|
+
const chunks = getChunks(playlist);
|
|
11884
|
+
const seekToSecondsToProcess = state.m3u.getSeekToSecondsToProcess(playlistUrl);
|
|
11885
|
+
const chunksToSubtract = state.m3u.getNextSeekShouldSubtractChunks(playlistUrl);
|
|
11886
|
+
let chunkIndex = null;
|
|
11887
|
+
if (seekToSecondsToProcess !== null) {
|
|
11888
|
+
chunkIndex = Math.max(0, getChunkToSeekTo({
|
|
11889
|
+
chunks,
|
|
11890
|
+
seekToSecondsToProcess: seekToSecondsToProcess.targetTime
|
|
11891
|
+
}) - chunksToSubtract);
|
|
11892
|
+
}
|
|
11893
|
+
const currentPromise = {
|
|
11894
|
+
resolver: () => {
|
|
11895
|
+
return;
|
|
11896
|
+
},
|
|
11897
|
+
rejector: reject
|
|
11898
|
+
};
|
|
11899
|
+
const requiresHeaderToBeFetched = chunks[0].isHeader;
|
|
11900
|
+
for (const chunk of chunks) {
|
|
11901
|
+
const mp4HeaderSegment = state.m3u.getMp4HeaderSegment(playlistUrl);
|
|
11902
|
+
if (requiresHeaderToBeFetched && mp4HeaderSegment && chunk.isHeader) {
|
|
11903
|
+
continue;
|
|
11904
|
+
}
|
|
11905
|
+
if (chunkIndex !== null && chunks.indexOf(chunk) < chunkIndex && !chunk.isHeader) {
|
|
11906
|
+
continue;
|
|
11907
|
+
}
|
|
11908
|
+
currentPromise.resolver = (newRun) => {
|
|
11909
|
+
state.m3u.setM3uStreamRun(playlistUrl, newRun);
|
|
11910
|
+
resolve();
|
|
11911
|
+
};
|
|
11912
|
+
currentPromise.rejector = reject;
|
|
11913
|
+
const childController = mediaParserController();
|
|
11914
|
+
const forwarded = forwardMediaParserControllerPauseResume({
|
|
11915
|
+
childController,
|
|
11916
|
+
parentController: state.controller
|
|
11917
|
+
});
|
|
11918
|
+
const nextChunk = chunks[chunks.indexOf(chunk) + 1];
|
|
11919
|
+
if (nextChunk) {
|
|
11920
|
+
const nextChunkSource = state.readerInterface.createAdjacentFileSource(nextChunk.url, playlistUrl);
|
|
11921
|
+
state.readerInterface.preload({
|
|
11922
|
+
logLevel: state.logLevel,
|
|
11923
|
+
range: null,
|
|
11924
|
+
src: nextChunkSource,
|
|
11925
|
+
prefetchCache: state.prefetchCache
|
|
11926
|
+
});
|
|
11927
|
+
}
|
|
11928
|
+
const makeContinuationFn = () => {
|
|
11929
|
+
return {
|
|
11930
|
+
continue() {
|
|
11931
|
+
const resolver = withResolvers();
|
|
11932
|
+
currentPromise.resolver = resolver.resolve;
|
|
11933
|
+
currentPromise.rejector = resolver.reject;
|
|
11934
|
+
childController.resume();
|
|
11935
|
+
return resolver.promise;
|
|
11936
|
+
},
|
|
11937
|
+
abort() {
|
|
11938
|
+
childController.abort();
|
|
11299
11939
|
}
|
|
11300
|
-
}
|
|
11301
|
-
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11940
|
+
};
|
|
11941
|
+
};
|
|
11942
|
+
const isLastChunk = chunk === chunks[chunks.length - 1];
|
|
11943
|
+
await childController._internals.checkForAbortAndPause();
|
|
11944
|
+
const src = state.readerInterface.createAdjacentFileSource(chunk.url, playlistUrl);
|
|
11945
|
+
try {
|
|
11946
|
+
const data = await parseMedia({
|
|
11947
|
+
src,
|
|
11948
|
+
acknowledgeRemotionLicense: true,
|
|
11949
|
+
logLevel: state.logLevel,
|
|
11950
|
+
controller: childController,
|
|
11951
|
+
progressIntervalInMs: 0,
|
|
11952
|
+
onParseProgress: () => {
|
|
11953
|
+
childController.pause();
|
|
11954
|
+
currentPromise.resolver(makeContinuationFn());
|
|
11955
|
+
},
|
|
11956
|
+
fields: chunk.isHeader ? { structure: true } : undefined,
|
|
11957
|
+
onTracks: () => {
|
|
11958
|
+
if (!state.m3u.hasEmittedDoneWithTracks(playlistUrl)) {
|
|
11959
|
+
state.m3u.setHasEmittedDoneWithTracks(playlistUrl);
|
|
11960
|
+
const allDone = state.m3u.setTracksDone(playlistUrl);
|
|
11961
|
+
if (allDone) {
|
|
11962
|
+
state.callbacks.tracks.setIsDone(state.logLevel);
|
|
11963
|
+
}
|
|
11964
|
+
return null;
|
|
11965
|
+
}
|
|
11966
|
+
},
|
|
11967
|
+
onAudioTrack: onGlobalAudioTrack === null ? null : async ({ track }) => {
|
|
11968
|
+
const callbackOrFalse = state.m3u.hasEmittedAudioTrack(playlistUrl);
|
|
11969
|
+
if (callbackOrFalse === false) {
|
|
11970
|
+
const callback = await onGlobalAudioTrack(track);
|
|
11971
|
+
if (!callback) {
|
|
11972
|
+
state.m3u.setHasEmittedAudioTrack(playlistUrl, null);
|
|
11973
|
+
return null;
|
|
11974
|
+
}
|
|
11975
|
+
state.m3u.setHasEmittedAudioTrack(playlistUrl, callback);
|
|
11976
|
+
return async (sample) => {
|
|
11977
|
+
await considerSeekBasedOnChunk({
|
|
11978
|
+
sample,
|
|
11979
|
+
callback,
|
|
11980
|
+
parentController: state.controller,
|
|
11981
|
+
childController,
|
|
11982
|
+
m3uState: state.m3u,
|
|
11983
|
+
playlistUrl,
|
|
11984
|
+
subtractChunks: chunksToSubtract,
|
|
11985
|
+
chunkIndex
|
|
11986
|
+
});
|
|
11987
|
+
};
|
|
11988
|
+
}
|
|
11989
|
+
if (callbackOrFalse === null) {
|
|
11307
11990
|
return null;
|
|
11308
11991
|
}
|
|
11309
|
-
|
|
11310
|
-
|
|
11311
|
-
|
|
11992
|
+
return async (sample) => {
|
|
11993
|
+
await considerSeekBasedOnChunk({
|
|
11994
|
+
sample,
|
|
11995
|
+
m3uState: state.m3u,
|
|
11996
|
+
playlistUrl,
|
|
11997
|
+
callback: callbackOrFalse,
|
|
11998
|
+
parentController: state.controller,
|
|
11999
|
+
childController,
|
|
12000
|
+
subtractChunks: chunksToSubtract,
|
|
12001
|
+
chunkIndex
|
|
12002
|
+
});
|
|
11312
12003
|
};
|
|
11313
|
-
}
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
|
|
11318
|
-
|
|
11319
|
-
|
|
11320
|
-
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
|
|
12004
|
+
},
|
|
12005
|
+
onVideoTrack: onGlobalVideoTrack === null ? null : async ({ track }) => {
|
|
12006
|
+
const callbackOrFalse = state.m3u.hasEmittedVideoTrack(playlistUrl);
|
|
12007
|
+
if (callbackOrFalse === false) {
|
|
12008
|
+
const callback = await onGlobalVideoTrack({
|
|
12009
|
+
...track,
|
|
12010
|
+
m3uStreamFormat: chunk.isHeader || mp4HeaderSegment ? "mp4" : "ts"
|
|
12011
|
+
});
|
|
12012
|
+
if (!callback) {
|
|
12013
|
+
state.m3u.setHasEmittedVideoTrack(playlistUrl, null);
|
|
12014
|
+
return null;
|
|
12015
|
+
}
|
|
12016
|
+
state.m3u.setHasEmittedVideoTrack(playlistUrl, callback);
|
|
12017
|
+
return async (sample) => {
|
|
12018
|
+
await considerSeekBasedOnChunk({
|
|
12019
|
+
sample,
|
|
12020
|
+
m3uState: state.m3u,
|
|
12021
|
+
playlistUrl,
|
|
12022
|
+
callback,
|
|
12023
|
+
parentController: state.controller,
|
|
12024
|
+
childController,
|
|
12025
|
+
subtractChunks: chunksToSubtract,
|
|
12026
|
+
chunkIndex
|
|
12027
|
+
});
|
|
12028
|
+
};
|
|
12029
|
+
}
|
|
12030
|
+
if (callbackOrFalse === null) {
|
|
11325
12031
|
return null;
|
|
11326
12032
|
}
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
12033
|
+
return async (sample) => {
|
|
12034
|
+
await considerSeekBasedOnChunk({
|
|
12035
|
+
sample,
|
|
12036
|
+
m3uState: state.m3u,
|
|
12037
|
+
playlistUrl,
|
|
12038
|
+
callback: callbackOrFalse,
|
|
12039
|
+
parentController: state.controller,
|
|
12040
|
+
childController,
|
|
12041
|
+
subtractChunks: chunksToSubtract,
|
|
12042
|
+
chunkIndex
|
|
12043
|
+
});
|
|
11330
12044
|
};
|
|
12045
|
+
},
|
|
12046
|
+
reader: state.readerInterface,
|
|
12047
|
+
makeSamplesStartAtZero: false,
|
|
12048
|
+
m3uPlaylistContext: {
|
|
12049
|
+
mp4HeaderSegment,
|
|
12050
|
+
isLastChunkInPlaylist: isLastChunk
|
|
11331
12051
|
}
|
|
11332
|
-
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
if (chunk.isHeader) {
|
|
11339
|
-
if (data.structure.type !== "iso-base-media") {
|
|
11340
|
-
throw new Error("Expected an mp4 file");
|
|
12052
|
+
});
|
|
12053
|
+
if (chunk.isHeader) {
|
|
12054
|
+
if (data.structure.type !== "iso-base-media") {
|
|
12055
|
+
throw new Error("Expected an mp4 file");
|
|
12056
|
+
}
|
|
12057
|
+
state.m3u.setMp4HeaderSegment(playlistUrl, data.structure);
|
|
11341
12058
|
}
|
|
11342
|
-
|
|
12059
|
+
} catch (e) {
|
|
12060
|
+
currentPromise.rejector(e);
|
|
12061
|
+
throw e;
|
|
12062
|
+
}
|
|
12063
|
+
forwarded.cleanup();
|
|
12064
|
+
if (!isLastChunk) {
|
|
12065
|
+
childController.pause();
|
|
12066
|
+
currentPromise.resolver(makeContinuationFn());
|
|
11343
12067
|
}
|
|
11344
|
-
} catch (e) {
|
|
11345
|
-
rejector(e);
|
|
11346
|
-
throw e;
|
|
11347
|
-
}
|
|
11348
|
-
forwarded.cleanup();
|
|
11349
|
-
if (!isLastChunk) {
|
|
11350
|
-
childController.pause();
|
|
11351
|
-
resolver(makeContinuationFn());
|
|
11352
12068
|
}
|
|
11353
|
-
|
|
11354
|
-
|
|
12069
|
+
currentPromise.resolver(null);
|
|
12070
|
+
};
|
|
12071
|
+
const run = pausableIterator();
|
|
12072
|
+
run.catch((err) => {
|
|
12073
|
+
reject(err);
|
|
12074
|
+
});
|
|
12075
|
+
return promise;
|
|
11355
12076
|
};
|
|
11356
12077
|
|
|
11357
12078
|
// src/containers/m3u/run-over-m3u.ts
|
|
@@ -11382,80 +12103,12 @@ var runOverM3u = async ({
|
|
|
11382
12103
|
return;
|
|
11383
12104
|
}
|
|
11384
12105
|
Log.trace(logLevel, "Starting new M3U parsing process for", playlistUrl);
|
|
11385
|
-
|
|
11386
|
-
|
|
11387
|
-
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
resolve();
|
|
11392
|
-
},
|
|
11393
|
-
logLevel: state.logLevel,
|
|
11394
|
-
onDoneWithTracks() {
|
|
11395
|
-
const allDone = state.m3u.setTracksDone(playlistUrl);
|
|
11396
|
-
if (allDone) {
|
|
11397
|
-
state.callbacks.tracks.setIsDone(state.logLevel);
|
|
11398
|
-
}
|
|
11399
|
-
},
|
|
11400
|
-
onAudioTrack: audioDone ? null : async (track) => {
|
|
11401
|
-
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11402
|
-
let { trackId } = track;
|
|
11403
|
-
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11404
|
-
trackId++;
|
|
11405
|
-
}
|
|
11406
|
-
const onAudioSample = await registerAudioTrack({
|
|
11407
|
-
container: "m3u8",
|
|
11408
|
-
track: {
|
|
11409
|
-
...track,
|
|
11410
|
-
trackId
|
|
11411
|
-
},
|
|
11412
|
-
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
11413
|
-
tracks: state.callbacks.tracks,
|
|
11414
|
-
logLevel: state.logLevel,
|
|
11415
|
-
onAudioTrack: state.onAudioTrack
|
|
11416
|
-
});
|
|
11417
|
-
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11418
|
-
if (onAudioSample === null) {
|
|
11419
|
-
return null;
|
|
11420
|
-
}
|
|
11421
|
-
state.m3u.sampleSorter.addAudioStreamToConsider(playlistUrl, onAudioSample);
|
|
11422
|
-
return async (sample) => {
|
|
11423
|
-
await state.m3u.sampleSorter.addAudioSample(playlistUrl, sample);
|
|
11424
|
-
};
|
|
11425
|
-
},
|
|
11426
|
-
onVideoTrack: videoDone ? null : async (track) => {
|
|
11427
|
-
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11428
|
-
let { trackId } = track;
|
|
11429
|
-
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11430
|
-
trackId++;
|
|
11431
|
-
}
|
|
11432
|
-
const onVideoSample = await registerVideoTrack({
|
|
11433
|
-
container: "m3u8",
|
|
11434
|
-
track: {
|
|
11435
|
-
...track,
|
|
11436
|
-
trackId
|
|
11437
|
-
},
|
|
11438
|
-
logLevel: state.logLevel,
|
|
11439
|
-
onVideoTrack: state.onVideoTrack,
|
|
11440
|
-
registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
|
|
11441
|
-
tracks: state.callbacks.tracks
|
|
11442
|
-
});
|
|
11443
|
-
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11444
|
-
if (onVideoSample === null) {
|
|
11445
|
-
return null;
|
|
11446
|
-
}
|
|
11447
|
-
state.m3u.sampleSorter.addVideoStreamToConsider(playlistUrl, onVideoSample);
|
|
11448
|
-
return async (sample) => {
|
|
11449
|
-
await state.m3u.sampleSorter.addVideoSample(playlistUrl, sample);
|
|
11450
|
-
};
|
|
11451
|
-
},
|
|
11452
|
-
m3uState: state.m3u,
|
|
11453
|
-
parentController: state.controller,
|
|
11454
|
-
readerInterface: state.readerInterface
|
|
11455
|
-
});
|
|
11456
|
-
run.catch((err) => {
|
|
11457
|
-
reject(err);
|
|
11458
|
-
});
|
|
12106
|
+
await processM3uChunk({
|
|
12107
|
+
playlistUrl,
|
|
12108
|
+
state,
|
|
12109
|
+
structure,
|
|
12110
|
+
audioDone,
|
|
12111
|
+
videoDone
|
|
11459
12112
|
});
|
|
11460
12113
|
};
|
|
11461
12114
|
|
|
@@ -11477,6 +12130,10 @@ var parseM3u = async ({ state }) => {
|
|
|
11477
12130
|
if (typeof state.src !== "string" && !(state.src instanceof URL)) {
|
|
11478
12131
|
throw new Error("Expected src to be a string");
|
|
11479
12132
|
}
|
|
12133
|
+
state.mediaSection.addMediaSection({
|
|
12134
|
+
start: 0,
|
|
12135
|
+
size: state.contentLength + 1
|
|
12136
|
+
});
|
|
11480
12137
|
await afterManifestFetch({
|
|
11481
12138
|
structure,
|
|
11482
12139
|
m3uState: state.m3u,
|
|
@@ -11484,7 +12141,9 @@ var parseM3u = async ({ state }) => {
|
|
|
11484
12141
|
selectM3uStreamFn: state.selectM3uStreamFn,
|
|
11485
12142
|
logLevel: state.logLevel,
|
|
11486
12143
|
selectAssociatedPlaylistsFn: state.selectM3uAssociatedPlaylistsFn,
|
|
11487
|
-
readerInterface: state.readerInterface
|
|
12144
|
+
readerInterface: state.readerInterface,
|
|
12145
|
+
onAudioTrack: state.onAudioTrack,
|
|
12146
|
+
canSkipTracks: state.callbacks.canSkipTracksState
|
|
11488
12147
|
});
|
|
11489
12148
|
return null;
|
|
11490
12149
|
}
|
|
@@ -13663,23 +14322,62 @@ var parseBlockFlags = (iterator, type) => {
|
|
|
13663
14322
|
};
|
|
13664
14323
|
|
|
13665
14324
|
// src/containers/webm/get-sample-from-block.ts
|
|
13666
|
-
var
|
|
14325
|
+
var addAvcToTrackAndActivateTrackIfNecessary = async ({
|
|
13667
14326
|
partialVideoSample,
|
|
13668
14327
|
codec,
|
|
13669
14328
|
structureState: structureState2,
|
|
13670
14329
|
webmState,
|
|
13671
|
-
trackNumber: trackNumber2
|
|
14330
|
+
trackNumber: trackNumber2,
|
|
14331
|
+
logLevel,
|
|
14332
|
+
callbacks,
|
|
14333
|
+
onVideoTrack
|
|
13672
14334
|
}) => {
|
|
13673
|
-
if (codec
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
14335
|
+
if (codec !== "V_MPEG4/ISO/AVC") {
|
|
14336
|
+
return;
|
|
14337
|
+
}
|
|
14338
|
+
const missingTracks = getTracksFromMatroska({
|
|
14339
|
+
structureState: structureState2,
|
|
14340
|
+
webmState
|
|
14341
|
+
}).missingInfo;
|
|
14342
|
+
if (missingTracks.length === 0) {
|
|
14343
|
+
return;
|
|
14344
|
+
}
|
|
14345
|
+
const parsed = parseAvc(partialVideoSample.data);
|
|
14346
|
+
for (const parse of parsed) {
|
|
14347
|
+
if (parse.type === "avc-profile") {
|
|
14348
|
+
webmState.setAvcProfileForTrackNumber(trackNumber2, parse);
|
|
14349
|
+
const track = missingTracks.find((t) => t.trackId === trackNumber2);
|
|
14350
|
+
if (!track) {
|
|
14351
|
+
throw new Error("Could not find track " + trackNumber2);
|
|
14352
|
+
}
|
|
14353
|
+
const resolvedTracks = getTracksFromMatroska({
|
|
14354
|
+
structureState: structureState2,
|
|
14355
|
+
webmState
|
|
14356
|
+
}).resolved;
|
|
14357
|
+
const resolvedTrack = resolvedTracks.find((t) => t.trackId === trackNumber2);
|
|
14358
|
+
if (!resolvedTrack) {
|
|
14359
|
+
throw new Error("Could not find track " + trackNumber2);
|
|
13678
14360
|
}
|
|
14361
|
+
await registerVideoTrack({
|
|
14362
|
+
track: resolvedTrack,
|
|
14363
|
+
container: "webm",
|
|
14364
|
+
logLevel,
|
|
14365
|
+
onVideoTrack,
|
|
14366
|
+
registerVideoSampleCallback: callbacks.registerVideoSampleCallback,
|
|
14367
|
+
tracks: callbacks.tracks
|
|
14368
|
+
});
|
|
13679
14369
|
}
|
|
13680
14370
|
}
|
|
13681
14371
|
};
|
|
13682
|
-
var getSampleFromBlock = (
|
|
14372
|
+
var getSampleFromBlock = async ({
|
|
14373
|
+
ebml,
|
|
14374
|
+
webmState,
|
|
14375
|
+
offset,
|
|
14376
|
+
structureState: structureState2,
|
|
14377
|
+
callbacks,
|
|
14378
|
+
logLevel,
|
|
14379
|
+
onVideoTrack
|
|
14380
|
+
}) => {
|
|
13683
14381
|
const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
|
|
13684
14382
|
const trackNumber2 = iterator.getVint();
|
|
13685
14383
|
if (trackNumber2 === null) {
|
|
@@ -13717,12 +14415,15 @@ var getSampleFromBlock = (ebml, webmState, offset, structureState2) => {
|
|
|
13717
14415
|
partialVideoSample
|
|
13718
14416
|
};
|
|
13719
14417
|
}
|
|
13720
|
-
|
|
14418
|
+
await addAvcToTrackAndActivateTrackIfNecessary({
|
|
13721
14419
|
codec,
|
|
13722
14420
|
partialVideoSample,
|
|
13723
14421
|
structureState: structureState2,
|
|
13724
14422
|
webmState,
|
|
13725
|
-
trackNumber: trackNumber2
|
|
14423
|
+
trackNumber: trackNumber2,
|
|
14424
|
+
callbacks,
|
|
14425
|
+
logLevel,
|
|
14426
|
+
onVideoTrack
|
|
13726
14427
|
});
|
|
13727
14428
|
const sample = {
|
|
13728
14429
|
...partialVideoSample,
|
|
@@ -13882,21 +14583,31 @@ var postprocessEbml = async ({
|
|
|
13882
14583
|
});
|
|
13883
14584
|
}
|
|
13884
14585
|
if (track && track.type === "video") {
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
14586
|
+
if (track.codec !== NO_CODEC_PRIVATE_SHOULD_BE_DERIVED_FROM_SPS) {
|
|
14587
|
+
await registerVideoTrack({
|
|
14588
|
+
track,
|
|
14589
|
+
container: "webm",
|
|
14590
|
+
logLevel,
|
|
14591
|
+
onVideoTrack,
|
|
14592
|
+
registerVideoSampleCallback: callbacks.registerVideoSampleCallback,
|
|
14593
|
+
tracks: callbacks.tracks
|
|
14594
|
+
});
|
|
14595
|
+
}
|
|
13893
14596
|
}
|
|
13894
14597
|
}
|
|
13895
14598
|
if (ebml.type === "Timestamp") {
|
|
13896
14599
|
webmState.setTimestampOffset(offset, ebml.value.value);
|
|
13897
14600
|
}
|
|
13898
14601
|
if (ebml.type === "Block" || ebml.type === "SimpleBlock") {
|
|
13899
|
-
const sample = getSampleFromBlock(
|
|
14602
|
+
const sample = await getSampleFromBlock({
|
|
14603
|
+
ebml,
|
|
14604
|
+
webmState,
|
|
14605
|
+
offset,
|
|
14606
|
+
structureState: structureState2,
|
|
14607
|
+
callbacks,
|
|
14608
|
+
logLevel,
|
|
14609
|
+
onVideoTrack
|
|
14610
|
+
});
|
|
13900
14611
|
if (sample.type === "video-sample") {
|
|
13901
14612
|
await callbacks.onVideoSample(sample.videoSample.trackId, sample.videoSample);
|
|
13902
14613
|
return {
|
|
@@ -13927,7 +14638,15 @@ var postprocessEbml = async ({
|
|
|
13927
14638
|
throw new Error("Expected block segment");
|
|
13928
14639
|
}
|
|
13929
14640
|
const hasReferenceBlock = ebml.value.find((c) => c.type === "ReferenceBlock");
|
|
13930
|
-
const sample = block2.value.length === 0 ? null : getSampleFromBlock(
|
|
14641
|
+
const sample = block2.value.length === 0 ? null : await getSampleFromBlock({
|
|
14642
|
+
ebml: block2,
|
|
14643
|
+
webmState,
|
|
14644
|
+
offset,
|
|
14645
|
+
structureState: structureState2,
|
|
14646
|
+
callbacks,
|
|
14647
|
+
logLevel,
|
|
14648
|
+
onVideoTrack
|
|
14649
|
+
});
|
|
13931
14650
|
if (sample && sample.type === "partial-video-sample") {
|
|
13932
14651
|
const completeFrame = {
|
|
13933
14652
|
...sample.partialVideoSample,
|
|
@@ -14128,9 +14847,9 @@ var initVideo = async ({ state }) => {
|
|
|
14128
14847
|
});
|
|
14129
14848
|
return;
|
|
14130
14849
|
}
|
|
14131
|
-
if (state.mp4HeaderSegment) {
|
|
14850
|
+
if (state.m3uPlaylistContext?.mp4HeaderSegment) {
|
|
14132
14851
|
Log.verbose(state.logLevel, "Detected ISO Base Media segment");
|
|
14133
|
-
const moovAtom = getMoovFromFromIsoStructure(state.mp4HeaderSegment);
|
|
14852
|
+
const moovAtom = getMoovFromFromIsoStructure(state.m3uPlaylistContext.mp4HeaderSegment);
|
|
14134
14853
|
if (!moovAtom) {
|
|
14135
14854
|
throw new Error("No moov box found");
|
|
14136
14855
|
}
|
|
@@ -14353,19 +15072,33 @@ var parseLoop = async ({
|
|
|
14353
15072
|
try {
|
|
14354
15073
|
await triggerInfoEmit(state);
|
|
14355
15074
|
await state.controller._internals.checkForAbortAndPause();
|
|
14356
|
-
const
|
|
15075
|
+
const result = await runParseIteration({
|
|
14357
15076
|
state
|
|
14358
15077
|
});
|
|
14359
|
-
if (
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
15078
|
+
if (result !== null && result.action === "fetch-more-data") {
|
|
15079
|
+
Log.verbose(state.logLevel, `Need to fetch ${result.bytesNeeded} more bytes before we can continue`);
|
|
15080
|
+
const startBytesRemaining = state.iterator.bytesRemaining();
|
|
15081
|
+
while (true) {
|
|
15082
|
+
const done = await fetchMoreData(state);
|
|
15083
|
+
if (done) {
|
|
15084
|
+
break;
|
|
15085
|
+
}
|
|
15086
|
+
if (state.iterator.bytesRemaining() - startBytesRemaining >= result.bytesNeeded) {
|
|
15087
|
+
break;
|
|
15088
|
+
}
|
|
15089
|
+
}
|
|
15090
|
+
continue;
|
|
15091
|
+
}
|
|
15092
|
+
if (result !== null && result.action === "skip") {
|
|
15093
|
+
state.increaseSkippedBytes(result.skipTo - state.iterator.counter.getOffset());
|
|
15094
|
+
if (result.skipTo === state.contentLength) {
|
|
15095
|
+
state.iterator.discard(result.skipTo - state.iterator.counter.getOffset());
|
|
14363
15096
|
Log.verbose(state.logLevel, "Skipped to end of file, not fetching.");
|
|
14364
15097
|
break;
|
|
14365
15098
|
}
|
|
14366
15099
|
const seekStart = Date.now();
|
|
14367
15100
|
await performSeek({
|
|
14368
|
-
seekTo:
|
|
15101
|
+
seekTo: result.skipTo,
|
|
14369
15102
|
userInitiated: false,
|
|
14370
15103
|
controller: state.controller,
|
|
14371
15104
|
mediaSection: state.mediaSection,
|
|
@@ -14378,7 +15111,8 @@ var parseLoop = async ({
|
|
|
14378
15111
|
readerInterface: state.readerInterface,
|
|
14379
15112
|
fields: state.fields,
|
|
14380
15113
|
src: state.src,
|
|
14381
|
-
discardReadBytes: state.discardReadBytes
|
|
15114
|
+
discardReadBytes: state.discardReadBytes,
|
|
15115
|
+
prefetchCache: state.prefetchCache
|
|
14382
15116
|
});
|
|
14383
15117
|
state.timings.timeSeeking += Date.now() - seekStart;
|
|
14384
15118
|
}
|
|
@@ -14485,6 +15219,9 @@ var setSeekingHints = ({
|
|
|
14485
15219
|
setSeekingHintsForAac();
|
|
14486
15220
|
return;
|
|
14487
15221
|
}
|
|
15222
|
+
if (hints.type === "m3u8-seeking-hints") {
|
|
15223
|
+
return;
|
|
15224
|
+
}
|
|
14488
15225
|
throw new Error(`Unknown seeking hints type: ${hints}`);
|
|
14489
15226
|
};
|
|
14490
15227
|
|
|
@@ -14640,12 +15377,16 @@ var getMfraAtom = async ({
|
|
|
14640
15377
|
contentLength,
|
|
14641
15378
|
readerInterface,
|
|
14642
15379
|
controller,
|
|
14643
|
-
parentSize
|
|
15380
|
+
parentSize,
|
|
15381
|
+
logLevel,
|
|
15382
|
+
prefetchCache
|
|
14644
15383
|
}) => {
|
|
14645
15384
|
const result = await readerInterface.read({
|
|
14646
15385
|
controller,
|
|
14647
15386
|
range: [contentLength - parentSize, contentLength - 1],
|
|
14648
|
-
src
|
|
15387
|
+
src,
|
|
15388
|
+
logLevel,
|
|
15389
|
+
prefetchCache
|
|
14649
15390
|
});
|
|
14650
15391
|
const iterator = getArrayBufferIterator(new Uint8Array, parentSize);
|
|
14651
15392
|
while (true) {
|
|
@@ -14665,12 +15406,16 @@ var getMfroAtom = async ({
|
|
|
14665
15406
|
src,
|
|
14666
15407
|
contentLength,
|
|
14667
15408
|
readerInterface,
|
|
14668
|
-
controller
|
|
15409
|
+
controller,
|
|
15410
|
+
logLevel,
|
|
15411
|
+
prefetchCache
|
|
14669
15412
|
}) => {
|
|
14670
15413
|
const result = await readerInterface.read({
|
|
14671
15414
|
controller,
|
|
14672
15415
|
range: [contentLength - 16, contentLength - 1],
|
|
14673
|
-
src
|
|
15416
|
+
src,
|
|
15417
|
+
logLevel,
|
|
15418
|
+
prefetchCache
|
|
14674
15419
|
});
|
|
14675
15420
|
const { value } = await result.reader.reader.read();
|
|
14676
15421
|
if (!value) {
|
|
@@ -14705,13 +15450,16 @@ var getMfraSeekingBox = async ({
|
|
|
14705
15450
|
controller,
|
|
14706
15451
|
readerInterface,
|
|
14707
15452
|
src,
|
|
14708
|
-
logLevel
|
|
15453
|
+
logLevel,
|
|
15454
|
+
prefetchCache
|
|
14709
15455
|
}) => {
|
|
14710
15456
|
const parentSize = await getMfroAtom({
|
|
14711
15457
|
contentLength,
|
|
14712
15458
|
controller,
|
|
14713
15459
|
readerInterface,
|
|
14714
|
-
src
|
|
15460
|
+
src,
|
|
15461
|
+
logLevel,
|
|
15462
|
+
prefetchCache
|
|
14715
15463
|
});
|
|
14716
15464
|
if (!parentSize) {
|
|
14717
15465
|
return null;
|
|
@@ -14721,7 +15469,9 @@ var getMfraSeekingBox = async ({
|
|
|
14721
15469
|
controller,
|
|
14722
15470
|
readerInterface,
|
|
14723
15471
|
src,
|
|
14724
|
-
parentSize
|
|
15472
|
+
parentSize,
|
|
15473
|
+
logLevel,
|
|
15474
|
+
prefetchCache
|
|
14725
15475
|
});
|
|
14726
15476
|
mfraAtom.discard(8);
|
|
14727
15477
|
return getIsoBaseMediaChildren({
|
|
@@ -14739,7 +15489,8 @@ var lazyMfraLoad = ({
|
|
|
14739
15489
|
controller,
|
|
14740
15490
|
readerInterface,
|
|
14741
15491
|
src,
|
|
14742
|
-
logLevel
|
|
15492
|
+
logLevel,
|
|
15493
|
+
prefetchCache
|
|
14743
15494
|
}) => {
|
|
14744
15495
|
let prom = null;
|
|
14745
15496
|
let result = null;
|
|
@@ -14753,7 +15504,8 @@ var lazyMfraLoad = ({
|
|
|
14753
15504
|
controller,
|
|
14754
15505
|
readerInterface,
|
|
14755
15506
|
src,
|
|
14756
|
-
logLevel
|
|
15507
|
+
logLevel,
|
|
15508
|
+
prefetchCache
|
|
14757
15509
|
}).then((boxes) => {
|
|
14758
15510
|
Log.verbose(logLevel, "Lazily found mfra atom.");
|
|
14759
15511
|
result = boxes;
|
|
@@ -14794,7 +15546,8 @@ var isoBaseMediaState = ({
|
|
|
14794
15546
|
controller,
|
|
14795
15547
|
readerInterface,
|
|
14796
15548
|
src,
|
|
14797
|
-
logLevel
|
|
15549
|
+
logLevel,
|
|
15550
|
+
prefetchCache
|
|
14798
15551
|
}) => {
|
|
14799
15552
|
return {
|
|
14800
15553
|
flatSamples: cachedSamplePositionsState(),
|
|
@@ -14804,7 +15557,8 @@ var isoBaseMediaState = ({
|
|
|
14804
15557
|
controller,
|
|
14805
15558
|
readerInterface,
|
|
14806
15559
|
src,
|
|
14807
|
-
logLevel
|
|
15560
|
+
logLevel,
|
|
15561
|
+
prefetchCache
|
|
14808
15562
|
}),
|
|
14809
15563
|
moof: precomputedMoofState(),
|
|
14810
15564
|
tfra: precomputedTfraState()
|
|
@@ -14821,6 +15575,7 @@ var keyframesState = () => {
|
|
|
14821
15575
|
keyframes.push(keyframe);
|
|
14822
15576
|
};
|
|
14823
15577
|
const getKeyframes2 = () => {
|
|
15578
|
+
keyframes.sort((a, b) => a.positionInBytes - b.positionInBytes);
|
|
14824
15579
|
return keyframes;
|
|
14825
15580
|
};
|
|
14826
15581
|
const setFromSeekingHints = (keyframesFromHints) => {
|
|
@@ -14843,8 +15598,11 @@ var sampleSorter = ({
|
|
|
14843
15598
|
const streamsWithTracks = [];
|
|
14844
15599
|
const audioCallbacks = {};
|
|
14845
15600
|
const videoCallbacks = {};
|
|
14846
|
-
|
|
15601
|
+
let latestSample = {};
|
|
14847
15602
|
return {
|
|
15603
|
+
clearSamples: () => {
|
|
15604
|
+
latestSample = {};
|
|
15605
|
+
},
|
|
14848
15606
|
addToStreamWithTrack: (src) => {
|
|
14849
15607
|
streamsWithTracks.push(src);
|
|
14850
15608
|
},
|
|
@@ -14917,6 +15675,8 @@ var m3uState = (logLevel) => {
|
|
|
14917
15675
|
const hasEmittedAudioTrack = {};
|
|
14918
15676
|
const hasEmittedDoneWithTracks = {};
|
|
14919
15677
|
let hasFinishedManifest = false;
|
|
15678
|
+
const seekToSecondsToProcess = {};
|
|
15679
|
+
const nextSeekShouldSubtractChunks = {};
|
|
14920
15680
|
let readyToIterateOverM3u = false;
|
|
14921
15681
|
const allChunksProcessed = {};
|
|
14922
15682
|
const m3uStreamRuns = {};
|
|
@@ -14978,6 +15738,11 @@ var m3uState = (logLevel) => {
|
|
|
14978
15738
|
setAllChunksProcessed: (src) => {
|
|
14979
15739
|
allChunksProcessed[src] = true;
|
|
14980
15740
|
},
|
|
15741
|
+
clearAllChunksProcessed: () => {
|
|
15742
|
+
Object.keys(allChunksProcessed).forEach((key) => {
|
|
15743
|
+
delete allChunksProcessed[key];
|
|
15744
|
+
});
|
|
15745
|
+
},
|
|
14981
15746
|
getAllChunksProcessedForPlaylist,
|
|
14982
15747
|
getAllChunksProcessedOverall: () => {
|
|
14983
15748
|
if (!selectedMainPlaylist) {
|
|
@@ -15005,6 +15770,11 @@ var m3uState = (logLevel) => {
|
|
|
15005
15770
|
getTrackDone: (playlistUrl) => {
|
|
15006
15771
|
return tracksDone[playlistUrl];
|
|
15007
15772
|
},
|
|
15773
|
+
clearTracksDone: () => {
|
|
15774
|
+
Object.keys(tracksDone).forEach((key) => {
|
|
15775
|
+
delete tracksDone[key];
|
|
15776
|
+
});
|
|
15777
|
+
},
|
|
15008
15778
|
getM3uStreamRun: (playlistUrl) => m3uStreamRuns[playlistUrl] ?? null,
|
|
15009
15779
|
abortM3UStreamRuns: () => {
|
|
15010
15780
|
const values = Object.values(m3uStreamRuns);
|
|
@@ -15023,7 +15793,15 @@ var m3uState = (logLevel) => {
|
|
|
15023
15793
|
getSelectedPlaylists,
|
|
15024
15794
|
sampleSorter: sampleSorter({ logLevel, getAllChunksProcessedForPlaylist }),
|
|
15025
15795
|
setMp4HeaderSegment,
|
|
15026
|
-
getMp4HeaderSegment
|
|
15796
|
+
getMp4HeaderSegment,
|
|
15797
|
+
setSeekToSecondsToProcess: (playlistUrl, m3uSeek) => {
|
|
15798
|
+
seekToSecondsToProcess[playlistUrl] = m3uSeek;
|
|
15799
|
+
},
|
|
15800
|
+
getSeekToSecondsToProcess: (playlistUrl) => seekToSecondsToProcess[playlistUrl] ?? null,
|
|
15801
|
+
setNextSeekShouldSubtractChunks: (playlistUrl, chunks) => {
|
|
15802
|
+
nextSeekShouldSubtractChunks[playlistUrl] = chunks;
|
|
15803
|
+
},
|
|
15804
|
+
getNextSeekShouldSubtractChunks: (playlistUrl) => nextSeekShouldSubtractChunks[playlistUrl] ?? 0
|
|
15027
15805
|
};
|
|
15028
15806
|
};
|
|
15029
15807
|
|
|
@@ -15072,12 +15850,15 @@ var fetchWebmCues = async ({
|
|
|
15072
15850
|
readerInterface,
|
|
15073
15851
|
controller,
|
|
15074
15852
|
position,
|
|
15075
|
-
logLevel
|
|
15853
|
+
logLevel,
|
|
15854
|
+
prefetchCache
|
|
15076
15855
|
}) => {
|
|
15077
15856
|
const result = await readerInterface.read({
|
|
15078
15857
|
controller,
|
|
15079
15858
|
range: position,
|
|
15080
|
-
src
|
|
15859
|
+
src,
|
|
15860
|
+
logLevel,
|
|
15861
|
+
prefetchCache
|
|
15081
15862
|
});
|
|
15082
15863
|
const { value } = await result.reader.reader.read();
|
|
15083
15864
|
if (!value) {
|
|
@@ -15104,7 +15885,8 @@ var lazyCuesFetch = ({
|
|
|
15104
15885
|
controller,
|
|
15105
15886
|
logLevel,
|
|
15106
15887
|
readerInterface,
|
|
15107
|
-
src
|
|
15888
|
+
src,
|
|
15889
|
+
prefetchCache
|
|
15108
15890
|
}) => {
|
|
15109
15891
|
let prom = null;
|
|
15110
15892
|
let sOffset = null;
|
|
@@ -15126,7 +15908,8 @@ var lazyCuesFetch = ({
|
|
|
15126
15908
|
logLevel,
|
|
15127
15909
|
position,
|
|
15128
15910
|
readerInterface,
|
|
15129
|
-
src
|
|
15911
|
+
src,
|
|
15912
|
+
prefetchCache
|
|
15130
15913
|
}).then((cues) => {
|
|
15131
15914
|
Log.verbose(logLevel, "Cues loaded");
|
|
15132
15915
|
result = cues;
|
|
@@ -15188,7 +15971,8 @@ var webmState = ({
|
|
|
15188
15971
|
controller,
|
|
15189
15972
|
logLevel,
|
|
15190
15973
|
readerInterface,
|
|
15191
|
-
src
|
|
15974
|
+
src,
|
|
15975
|
+
prefetchCache
|
|
15192
15976
|
}) => {
|
|
15193
15977
|
const trackEntries = {};
|
|
15194
15978
|
const onTrackEntrySegment = (trackEntry2) => {
|
|
@@ -15249,7 +16033,8 @@ var webmState = ({
|
|
|
15249
16033
|
controller,
|
|
15250
16034
|
logLevel,
|
|
15251
16035
|
readerInterface,
|
|
15252
|
-
src
|
|
16036
|
+
src,
|
|
16037
|
+
prefetchCache
|
|
15253
16038
|
});
|
|
15254
16039
|
const getTimeStampMapForSeekingHints = () => {
|
|
15255
16040
|
return timestampMap;
|
|
@@ -15330,13 +16115,16 @@ var fetchIdx1 = async ({
|
|
|
15330
16115
|
readerInterface,
|
|
15331
16116
|
controller,
|
|
15332
16117
|
position,
|
|
15333
|
-
logLevel
|
|
16118
|
+
logLevel,
|
|
16119
|
+
prefetchCache
|
|
15334
16120
|
}) => {
|
|
15335
16121
|
Log.verbose(logLevel, "Making request to fetch idx1 from ", src, "position", position);
|
|
15336
16122
|
const result = await readerInterface.read({
|
|
15337
16123
|
controller,
|
|
15338
16124
|
range: position,
|
|
15339
|
-
src
|
|
16125
|
+
src,
|
|
16126
|
+
logLevel,
|
|
16127
|
+
prefetchCache
|
|
15340
16128
|
});
|
|
15341
16129
|
const iterator = getArrayBufferIterator(new Uint8Array, Infinity);
|
|
15342
16130
|
while (true) {
|
|
@@ -15367,7 +16155,8 @@ var lazyIdx1Fetch = ({
|
|
|
15367
16155
|
controller,
|
|
15368
16156
|
logLevel,
|
|
15369
16157
|
readerInterface,
|
|
15370
|
-
src
|
|
16158
|
+
src,
|
|
16159
|
+
prefetchCache
|
|
15371
16160
|
}) => {
|
|
15372
16161
|
let prom = null;
|
|
15373
16162
|
let result = null;
|
|
@@ -15383,7 +16172,8 @@ var lazyIdx1Fetch = ({
|
|
|
15383
16172
|
logLevel,
|
|
15384
16173
|
position,
|
|
15385
16174
|
readerInterface,
|
|
15386
|
-
src
|
|
16175
|
+
src,
|
|
16176
|
+
prefetchCache
|
|
15387
16177
|
}).then((entries) => {
|
|
15388
16178
|
prom = null;
|
|
15389
16179
|
result = entries;
|
|
@@ -15504,7 +16294,8 @@ var riffSpecificState = ({
|
|
|
15504
16294
|
controller,
|
|
15505
16295
|
logLevel,
|
|
15506
16296
|
readerInterface,
|
|
15507
|
-
src
|
|
16297
|
+
src,
|
|
16298
|
+
prefetchCache
|
|
15508
16299
|
}) => {
|
|
15509
16300
|
let avcProfile = null;
|
|
15510
16301
|
let nextTrackIndex = 0;
|
|
@@ -15523,7 +16314,8 @@ var riffSpecificState = ({
|
|
|
15523
16314
|
controller,
|
|
15524
16315
|
logLevel,
|
|
15525
16316
|
readerInterface,
|
|
15526
|
-
src
|
|
16317
|
+
src,
|
|
16318
|
+
prefetchCache
|
|
15527
16319
|
});
|
|
15528
16320
|
const sampleCounter = riffSampleCounter();
|
|
15529
16321
|
return {
|
|
@@ -15544,7 +16336,7 @@ var riffSpecificState = ({
|
|
|
15544
16336
|
};
|
|
15545
16337
|
|
|
15546
16338
|
// src/state/sample-callbacks.ts
|
|
15547
|
-
var
|
|
16339
|
+
var callbacksState = ({
|
|
15548
16340
|
controller,
|
|
15549
16341
|
hasAudioTrackHandlers,
|
|
15550
16342
|
hasVideoTrackHandlers,
|
|
@@ -15851,14 +16643,15 @@ var makeParserState = ({
|
|
|
15851
16643
|
onDiscardedData,
|
|
15852
16644
|
selectM3uStreamFn,
|
|
15853
16645
|
selectM3uAssociatedPlaylistsFn,
|
|
15854
|
-
|
|
16646
|
+
m3uPlaylistContext,
|
|
15855
16647
|
contentType,
|
|
15856
16648
|
name,
|
|
15857
16649
|
callbacks,
|
|
15858
16650
|
fieldsInReturnValue,
|
|
15859
16651
|
mimeType,
|
|
15860
16652
|
initialReaderInstance,
|
|
15861
|
-
makeSamplesStartAtZero
|
|
16653
|
+
makeSamplesStartAtZero,
|
|
16654
|
+
prefetchCache
|
|
15862
16655
|
}) => {
|
|
15863
16656
|
let skippedBytes = 0;
|
|
15864
16657
|
const returnValue = {};
|
|
@@ -15890,22 +16683,35 @@ var makeParserState = ({
|
|
|
15890
16683
|
callbacks
|
|
15891
16684
|
});
|
|
15892
16685
|
return {
|
|
15893
|
-
riff: riffSpecificState({
|
|
16686
|
+
riff: riffSpecificState({
|
|
16687
|
+
controller,
|
|
16688
|
+
logLevel,
|
|
16689
|
+
readerInterface,
|
|
16690
|
+
src,
|
|
16691
|
+
prefetchCache
|
|
16692
|
+
}),
|
|
15894
16693
|
transportStream: transportStreamState(),
|
|
15895
|
-
webm: webmState({
|
|
16694
|
+
webm: webmState({
|
|
16695
|
+
controller,
|
|
16696
|
+
logLevel,
|
|
16697
|
+
readerInterface,
|
|
16698
|
+
src,
|
|
16699
|
+
prefetchCache
|
|
16700
|
+
}),
|
|
15896
16701
|
iso: isoBaseMediaState({
|
|
15897
16702
|
contentLength,
|
|
15898
16703
|
controller,
|
|
15899
16704
|
readerInterface,
|
|
15900
16705
|
src,
|
|
15901
|
-
logLevel
|
|
16706
|
+
logLevel,
|
|
16707
|
+
prefetchCache
|
|
15902
16708
|
}),
|
|
15903
16709
|
mp3,
|
|
15904
16710
|
aac: aacState(),
|
|
15905
16711
|
flac: flacState(),
|
|
15906
16712
|
m3u: m3uState(logLevel),
|
|
15907
16713
|
timings,
|
|
15908
|
-
callbacks:
|
|
16714
|
+
callbacks: callbacksState({
|
|
15909
16715
|
controller,
|
|
15910
16716
|
hasAudioTrackHandlers,
|
|
15911
16717
|
hasVideoTrackHandlers,
|
|
@@ -15943,7 +16749,7 @@ var makeParserState = ({
|
|
|
15943
16749
|
discardReadBytes,
|
|
15944
16750
|
selectM3uStreamFn,
|
|
15945
16751
|
selectM3uAssociatedPlaylistsFn,
|
|
15946
|
-
|
|
16752
|
+
m3uPlaylistContext,
|
|
15947
16753
|
contentType,
|
|
15948
16754
|
name,
|
|
15949
16755
|
returnValue,
|
|
@@ -15953,7 +16759,8 @@ var makeParserState = ({
|
|
|
15953
16759
|
errored,
|
|
15954
16760
|
currentReader: currentReaderState,
|
|
15955
16761
|
seekInfiniteLoop,
|
|
15956
|
-
makeSamplesStartAtZero
|
|
16762
|
+
makeSamplesStartAtZero,
|
|
16763
|
+
prefetchCache
|
|
15957
16764
|
};
|
|
15958
16765
|
};
|
|
15959
16766
|
|
|
@@ -16032,7 +16839,7 @@ var internalParseMedia = async function({
|
|
|
16032
16839
|
apiName,
|
|
16033
16840
|
selectM3uStream: selectM3uStreamFn,
|
|
16034
16841
|
selectM3uAssociatedPlaylists: selectM3uAssociatedPlaylistsFn,
|
|
16035
|
-
|
|
16842
|
+
m3uPlaylistContext,
|
|
16036
16843
|
makeSamplesStartAtZero,
|
|
16037
16844
|
seekingHints,
|
|
16038
16845
|
...more
|
|
@@ -16044,6 +16851,7 @@ var internalParseMedia = async function({
|
|
|
16044
16851
|
apiName
|
|
16045
16852
|
});
|
|
16046
16853
|
Log.verbose(logLevel, `Reading ${typeof src === "string" ? src : src instanceof URL ? src.toString() : src instanceof File ? src.name : src.toString()}`);
|
|
16854
|
+
const prefetchCache = new Map;
|
|
16047
16855
|
const {
|
|
16048
16856
|
reader: readerInstance,
|
|
16049
16857
|
contentLength,
|
|
@@ -16051,7 +16859,13 @@ var internalParseMedia = async function({
|
|
|
16051
16859
|
contentType,
|
|
16052
16860
|
supportsContentRange,
|
|
16053
16861
|
needsContentRange
|
|
16054
|
-
} = await readerInterface.read({
|
|
16862
|
+
} = await readerInterface.read({
|
|
16863
|
+
src,
|
|
16864
|
+
range: null,
|
|
16865
|
+
controller,
|
|
16866
|
+
logLevel,
|
|
16867
|
+
prefetchCache
|
|
16868
|
+
});
|
|
16055
16869
|
if (contentLength === null) {
|
|
16056
16870
|
throw new Error(`Cannot read media ${src} without a content length. This is currently not supported. Ensure the media has a "Content-Length" HTTP header.`);
|
|
16057
16871
|
}
|
|
@@ -16074,14 +16888,15 @@ var internalParseMedia = async function({
|
|
|
16074
16888
|
onDiscardedData,
|
|
16075
16889
|
selectM3uStreamFn,
|
|
16076
16890
|
selectM3uAssociatedPlaylistsFn,
|
|
16077
|
-
|
|
16891
|
+
m3uPlaylistContext,
|
|
16078
16892
|
contentType,
|
|
16079
16893
|
name,
|
|
16080
16894
|
callbacks: more,
|
|
16081
16895
|
fieldsInReturnValue: _fieldsInReturnValue ?? {},
|
|
16082
16896
|
mimeType: contentType,
|
|
16083
16897
|
initialReaderInstance: readerInstance,
|
|
16084
|
-
makeSamplesStartAtZero
|
|
16898
|
+
makeSamplesStartAtZero,
|
|
16899
|
+
prefetchCache
|
|
16085
16900
|
});
|
|
16086
16901
|
if (seekingHints) {
|
|
16087
16902
|
setSeekingHints({ hints: seekingHints, state });
|
|
@@ -16091,7 +16906,7 @@ var internalParseMedia = async function({
|
|
|
16091
16906
|
keyframesState: state.keyframes,
|
|
16092
16907
|
webmState: state.webm,
|
|
16093
16908
|
structureState: state.structure,
|
|
16094
|
-
|
|
16909
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
16095
16910
|
mediaSectionState: state.mediaSection,
|
|
16096
16911
|
isoState: state.iso,
|
|
16097
16912
|
transportStream: state.transportStream,
|
|
@@ -16120,6 +16935,7 @@ var internalParseMedia = async function({
|
|
|
16120
16935
|
state.iterator?.destroy();
|
|
16121
16936
|
state.callbacks.tracks.ensureHasTracksAtEnd(state.fields);
|
|
16122
16937
|
state.m3u.abortM3UStreamRuns();
|
|
16938
|
+
prefetchCache.clear();
|
|
16123
16939
|
if (state.errored) {
|
|
16124
16940
|
throw state.errored;
|
|
16125
16941
|
}
|
|
@@ -16137,7 +16953,7 @@ var forwardMediaParserControllerToWorker = (controller) => {
|
|
|
16137
16953
|
return;
|
|
16138
16954
|
}
|
|
16139
16955
|
if (message.type === "request-seek") {
|
|
16140
|
-
controller.
|
|
16956
|
+
controller.seek(message.payload);
|
|
16141
16957
|
return;
|
|
16142
16958
|
}
|
|
16143
16959
|
if (message.type === "request-get-seeking-hints") {
|
|
@@ -16218,6 +17034,22 @@ var serializeError = ({
|
|
|
16218
17034
|
seekingHints
|
|
16219
17035
|
};
|
|
16220
17036
|
}
|
|
17037
|
+
if (error.name === "AbortError") {
|
|
17038
|
+
return {
|
|
17039
|
+
type: "response-error",
|
|
17040
|
+
errorName: "AbortError",
|
|
17041
|
+
errorMessage: error.message,
|
|
17042
|
+
errorStack: error.stack ?? ""
|
|
17043
|
+
};
|
|
17044
|
+
}
|
|
17045
|
+
if (error.name === "NotReadableError") {
|
|
17046
|
+
return {
|
|
17047
|
+
type: "response-error",
|
|
17048
|
+
errorName: "NotReadableError",
|
|
17049
|
+
errorMessage: error.message,
|
|
17050
|
+
errorStack: error.stack ?? ""
|
|
17051
|
+
};
|
|
17052
|
+
}
|
|
16221
17053
|
if (error.name !== "Error") {
|
|
16222
17054
|
Log.warn(logLevel, `Original error was of type ${error.name} did not properly propagate`);
|
|
16223
17055
|
}
|
|
@@ -16267,7 +17099,7 @@ var startParsing = async (message, reader) => {
|
|
|
16267
17099
|
acknowledgeRemotionLicense,
|
|
16268
17100
|
logLevel: userLogLevel,
|
|
16269
17101
|
progressIntervalInMs,
|
|
16270
|
-
|
|
17102
|
+
m3uPlaylistContext,
|
|
16271
17103
|
seekingHints,
|
|
16272
17104
|
makeSamplesStartAtZero
|
|
16273
17105
|
} = payload;
|
|
@@ -16503,7 +17335,7 @@ var startParsing = async (message, reader) => {
|
|
|
16503
17335
|
}
|
|
16504
17336
|
return res.value;
|
|
16505
17337
|
} : defaultSelectM3uStreamFn,
|
|
16506
|
-
|
|
17338
|
+
m3uPlaylistContext: m3uPlaylistContext ?? null,
|
|
16507
17339
|
selectM3uAssociatedPlaylists: postM3uAssociatedPlaylistsSelection ? async (playlists) => {
|
|
16508
17340
|
const res = await executeCallback({
|
|
16509
17341
|
callbackType: "m3u-associated-playlists-selection",
|