@remotion/media-parser 4.0.290 → 4.0.292
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`");
|
|
@@ -340,13 +466,20 @@ var webReader = {
|
|
|
340
466
|
return webFileReadWholeAsText(src);
|
|
341
467
|
}
|
|
342
468
|
return fetchReadWholeAsText(src);
|
|
469
|
+
},
|
|
470
|
+
preload: ({ range, src, logLevel, prefetchCache }) => {
|
|
471
|
+
if (src instanceof Blob) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
return fetchPreload({ range, src, logLevel, prefetchCache });
|
|
343
475
|
}
|
|
344
476
|
};
|
|
345
477
|
|
|
346
478
|
// src/containers/m3u/select-stream.ts
|
|
347
479
|
var selectAssociatedPlaylists = async ({
|
|
348
480
|
playlists,
|
|
349
|
-
fn
|
|
481
|
+
fn,
|
|
482
|
+
skipAudioTracks
|
|
350
483
|
}) => {
|
|
351
484
|
if (playlists.length < 1) {
|
|
352
485
|
return Promise.resolve([]);
|
|
@@ -355,12 +488,17 @@ var selectAssociatedPlaylists = async ({
|
|
|
355
488
|
if (!Array.isArray(streams)) {
|
|
356
489
|
throw new Error("Expected an array of associated playlists");
|
|
357
490
|
}
|
|
491
|
+
const selectedStreams = [];
|
|
358
492
|
for (const stream of streams) {
|
|
493
|
+
if (stream.isAudio && skipAudioTracks) {
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
359
496
|
if (!playlists.find((playlist) => playlist.src === stream.src)) {
|
|
360
497
|
throw new Error(`The associated playlist ${JSON.stringify(streams)} cannot be selected because it was not in the list of selectable playlists`);
|
|
361
498
|
}
|
|
499
|
+
selectedStreams.push(stream);
|
|
362
500
|
}
|
|
363
|
-
return
|
|
501
|
+
return selectedStreams;
|
|
364
502
|
};
|
|
365
503
|
var defaultSelectM3uAssociatedPlaylists = ({ associatedPlaylists }) => {
|
|
366
504
|
if (associatedPlaylists.length === 1) {
|
|
@@ -532,7 +670,11 @@ var mediaParserController = () => {
|
|
|
532
670
|
const performedSeeksSignal = performedSeeksStats();
|
|
533
671
|
const checkForAbortAndPause = async () => {
|
|
534
672
|
if (abortController.signal.aborted) {
|
|
535
|
-
|
|
673
|
+
const err = new MediaParserAbortError("Aborted");
|
|
674
|
+
if (abortController.signal.reason) {
|
|
675
|
+
err.cause = abortController.signal.reason;
|
|
676
|
+
}
|
|
677
|
+
throw err;
|
|
536
678
|
}
|
|
537
679
|
await pauseSignal.waitUntilResume();
|
|
538
680
|
};
|
|
@@ -554,7 +696,7 @@ var mediaParserController = () => {
|
|
|
554
696
|
abortController.abort(reason);
|
|
555
697
|
emitter.dispatchAbort(reason);
|
|
556
698
|
},
|
|
557
|
-
|
|
699
|
+
seek: seekSignal.seek,
|
|
558
700
|
pause: pauseSignal.pause,
|
|
559
701
|
resume: pauseSignal.resume,
|
|
560
702
|
addEventListener: emitter.addEventListener,
|
|
@@ -608,7 +750,8 @@ var getM3uStreams = ({
|
|
|
608
750
|
language: audioTrack.language,
|
|
609
751
|
name: audioTrack.name,
|
|
610
752
|
src: readerInterface.createAdjacentFileSource(audioTrack.uri, originalSrc),
|
|
611
|
-
id: associatedPlaylists.length
|
|
753
|
+
id: associatedPlaylists.length,
|
|
754
|
+
isAudio: true
|
|
612
755
|
});
|
|
613
756
|
}
|
|
614
757
|
}
|
|
@@ -969,7 +1112,7 @@ var getFpsFromIsoMaseMedia = (state) => {
|
|
|
969
1112
|
const moovBox = getMoovBoxFromState({
|
|
970
1113
|
structureState: state.structure,
|
|
971
1114
|
isoState: state.iso,
|
|
972
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
1115
|
+
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
973
1116
|
mayUsePrecomputed: true
|
|
974
1117
|
});
|
|
975
1118
|
if (!moovBox) {
|
|
@@ -2128,40 +2271,6 @@ var detectFileType = (data) => {
|
|
|
2128
2271
|
return { type: "unknown" };
|
|
2129
2272
|
};
|
|
2130
2273
|
|
|
2131
|
-
// src/log.ts
|
|
2132
|
-
var logLevels = ["trace", "verbose", "info", "warn", "error"];
|
|
2133
|
-
var getNumberForLogLevel = (level) => {
|
|
2134
|
-
return logLevels.indexOf(level);
|
|
2135
|
-
};
|
|
2136
|
-
var isEqualOrBelowLogLevel = (currentLevel, level) => {
|
|
2137
|
-
return getNumberForLogLevel(currentLevel) <= getNumberForLogLevel(level);
|
|
2138
|
-
};
|
|
2139
|
-
var Log = {
|
|
2140
|
-
trace: (logLevel, ...args) => {
|
|
2141
|
-
if (isEqualOrBelowLogLevel(logLevel, "trace")) {
|
|
2142
|
-
return console.log(...args);
|
|
2143
|
-
}
|
|
2144
|
-
},
|
|
2145
|
-
verbose: (logLevel, ...args) => {
|
|
2146
|
-
if (isEqualOrBelowLogLevel(logLevel, "verbose")) {
|
|
2147
|
-
return console.log(...args);
|
|
2148
|
-
}
|
|
2149
|
-
},
|
|
2150
|
-
info: (logLevel, ...args) => {
|
|
2151
|
-
if (isEqualOrBelowLogLevel(logLevel, "info")) {
|
|
2152
|
-
return console.log(...args);
|
|
2153
|
-
}
|
|
2154
|
-
},
|
|
2155
|
-
warn: (logLevel, ...args) => {
|
|
2156
|
-
if (isEqualOrBelowLogLevel(logLevel, "warn")) {
|
|
2157
|
-
return console.warn(...args);
|
|
2158
|
-
}
|
|
2159
|
-
},
|
|
2160
|
-
error: (...args) => {
|
|
2161
|
-
return console.error(...args);
|
|
2162
|
-
}
|
|
2163
|
-
};
|
|
2164
|
-
|
|
2165
2274
|
// src/iterator/buffer-manager.ts
|
|
2166
2275
|
var bufferManager = ({
|
|
2167
2276
|
initialData,
|
|
@@ -2339,7 +2448,7 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
2339
2448
|
const six = getUint8();
|
|
2340
2449
|
const seven = getUint8();
|
|
2341
2450
|
const eight = getUint8();
|
|
2342
|
-
return eight << 56 | seven << 48 | six << 40 | five << 32 | four << 24 | three << 16 | two << 8 | one;
|
|
2451
|
+
return (eight << 56 | seven << 48 | six << 40 | five << 32 | four << 24 | three << 16 | two << 8 | one) >>> 0;
|
|
2343
2452
|
}
|
|
2344
2453
|
function byteArrayToBigInt(byteArray) {
|
|
2345
2454
|
let result = BigInt(0);
|
|
@@ -2361,7 +2470,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
2361
2470
|
return Number(bigInt);
|
|
2362
2471
|
};
|
|
2363
2472
|
const getFourByteNumber = () => {
|
|
2364
|
-
|
|
2473
|
+
const unsigned = getUint8() << 24 | getUint8() << 16 | getUint8() << 8 | getUint8();
|
|
2474
|
+
return unsigned >>> 0;
|
|
2365
2475
|
};
|
|
2366
2476
|
const getPaddedFourByteNumber = () => {
|
|
2367
2477
|
let lastInt = 128;
|
|
@@ -4027,7 +4137,7 @@ var isoBaseMediaHasTracks = (state, mayUsePrecomputed) => {
|
|
|
4027
4137
|
return Boolean(getMoovBoxFromState({
|
|
4028
4138
|
structureState: state.structure,
|
|
4029
4139
|
isoState: state.iso,
|
|
4030
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
4140
|
+
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
4031
4141
|
mayUsePrecomputed
|
|
4032
4142
|
}));
|
|
4033
4143
|
};
|
|
@@ -4112,11 +4222,16 @@ var getTracksFromMoovBox = (moovBox) => {
|
|
|
4112
4222
|
otherTracks
|
|
4113
4223
|
};
|
|
4114
4224
|
};
|
|
4115
|
-
var getTracksFromIsoBaseMedia = (
|
|
4225
|
+
var getTracksFromIsoBaseMedia = ({
|
|
4226
|
+
mayUsePrecomputed,
|
|
4227
|
+
structure,
|
|
4228
|
+
isoState,
|
|
4229
|
+
m3uPlaylistContext
|
|
4230
|
+
}) => {
|
|
4116
4231
|
const moovBox = getMoovBoxFromState({
|
|
4117
|
-
structureState:
|
|
4118
|
-
isoState
|
|
4119
|
-
mp4HeaderSegment:
|
|
4232
|
+
structureState: structure,
|
|
4233
|
+
isoState,
|
|
4234
|
+
mp4HeaderSegment: m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
4120
4235
|
mayUsePrecomputed
|
|
4121
4236
|
});
|
|
4122
4237
|
if (!moovBox) {
|
|
@@ -4145,7 +4260,12 @@ var getTracks = (state, mayUsePrecomputed) => {
|
|
|
4145
4260
|
return getCategorizedTracksFromMatroska(state);
|
|
4146
4261
|
}
|
|
4147
4262
|
if (structure.type === "iso-base-media") {
|
|
4148
|
-
return getTracksFromIsoBaseMedia(
|
|
4263
|
+
return getTracksFromIsoBaseMedia({
|
|
4264
|
+
isoState: state.iso,
|
|
4265
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
4266
|
+
structure: state.structure,
|
|
4267
|
+
mayUsePrecomputed
|
|
4268
|
+
});
|
|
4149
4269
|
}
|
|
4150
4270
|
if (structure.type === "riff") {
|
|
4151
4271
|
return getTracksFromAvi(structure, state);
|
|
@@ -4351,6 +4471,9 @@ var getAudioCodecFromAudioCodecInfo = (codec) => {
|
|
|
4351
4471
|
if (codec.format === "ac-3") {
|
|
4352
4472
|
return "ac3";
|
|
4353
4473
|
}
|
|
4474
|
+
if (codec.format === "Opus") {
|
|
4475
|
+
return "opus";
|
|
4476
|
+
}
|
|
4354
4477
|
if (codec.format === "mp4a") {
|
|
4355
4478
|
if (codec.primarySpecificator === 64) {
|
|
4356
4479
|
return "aac";
|
|
@@ -4533,11 +4656,15 @@ var collectSamplePositionsFromMoofBoxes = ({
|
|
|
4533
4656
|
tkhdBox
|
|
4534
4657
|
}) => {
|
|
4535
4658
|
const isComplete = tfraBoxes.length > 0 && tfraBoxes.every((t) => t.entries.length === moofBoxes.length);
|
|
4536
|
-
const samplePositions = moofBoxes.map((m) => {
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4659
|
+
const samplePositions = moofBoxes.map((m, index) => {
|
|
4660
|
+
const isLastFragment = index === moofBoxes.length - 1 && isComplete;
|
|
4661
|
+
return {
|
|
4662
|
+
isLastFragment,
|
|
4663
|
+
samples: getSamplesFromMoof({
|
|
4664
|
+
moofBox: m,
|
|
4665
|
+
trackId: tkhdBox.trackId
|
|
4666
|
+
})
|
|
4667
|
+
};
|
|
4541
4668
|
});
|
|
4542
4669
|
return { samplePositions, isComplete };
|
|
4543
4670
|
};
|
|
@@ -4570,14 +4697,14 @@ var getSamplePositions = ({
|
|
|
4570
4697
|
const samples = [];
|
|
4571
4698
|
let samplesPerChunk = 1;
|
|
4572
4699
|
for (let i = 0;i < chunks.length; i++) {
|
|
4573
|
-
const hasEntry = stscBox.entries.
|
|
4574
|
-
if (hasEntry) {
|
|
4575
|
-
samplesPerChunk = hasEntry
|
|
4700
|
+
const hasEntry = stscBox.entries.get(i + 1);
|
|
4701
|
+
if (hasEntry !== undefined) {
|
|
4702
|
+
samplesPerChunk = hasEntry;
|
|
4576
4703
|
}
|
|
4577
4704
|
let offsetInThisChunk = 0;
|
|
4578
4705
|
for (let j = 0;j < samplesPerChunk; j++) {
|
|
4579
4706
|
const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
|
|
4580
|
-
const isKeyframe = stssBox ? stssBox.sampleNumber.
|
|
4707
|
+
const isKeyframe = stssBox ? stssBox.sampleNumber.has(samples.length + 1) : true;
|
|
4581
4708
|
const delta = sttsDeltas[samples.length];
|
|
4582
4709
|
const ctsOffset = cttsEntries[samples.length];
|
|
4583
4710
|
const cts = dts + ctsOffset;
|
|
@@ -4621,11 +4748,16 @@ var getGroupedSamplesPositionsFromMp4 = ({
|
|
|
4621
4748
|
}
|
|
4622
4749
|
const samples = [];
|
|
4623
4750
|
let timestamp = 0;
|
|
4751
|
+
const stscKeys = Array.from(stscBox.entries.keys());
|
|
4624
4752
|
for (let i = 0;i < stcoBox.entries.length; i++) {
|
|
4625
4753
|
const entry = stcoBox.entries[i];
|
|
4626
4754
|
const chunk = i + 1;
|
|
4627
|
-
const stscEntry =
|
|
4628
|
-
if (
|
|
4755
|
+
const stscEntry = stscKeys.findLast((e) => e <= chunk);
|
|
4756
|
+
if (stscEntry === undefined) {
|
|
4757
|
+
throw new Error("should not be");
|
|
4758
|
+
}
|
|
4759
|
+
const samplesPerChunk = stscBox.entries.get(stscEntry);
|
|
4760
|
+
if (samplesPerChunk === undefined) {
|
|
4629
4761
|
throw new Error("should not be");
|
|
4630
4762
|
}
|
|
4631
4763
|
samples.push({
|
|
@@ -4633,13 +4765,13 @@ var getGroupedSamplesPositionsFromMp4 = ({
|
|
|
4633
4765
|
cts: timestamp,
|
|
4634
4766
|
dts: timestamp,
|
|
4635
4767
|
offset: Number(entry),
|
|
4636
|
-
size: stszBox.sampleSize *
|
|
4637
|
-
duration:
|
|
4768
|
+
size: stszBox.sampleSize * samplesPerChunk,
|
|
4769
|
+
duration: samplesPerChunk,
|
|
4638
4770
|
isKeyframe: true,
|
|
4639
4771
|
bigEndian,
|
|
4640
4772
|
chunkSize: stszBox.sampleSize
|
|
4641
4773
|
});
|
|
4642
|
-
timestamp +=
|
|
4774
|
+
timestamp += samplesPerChunk;
|
|
4643
4775
|
}
|
|
4644
4776
|
return samples;
|
|
4645
4777
|
};
|
|
@@ -4716,7 +4848,7 @@ var getSamplePositionsFromTrack = ({
|
|
|
4716
4848
|
tkhdBox
|
|
4717
4849
|
});
|
|
4718
4850
|
return {
|
|
4719
|
-
samplePositions: samplePositions.flat(1),
|
|
4851
|
+
samplePositions: samplePositions.map((s) => s.samples).flat(1),
|
|
4720
4852
|
isComplete
|
|
4721
4853
|
};
|
|
4722
4854
|
}
|
|
@@ -4950,7 +5082,7 @@ var getDurationFromIsoBaseMedia = (parserState) => {
|
|
|
4950
5082
|
const moovBox = getMoovBoxFromState({
|
|
4951
5083
|
structureState: parserState.structure,
|
|
4952
5084
|
isoState: parserState.iso,
|
|
4953
|
-
mp4HeaderSegment: parserState.mp4HeaderSegment,
|
|
5085
|
+
mp4HeaderSegment: parserState.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
4954
5086
|
mayUsePrecomputed: true
|
|
4955
5087
|
});
|
|
4956
5088
|
if (!moovBox) {
|
|
@@ -5056,7 +5188,12 @@ var hasHdr = (state) => {
|
|
|
5056
5188
|
|
|
5057
5189
|
// src/containers/iso-base-media/get-keyframes.ts
|
|
5058
5190
|
var getKeyframesFromIsoBaseMedia = (state) => {
|
|
5059
|
-
const { videoTracks } = getTracksFromIsoBaseMedia(
|
|
5191
|
+
const { videoTracks } = getTracksFromIsoBaseMedia({
|
|
5192
|
+
isoState: state.iso,
|
|
5193
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
5194
|
+
structure: state.structure,
|
|
5195
|
+
mayUsePrecomputed: true
|
|
5196
|
+
});
|
|
5060
5197
|
const structure = state.structure.getIsoStructure();
|
|
5061
5198
|
const moofBoxes = getMoofBoxes(structure.boxes);
|
|
5062
5199
|
const tfraBoxes = getTfraBoxes(structure);
|
|
@@ -5210,7 +5347,7 @@ var getMetadataFromIsoBase = (state) => {
|
|
|
5210
5347
|
const moov = getMoovBoxFromState({
|
|
5211
5348
|
structureState: state.structure,
|
|
5212
5349
|
isoState: state.iso,
|
|
5213
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
5350
|
+
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
5214
5351
|
mayUsePrecomputed: true
|
|
5215
5352
|
});
|
|
5216
5353
|
if (!moov) {
|
|
@@ -5476,6 +5613,75 @@ var getSeekingByteForFlac = ({
|
|
|
5476
5613
|
return null;
|
|
5477
5614
|
};
|
|
5478
5615
|
|
|
5616
|
+
// src/containers/iso-base-media/find-keyframe-before-time.ts
|
|
5617
|
+
var findKeyframeBeforeTime = ({
|
|
5618
|
+
samplePositions,
|
|
5619
|
+
time,
|
|
5620
|
+
timescale,
|
|
5621
|
+
mediaSections,
|
|
5622
|
+
logLevel
|
|
5623
|
+
}) => {
|
|
5624
|
+
let videoByte = 0;
|
|
5625
|
+
let videoSample = null;
|
|
5626
|
+
for (const sample of samplePositions) {
|
|
5627
|
+
const ctsInSeconds = sample.cts / timescale;
|
|
5628
|
+
const dtsInSeconds = sample.dts / timescale;
|
|
5629
|
+
if (!sample.isKeyframe) {
|
|
5630
|
+
continue;
|
|
5631
|
+
}
|
|
5632
|
+
if (!(ctsInSeconds <= time || dtsInSeconds <= time)) {
|
|
5633
|
+
continue;
|
|
5634
|
+
}
|
|
5635
|
+
if (videoByte <= sample.offset) {
|
|
5636
|
+
videoByte = sample.offset;
|
|
5637
|
+
videoSample = sample;
|
|
5638
|
+
}
|
|
5639
|
+
}
|
|
5640
|
+
if (!videoSample) {
|
|
5641
|
+
throw new Error("No sample found");
|
|
5642
|
+
}
|
|
5643
|
+
const mediaSection = mediaSections.find((section) => videoSample.offset >= section.start && videoSample.offset < section.start + section.size);
|
|
5644
|
+
if (!mediaSection) {
|
|
5645
|
+
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);
|
|
5646
|
+
return null;
|
|
5647
|
+
}
|
|
5648
|
+
return videoSample.offset;
|
|
5649
|
+
};
|
|
5650
|
+
|
|
5651
|
+
// src/containers/iso-base-media/find-track-to-seek.ts
|
|
5652
|
+
var findAnyTrackWithSamplePositions = (allTracks, struc) => {
|
|
5653
|
+
for (const track of allTracks) {
|
|
5654
|
+
if (track.type === "video" || track.type === "audio") {
|
|
5655
|
+
const { samplePositions } = getSamplePositionsFromTrack({
|
|
5656
|
+
trakBox: track.trakBox,
|
|
5657
|
+
moofBoxes: getMoofBoxes(struc.boxes),
|
|
5658
|
+
tfraBoxes: getTfraBoxes(struc)
|
|
5659
|
+
});
|
|
5660
|
+
if (samplePositions.length === 0) {
|
|
5661
|
+
continue;
|
|
5662
|
+
}
|
|
5663
|
+
return { track, samplePositions };
|
|
5664
|
+
}
|
|
5665
|
+
}
|
|
5666
|
+
return null;
|
|
5667
|
+
};
|
|
5668
|
+
var findTrackToSeek = (allTracks, structure) => {
|
|
5669
|
+
const firstVideoTrack = allTracks.find((t) => t.type === "video");
|
|
5670
|
+
const struc = structure.getIsoStructure();
|
|
5671
|
+
if (!firstVideoTrack) {
|
|
5672
|
+
return findAnyTrackWithSamplePositions(allTracks, struc);
|
|
5673
|
+
}
|
|
5674
|
+
const { samplePositions } = getSamplePositionsFromTrack({
|
|
5675
|
+
trakBox: firstVideoTrack.trakBox,
|
|
5676
|
+
moofBoxes: getMoofBoxes(struc.boxes),
|
|
5677
|
+
tfraBoxes: getTfraBoxes(struc)
|
|
5678
|
+
});
|
|
5679
|
+
if (samplePositions.length === 0) {
|
|
5680
|
+
return findAnyTrackWithSamplePositions(allTracks, struc);
|
|
5681
|
+
}
|
|
5682
|
+
return { track: firstVideoTrack, samplePositions };
|
|
5683
|
+
};
|
|
5684
|
+
|
|
5479
5685
|
// src/state/video-section.ts
|
|
5480
5686
|
var isByteInMediaSection = ({
|
|
5481
5687
|
position,
|
|
@@ -5544,42 +5750,13 @@ var mediaSectionState = () => {
|
|
|
5544
5750
|
};
|
|
5545
5751
|
};
|
|
5546
5752
|
|
|
5547
|
-
// src/containers/iso-base-media/find-keyframe-before-time.ts
|
|
5548
|
-
var findKeyframeBeforeTime = ({
|
|
5549
|
-
samplePositions,
|
|
5550
|
-
time,
|
|
5551
|
-
timescale,
|
|
5552
|
-
mediaSections,
|
|
5553
|
-
logLevel
|
|
5554
|
-
}) => {
|
|
5555
|
-
let byte = 0;
|
|
5556
|
-
let sam = null;
|
|
5557
|
-
for (const sample of samplePositions) {
|
|
5558
|
-
const ctsInSeconds = sample.cts / timescale;
|
|
5559
|
-
const dtsInSeconds = sample.dts / timescale;
|
|
5560
|
-
if ((ctsInSeconds <= time || dtsInSeconds <= time) && byte <= sample.offset && sample.isKeyframe) {
|
|
5561
|
-
byte = sample.offset;
|
|
5562
|
-
sam = sample;
|
|
5563
|
-
}
|
|
5564
|
-
}
|
|
5565
|
-
if (!sam) {
|
|
5566
|
-
throw new Error("No sample found");
|
|
5567
|
-
}
|
|
5568
|
-
const mediaSection = mediaSections.find((section) => sam.offset >= section.start && sam.offset < section.start + section.size);
|
|
5569
|
-
if (!mediaSection) {
|
|
5570
|
-
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);
|
|
5571
|
-
return null;
|
|
5572
|
-
}
|
|
5573
|
-
return sam.offset;
|
|
5574
|
-
};
|
|
5575
|
-
|
|
5576
5753
|
// src/containers/iso-base-media/get-sample-position-bounds.ts
|
|
5577
5754
|
var getSamplePositionBounds = (samplePositions, timescale) => {
|
|
5578
5755
|
let min = Infinity;
|
|
5579
5756
|
let max = -Infinity;
|
|
5580
5757
|
for (const samplePosition of samplePositions) {
|
|
5581
5758
|
const timestampMin = Math.min(samplePosition.cts, samplePosition.dts);
|
|
5582
|
-
const timestampMax = Math.max(samplePosition.cts, samplePosition.dts);
|
|
5759
|
+
const timestampMax = Math.max(samplePosition.cts, samplePosition.dts) + (samplePosition.duration ?? 0);
|
|
5583
5760
|
if (timestampMin < min) {
|
|
5584
5761
|
min = timestampMin;
|
|
5585
5762
|
}
|
|
@@ -5594,10 +5771,10 @@ var getSamplePositionBounds = (samplePositions, timescale) => {
|
|
|
5594
5771
|
var findBestSegmentFromTfra = ({
|
|
5595
5772
|
mfra,
|
|
5596
5773
|
time,
|
|
5597
|
-
|
|
5774
|
+
firstTrack,
|
|
5598
5775
|
timescale
|
|
5599
5776
|
}) => {
|
|
5600
|
-
const tfra = mfra.find((b) => b.type === "tfra-box" && b.trackId ===
|
|
5777
|
+
const tfra = mfra.find((b) => b.type === "tfra-box" && b.trackId === firstTrack.trackId);
|
|
5601
5778
|
if (!tfra) {
|
|
5602
5779
|
return null;
|
|
5603
5780
|
}
|
|
@@ -5618,130 +5795,191 @@ var findBestSegmentFromTfra = ({
|
|
|
5618
5795
|
};
|
|
5619
5796
|
};
|
|
5620
5797
|
|
|
5621
|
-
// src/containers/iso-base-media/get-seeking-byte.ts
|
|
5622
|
-
var
|
|
5798
|
+
// src/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.ts
|
|
5799
|
+
var getSeekingByteFromFragmentedMp4 = async ({
|
|
5623
5800
|
info,
|
|
5624
5801
|
time,
|
|
5625
5802
|
logLevel,
|
|
5626
5803
|
currentPosition,
|
|
5627
5804
|
isoState,
|
|
5628
|
-
|
|
5629
|
-
|
|
5805
|
+
allTracks,
|
|
5806
|
+
isLastChunkInPlaylist
|
|
5630
5807
|
}) => {
|
|
5631
|
-
const tracks2 = getTracksFromMoovBox(info.moovBox);
|
|
5632
|
-
const allTracks = [
|
|
5633
|
-
...tracks2.videoTracks,
|
|
5634
|
-
...tracks2.audioTracks,
|
|
5635
|
-
...tracks2.otherTracks
|
|
5636
|
-
];
|
|
5637
|
-
const hasMoov = Boolean(getMoovBoxFromState({
|
|
5638
|
-
mp4HeaderSegment,
|
|
5639
|
-
structureState: structure,
|
|
5640
|
-
isoState,
|
|
5641
|
-
mayUsePrecomputed: false
|
|
5642
|
-
}));
|
|
5643
|
-
if (!hasMoov) {
|
|
5644
|
-
Log.trace(logLevel, "No moov box found, must wait");
|
|
5645
|
-
return {
|
|
5646
|
-
type: "valid-but-must-wait"
|
|
5647
|
-
};
|
|
5648
|
-
}
|
|
5649
5808
|
const firstVideoTrack = allTracks.find((t) => t.type === "video");
|
|
5650
|
-
|
|
5651
|
-
|
|
5809
|
+
const firstTrack = firstVideoTrack ?? allTracks.find((t) => t.type === "audio");
|
|
5810
|
+
if (!firstTrack) {
|
|
5811
|
+
throw new Error("no video and no audio tracks");
|
|
5652
5812
|
}
|
|
5653
|
-
const
|
|
5654
|
-
if (
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
const kf = findKeyframeBeforeTime({
|
|
5670
|
-
samplePositions: positions,
|
|
5671
|
-
time,
|
|
5672
|
-
timescale,
|
|
5673
|
-
logLevel,
|
|
5674
|
-
mediaSections: info.mediaSections
|
|
5675
|
-
});
|
|
5676
|
-
if (kf) {
|
|
5677
|
-
return {
|
|
5678
|
-
type: "do-seek",
|
|
5679
|
-
byte: kf
|
|
5680
|
-
};
|
|
5681
|
-
}
|
|
5682
|
-
}
|
|
5683
|
-
}
|
|
5684
|
-
const atom = await (info.mfraAlreadyLoaded ? Promise.resolve(info.mfraAlreadyLoaded) : isoState.mfra.triggerLoad());
|
|
5685
|
-
if (atom) {
|
|
5686
|
-
const moofOffset = findBestSegmentFromTfra({
|
|
5687
|
-
mfra: atom,
|
|
5813
|
+
const tkhdBox = getTkhdBox(firstTrack.trakBox);
|
|
5814
|
+
if (!tkhdBox) {
|
|
5815
|
+
throw new Error("Expected tkhd box in trak box");
|
|
5816
|
+
}
|
|
5817
|
+
const { samplePositions: samplePositionsArray } = collectSamplePositionsFromMoofBoxes({
|
|
5818
|
+
moofBoxes: info.moofBoxes,
|
|
5819
|
+
tfraBoxes: info.tfraBoxes,
|
|
5820
|
+
tkhdBox
|
|
5821
|
+
});
|
|
5822
|
+
Log.trace(logLevel, "Fragmented MP4 - Checking if we have seeking info for this time range");
|
|
5823
|
+
for (const positions of samplePositionsArray) {
|
|
5824
|
+
const { min, max } = getSamplePositionBounds(positions.samples, firstTrack.timescale);
|
|
5825
|
+
if (min <= time && (positions.isLastFragment || isLastChunkInPlaylist || time <= max)) {
|
|
5826
|
+
Log.trace(logLevel, `Fragmented MP4 - Found that we have seeking info for this time range: ${min} <= ${time} <= ${max}`);
|
|
5827
|
+
const kf = findKeyframeBeforeTime({
|
|
5828
|
+
samplePositions: positions.samples,
|
|
5688
5829
|
time,
|
|
5689
|
-
|
|
5690
|
-
|
|
5830
|
+
timescale: firstTrack.timescale,
|
|
5831
|
+
logLevel,
|
|
5832
|
+
mediaSections: info.mediaSections
|
|
5691
5833
|
});
|
|
5692
|
-
if (
|
|
5693
|
-
Log.verbose(logLevel, `Fragmented MP4 - Found based on mfra information that we should seek to: ${moofOffset.start} ${moofOffset.end}`);
|
|
5834
|
+
if (kf) {
|
|
5694
5835
|
return {
|
|
5695
|
-
type: "
|
|
5696
|
-
byte:
|
|
5836
|
+
type: "do-seek",
|
|
5837
|
+
byte: kf
|
|
5697
5838
|
};
|
|
5698
5839
|
}
|
|
5699
5840
|
}
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
}
|
|
5709
|
-
Log.trace(logLevel, "Fragmented MP4 - Inside the wrong video section, skipping to the end of the section");
|
|
5710
|
-
const mediaSection = getCurrentMediaSection({
|
|
5711
|
-
offset: currentPosition,
|
|
5712
|
-
mediaSections: info.mediaSections
|
|
5841
|
+
}
|
|
5842
|
+
const atom = await (info.mfraAlreadyLoaded ? Promise.resolve(info.mfraAlreadyLoaded) : isoState.mfra.triggerLoad());
|
|
5843
|
+
if (atom) {
|
|
5844
|
+
const moofOffset = findBestSegmentFromTfra({
|
|
5845
|
+
mfra: atom,
|
|
5846
|
+
time,
|
|
5847
|
+
firstTrack,
|
|
5848
|
+
timescale: firstTrack.timescale
|
|
5713
5849
|
});
|
|
5714
|
-
if (!
|
|
5715
|
-
|
|
5850
|
+
if (moofOffset !== null && !(moofOffset.start <= currentPosition && currentPosition < moofOffset.end)) {
|
|
5851
|
+
Log.verbose(logLevel, `Fragmented MP4 - Found based on mfra information that we should seek to: ${moofOffset.start} ${moofOffset.end}`);
|
|
5852
|
+
return {
|
|
5853
|
+
type: "intermediary-seek",
|
|
5854
|
+
byte: moofOffset.start
|
|
5855
|
+
};
|
|
5716
5856
|
}
|
|
5857
|
+
}
|
|
5858
|
+
Log.trace(logLevel, "Fragmented MP4 - No seeking info found for this time range.");
|
|
5859
|
+
if (isByteInMediaSection({
|
|
5860
|
+
position: currentPosition,
|
|
5861
|
+
mediaSections: info.mediaSections
|
|
5862
|
+
}) !== "in-section") {
|
|
5717
5863
|
return {
|
|
5718
|
-
type: "
|
|
5719
|
-
byte: mediaSection.start + mediaSection.size
|
|
5864
|
+
type: "valid-but-must-wait"
|
|
5720
5865
|
};
|
|
5721
5866
|
}
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5867
|
+
Log.trace(logLevel, "Fragmented MP4 - Inside the wrong video section, skipping to the end of the section");
|
|
5868
|
+
const mediaSection = getCurrentMediaSection({
|
|
5869
|
+
offset: currentPosition,
|
|
5870
|
+
mediaSections: info.mediaSections
|
|
5871
|
+
});
|
|
5872
|
+
if (!mediaSection) {
|
|
5873
|
+
throw new Error("No video section defined");
|
|
5874
|
+
}
|
|
5875
|
+
return {
|
|
5876
|
+
type: "intermediary-seek",
|
|
5877
|
+
byte: mediaSection.start + mediaSection.size
|
|
5878
|
+
};
|
|
5879
|
+
};
|
|
5880
|
+
|
|
5881
|
+
// src/containers/iso-base-media/get-seeking-byte.ts
|
|
5882
|
+
var getSeekingByteFromIsoBaseMedia = ({
|
|
5883
|
+
info,
|
|
5884
|
+
time,
|
|
5885
|
+
logLevel,
|
|
5886
|
+
currentPosition,
|
|
5887
|
+
isoState,
|
|
5888
|
+
m3uPlaylistContext,
|
|
5889
|
+
structure
|
|
5890
|
+
}) => {
|
|
5891
|
+
const tracks2 = getTracksFromIsoBaseMedia({
|
|
5892
|
+
isoState,
|
|
5893
|
+
m3uPlaylistContext,
|
|
5894
|
+
structure,
|
|
5895
|
+
mayUsePrecomputed: false
|
|
5726
5896
|
});
|
|
5727
|
-
|
|
5728
|
-
|
|
5897
|
+
const allTracks = [
|
|
5898
|
+
...tracks2.videoTracks,
|
|
5899
|
+
...tracks2.audioTracks,
|
|
5900
|
+
...tracks2.otherTracks
|
|
5901
|
+
];
|
|
5902
|
+
const hasMoov = Boolean(getMoovBoxFromState({
|
|
5903
|
+
structureState: structure,
|
|
5904
|
+
isoState,
|
|
5905
|
+
mayUsePrecomputed: false,
|
|
5906
|
+
mp4HeaderSegment: m3uPlaylistContext?.mp4HeaderSegment ?? null
|
|
5907
|
+
}));
|
|
5908
|
+
if (!hasMoov) {
|
|
5909
|
+
Log.trace(logLevel, "No moov box found, must wait");
|
|
5910
|
+
return Promise.resolve({
|
|
5911
|
+
type: "valid-but-must-wait"
|
|
5912
|
+
});
|
|
5913
|
+
}
|
|
5914
|
+
if (info.moofBoxes.length > 0) {
|
|
5915
|
+
return getSeekingByteFromFragmentedMp4({
|
|
5916
|
+
info,
|
|
5917
|
+
time,
|
|
5918
|
+
logLevel,
|
|
5919
|
+
currentPosition,
|
|
5920
|
+
isoState,
|
|
5921
|
+
allTracks,
|
|
5922
|
+
isLastChunkInPlaylist: m3uPlaylistContext?.isLastChunkInPlaylist ?? false
|
|
5923
|
+
});
|
|
5729
5924
|
}
|
|
5925
|
+
const trackWithSamplePositions = findTrackToSeek(allTracks, structure);
|
|
5926
|
+
if (!trackWithSamplePositions) {
|
|
5927
|
+
return Promise.resolve({
|
|
5928
|
+
type: "valid-but-must-wait"
|
|
5929
|
+
});
|
|
5930
|
+
}
|
|
5931
|
+
const { track, samplePositions } = trackWithSamplePositions;
|
|
5730
5932
|
const keyframe = findKeyframeBeforeTime({
|
|
5731
5933
|
samplePositions,
|
|
5732
5934
|
time,
|
|
5733
|
-
timescale,
|
|
5935
|
+
timescale: track.timescale,
|
|
5734
5936
|
logLevel,
|
|
5735
5937
|
mediaSections: info.mediaSections
|
|
5736
5938
|
});
|
|
5737
5939
|
if (keyframe) {
|
|
5738
|
-
return {
|
|
5940
|
+
return Promise.resolve({
|
|
5739
5941
|
type: "do-seek",
|
|
5740
5942
|
byte: keyframe
|
|
5741
|
-
};
|
|
5943
|
+
});
|
|
5742
5944
|
}
|
|
5743
|
-
return {
|
|
5945
|
+
return Promise.resolve({
|
|
5744
5946
|
type: "invalid"
|
|
5947
|
+
});
|
|
5948
|
+
};
|
|
5949
|
+
|
|
5950
|
+
// src/containers/m3u/get-seeking-byte.ts
|
|
5951
|
+
var clearM3uStateInPrepareForSeek = ({
|
|
5952
|
+
m3uState,
|
|
5953
|
+
logLevel
|
|
5954
|
+
}) => {
|
|
5955
|
+
const selectedPlaylists = m3uState.getSelectedPlaylists();
|
|
5956
|
+
for (const playlistUrl of selectedPlaylists) {
|
|
5957
|
+
const streamRun = m3uState.getM3uStreamRun(playlistUrl);
|
|
5958
|
+
if (streamRun) {
|
|
5959
|
+
streamRun.abort();
|
|
5960
|
+
}
|
|
5961
|
+
Log.trace(logLevel, "Clearing M3U stream run for", playlistUrl);
|
|
5962
|
+
m3uState.setM3uStreamRun(playlistUrl, null);
|
|
5963
|
+
}
|
|
5964
|
+
m3uState.clearAllChunksProcessed();
|
|
5965
|
+
m3uState.sampleSorter.clearSamples();
|
|
5966
|
+
};
|
|
5967
|
+
var getSeekingByteForM3u8 = ({
|
|
5968
|
+
time,
|
|
5969
|
+
currentPosition,
|
|
5970
|
+
m3uState,
|
|
5971
|
+
logLevel
|
|
5972
|
+
}) => {
|
|
5973
|
+
clearM3uStateInPrepareForSeek({ m3uState, logLevel });
|
|
5974
|
+
const selectedPlaylists = m3uState.getSelectedPlaylists();
|
|
5975
|
+
for (const playlistUrl of selectedPlaylists) {
|
|
5976
|
+
m3uState.setSeekToSecondsToProcess(playlistUrl, {
|
|
5977
|
+
targetTime: time
|
|
5978
|
+
});
|
|
5979
|
+
}
|
|
5980
|
+
return {
|
|
5981
|
+
type: "do-seek",
|
|
5982
|
+
byte: currentPosition
|
|
5745
5983
|
};
|
|
5746
5984
|
};
|
|
5747
5985
|
|
|
@@ -6678,9 +6916,10 @@ var getSeekingByte = ({
|
|
|
6678
6916
|
transportStream,
|
|
6679
6917
|
webmState,
|
|
6680
6918
|
mediaSection,
|
|
6681
|
-
|
|
6919
|
+
m3uPlaylistContext,
|
|
6682
6920
|
structure,
|
|
6683
|
-
riffState
|
|
6921
|
+
riffState,
|
|
6922
|
+
m3uState
|
|
6684
6923
|
}) => {
|
|
6685
6924
|
if (info.type === "iso-base-media-seeking-hints") {
|
|
6686
6925
|
return getSeekingByteFromIsoBaseMedia({
|
|
@@ -6689,8 +6928,8 @@ var getSeekingByte = ({
|
|
|
6689
6928
|
logLevel,
|
|
6690
6929
|
currentPosition,
|
|
6691
6930
|
isoState,
|
|
6692
|
-
|
|
6693
|
-
|
|
6931
|
+
structure,
|
|
6932
|
+
m3uPlaylistContext
|
|
6694
6933
|
});
|
|
6695
6934
|
}
|
|
6696
6935
|
if (info.type === "wav-seeking-hints") {
|
|
@@ -6755,6 +6994,14 @@ var getSeekingByte = ({
|
|
|
6755
6994
|
seekingHints: info
|
|
6756
6995
|
}));
|
|
6757
6996
|
}
|
|
6997
|
+
if (info.type === "m3u8-seeking-hints") {
|
|
6998
|
+
return Promise.resolve(getSeekingByteForM3u8({
|
|
6999
|
+
time,
|
|
7000
|
+
currentPosition,
|
|
7001
|
+
m3uState,
|
|
7002
|
+
logLevel
|
|
7003
|
+
}));
|
|
7004
|
+
}
|
|
6758
7005
|
throw new Error(`Unknown seeking info type: ${info}`);
|
|
6759
7006
|
};
|
|
6760
7007
|
|
|
@@ -6843,6 +7090,13 @@ var getSeekingHintsFromMp4 = ({
|
|
|
6843
7090
|
};
|
|
6844
7091
|
var setSeekingHintsForMp4 = ({}) => {};
|
|
6845
7092
|
|
|
7093
|
+
// src/containers/m3u/seeking-hints.ts
|
|
7094
|
+
var getSeekingHintsForM3u = () => {
|
|
7095
|
+
return {
|
|
7096
|
+
type: "m3u8-seeking-hints"
|
|
7097
|
+
};
|
|
7098
|
+
};
|
|
7099
|
+
|
|
6846
7100
|
// src/containers/mp3/seeking-hints.ts
|
|
6847
7101
|
var getSeekingHintsForMp3 = ({
|
|
6848
7102
|
mp3State,
|
|
@@ -6989,7 +7243,7 @@ var setSeekingHintsForWebm = ({
|
|
|
6989
7243
|
// src/get-seeking-hints.ts
|
|
6990
7244
|
var getSeekingHints = ({
|
|
6991
7245
|
structureState,
|
|
6992
|
-
|
|
7246
|
+
m3uPlaylistContext,
|
|
6993
7247
|
mediaSectionState: mediaSectionState2,
|
|
6994
7248
|
isoState,
|
|
6995
7249
|
transportStream,
|
|
@@ -7011,7 +7265,7 @@ var getSeekingHints = ({
|
|
|
7011
7265
|
return getSeekingHintsFromMp4({
|
|
7012
7266
|
structureState,
|
|
7013
7267
|
isoState,
|
|
7014
|
-
mp4HeaderSegment,
|
|
7268
|
+
mp4HeaderSegment: m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
7015
7269
|
mediaSectionState: mediaSectionState2
|
|
7016
7270
|
});
|
|
7017
7271
|
}
|
|
@@ -7054,7 +7308,10 @@ var getSeekingHints = ({
|
|
|
7054
7308
|
samplesObserved
|
|
7055
7309
|
});
|
|
7056
7310
|
}
|
|
7057
|
-
|
|
7311
|
+
if (structure.type === "m3u") {
|
|
7312
|
+
return getSeekingHintsForM3u();
|
|
7313
|
+
}
|
|
7314
|
+
throw new Error(`Seeking is not supported for this format: ${structure}`);
|
|
7058
7315
|
};
|
|
7059
7316
|
|
|
7060
7317
|
// src/seek-backwards.ts
|
|
@@ -7065,10 +7322,12 @@ var seekBackwards = async ({
|
|
|
7065
7322
|
src,
|
|
7066
7323
|
controller,
|
|
7067
7324
|
logLevel,
|
|
7068
|
-
currentReader
|
|
7325
|
+
currentReader,
|
|
7326
|
+
prefetchCache
|
|
7069
7327
|
}) => {
|
|
7070
7328
|
const howManyBytesWeCanGoBack = iterator.counter.getDiscardedOffset();
|
|
7071
7329
|
if (iterator.counter.getOffset() - howManyBytesWeCanGoBack <= seekTo) {
|
|
7330
|
+
Log.verbose(logLevel, `Seeking back to ${seekTo}`);
|
|
7072
7331
|
iterator.skipTo(seekTo);
|
|
7073
7332
|
return;
|
|
7074
7333
|
}
|
|
@@ -7077,7 +7336,9 @@ var seekBackwards = async ({
|
|
|
7077
7336
|
const { reader: newReader } = await readerInterface.read({
|
|
7078
7337
|
src,
|
|
7079
7338
|
range: seekTo,
|
|
7080
|
-
controller
|
|
7339
|
+
controller,
|
|
7340
|
+
logLevel,
|
|
7341
|
+
prefetchCache
|
|
7081
7342
|
});
|
|
7082
7343
|
iterator.replaceData(new Uint8Array([]), seekTo);
|
|
7083
7344
|
Log.verbose(logLevel, `Re-reading took ${Date.now() - time}ms. New position: ${iterator.counter.getOffset()}`);
|
|
@@ -7147,7 +7408,8 @@ var seekForward = async ({
|
|
|
7147
7408
|
readerInterface,
|
|
7148
7409
|
src,
|
|
7149
7410
|
controller,
|
|
7150
|
-
discardReadBytes
|
|
7411
|
+
discardReadBytes,
|
|
7412
|
+
prefetchCache
|
|
7151
7413
|
}) => {
|
|
7152
7414
|
if (userInitiated) {
|
|
7153
7415
|
disallowForwardSeekIfSamplesAreNeeded({
|
|
@@ -7168,7 +7430,9 @@ var seekForward = async ({
|
|
|
7168
7430
|
const { reader: newReader } = await readerInterface.read({
|
|
7169
7431
|
src,
|
|
7170
7432
|
range: seekTo,
|
|
7171
|
-
controller
|
|
7433
|
+
controller,
|
|
7434
|
+
logLevel,
|
|
7435
|
+
prefetchCache
|
|
7172
7436
|
});
|
|
7173
7437
|
iterator.skipTo(seekTo);
|
|
7174
7438
|
await discardReadBytes(true);
|
|
@@ -7191,7 +7455,8 @@ var performSeek = async ({
|
|
|
7191
7455
|
readerInterface,
|
|
7192
7456
|
src,
|
|
7193
7457
|
discardReadBytes,
|
|
7194
|
-
fields
|
|
7458
|
+
fields,
|
|
7459
|
+
prefetchCache
|
|
7195
7460
|
}) => {
|
|
7196
7461
|
const byteInMediaSection = isByteInMediaSection({
|
|
7197
7462
|
position: seekTo,
|
|
@@ -7240,7 +7505,8 @@ var performSeek = async ({
|
|
|
7240
7505
|
readerInterface,
|
|
7241
7506
|
src,
|
|
7242
7507
|
controller,
|
|
7243
|
-
discardReadBytes
|
|
7508
|
+
discardReadBytes,
|
|
7509
|
+
prefetchCache
|
|
7244
7510
|
});
|
|
7245
7511
|
} else {
|
|
7246
7512
|
await seekBackwards({
|
|
@@ -7250,7 +7516,8 @@ var performSeek = async ({
|
|
|
7250
7516
|
logLevel,
|
|
7251
7517
|
currentReader,
|
|
7252
7518
|
readerInterface,
|
|
7253
|
-
src
|
|
7519
|
+
src,
|
|
7520
|
+
prefetchCache
|
|
7254
7521
|
});
|
|
7255
7522
|
}
|
|
7256
7523
|
await controller._internals.checkForAbortAndPause();
|
|
@@ -7263,7 +7530,7 @@ var turnSeekIntoByte = async ({
|
|
|
7263
7530
|
logLevel,
|
|
7264
7531
|
iterator,
|
|
7265
7532
|
structureState,
|
|
7266
|
-
|
|
7533
|
+
m3uPlaylistContext,
|
|
7267
7534
|
isoState,
|
|
7268
7535
|
transportStream,
|
|
7269
7536
|
tracksState,
|
|
@@ -7274,7 +7541,8 @@ var turnSeekIntoByte = async ({
|
|
|
7274
7541
|
riffState,
|
|
7275
7542
|
mp3State,
|
|
7276
7543
|
contentLength,
|
|
7277
|
-
aacState
|
|
7544
|
+
aacState,
|
|
7545
|
+
m3uState
|
|
7278
7546
|
}) => {
|
|
7279
7547
|
const mediaSections = mediaSectionState2.getMediaSections();
|
|
7280
7548
|
if (mediaSections.length === 0) {
|
|
@@ -7291,7 +7559,6 @@ var turnSeekIntoByte = async ({
|
|
|
7291
7559
|
riffState,
|
|
7292
7560
|
samplesObserved,
|
|
7293
7561
|
structureState,
|
|
7294
|
-
mp4HeaderSegment,
|
|
7295
7562
|
mediaSectionState: mediaSectionState2,
|
|
7296
7563
|
isoState,
|
|
7297
7564
|
transportStream,
|
|
@@ -7301,7 +7568,8 @@ var turnSeekIntoByte = async ({
|
|
|
7301
7568
|
flacState,
|
|
7302
7569
|
mp3State,
|
|
7303
7570
|
contentLength,
|
|
7304
|
-
aacState
|
|
7571
|
+
aacState,
|
|
7572
|
+
m3uPlaylistContext
|
|
7305
7573
|
});
|
|
7306
7574
|
if (!seekingHints) {
|
|
7307
7575
|
Log.trace(logLevel, "No seeking info, cannot seek yet");
|
|
@@ -7318,18 +7586,13 @@ var turnSeekIntoByte = async ({
|
|
|
7318
7586
|
transportStream,
|
|
7319
7587
|
webmState,
|
|
7320
7588
|
mediaSection: mediaSectionState2,
|
|
7321
|
-
|
|
7589
|
+
m3uPlaylistContext,
|
|
7322
7590
|
structure: structureState,
|
|
7323
|
-
riffState
|
|
7591
|
+
riffState,
|
|
7592
|
+
m3uState
|
|
7324
7593
|
});
|
|
7325
7594
|
return seekingByte;
|
|
7326
7595
|
}
|
|
7327
|
-
if (seek2.type === "byte") {
|
|
7328
|
-
return {
|
|
7329
|
-
type: "do-seek",
|
|
7330
|
-
byte: seek2.byte
|
|
7331
|
-
};
|
|
7332
|
-
}
|
|
7333
7596
|
throw new Error(`Cannot process seek request for ${seek2}: ${JSON.stringify(seek2)}`);
|
|
7334
7597
|
};
|
|
7335
7598
|
var getWorkOnSeekRequestOptions = (state) => {
|
|
@@ -7343,7 +7606,7 @@ var getWorkOnSeekRequestOptions = (state) => {
|
|
|
7343
7606
|
contentLength: state.contentLength,
|
|
7344
7607
|
readerInterface: state.readerInterface,
|
|
7345
7608
|
mediaSection: state.mediaSection,
|
|
7346
|
-
|
|
7609
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
7347
7610
|
mode: state.mode,
|
|
7348
7611
|
seekInfiniteLoop: state.seekInfiniteLoop,
|
|
7349
7612
|
currentReader: state.currentReader,
|
|
@@ -7357,7 +7620,9 @@ var getWorkOnSeekRequestOptions = (state) => {
|
|
|
7357
7620
|
samplesObserved: state.samplesObserved,
|
|
7358
7621
|
riffState: state.riff,
|
|
7359
7622
|
mp3State: state.mp3,
|
|
7360
|
-
aacState: state.aac
|
|
7623
|
+
aacState: state.aac,
|
|
7624
|
+
m3uState: state.m3u,
|
|
7625
|
+
prefetchCache: state.prefetchCache
|
|
7361
7626
|
};
|
|
7362
7627
|
};
|
|
7363
7628
|
var workOnSeekRequest = async (options) => {
|
|
@@ -7365,7 +7630,7 @@ var workOnSeekRequest = async (options) => {
|
|
|
7365
7630
|
logLevel,
|
|
7366
7631
|
controller,
|
|
7367
7632
|
mediaSection,
|
|
7368
|
-
|
|
7633
|
+
m3uPlaylistContext,
|
|
7369
7634
|
isoState,
|
|
7370
7635
|
iterator,
|
|
7371
7636
|
structureState,
|
|
@@ -7385,20 +7650,22 @@ var workOnSeekRequest = async (options) => {
|
|
|
7385
7650
|
samplesObserved,
|
|
7386
7651
|
riffState,
|
|
7387
7652
|
mp3State,
|
|
7388
|
-
aacState
|
|
7653
|
+
aacState,
|
|
7654
|
+
prefetchCache,
|
|
7655
|
+
m3uState
|
|
7389
7656
|
} = options;
|
|
7390
7657
|
const seek2 = controller._internals.seekSignal.getSeek();
|
|
7391
7658
|
if (!seek2) {
|
|
7392
7659
|
return;
|
|
7393
7660
|
}
|
|
7394
|
-
Log.trace(logLevel, `Has seek request: ${JSON.stringify(seek2)}`);
|
|
7661
|
+
Log.trace(logLevel, `Has seek request for ${src}: ${JSON.stringify(seek2)}`);
|
|
7395
7662
|
const resolution = await turnSeekIntoByte({
|
|
7396
7663
|
seek: seek2,
|
|
7397
7664
|
mediaSectionState: mediaSection,
|
|
7398
7665
|
logLevel,
|
|
7399
7666
|
iterator,
|
|
7400
7667
|
structureState,
|
|
7401
|
-
|
|
7668
|
+
m3uPlaylistContext,
|
|
7402
7669
|
isoState,
|
|
7403
7670
|
transportStream,
|
|
7404
7671
|
tracksState,
|
|
@@ -7409,7 +7676,8 @@ var workOnSeekRequest = async (options) => {
|
|
|
7409
7676
|
riffState,
|
|
7410
7677
|
mp3State,
|
|
7411
7678
|
contentLength,
|
|
7412
|
-
aacState
|
|
7679
|
+
aacState,
|
|
7680
|
+
m3uState
|
|
7413
7681
|
});
|
|
7414
7682
|
Log.trace(logLevel, `Seek action: ${JSON.stringify(resolution)}`);
|
|
7415
7683
|
if (resolution.type === "intermediary-seek") {
|
|
@@ -7427,7 +7695,8 @@ var workOnSeekRequest = async (options) => {
|
|
|
7427
7695
|
readerInterface,
|
|
7428
7696
|
src,
|
|
7429
7697
|
discardReadBytes,
|
|
7430
|
-
fields
|
|
7698
|
+
fields,
|
|
7699
|
+
prefetchCache
|
|
7431
7700
|
});
|
|
7432
7701
|
return;
|
|
7433
7702
|
}
|
|
@@ -7446,7 +7715,8 @@ var workOnSeekRequest = async (options) => {
|
|
|
7446
7715
|
readerInterface,
|
|
7447
7716
|
src,
|
|
7448
7717
|
discardReadBytes,
|
|
7449
|
-
fields
|
|
7718
|
+
fields,
|
|
7719
|
+
prefetchCache
|
|
7450
7720
|
});
|
|
7451
7721
|
const { hasChanged } = controller._internals.seekSignal.clearSeekIfStillSame(seek2);
|
|
7452
7722
|
if (hasChanged) {
|
|
@@ -8072,6 +8342,10 @@ var makeSkip = (skipTo) => ({
|
|
|
8072
8342
|
action: "skip",
|
|
8073
8343
|
skipTo
|
|
8074
8344
|
});
|
|
8345
|
+
var makeFetchMoreData = (bytesNeeded) => ({
|
|
8346
|
+
action: "fetch-more-data",
|
|
8347
|
+
bytesNeeded
|
|
8348
|
+
});
|
|
8075
8349
|
|
|
8076
8350
|
// src/containers/flac/get-block-size.ts
|
|
8077
8351
|
var getBlockSize = (iterator) => {
|
|
@@ -8526,11 +8800,12 @@ var calculateFlatSamples = (state) => {
|
|
|
8526
8800
|
samplePosition
|
|
8527
8801
|
};
|
|
8528
8802
|
});
|
|
8529
|
-
})
|
|
8803
|
+
});
|
|
8530
8804
|
return flatSamples;
|
|
8531
8805
|
};
|
|
8532
8806
|
var cachedSamplePositionsState = () => {
|
|
8533
8807
|
const cachedForMdatStart = {};
|
|
8808
|
+
const jumpMarksForMdatStart = {};
|
|
8534
8809
|
return {
|
|
8535
8810
|
getSamples: (mdatStart) => {
|
|
8536
8811
|
if (cachedForMdatStart[mdatStart]) {
|
|
@@ -8540,6 +8815,12 @@ var cachedSamplePositionsState = () => {
|
|
|
8540
8815
|
},
|
|
8541
8816
|
setSamples: (mdatStart, samples) => {
|
|
8542
8817
|
cachedForMdatStart[mdatStart] = samples;
|
|
8818
|
+
},
|
|
8819
|
+
setJumpMarks: (mdatStart, marks) => {
|
|
8820
|
+
jumpMarksForMdatStart[mdatStart] = marks;
|
|
8821
|
+
},
|
|
8822
|
+
getJumpMarks: (mdatStart) => {
|
|
8823
|
+
return jumpMarksForMdatStart[mdatStart];
|
|
8543
8824
|
}
|
|
8544
8825
|
};
|
|
8545
8826
|
};
|
|
@@ -8569,17 +8850,21 @@ var makeCanSkipTracksState = ({
|
|
|
8569
8850
|
hasVideoTrackHandlers,
|
|
8570
8851
|
structure
|
|
8571
8852
|
}) => {
|
|
8853
|
+
const doFieldsNeedTracks = () => {
|
|
8854
|
+
const keys = Object.keys(fields ?? {});
|
|
8855
|
+
const selectedKeys = keys.filter((k) => fields[k]);
|
|
8856
|
+
return selectedKeys.some((k) => needsTracksForField({
|
|
8857
|
+
field: k,
|
|
8858
|
+
structure: structure.getStructureOrNull()
|
|
8859
|
+
}));
|
|
8860
|
+
};
|
|
8572
8861
|
return {
|
|
8862
|
+
doFieldsNeedTracks,
|
|
8573
8863
|
canSkipTracks: () => {
|
|
8574
8864
|
if (hasAudioTrackHandlers || hasVideoTrackHandlers) {
|
|
8575
8865
|
return false;
|
|
8576
8866
|
}
|
|
8577
|
-
|
|
8578
|
-
const selectedKeys = keys.filter((k) => fields[k]);
|
|
8579
|
-
return !selectedKeys.some((k) => needsTracksForField({
|
|
8580
|
-
field: k,
|
|
8581
|
-
structure: structure.getStructureOrNull()
|
|
8582
|
-
}));
|
|
8867
|
+
return !doFieldsNeedTracks();
|
|
8583
8868
|
}
|
|
8584
8869
|
};
|
|
8585
8870
|
};
|
|
@@ -8870,10 +9155,10 @@ var getIsoBaseMediaChildren = async ({
|
|
|
8870
9155
|
onlyIfMdatAtomExpected: null,
|
|
8871
9156
|
contentLength
|
|
8872
9157
|
});
|
|
8873
|
-
if (
|
|
9158
|
+
if (parsed.type !== "box") {
|
|
8874
9159
|
throw new Error("Expected box");
|
|
8875
9160
|
}
|
|
8876
|
-
boxes.push(parsed);
|
|
9161
|
+
boxes.push(parsed.box);
|
|
8877
9162
|
}
|
|
8878
9163
|
if (iterator.counter.getOffset() > size + initial) {
|
|
8879
9164
|
throw new Error(`read too many bytes - size: ${size}, read: ${iterator.counter.getOffset() - initial}. initial offset: ${initial}`);
|
|
@@ -9573,7 +9858,7 @@ var parseStsc = ({
|
|
|
9573
9858
|
}
|
|
9574
9859
|
const flags = iterator.getSlice(3);
|
|
9575
9860
|
const entryCount = iterator.getUint32();
|
|
9576
|
-
const entries =
|
|
9861
|
+
const entries = new Map;
|
|
9577
9862
|
for (let i = 0;i < entryCount; i++) {
|
|
9578
9863
|
const firstChunk = iterator.getUint32();
|
|
9579
9864
|
const samplesPerChunk = iterator.getUint32();
|
|
@@ -9581,10 +9866,7 @@ var parseStsc = ({
|
|
|
9581
9866
|
if (sampleDescriptionIndex !== 1) {
|
|
9582
9867
|
throw new Error(`Expected sampleDescriptionIndex to be 1, but got ${sampleDescriptionIndex}`);
|
|
9583
9868
|
}
|
|
9584
|
-
entries.
|
|
9585
|
-
firstChunk,
|
|
9586
|
-
samplesPerChunk
|
|
9587
|
-
});
|
|
9869
|
+
entries.set(firstChunk, samplesPerChunk);
|
|
9588
9870
|
}
|
|
9589
9871
|
return {
|
|
9590
9872
|
type: "stsc-box",
|
|
@@ -9655,7 +9937,8 @@ var audioTags = [
|
|
|
9655
9937
|
1836253269,
|
|
9656
9938
|
".mp3",
|
|
9657
9939
|
"mp4a",
|
|
9658
|
-
"ac-3"
|
|
9940
|
+
"ac-3",
|
|
9941
|
+
"Opus"
|
|
9659
9942
|
];
|
|
9660
9943
|
var processIsoFormatBox = async ({
|
|
9661
9944
|
iterator,
|
|
@@ -9928,9 +10211,9 @@ var parseStss = ({
|
|
|
9928
10211
|
}
|
|
9929
10212
|
const flags = iterator.getSlice(3);
|
|
9930
10213
|
const sampleCount = iterator.getUint32();
|
|
9931
|
-
const sampleNumber =
|
|
10214
|
+
const sampleNumber = new Set;
|
|
9932
10215
|
for (let i = 0;i < sampleCount; i++) {
|
|
9933
|
-
sampleNumber.
|
|
10216
|
+
sampleNumber.add(iterator.getUint32());
|
|
9934
10217
|
}
|
|
9935
10218
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - offset);
|
|
9936
10219
|
if (bytesRemainingInBox > 0) {
|
|
@@ -10246,8 +10529,11 @@ var processBox = async ({
|
|
|
10246
10529
|
const boxSizeRaw = iterator.getFourByteNumber();
|
|
10247
10530
|
if (boxSizeRaw === 0) {
|
|
10248
10531
|
return {
|
|
10249
|
-
type: "
|
|
10250
|
-
|
|
10532
|
+
type: "box",
|
|
10533
|
+
box: {
|
|
10534
|
+
type: "void-box",
|
|
10535
|
+
boxSize: 0
|
|
10536
|
+
}
|
|
10251
10537
|
};
|
|
10252
10538
|
}
|
|
10253
10539
|
if (boxSizeRaw === 1 && iterator.bytesRemaining() < 12 || iterator.bytesRemaining() < 4) {
|
|
@@ -10261,120 +10547,177 @@ var processBox = async ({
|
|
|
10261
10547
|
const headerLength = iterator.counter.getOffset() - startOff;
|
|
10262
10548
|
if (boxType === "mdat") {
|
|
10263
10549
|
if (!onlyIfMdatAtomExpected) {
|
|
10264
|
-
return
|
|
10550
|
+
return { type: "nothing" };
|
|
10265
10551
|
}
|
|
10266
10552
|
const { mediaSectionState: mediaSectionState2 } = onlyIfMdatAtomExpected;
|
|
10267
10553
|
mediaSectionState2.addMediaSection({
|
|
10268
10554
|
size: boxSize - headerLength,
|
|
10269
10555
|
start: iterator.counter.getOffset()
|
|
10270
10556
|
});
|
|
10271
|
-
return
|
|
10557
|
+
return { type: "nothing" };
|
|
10272
10558
|
}
|
|
10273
10559
|
if (bytesRemaining < boxSize) {
|
|
10274
10560
|
returnToCheckpoint();
|
|
10275
|
-
return
|
|
10561
|
+
return {
|
|
10562
|
+
type: "fetch-more-data",
|
|
10563
|
+
bytesNeeded: makeFetchMoreData(boxSize - bytesRemaining)
|
|
10564
|
+
};
|
|
10276
10565
|
}
|
|
10277
10566
|
if (boxType === "ftyp") {
|
|
10278
|
-
return
|
|
10567
|
+
return {
|
|
10568
|
+
type: "box",
|
|
10569
|
+
box: await parseFtyp({ iterator, size: boxSize, offset: fileOffset })
|
|
10570
|
+
};
|
|
10279
10571
|
}
|
|
10280
10572
|
if (boxType === "colr") {
|
|
10281
|
-
return
|
|
10282
|
-
|
|
10283
|
-
|
|
10284
|
-
|
|
10573
|
+
return {
|
|
10574
|
+
type: "box",
|
|
10575
|
+
box: await parseColorParameterBox({
|
|
10576
|
+
iterator,
|
|
10577
|
+
size: boxSize
|
|
10578
|
+
})
|
|
10579
|
+
};
|
|
10285
10580
|
}
|
|
10286
10581
|
if (boxType === "mvhd") {
|
|
10287
|
-
return
|
|
10582
|
+
return {
|
|
10583
|
+
type: "box",
|
|
10584
|
+
box: await parseMvhd({ iterator, offset: fileOffset, size: boxSize })
|
|
10585
|
+
};
|
|
10288
10586
|
}
|
|
10289
10587
|
if (boxType === "tkhd") {
|
|
10290
|
-
return
|
|
10588
|
+
return {
|
|
10589
|
+
type: "box",
|
|
10590
|
+
box: await parseTkhd({ iterator, offset: fileOffset, size: boxSize })
|
|
10591
|
+
};
|
|
10291
10592
|
}
|
|
10292
10593
|
if (boxType === "trun") {
|
|
10293
|
-
return
|
|
10594
|
+
return {
|
|
10595
|
+
type: "box",
|
|
10596
|
+
box: await parseTrun({ iterator, offset: fileOffset, size: boxSize })
|
|
10597
|
+
};
|
|
10294
10598
|
}
|
|
10295
10599
|
if (boxType === "tfdt") {
|
|
10296
|
-
return
|
|
10600
|
+
return {
|
|
10601
|
+
type: "box",
|
|
10602
|
+
box: await parseTfdt({ iterator, size: boxSize, offset: fileOffset })
|
|
10603
|
+
};
|
|
10297
10604
|
}
|
|
10298
10605
|
if (boxType === "stsd") {
|
|
10299
|
-
return
|
|
10300
|
-
|
|
10301
|
-
|
|
10302
|
-
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10606
|
+
return {
|
|
10607
|
+
type: "box",
|
|
10608
|
+
box: await parseStsd({
|
|
10609
|
+
offset: fileOffset,
|
|
10610
|
+
size: boxSize,
|
|
10611
|
+
iterator,
|
|
10612
|
+
logLevel,
|
|
10613
|
+
contentLength
|
|
10614
|
+
})
|
|
10615
|
+
};
|
|
10306
10616
|
}
|
|
10307
10617
|
if (boxType === "stsz") {
|
|
10308
|
-
return
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
|
|
10618
|
+
return {
|
|
10619
|
+
type: "box",
|
|
10620
|
+
box: await parseStsz({
|
|
10621
|
+
iterator,
|
|
10622
|
+
offset: fileOffset,
|
|
10623
|
+
size: boxSize
|
|
10624
|
+
})
|
|
10625
|
+
};
|
|
10313
10626
|
}
|
|
10314
10627
|
if (boxType === "stco" || boxType === "co64") {
|
|
10315
|
-
return
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10628
|
+
return {
|
|
10629
|
+
type: "box",
|
|
10630
|
+
box: await parseStco({
|
|
10631
|
+
iterator,
|
|
10632
|
+
offset: fileOffset,
|
|
10633
|
+
size: boxSize,
|
|
10634
|
+
mode64Bit: boxType === "co64"
|
|
10635
|
+
})
|
|
10636
|
+
};
|
|
10321
10637
|
}
|
|
10322
10638
|
if (boxType === "pasp") {
|
|
10323
|
-
return
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10639
|
+
return {
|
|
10640
|
+
type: "box",
|
|
10641
|
+
box: await parsePasp({
|
|
10642
|
+
iterator,
|
|
10643
|
+
offset: fileOffset,
|
|
10644
|
+
size: boxSize
|
|
10645
|
+
})
|
|
10646
|
+
};
|
|
10328
10647
|
}
|
|
10329
10648
|
if (boxType === "stss") {
|
|
10330
|
-
return
|
|
10331
|
-
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
|
|
10649
|
+
return {
|
|
10650
|
+
type: "box",
|
|
10651
|
+
box: await parseStss({
|
|
10652
|
+
iterator,
|
|
10653
|
+
offset: fileOffset,
|
|
10654
|
+
boxSize
|
|
10655
|
+
})
|
|
10656
|
+
};
|
|
10335
10657
|
}
|
|
10336
10658
|
if (boxType === "ctts") {
|
|
10337
|
-
return
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10341
|
-
|
|
10659
|
+
return {
|
|
10660
|
+
type: "box",
|
|
10661
|
+
box: await parseCtts({
|
|
10662
|
+
iterator,
|
|
10663
|
+
offset: fileOffset,
|
|
10664
|
+
size: boxSize
|
|
10665
|
+
})
|
|
10666
|
+
};
|
|
10342
10667
|
}
|
|
10343
10668
|
if (boxType === "stsc") {
|
|
10344
|
-
return
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10669
|
+
return {
|
|
10670
|
+
type: "box",
|
|
10671
|
+
box: await parseStsc({
|
|
10672
|
+
iterator,
|
|
10673
|
+
offset: fileOffset,
|
|
10674
|
+
size: boxSize
|
|
10675
|
+
})
|
|
10676
|
+
};
|
|
10349
10677
|
}
|
|
10350
10678
|
if (boxType === "mebx") {
|
|
10351
|
-
return
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10679
|
+
return {
|
|
10680
|
+
type: "box",
|
|
10681
|
+
box: await parseMebx({
|
|
10682
|
+
offset: fileOffset,
|
|
10683
|
+
size: boxSize,
|
|
10684
|
+
iterator,
|
|
10685
|
+
logLevel,
|
|
10686
|
+
contentLength
|
|
10687
|
+
})
|
|
10688
|
+
};
|
|
10358
10689
|
}
|
|
10359
10690
|
if (boxType === "hdlr") {
|
|
10360
|
-
return
|
|
10691
|
+
return {
|
|
10692
|
+
type: "box",
|
|
10693
|
+
box: await parseHdlr({ iterator, size: boxSize, offset: fileOffset })
|
|
10694
|
+
};
|
|
10361
10695
|
}
|
|
10362
10696
|
if (boxType === "keys") {
|
|
10363
|
-
return
|
|
10697
|
+
return {
|
|
10698
|
+
type: "box",
|
|
10699
|
+
box: await parseKeys({ iterator, size: boxSize, offset: fileOffset })
|
|
10700
|
+
};
|
|
10364
10701
|
}
|
|
10365
10702
|
if (boxType === "ilst") {
|
|
10366
|
-
return
|
|
10367
|
-
|
|
10368
|
-
|
|
10369
|
-
|
|
10370
|
-
|
|
10703
|
+
return {
|
|
10704
|
+
type: "box",
|
|
10705
|
+
box: await parseIlstBox({
|
|
10706
|
+
iterator,
|
|
10707
|
+
offset: fileOffset,
|
|
10708
|
+
size: boxSize
|
|
10709
|
+
})
|
|
10710
|
+
};
|
|
10371
10711
|
}
|
|
10372
10712
|
if (boxType === "tfra") {
|
|
10373
|
-
return
|
|
10374
|
-
|
|
10375
|
-
|
|
10376
|
-
|
|
10377
|
-
|
|
10713
|
+
return {
|
|
10714
|
+
type: "box",
|
|
10715
|
+
box: await parseTfraBox({
|
|
10716
|
+
iterator,
|
|
10717
|
+
offset: fileOffset,
|
|
10718
|
+
size: boxSize
|
|
10719
|
+
})
|
|
10720
|
+
};
|
|
10378
10721
|
}
|
|
10379
10722
|
if (boxType === "moov") {
|
|
10380
10723
|
if (!onlyIfMoovAtomExpected) {
|
|
@@ -10383,12 +10726,12 @@ var processBox = async ({
|
|
|
10383
10726
|
const { tracks: tracks2, isoState } = onlyIfMoovAtomExpected;
|
|
10384
10727
|
if (tracks2.hasAllTracks()) {
|
|
10385
10728
|
iterator.discard(boxSize - 8);
|
|
10386
|
-
return
|
|
10729
|
+
return { type: "nothing" };
|
|
10387
10730
|
}
|
|
10388
10731
|
if (isoState && isoState.moov.getMoovBoxAndPrecomputed() && !isoState.moov.getMoovBoxAndPrecomputed()?.precomputed) {
|
|
10389
10732
|
Log.verbose(logLevel, "Moov box already parsed, skipping");
|
|
10390
10733
|
iterator.discard(boxSize - 8);
|
|
10391
|
-
return
|
|
10734
|
+
return { type: "nothing" };
|
|
10392
10735
|
}
|
|
10393
10736
|
const box = await parseMoov({
|
|
10394
10737
|
offset: fileOffset,
|
|
@@ -10399,7 +10742,7 @@ var processBox = async ({
|
|
|
10399
10742
|
contentLength
|
|
10400
10743
|
});
|
|
10401
10744
|
tracks2.setIsDone(logLevel);
|
|
10402
|
-
return box;
|
|
10745
|
+
return { type: "box", box };
|
|
10403
10746
|
}
|
|
10404
10747
|
if (boxType === "trak") {
|
|
10405
10748
|
if (!onlyIfMoovAtomExpected) {
|
|
@@ -10434,54 +10777,75 @@ var processBox = async ({
|
|
|
10434
10777
|
onAudioTrack
|
|
10435
10778
|
});
|
|
10436
10779
|
}
|
|
10437
|
-
return box;
|
|
10780
|
+
return { type: "box", box };
|
|
10438
10781
|
}
|
|
10439
10782
|
if (boxType === "stts") {
|
|
10440
|
-
return
|
|
10441
|
-
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10783
|
+
return {
|
|
10784
|
+
type: "box",
|
|
10785
|
+
box: await parseStts({
|
|
10786
|
+
data: iterator,
|
|
10787
|
+
size: boxSize,
|
|
10788
|
+
fileOffset
|
|
10789
|
+
})
|
|
10790
|
+
};
|
|
10445
10791
|
}
|
|
10446
10792
|
if (boxType === "avcC") {
|
|
10447
|
-
return
|
|
10448
|
-
|
|
10449
|
-
|
|
10450
|
-
|
|
10793
|
+
return {
|
|
10794
|
+
type: "box",
|
|
10795
|
+
box: await parseAvcc({
|
|
10796
|
+
data: iterator,
|
|
10797
|
+
size: boxSize
|
|
10798
|
+
})
|
|
10799
|
+
};
|
|
10451
10800
|
}
|
|
10452
10801
|
if (boxType === "av1C") {
|
|
10453
|
-
return
|
|
10454
|
-
|
|
10455
|
-
|
|
10456
|
-
|
|
10802
|
+
return {
|
|
10803
|
+
type: "box",
|
|
10804
|
+
box: await parseAv1C({
|
|
10805
|
+
data: iterator,
|
|
10806
|
+
size: boxSize
|
|
10807
|
+
})
|
|
10808
|
+
};
|
|
10457
10809
|
}
|
|
10458
10810
|
if (boxType === "hvcC") {
|
|
10459
|
-
return
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10811
|
+
return {
|
|
10812
|
+
type: "box",
|
|
10813
|
+
box: await parseHvcc({
|
|
10814
|
+
data: iterator,
|
|
10815
|
+
size: boxSize,
|
|
10816
|
+
offset: fileOffset
|
|
10817
|
+
})
|
|
10818
|
+
};
|
|
10464
10819
|
}
|
|
10465
10820
|
if (boxType === "tfhd") {
|
|
10466
|
-
return
|
|
10467
|
-
|
|
10468
|
-
|
|
10469
|
-
|
|
10470
|
-
|
|
10821
|
+
return {
|
|
10822
|
+
type: "box",
|
|
10823
|
+
box: await getTfhd({
|
|
10824
|
+
iterator,
|
|
10825
|
+
offset: fileOffset,
|
|
10826
|
+
size: boxSize
|
|
10827
|
+
})
|
|
10828
|
+
};
|
|
10471
10829
|
}
|
|
10472
10830
|
if (boxType === "mdhd") {
|
|
10473
|
-
return
|
|
10474
|
-
|
|
10475
|
-
|
|
10476
|
-
|
|
10477
|
-
|
|
10831
|
+
return {
|
|
10832
|
+
type: "box",
|
|
10833
|
+
box: await parseMdhd({
|
|
10834
|
+
data: iterator,
|
|
10835
|
+
size: boxSize,
|
|
10836
|
+
fileOffset
|
|
10837
|
+
})
|
|
10838
|
+
};
|
|
10478
10839
|
}
|
|
10479
10840
|
if (boxType === "esds") {
|
|
10480
|
-
return
|
|
10481
|
-
|
|
10482
|
-
|
|
10483
|
-
|
|
10484
|
-
|
|
10841
|
+
return {
|
|
10842
|
+
type: "box",
|
|
10843
|
+
box: await parseEsds({
|
|
10844
|
+
data: iterator,
|
|
10845
|
+
size: boxSize,
|
|
10846
|
+
fileOffset
|
|
10847
|
+
})
|
|
10848
|
+
};
|
|
10485
10849
|
}
|
|
10486
10850
|
if (boxType === "moof") {
|
|
10487
10851
|
onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
|
|
@@ -10495,20 +10859,26 @@ var processBox = async ({
|
|
|
10495
10859
|
contentLength
|
|
10496
10860
|
});
|
|
10497
10861
|
return {
|
|
10498
|
-
type: "
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10502
|
-
|
|
10862
|
+
type: "box",
|
|
10863
|
+
box: {
|
|
10864
|
+
type: "regular-box",
|
|
10865
|
+
boxType,
|
|
10866
|
+
boxSize,
|
|
10867
|
+
children,
|
|
10868
|
+
offset: fileOffset
|
|
10869
|
+
}
|
|
10503
10870
|
};
|
|
10504
10871
|
}
|
|
10505
10872
|
iterator.discard(boxSize - 8);
|
|
10506
10873
|
return {
|
|
10507
|
-
type: "
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10874
|
+
type: "box",
|
|
10875
|
+
box: {
|
|
10876
|
+
type: "regular-box",
|
|
10877
|
+
boxType,
|
|
10878
|
+
boxSize,
|
|
10879
|
+
children: [],
|
|
10880
|
+
offset: fileOffset
|
|
10881
|
+
}
|
|
10512
10882
|
};
|
|
10513
10883
|
};
|
|
10514
10884
|
|
|
@@ -10517,7 +10887,7 @@ var getMoovAtom = async ({
|
|
|
10517
10887
|
endOfMdat,
|
|
10518
10888
|
state
|
|
10519
10889
|
}) => {
|
|
10520
|
-
const headerSegment = state.mp4HeaderSegment;
|
|
10890
|
+
const headerSegment = state.m3uPlaylistContext?.mp4HeaderSegment;
|
|
10521
10891
|
if (headerSegment) {
|
|
10522
10892
|
const segment = getMoovFromFromIsoStructure(headerSegment);
|
|
10523
10893
|
if (!segment) {
|
|
@@ -10530,7 +10900,9 @@ var getMoovAtom = async ({
|
|
|
10530
10900
|
const { reader } = await state.readerInterface.read({
|
|
10531
10901
|
src: state.src,
|
|
10532
10902
|
range: endOfMdat,
|
|
10533
|
-
controller: state.controller
|
|
10903
|
+
controller: state.controller,
|
|
10904
|
+
logLevel: state.logLevel,
|
|
10905
|
+
prefetchCache: state.prefetchCache
|
|
10534
10906
|
});
|
|
10535
10907
|
const onAudioTrack = state.onAudioTrack ? async ({ track, container }) => {
|
|
10536
10908
|
await registerAudioTrack({
|
|
@@ -10587,8 +10959,8 @@ var getMoovAtom = async ({
|
|
|
10587
10959
|
onlyIfMdatAtomExpected: null,
|
|
10588
10960
|
contentLength: state.contentLength - endOfMdat
|
|
10589
10961
|
});
|
|
10590
|
-
if (box) {
|
|
10591
|
-
boxes.push(box);
|
|
10962
|
+
if (box.type === "box") {
|
|
10963
|
+
boxes.push(box.box);
|
|
10592
10964
|
}
|
|
10593
10965
|
if (iterator.counter.getOffset() + endOfMdat > state.contentLength) {
|
|
10594
10966
|
throw new Error("Read past end of file");
|
|
@@ -10605,6 +10977,121 @@ var getMoovAtom = async ({
|
|
|
10605
10977
|
return moov;
|
|
10606
10978
|
};
|
|
10607
10979
|
|
|
10980
|
+
// src/containers/iso-base-media/mdat/calculate-jump-marks.ts
|
|
10981
|
+
var MAX_SPREAD_IN_SECONDS = 8;
|
|
10982
|
+
var getKey = (samplePositionTrack) => {
|
|
10983
|
+
return `${samplePositionTrack.track.trackId}-${samplePositionTrack.samplePosition.dts}`;
|
|
10984
|
+
};
|
|
10985
|
+
var findBestJump = ({
|
|
10986
|
+
allSamplesSortedByOffset,
|
|
10987
|
+
visited,
|
|
10988
|
+
progresses
|
|
10989
|
+
}) => {
|
|
10990
|
+
const minProgress = Math.min(...Object.values(progresses));
|
|
10991
|
+
const trackNumberWithLowestProgress = Object.entries(progresses).find(([, progress]) => progress === minProgress)?.[0];
|
|
10992
|
+
const firstSampleAboveMinProgress = allSamplesSortedByOffset.findIndex((sample) => sample.track.trackId === Number(trackNumberWithLowestProgress) && !visited.has(getKey(sample)));
|
|
10993
|
+
return firstSampleAboveMinProgress;
|
|
10994
|
+
};
|
|
10995
|
+
var calculateJumpMarks = (samplePositionTracks, endOfMdat) => {
|
|
10996
|
+
const progresses = {};
|
|
10997
|
+
for (const track of samplePositionTracks) {
|
|
10998
|
+
progresses[track[0].track.trackId] = 0;
|
|
10999
|
+
}
|
|
11000
|
+
const jumpMarks = [];
|
|
11001
|
+
const allSamplesSortedByOffset = samplePositionTracks.flat(1).sort((a, b) => a.samplePosition.offset - b.samplePosition.offset);
|
|
11002
|
+
let indexToVisit = 0;
|
|
11003
|
+
const visited = new Set;
|
|
11004
|
+
let rollOverToProcess = false;
|
|
11005
|
+
const increaseIndex = () => {
|
|
11006
|
+
indexToVisit++;
|
|
11007
|
+
if (indexToVisit >= allSamplesSortedByOffset.length) {
|
|
11008
|
+
rollOverToProcess = true;
|
|
11009
|
+
indexToVisit = 0;
|
|
11010
|
+
}
|
|
11011
|
+
};
|
|
11012
|
+
let lastVisitedSample = null;
|
|
11013
|
+
const addJumpMark = ({
|
|
11014
|
+
firstSampleAboveMinProgress
|
|
11015
|
+
}) => {
|
|
11016
|
+
if (!lastVisitedSample) {
|
|
11017
|
+
throw new Error("no last visited sample");
|
|
11018
|
+
}
|
|
11019
|
+
const jumpMark = {
|
|
11020
|
+
afterSampleWithOffset: lastVisitedSample.samplePosition.offset,
|
|
11021
|
+
jumpToOffset: allSamplesSortedByOffset[firstSampleAboveMinProgress].samplePosition.offset
|
|
11022
|
+
};
|
|
11023
|
+
indexToVisit = firstSampleAboveMinProgress;
|
|
11024
|
+
jumpMarks.push(jumpMark);
|
|
11025
|
+
};
|
|
11026
|
+
const addFinalJumpIfNecessary = () => {
|
|
11027
|
+
if (indexToVisit === allSamplesSortedByOffset.length - 1) {
|
|
11028
|
+
return;
|
|
11029
|
+
}
|
|
11030
|
+
jumpMarks.push({
|
|
11031
|
+
afterSampleWithOffset: allSamplesSortedByOffset[indexToVisit].samplePosition.offset,
|
|
11032
|
+
jumpToOffset: endOfMdat
|
|
11033
|
+
});
|
|
11034
|
+
};
|
|
11035
|
+
const considerJump = () => {
|
|
11036
|
+
const firstSampleAboveMinProgress = findBestJump({
|
|
11037
|
+
allSamplesSortedByOffset,
|
|
11038
|
+
visited,
|
|
11039
|
+
progresses
|
|
11040
|
+
});
|
|
11041
|
+
if (firstSampleAboveMinProgress > -1 && firstSampleAboveMinProgress !== indexToVisit + 1) {
|
|
11042
|
+
addJumpMark({ firstSampleAboveMinProgress });
|
|
11043
|
+
indexToVisit = firstSampleAboveMinProgress;
|
|
11044
|
+
} else {
|
|
11045
|
+
while (true) {
|
|
11046
|
+
increaseIndex();
|
|
11047
|
+
if (!visited.has(getKey(allSamplesSortedByOffset[indexToVisit]))) {
|
|
11048
|
+
break;
|
|
11049
|
+
}
|
|
11050
|
+
}
|
|
11051
|
+
}
|
|
11052
|
+
};
|
|
11053
|
+
while (true) {
|
|
11054
|
+
const currentSamplePosition = allSamplesSortedByOffset[indexToVisit];
|
|
11055
|
+
const sampleKey = getKey(currentSamplePosition);
|
|
11056
|
+
if (visited.has(sampleKey)) {
|
|
11057
|
+
considerJump();
|
|
11058
|
+
continue;
|
|
11059
|
+
}
|
|
11060
|
+
visited.add(sampleKey);
|
|
11061
|
+
if (rollOverToProcess) {
|
|
11062
|
+
if (!lastVisitedSample) {
|
|
11063
|
+
throw new Error("no last visited sample");
|
|
11064
|
+
}
|
|
11065
|
+
jumpMarks.push({
|
|
11066
|
+
afterSampleWithOffset: lastVisitedSample.samplePosition.offset,
|
|
11067
|
+
jumpToOffset: currentSamplePosition.samplePosition.offset
|
|
11068
|
+
});
|
|
11069
|
+
rollOverToProcess = false;
|
|
11070
|
+
}
|
|
11071
|
+
lastVisitedSample = currentSamplePosition;
|
|
11072
|
+
if (visited.size === allSamplesSortedByOffset.length) {
|
|
11073
|
+
addFinalJumpIfNecessary();
|
|
11074
|
+
break;
|
|
11075
|
+
}
|
|
11076
|
+
const timestamp = currentSamplePosition.samplePosition.dts / currentSamplePosition.track.timescale;
|
|
11077
|
+
progresses[currentSamplePosition.track.trackId] = timestamp;
|
|
11078
|
+
const progressValues = Object.values(progresses);
|
|
11079
|
+
const maxProgress = Math.max(...progressValues);
|
|
11080
|
+
const minProgress = Math.min(...progressValues);
|
|
11081
|
+
const spread = maxProgress - minProgress;
|
|
11082
|
+
if (visited.size === allSamplesSortedByOffset.length) {
|
|
11083
|
+
addFinalJumpIfNecessary();
|
|
11084
|
+
break;
|
|
11085
|
+
}
|
|
11086
|
+
if (spread > MAX_SPREAD_IN_SECONDS) {
|
|
11087
|
+
considerJump();
|
|
11088
|
+
} else {
|
|
11089
|
+
increaseIndex();
|
|
11090
|
+
}
|
|
11091
|
+
}
|
|
11092
|
+
return jumpMarks;
|
|
11093
|
+
};
|
|
11094
|
+
|
|
10608
11095
|
// src/containers/iso-base-media/mdat/postprocess-bytes.ts
|
|
10609
11096
|
var postprocessBytes = ({
|
|
10610
11097
|
bytes,
|
|
@@ -10654,9 +11141,13 @@ var parseMdatSection = async (state) => {
|
|
|
10654
11141
|
return parseMdatSection(state);
|
|
10655
11142
|
}
|
|
10656
11143
|
if (!state.iso.flatSamples.getSamples(mediaSection.start)) {
|
|
10657
|
-
|
|
11144
|
+
const flattedSamples = calculateFlatSamples(state);
|
|
11145
|
+
const calcedJumpMarks = calculateJumpMarks(flattedSamples, endOfMdat);
|
|
11146
|
+
state.iso.flatSamples.setJumpMarks(mediaSection.start, calcedJumpMarks);
|
|
11147
|
+
state.iso.flatSamples.setSamples(mediaSection.start, flattedSamples.flat(1));
|
|
10658
11148
|
}
|
|
10659
11149
|
const flatSamples = state.iso.flatSamples.getSamples(mediaSection.start);
|
|
11150
|
+
const jumpMarks = state.iso.flatSamples.getJumpMarks(mediaSection.start);
|
|
10660
11151
|
const { iterator } = state;
|
|
10661
11152
|
const samplesWithIndex = flatSamples.find((sample) => {
|
|
10662
11153
|
return sample.samplePosition.offset === iterator.counter.getOffset();
|
|
@@ -10669,8 +11160,11 @@ var parseMdatSection = async (state) => {
|
|
|
10669
11160
|
}
|
|
10670
11161
|
return makeSkip(endOfMdat);
|
|
10671
11162
|
}
|
|
11163
|
+
if (samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size > state.contentLength) {
|
|
11164
|
+
return makeSkip(endOfMdat);
|
|
11165
|
+
}
|
|
10672
11166
|
if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
|
|
10673
|
-
return
|
|
11167
|
+
return makeFetchMoreData(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
|
|
10674
11168
|
}
|
|
10675
11169
|
const { cts, dts, duration: duration2, isKeyframe, offset, bigEndian, chunkSize } = samplesWithIndex.samplePosition;
|
|
10676
11170
|
const bytes = postprocessBytes({
|
|
@@ -10718,6 +11212,10 @@ var parseMdatSection = async (state) => {
|
|
|
10718
11212
|
});
|
|
10719
11213
|
await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, videoSample);
|
|
10720
11214
|
}
|
|
11215
|
+
const jump = jumpMarks.find((j) => j.afterSampleWithOffset === offset);
|
|
11216
|
+
if (jump) {
|
|
11217
|
+
return makeSkip(jump.jumpToOffset);
|
|
11218
|
+
}
|
|
10721
11219
|
return null;
|
|
10722
11220
|
};
|
|
10723
11221
|
|
|
@@ -10744,8 +11242,11 @@ var parseIsoBaseMedia = async (state) => {
|
|
|
10744
11242
|
},
|
|
10745
11243
|
contentLength: state.contentLength
|
|
10746
11244
|
});
|
|
10747
|
-
if (result) {
|
|
10748
|
-
|
|
11245
|
+
if (result.type === "fetch-more-data") {
|
|
11246
|
+
return result.bytesNeeded;
|
|
11247
|
+
}
|
|
11248
|
+
if (result.type === "box") {
|
|
11249
|
+
state.structure.getIsoStructure().boxes.push(result.box);
|
|
10749
11250
|
}
|
|
10750
11251
|
return null;
|
|
10751
11252
|
};
|
|
@@ -10824,7 +11325,8 @@ var parseM3uMediaDirective = (str) => {
|
|
|
10824
11325
|
groupId: map["GROUP-ID"],
|
|
10825
11326
|
language: map.LANGUAGE || null,
|
|
10826
11327
|
name: map.NAME || null,
|
|
10827
|
-
uri: map.URI
|
|
11328
|
+
uri: map.URI,
|
|
11329
|
+
mediaType: map.TYPE || null
|
|
10828
11330
|
};
|
|
10829
11331
|
};
|
|
10830
11332
|
|
|
@@ -10984,7 +11486,9 @@ var afterManifestFetch = async ({
|
|
|
10984
11486
|
selectM3uStreamFn,
|
|
10985
11487
|
logLevel,
|
|
10986
11488
|
selectAssociatedPlaylistsFn,
|
|
10987
|
-
readerInterface
|
|
11489
|
+
readerInterface,
|
|
11490
|
+
onAudioTrack,
|
|
11491
|
+
canSkipTracks
|
|
10988
11492
|
}) => {
|
|
10989
11493
|
const independentSegments = isIndependentSegments(structure);
|
|
10990
11494
|
if (!independentSegments) {
|
|
@@ -11009,9 +11513,11 @@ var afterManifestFetch = async ({
|
|
|
11009
11513
|
type: "selected-stream",
|
|
11010
11514
|
stream: selectedPlaylist
|
|
11011
11515
|
});
|
|
11516
|
+
const skipAudioTracks = onAudioTrack === null && canSkipTracks.doFieldsNeedTracks() === false;
|
|
11012
11517
|
const associatedPlaylists = await selectAssociatedPlaylists({
|
|
11013
11518
|
playlists: selectedPlaylist.associatedPlaylists,
|
|
11014
|
-
fn: selectAssociatedPlaylistsFn
|
|
11519
|
+
fn: selectAssociatedPlaylistsFn,
|
|
11520
|
+
skipAudioTracks
|
|
11015
11521
|
});
|
|
11016
11522
|
m3uState.setAssociatedPlaylists(associatedPlaylists);
|
|
11017
11523
|
const playlistUrls = [
|
|
@@ -11116,7 +11622,7 @@ var parseMedia = (options) => {
|
|
|
11116
11622
|
controller: options.controller ?? undefined,
|
|
11117
11623
|
selectM3uStream: options.selectM3uStream ?? defaultSelectM3uStreamFn,
|
|
11118
11624
|
selectM3uAssociatedPlaylists: options.selectM3uAssociatedPlaylists ?? defaultSelectM3uAssociatedPlaylists,
|
|
11119
|
-
|
|
11625
|
+
m3uPlaylistContext: options.m3uPlaylistContext ?? null,
|
|
11120
11626
|
src: options.src,
|
|
11121
11627
|
mode: "query",
|
|
11122
11628
|
onDiscardedData: null,
|
|
@@ -11128,6 +11634,39 @@ var parseMedia = (options) => {
|
|
|
11128
11634
|
});
|
|
11129
11635
|
};
|
|
11130
11636
|
|
|
11637
|
+
// src/containers/m3u/first-sample-in-m3u-chunk.ts
|
|
11638
|
+
var considerSeekBasedOnChunk = async ({
|
|
11639
|
+
sample,
|
|
11640
|
+
parentController,
|
|
11641
|
+
childController,
|
|
11642
|
+
callback,
|
|
11643
|
+
m3uState,
|
|
11644
|
+
playlistUrl,
|
|
11645
|
+
subtractChunks,
|
|
11646
|
+
chunkIndex
|
|
11647
|
+
}) => {
|
|
11648
|
+
const pendingSeek = m3uState.getSeekToSecondsToProcess(playlistUrl);
|
|
11649
|
+
if (pendingSeek === null) {
|
|
11650
|
+
await callback(sample);
|
|
11651
|
+
return;
|
|
11652
|
+
}
|
|
11653
|
+
const timestamp = Math.min(sample.dts / sample.timescale, sample.cts / sample.timescale);
|
|
11654
|
+
if (timestamp > pendingSeek.targetTime && chunkIndex !== null && chunkIndex > 0) {
|
|
11655
|
+
m3uState.setNextSeekShouldSubtractChunks(playlistUrl, subtractChunks + 1);
|
|
11656
|
+
parentController.seek({
|
|
11657
|
+
type: "keyframe-before-time",
|
|
11658
|
+
timeInSeconds: pendingSeek.targetTime
|
|
11659
|
+
});
|
|
11660
|
+
return;
|
|
11661
|
+
}
|
|
11662
|
+
childController.seek({
|
|
11663
|
+
type: "keyframe-before-time",
|
|
11664
|
+
timeInSeconds: pendingSeek.targetTime
|
|
11665
|
+
});
|
|
11666
|
+
m3uState.setNextSeekShouldSubtractChunks(playlistUrl, 0);
|
|
11667
|
+
m3uState.setSeekToSecondsToProcess(playlistUrl, null);
|
|
11668
|
+
};
|
|
11669
|
+
|
|
11131
11670
|
// src/containers/m3u/get-chunks.ts
|
|
11132
11671
|
var getChunks = (playlist) => {
|
|
11133
11672
|
const chunks = [];
|
|
@@ -11145,127 +11684,282 @@ var getChunks = (playlist) => {
|
|
|
11145
11684
|
}
|
|
11146
11685
|
chunks.push({ duration: box.value, url: nextBox.value, isHeader: false });
|
|
11147
11686
|
}
|
|
11148
|
-
continue;
|
|
11687
|
+
continue;
|
|
11688
|
+
}
|
|
11689
|
+
return chunks;
|
|
11690
|
+
};
|
|
11691
|
+
|
|
11692
|
+
// src/containers/m3u/seek/get-chunk-to-seek-to.ts
|
|
11693
|
+
var getChunkToSeekTo = ({
|
|
11694
|
+
chunks,
|
|
11695
|
+
seekToSecondsToProcess
|
|
11696
|
+
}) => {
|
|
11697
|
+
let duration2 = 0;
|
|
11698
|
+
for (let i = 0;i < chunks.length; i++) {
|
|
11699
|
+
if (duration2 >= seekToSecondsToProcess) {
|
|
11700
|
+
return Math.max(0, i - 1);
|
|
11701
|
+
}
|
|
11702
|
+
duration2 += chunks[i].duration;
|
|
11149
11703
|
}
|
|
11150
|
-
return chunks;
|
|
11704
|
+
return Math.max(0, chunks.length - 1);
|
|
11151
11705
|
};
|
|
11152
11706
|
|
|
11153
|
-
// src/containers/m3u/
|
|
11154
|
-
var
|
|
11155
|
-
structure,
|
|
11156
|
-
onVideoTrack,
|
|
11157
|
-
m3uState,
|
|
11158
|
-
onAudioTrack,
|
|
11159
|
-
onDoneWithTracks,
|
|
11707
|
+
// src/containers/m3u/process-m3u-chunk.ts
|
|
11708
|
+
var processM3uChunk = ({
|
|
11160
11709
|
playlistUrl,
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11710
|
+
state,
|
|
11711
|
+
structure,
|
|
11712
|
+
audioDone,
|
|
11713
|
+
videoDone
|
|
11165
11714
|
}) => {
|
|
11166
|
-
const
|
|
11167
|
-
const
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11172
|
-
|
|
11173
|
-
const
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11715
|
+
const { promise, reject, resolve } = withResolvers();
|
|
11716
|
+
const onGlobalAudioTrack = audioDone ? null : async (track) => {
|
|
11717
|
+
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11718
|
+
let { trackId } = track;
|
|
11719
|
+
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11720
|
+
trackId++;
|
|
11721
|
+
}
|
|
11722
|
+
const onAudioSample = await registerAudioTrack({
|
|
11723
|
+
container: "m3u8",
|
|
11724
|
+
track: {
|
|
11725
|
+
...track,
|
|
11726
|
+
trackId
|
|
11727
|
+
},
|
|
11728
|
+
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
11729
|
+
tracks: state.callbacks.tracks,
|
|
11730
|
+
logLevel: state.logLevel,
|
|
11731
|
+
onAudioTrack: state.onAudioTrack
|
|
11177
11732
|
});
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
return promise;
|
|
11186
|
-
},
|
|
11187
|
-
abort() {
|
|
11188
|
-
childController.abort();
|
|
11189
|
-
}
|
|
11190
|
-
};
|
|
11733
|
+
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11734
|
+
if (onAudioSample === null) {
|
|
11735
|
+
return null;
|
|
11736
|
+
}
|
|
11737
|
+
state.m3u.sampleSorter.addAudioStreamToConsider(playlistUrl, onAudioSample);
|
|
11738
|
+
return async (sample) => {
|
|
11739
|
+
await state.m3u.sampleSorter.addAudioSample(playlistUrl, sample);
|
|
11191
11740
|
};
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
const
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11741
|
+
};
|
|
11742
|
+
const onGlobalVideoTrack = videoDone ? null : async (track) => {
|
|
11743
|
+
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11744
|
+
let { trackId } = track;
|
|
11745
|
+
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11746
|
+
trackId++;
|
|
11747
|
+
}
|
|
11748
|
+
const onVideoSample = await registerVideoTrack({
|
|
11749
|
+
container: "m3u8",
|
|
11750
|
+
track: {
|
|
11751
|
+
...track,
|
|
11752
|
+
trackId
|
|
11753
|
+
},
|
|
11754
|
+
logLevel: state.logLevel,
|
|
11755
|
+
onVideoTrack: state.onVideoTrack,
|
|
11756
|
+
registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
|
|
11757
|
+
tracks: state.callbacks.tracks
|
|
11758
|
+
});
|
|
11759
|
+
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11760
|
+
if (onVideoSample === null) {
|
|
11761
|
+
return null;
|
|
11762
|
+
}
|
|
11763
|
+
state.m3u.sampleSorter.addVideoStreamToConsider(playlistUrl, onVideoSample);
|
|
11764
|
+
return async (sample) => {
|
|
11765
|
+
await state.m3u.sampleSorter.addVideoSample(playlistUrl, sample);
|
|
11766
|
+
};
|
|
11767
|
+
};
|
|
11768
|
+
const pausableIterator = async () => {
|
|
11769
|
+
const playlist = getPlaylist(structure, playlistUrl);
|
|
11770
|
+
const chunks = getChunks(playlist);
|
|
11771
|
+
const seekToSecondsToProcess = state.m3u.getSeekToSecondsToProcess(playlistUrl);
|
|
11772
|
+
const chunksToSubtract = state.m3u.getNextSeekShouldSubtractChunks(playlistUrl);
|
|
11773
|
+
let chunkIndex = null;
|
|
11774
|
+
if (seekToSecondsToProcess !== null) {
|
|
11775
|
+
chunkIndex = Math.max(0, getChunkToSeekTo({
|
|
11776
|
+
chunks,
|
|
11777
|
+
seekToSecondsToProcess: seekToSecondsToProcess.targetTime
|
|
11778
|
+
}) - chunksToSubtract);
|
|
11779
|
+
}
|
|
11780
|
+
const currentPromise = {
|
|
11781
|
+
resolver: () => {
|
|
11782
|
+
return;
|
|
11783
|
+
},
|
|
11784
|
+
rejector: reject
|
|
11785
|
+
};
|
|
11786
|
+
const requiresHeaderToBeFetched = chunks[0].isHeader;
|
|
11787
|
+
for (const chunk of chunks) {
|
|
11788
|
+
const mp4HeaderSegment = state.m3u.getMp4HeaderSegment(playlistUrl);
|
|
11789
|
+
if (requiresHeaderToBeFetched && mp4HeaderSegment && chunk.isHeader) {
|
|
11790
|
+
continue;
|
|
11791
|
+
}
|
|
11792
|
+
if (chunkIndex !== null && chunks.indexOf(chunk) < chunkIndex && !chunk.isHeader) {
|
|
11793
|
+
continue;
|
|
11794
|
+
}
|
|
11795
|
+
currentPromise.resolver = (newRun) => {
|
|
11796
|
+
state.m3u.setM3uStreamRun(playlistUrl, newRun);
|
|
11797
|
+
resolve();
|
|
11798
|
+
};
|
|
11799
|
+
currentPromise.rejector = reject;
|
|
11800
|
+
const childController = mediaParserController();
|
|
11801
|
+
const forwarded = forwardMediaParserControllerPauseResume({
|
|
11802
|
+
childController,
|
|
11803
|
+
parentController: state.controller
|
|
11804
|
+
});
|
|
11805
|
+
const nextChunk = chunks[chunks.indexOf(chunk) + 1];
|
|
11806
|
+
if (nextChunk) {
|
|
11807
|
+
const nextChunkSource = state.readerInterface.createAdjacentFileSource(nextChunk.url, playlistUrl);
|
|
11808
|
+
state.readerInterface.preload({
|
|
11809
|
+
logLevel: state.logLevel,
|
|
11810
|
+
range: null,
|
|
11811
|
+
src: nextChunkSource,
|
|
11812
|
+
prefetchCache: state.prefetchCache
|
|
11813
|
+
});
|
|
11814
|
+
}
|
|
11815
|
+
const makeContinuationFn = () => {
|
|
11816
|
+
return {
|
|
11817
|
+
continue() {
|
|
11818
|
+
const resolver = withResolvers();
|
|
11819
|
+
currentPromise.resolver = resolver.resolve;
|
|
11820
|
+
currentPromise.rejector = resolver.reject;
|
|
11821
|
+
childController.resume();
|
|
11822
|
+
return resolver.promise;
|
|
11823
|
+
},
|
|
11824
|
+
abort() {
|
|
11825
|
+
childController.abort();
|
|
11213
11826
|
}
|
|
11214
|
-
}
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
|
|
11220
|
-
|
|
11827
|
+
};
|
|
11828
|
+
};
|
|
11829
|
+
const isLastChunk = chunk === chunks[chunks.length - 1];
|
|
11830
|
+
await childController._internals.checkForAbortAndPause();
|
|
11831
|
+
const src = state.readerInterface.createAdjacentFileSource(chunk.url, playlistUrl);
|
|
11832
|
+
try {
|
|
11833
|
+
const data = await parseMedia({
|
|
11834
|
+
src,
|
|
11835
|
+
acknowledgeRemotionLicense: true,
|
|
11836
|
+
logLevel: state.logLevel,
|
|
11837
|
+
controller: childController,
|
|
11838
|
+
progressIntervalInMs: 0,
|
|
11839
|
+
onParseProgress: () => {
|
|
11840
|
+
childController.pause();
|
|
11841
|
+
currentPromise.resolver(makeContinuationFn());
|
|
11842
|
+
},
|
|
11843
|
+
fields: chunk.isHeader ? { structure: true } : undefined,
|
|
11844
|
+
onTracks: () => {
|
|
11845
|
+
if (!state.m3u.hasEmittedDoneWithTracks(playlistUrl)) {
|
|
11846
|
+
state.m3u.setHasEmittedDoneWithTracks(playlistUrl);
|
|
11847
|
+
const allDone = state.m3u.setTracksDone(playlistUrl);
|
|
11848
|
+
if (allDone) {
|
|
11849
|
+
state.callbacks.tracks.setIsDone(state.logLevel);
|
|
11850
|
+
}
|
|
11851
|
+
return null;
|
|
11852
|
+
}
|
|
11853
|
+
},
|
|
11854
|
+
onAudioTrack: onGlobalAudioTrack === null ? null : async ({ track }) => {
|
|
11855
|
+
const callbackOrFalse = state.m3u.hasEmittedAudioTrack(playlistUrl);
|
|
11856
|
+
if (callbackOrFalse === false) {
|
|
11857
|
+
const callback = await onGlobalAudioTrack(track);
|
|
11858
|
+
if (!callback) {
|
|
11859
|
+
state.m3u.setHasEmittedAudioTrack(playlistUrl, null);
|
|
11860
|
+
return null;
|
|
11861
|
+
}
|
|
11862
|
+
state.m3u.setHasEmittedAudioTrack(playlistUrl, callback);
|
|
11863
|
+
return async (sample) => {
|
|
11864
|
+
await considerSeekBasedOnChunk({
|
|
11865
|
+
sample,
|
|
11866
|
+
callback,
|
|
11867
|
+
parentController: state.controller,
|
|
11868
|
+
childController,
|
|
11869
|
+
m3uState: state.m3u,
|
|
11870
|
+
playlistUrl,
|
|
11871
|
+
subtractChunks: chunksToSubtract,
|
|
11872
|
+
chunkIndex
|
|
11873
|
+
});
|
|
11874
|
+
};
|
|
11875
|
+
}
|
|
11876
|
+
if (callbackOrFalse === null) {
|
|
11221
11877
|
return null;
|
|
11222
11878
|
}
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11879
|
+
return async (sample) => {
|
|
11880
|
+
await considerSeekBasedOnChunk({
|
|
11881
|
+
sample,
|
|
11882
|
+
m3uState: state.m3u,
|
|
11883
|
+
playlistUrl,
|
|
11884
|
+
callback: callbackOrFalse,
|
|
11885
|
+
parentController: state.controller,
|
|
11886
|
+
childController,
|
|
11887
|
+
subtractChunks: chunksToSubtract,
|
|
11888
|
+
chunkIndex
|
|
11889
|
+
});
|
|
11226
11890
|
};
|
|
11227
|
-
}
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
11891
|
+
},
|
|
11892
|
+
onVideoTrack: onGlobalVideoTrack === null ? null : async ({ track }) => {
|
|
11893
|
+
const callbackOrFalse = state.m3u.hasEmittedVideoTrack(playlistUrl);
|
|
11894
|
+
if (callbackOrFalse === false) {
|
|
11895
|
+
const callback = await onGlobalVideoTrack({
|
|
11896
|
+
...track,
|
|
11897
|
+
m3uStreamFormat: chunk.isHeader || mp4HeaderSegment ? "mp4" : "ts"
|
|
11898
|
+
});
|
|
11899
|
+
if (!callback) {
|
|
11900
|
+
state.m3u.setHasEmittedVideoTrack(playlistUrl, null);
|
|
11901
|
+
return null;
|
|
11902
|
+
}
|
|
11903
|
+
state.m3u.setHasEmittedVideoTrack(playlistUrl, callback);
|
|
11904
|
+
return async (sample) => {
|
|
11905
|
+
await considerSeekBasedOnChunk({
|
|
11906
|
+
sample,
|
|
11907
|
+
m3uState: state.m3u,
|
|
11908
|
+
playlistUrl,
|
|
11909
|
+
callback,
|
|
11910
|
+
parentController: state.controller,
|
|
11911
|
+
childController,
|
|
11912
|
+
subtractChunks: chunksToSubtract,
|
|
11913
|
+
chunkIndex
|
|
11914
|
+
});
|
|
11915
|
+
};
|
|
11916
|
+
}
|
|
11917
|
+
if (callbackOrFalse === null) {
|
|
11239
11918
|
return null;
|
|
11240
11919
|
}
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11920
|
+
return async (sample) => {
|
|
11921
|
+
await considerSeekBasedOnChunk({
|
|
11922
|
+
sample,
|
|
11923
|
+
m3uState: state.m3u,
|
|
11924
|
+
playlistUrl,
|
|
11925
|
+
callback: callbackOrFalse,
|
|
11926
|
+
parentController: state.controller,
|
|
11927
|
+
childController,
|
|
11928
|
+
subtractChunks: chunksToSubtract,
|
|
11929
|
+
chunkIndex
|
|
11930
|
+
});
|
|
11244
11931
|
};
|
|
11932
|
+
},
|
|
11933
|
+
reader: state.readerInterface,
|
|
11934
|
+
makeSamplesStartAtZero: false,
|
|
11935
|
+
m3uPlaylistContext: {
|
|
11936
|
+
mp4HeaderSegment,
|
|
11937
|
+
isLastChunkInPlaylist: isLastChunk
|
|
11245
11938
|
}
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
if (chunk.isHeader) {
|
|
11253
|
-
if (data.structure.type !== "iso-base-media") {
|
|
11254
|
-
throw new Error("Expected an mp4 file");
|
|
11939
|
+
});
|
|
11940
|
+
if (chunk.isHeader) {
|
|
11941
|
+
if (data.structure.type !== "iso-base-media") {
|
|
11942
|
+
throw new Error("Expected an mp4 file");
|
|
11943
|
+
}
|
|
11944
|
+
state.m3u.setMp4HeaderSegment(playlistUrl, data.structure);
|
|
11255
11945
|
}
|
|
11256
|
-
|
|
11946
|
+
} catch (e) {
|
|
11947
|
+
currentPromise.rejector(e);
|
|
11948
|
+
throw e;
|
|
11949
|
+
}
|
|
11950
|
+
forwarded.cleanup();
|
|
11951
|
+
if (!isLastChunk) {
|
|
11952
|
+
childController.pause();
|
|
11953
|
+
currentPromise.resolver(makeContinuationFn());
|
|
11257
11954
|
}
|
|
11258
|
-
} catch (e) {
|
|
11259
|
-
rejector(e);
|
|
11260
|
-
throw e;
|
|
11261
|
-
}
|
|
11262
|
-
forwarded.cleanup();
|
|
11263
|
-
if (!isLastChunk) {
|
|
11264
|
-
childController.pause();
|
|
11265
|
-
resolver(makeContinuationFn());
|
|
11266
11955
|
}
|
|
11267
|
-
|
|
11268
|
-
|
|
11956
|
+
currentPromise.resolver(null);
|
|
11957
|
+
};
|
|
11958
|
+
const run = pausableIterator();
|
|
11959
|
+
run.catch((err) => {
|
|
11960
|
+
reject(err);
|
|
11961
|
+
});
|
|
11962
|
+
return promise;
|
|
11269
11963
|
};
|
|
11270
11964
|
|
|
11271
11965
|
// src/containers/m3u/run-over-m3u.ts
|
|
@@ -11296,80 +11990,12 @@ var runOverM3u = async ({
|
|
|
11296
11990
|
return;
|
|
11297
11991
|
}
|
|
11298
11992
|
Log.trace(logLevel, "Starting new M3U parsing process for", playlistUrl);
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
resolve();
|
|
11306
|
-
},
|
|
11307
|
-
logLevel: state.logLevel,
|
|
11308
|
-
onDoneWithTracks() {
|
|
11309
|
-
const allDone = state.m3u.setTracksDone(playlistUrl);
|
|
11310
|
-
if (allDone) {
|
|
11311
|
-
state.callbacks.tracks.setIsDone(state.logLevel);
|
|
11312
|
-
}
|
|
11313
|
-
},
|
|
11314
|
-
onAudioTrack: audioDone ? null : async (track) => {
|
|
11315
|
-
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11316
|
-
let { trackId } = track;
|
|
11317
|
-
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11318
|
-
trackId++;
|
|
11319
|
-
}
|
|
11320
|
-
const onAudioSample = await registerAudioTrack({
|
|
11321
|
-
container: "m3u8",
|
|
11322
|
-
track: {
|
|
11323
|
-
...track,
|
|
11324
|
-
trackId
|
|
11325
|
-
},
|
|
11326
|
-
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
11327
|
-
tracks: state.callbacks.tracks,
|
|
11328
|
-
logLevel: state.logLevel,
|
|
11329
|
-
onAudioTrack: state.onAudioTrack
|
|
11330
|
-
});
|
|
11331
|
-
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11332
|
-
if (onAudioSample === null) {
|
|
11333
|
-
return null;
|
|
11334
|
-
}
|
|
11335
|
-
state.m3u.sampleSorter.addAudioStreamToConsider(playlistUrl, onAudioSample);
|
|
11336
|
-
return async (sample) => {
|
|
11337
|
-
await state.m3u.sampleSorter.addAudioSample(playlistUrl, sample);
|
|
11338
|
-
};
|
|
11339
|
-
},
|
|
11340
|
-
onVideoTrack: videoDone ? null : async (track) => {
|
|
11341
|
-
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11342
|
-
let { trackId } = track;
|
|
11343
|
-
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11344
|
-
trackId++;
|
|
11345
|
-
}
|
|
11346
|
-
const onVideoSample = await registerVideoTrack({
|
|
11347
|
-
container: "m3u8",
|
|
11348
|
-
track: {
|
|
11349
|
-
...track,
|
|
11350
|
-
trackId
|
|
11351
|
-
},
|
|
11352
|
-
logLevel: state.logLevel,
|
|
11353
|
-
onVideoTrack: state.onVideoTrack,
|
|
11354
|
-
registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
|
|
11355
|
-
tracks: state.callbacks.tracks
|
|
11356
|
-
});
|
|
11357
|
-
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11358
|
-
if (onVideoSample === null) {
|
|
11359
|
-
return null;
|
|
11360
|
-
}
|
|
11361
|
-
state.m3u.sampleSorter.addVideoStreamToConsider(playlistUrl, onVideoSample);
|
|
11362
|
-
return async (sample) => {
|
|
11363
|
-
await state.m3u.sampleSorter.addVideoSample(playlistUrl, sample);
|
|
11364
|
-
};
|
|
11365
|
-
},
|
|
11366
|
-
m3uState: state.m3u,
|
|
11367
|
-
parentController: state.controller,
|
|
11368
|
-
readerInterface: state.readerInterface
|
|
11369
|
-
});
|
|
11370
|
-
run.catch((err) => {
|
|
11371
|
-
reject(err);
|
|
11372
|
-
});
|
|
11993
|
+
await processM3uChunk({
|
|
11994
|
+
playlistUrl,
|
|
11995
|
+
state,
|
|
11996
|
+
structure,
|
|
11997
|
+
audioDone,
|
|
11998
|
+
videoDone
|
|
11373
11999
|
});
|
|
11374
12000
|
};
|
|
11375
12001
|
|
|
@@ -11391,6 +12017,10 @@ var parseM3u = async ({ state }) => {
|
|
|
11391
12017
|
if (typeof state.src !== "string" && !(state.src instanceof URL)) {
|
|
11392
12018
|
throw new Error("Expected src to be a string");
|
|
11393
12019
|
}
|
|
12020
|
+
state.mediaSection.addMediaSection({
|
|
12021
|
+
start: 0,
|
|
12022
|
+
size: state.contentLength + 1
|
|
12023
|
+
});
|
|
11394
12024
|
await afterManifestFetch({
|
|
11395
12025
|
structure,
|
|
11396
12026
|
m3uState: state.m3u,
|
|
@@ -11398,7 +12028,9 @@ var parseM3u = async ({ state }) => {
|
|
|
11398
12028
|
selectM3uStreamFn: state.selectM3uStreamFn,
|
|
11399
12029
|
logLevel: state.logLevel,
|
|
11400
12030
|
selectAssociatedPlaylistsFn: state.selectM3uAssociatedPlaylistsFn,
|
|
11401
|
-
readerInterface: state.readerInterface
|
|
12031
|
+
readerInterface: state.readerInterface,
|
|
12032
|
+
onAudioTrack: state.onAudioTrack,
|
|
12033
|
+
canSkipTracks: state.callbacks.canSkipTracksState
|
|
11402
12034
|
});
|
|
11403
12035
|
return null;
|
|
11404
12036
|
}
|
|
@@ -13577,23 +14209,62 @@ var parseBlockFlags = (iterator, type) => {
|
|
|
13577
14209
|
};
|
|
13578
14210
|
|
|
13579
14211
|
// src/containers/webm/get-sample-from-block.ts
|
|
13580
|
-
var
|
|
14212
|
+
var addAvcToTrackAndActivateTrackIfNecessary = async ({
|
|
13581
14213
|
partialVideoSample,
|
|
13582
14214
|
codec,
|
|
13583
14215
|
structureState: structureState2,
|
|
13584
14216
|
webmState,
|
|
13585
|
-
trackNumber: trackNumber2
|
|
14217
|
+
trackNumber: trackNumber2,
|
|
14218
|
+
logLevel,
|
|
14219
|
+
callbacks,
|
|
14220
|
+
onVideoTrack
|
|
13586
14221
|
}) => {
|
|
13587
|
-
if (codec
|
|
13588
|
-
|
|
13589
|
-
|
|
13590
|
-
|
|
13591
|
-
|
|
14222
|
+
if (codec !== "V_MPEG4/ISO/AVC") {
|
|
14223
|
+
return;
|
|
14224
|
+
}
|
|
14225
|
+
const missingTracks = getTracksFromMatroska({
|
|
14226
|
+
structureState: structureState2,
|
|
14227
|
+
webmState
|
|
14228
|
+
}).missingInfo;
|
|
14229
|
+
if (missingTracks.length === 0) {
|
|
14230
|
+
return;
|
|
14231
|
+
}
|
|
14232
|
+
const parsed = parseAvc(partialVideoSample.data);
|
|
14233
|
+
for (const parse of parsed) {
|
|
14234
|
+
if (parse.type === "avc-profile") {
|
|
14235
|
+
webmState.setAvcProfileForTrackNumber(trackNumber2, parse);
|
|
14236
|
+
const track = missingTracks.find((t) => t.trackId === trackNumber2);
|
|
14237
|
+
if (!track) {
|
|
14238
|
+
throw new Error("Could not find track " + trackNumber2);
|
|
14239
|
+
}
|
|
14240
|
+
const resolvedTracks = getTracksFromMatroska({
|
|
14241
|
+
structureState: structureState2,
|
|
14242
|
+
webmState
|
|
14243
|
+
}).resolved;
|
|
14244
|
+
const resolvedTrack = resolvedTracks.find((t) => t.trackId === trackNumber2);
|
|
14245
|
+
if (!resolvedTrack) {
|
|
14246
|
+
throw new Error("Could not find track " + trackNumber2);
|
|
13592
14247
|
}
|
|
14248
|
+
await registerVideoTrack({
|
|
14249
|
+
track: resolvedTrack,
|
|
14250
|
+
container: "webm",
|
|
14251
|
+
logLevel,
|
|
14252
|
+
onVideoTrack,
|
|
14253
|
+
registerVideoSampleCallback: callbacks.registerVideoSampleCallback,
|
|
14254
|
+
tracks: callbacks.tracks
|
|
14255
|
+
});
|
|
13593
14256
|
}
|
|
13594
14257
|
}
|
|
13595
14258
|
};
|
|
13596
|
-
var getSampleFromBlock = (
|
|
14259
|
+
var getSampleFromBlock = async ({
|
|
14260
|
+
ebml,
|
|
14261
|
+
webmState,
|
|
14262
|
+
offset,
|
|
14263
|
+
structureState: structureState2,
|
|
14264
|
+
callbacks,
|
|
14265
|
+
logLevel,
|
|
14266
|
+
onVideoTrack
|
|
14267
|
+
}) => {
|
|
13597
14268
|
const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
|
|
13598
14269
|
const trackNumber2 = iterator.getVint();
|
|
13599
14270
|
if (trackNumber2 === null) {
|
|
@@ -13631,12 +14302,15 @@ var getSampleFromBlock = (ebml, webmState, offset, structureState2) => {
|
|
|
13631
14302
|
partialVideoSample
|
|
13632
14303
|
};
|
|
13633
14304
|
}
|
|
13634
|
-
|
|
14305
|
+
await addAvcToTrackAndActivateTrackIfNecessary({
|
|
13635
14306
|
codec,
|
|
13636
14307
|
partialVideoSample,
|
|
13637
14308
|
structureState: structureState2,
|
|
13638
14309
|
webmState,
|
|
13639
|
-
trackNumber: trackNumber2
|
|
14310
|
+
trackNumber: trackNumber2,
|
|
14311
|
+
callbacks,
|
|
14312
|
+
logLevel,
|
|
14313
|
+
onVideoTrack
|
|
13640
14314
|
});
|
|
13641
14315
|
const sample = {
|
|
13642
14316
|
...partialVideoSample,
|
|
@@ -13796,21 +14470,31 @@ var postprocessEbml = async ({
|
|
|
13796
14470
|
});
|
|
13797
14471
|
}
|
|
13798
14472
|
if (track && track.type === "video") {
|
|
13799
|
-
|
|
13800
|
-
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
|
|
13806
|
-
|
|
14473
|
+
if (track.codec !== NO_CODEC_PRIVATE_SHOULD_BE_DERIVED_FROM_SPS) {
|
|
14474
|
+
await registerVideoTrack({
|
|
14475
|
+
track,
|
|
14476
|
+
container: "webm",
|
|
14477
|
+
logLevel,
|
|
14478
|
+
onVideoTrack,
|
|
14479
|
+
registerVideoSampleCallback: callbacks.registerVideoSampleCallback,
|
|
14480
|
+
tracks: callbacks.tracks
|
|
14481
|
+
});
|
|
14482
|
+
}
|
|
13807
14483
|
}
|
|
13808
14484
|
}
|
|
13809
14485
|
if (ebml.type === "Timestamp") {
|
|
13810
14486
|
webmState.setTimestampOffset(offset, ebml.value.value);
|
|
13811
14487
|
}
|
|
13812
14488
|
if (ebml.type === "Block" || ebml.type === "SimpleBlock") {
|
|
13813
|
-
const sample = getSampleFromBlock(
|
|
14489
|
+
const sample = await getSampleFromBlock({
|
|
14490
|
+
ebml,
|
|
14491
|
+
webmState,
|
|
14492
|
+
offset,
|
|
14493
|
+
structureState: structureState2,
|
|
14494
|
+
callbacks,
|
|
14495
|
+
logLevel,
|
|
14496
|
+
onVideoTrack
|
|
14497
|
+
});
|
|
13814
14498
|
if (sample.type === "video-sample") {
|
|
13815
14499
|
await callbacks.onVideoSample(sample.videoSample.trackId, sample.videoSample);
|
|
13816
14500
|
return {
|
|
@@ -13841,7 +14525,15 @@ var postprocessEbml = async ({
|
|
|
13841
14525
|
throw new Error("Expected block segment");
|
|
13842
14526
|
}
|
|
13843
14527
|
const hasReferenceBlock = ebml.value.find((c) => c.type === "ReferenceBlock");
|
|
13844
|
-
const sample = block2.value.length === 0 ? null : getSampleFromBlock(
|
|
14528
|
+
const sample = block2.value.length === 0 ? null : await getSampleFromBlock({
|
|
14529
|
+
ebml: block2,
|
|
14530
|
+
webmState,
|
|
14531
|
+
offset,
|
|
14532
|
+
structureState: structureState2,
|
|
14533
|
+
callbacks,
|
|
14534
|
+
logLevel,
|
|
14535
|
+
onVideoTrack
|
|
14536
|
+
});
|
|
13845
14537
|
if (sample && sample.type === "partial-video-sample") {
|
|
13846
14538
|
const completeFrame = {
|
|
13847
14539
|
...sample.partialVideoSample,
|
|
@@ -14042,9 +14734,9 @@ var initVideo = async ({ state }) => {
|
|
|
14042
14734
|
});
|
|
14043
14735
|
return;
|
|
14044
14736
|
}
|
|
14045
|
-
if (state.mp4HeaderSegment) {
|
|
14737
|
+
if (state.m3uPlaylistContext?.mp4HeaderSegment) {
|
|
14046
14738
|
Log.verbose(state.logLevel, "Detected ISO Base Media segment");
|
|
14047
|
-
const moovAtom = getMoovFromFromIsoStructure(state.mp4HeaderSegment);
|
|
14739
|
+
const moovAtom = getMoovFromFromIsoStructure(state.m3uPlaylistContext.mp4HeaderSegment);
|
|
14048
14740
|
if (!moovAtom) {
|
|
14049
14741
|
throw new Error("No moov box found");
|
|
14050
14742
|
}
|
|
@@ -14267,19 +14959,33 @@ var parseLoop = async ({
|
|
|
14267
14959
|
try {
|
|
14268
14960
|
await triggerInfoEmit(state);
|
|
14269
14961
|
await state.controller._internals.checkForAbortAndPause();
|
|
14270
|
-
const
|
|
14962
|
+
const result = await runParseIteration({
|
|
14271
14963
|
state
|
|
14272
14964
|
});
|
|
14273
|
-
if (
|
|
14274
|
-
|
|
14275
|
-
|
|
14276
|
-
|
|
14965
|
+
if (result !== null && result.action === "fetch-more-data") {
|
|
14966
|
+
Log.verbose(state.logLevel, `Need to fetch ${result.bytesNeeded} more bytes before we can continue`);
|
|
14967
|
+
const startBytesRemaining = state.iterator.bytesRemaining();
|
|
14968
|
+
while (true) {
|
|
14969
|
+
const done = await fetchMoreData(state);
|
|
14970
|
+
if (done) {
|
|
14971
|
+
break;
|
|
14972
|
+
}
|
|
14973
|
+
if (state.iterator.bytesRemaining() - startBytesRemaining >= result.bytesNeeded) {
|
|
14974
|
+
break;
|
|
14975
|
+
}
|
|
14976
|
+
}
|
|
14977
|
+
continue;
|
|
14978
|
+
}
|
|
14979
|
+
if (result !== null && result.action === "skip") {
|
|
14980
|
+
state.increaseSkippedBytes(result.skipTo - state.iterator.counter.getOffset());
|
|
14981
|
+
if (result.skipTo === state.contentLength) {
|
|
14982
|
+
state.iterator.discard(result.skipTo - state.iterator.counter.getOffset());
|
|
14277
14983
|
Log.verbose(state.logLevel, "Skipped to end of file, not fetching.");
|
|
14278
14984
|
break;
|
|
14279
14985
|
}
|
|
14280
14986
|
const seekStart = Date.now();
|
|
14281
14987
|
await performSeek({
|
|
14282
|
-
seekTo:
|
|
14988
|
+
seekTo: result.skipTo,
|
|
14283
14989
|
userInitiated: false,
|
|
14284
14990
|
controller: state.controller,
|
|
14285
14991
|
mediaSection: state.mediaSection,
|
|
@@ -14292,7 +14998,8 @@ var parseLoop = async ({
|
|
|
14292
14998
|
readerInterface: state.readerInterface,
|
|
14293
14999
|
fields: state.fields,
|
|
14294
15000
|
src: state.src,
|
|
14295
|
-
discardReadBytes: state.discardReadBytes
|
|
15001
|
+
discardReadBytes: state.discardReadBytes,
|
|
15002
|
+
prefetchCache: state.prefetchCache
|
|
14296
15003
|
});
|
|
14297
15004
|
state.timings.timeSeeking += Date.now() - seekStart;
|
|
14298
15005
|
}
|
|
@@ -14399,6 +15106,9 @@ var setSeekingHints = ({
|
|
|
14399
15106
|
setSeekingHintsForAac();
|
|
14400
15107
|
return;
|
|
14401
15108
|
}
|
|
15109
|
+
if (hints.type === "m3u8-seeking-hints") {
|
|
15110
|
+
return;
|
|
15111
|
+
}
|
|
14402
15112
|
throw new Error(`Unknown seeking hints type: ${hints}`);
|
|
14403
15113
|
};
|
|
14404
15114
|
|
|
@@ -14554,12 +15264,16 @@ var getMfraAtom = async ({
|
|
|
14554
15264
|
contentLength,
|
|
14555
15265
|
readerInterface,
|
|
14556
15266
|
controller,
|
|
14557
|
-
parentSize
|
|
15267
|
+
parentSize,
|
|
15268
|
+
logLevel,
|
|
15269
|
+
prefetchCache
|
|
14558
15270
|
}) => {
|
|
14559
15271
|
const result = await readerInterface.read({
|
|
14560
15272
|
controller,
|
|
14561
15273
|
range: [contentLength - parentSize, contentLength - 1],
|
|
14562
|
-
src
|
|
15274
|
+
src,
|
|
15275
|
+
logLevel,
|
|
15276
|
+
prefetchCache
|
|
14563
15277
|
});
|
|
14564
15278
|
const iterator = getArrayBufferIterator(new Uint8Array, parentSize);
|
|
14565
15279
|
while (true) {
|
|
@@ -14579,12 +15293,16 @@ var getMfroAtom = async ({
|
|
|
14579
15293
|
src,
|
|
14580
15294
|
contentLength,
|
|
14581
15295
|
readerInterface,
|
|
14582
|
-
controller
|
|
15296
|
+
controller,
|
|
15297
|
+
logLevel,
|
|
15298
|
+
prefetchCache
|
|
14583
15299
|
}) => {
|
|
14584
15300
|
const result = await readerInterface.read({
|
|
14585
15301
|
controller,
|
|
14586
15302
|
range: [contentLength - 16, contentLength - 1],
|
|
14587
|
-
src
|
|
15303
|
+
src,
|
|
15304
|
+
logLevel,
|
|
15305
|
+
prefetchCache
|
|
14588
15306
|
});
|
|
14589
15307
|
const { value } = await result.reader.reader.read();
|
|
14590
15308
|
if (!value) {
|
|
@@ -14619,13 +15337,16 @@ var getMfraSeekingBox = async ({
|
|
|
14619
15337
|
controller,
|
|
14620
15338
|
readerInterface,
|
|
14621
15339
|
src,
|
|
14622
|
-
logLevel
|
|
15340
|
+
logLevel,
|
|
15341
|
+
prefetchCache
|
|
14623
15342
|
}) => {
|
|
14624
15343
|
const parentSize = await getMfroAtom({
|
|
14625
15344
|
contentLength,
|
|
14626
15345
|
controller,
|
|
14627
15346
|
readerInterface,
|
|
14628
|
-
src
|
|
15347
|
+
src,
|
|
15348
|
+
logLevel,
|
|
15349
|
+
prefetchCache
|
|
14629
15350
|
});
|
|
14630
15351
|
if (!parentSize) {
|
|
14631
15352
|
return null;
|
|
@@ -14635,7 +15356,9 @@ var getMfraSeekingBox = async ({
|
|
|
14635
15356
|
controller,
|
|
14636
15357
|
readerInterface,
|
|
14637
15358
|
src,
|
|
14638
|
-
parentSize
|
|
15359
|
+
parentSize,
|
|
15360
|
+
logLevel,
|
|
15361
|
+
prefetchCache
|
|
14639
15362
|
});
|
|
14640
15363
|
mfraAtom.discard(8);
|
|
14641
15364
|
return getIsoBaseMediaChildren({
|
|
@@ -14653,7 +15376,8 @@ var lazyMfraLoad = ({
|
|
|
14653
15376
|
controller,
|
|
14654
15377
|
readerInterface,
|
|
14655
15378
|
src,
|
|
14656
|
-
logLevel
|
|
15379
|
+
logLevel,
|
|
15380
|
+
prefetchCache
|
|
14657
15381
|
}) => {
|
|
14658
15382
|
let prom = null;
|
|
14659
15383
|
let result = null;
|
|
@@ -14667,7 +15391,8 @@ var lazyMfraLoad = ({
|
|
|
14667
15391
|
controller,
|
|
14668
15392
|
readerInterface,
|
|
14669
15393
|
src,
|
|
14670
|
-
logLevel
|
|
15394
|
+
logLevel,
|
|
15395
|
+
prefetchCache
|
|
14671
15396
|
}).then((boxes) => {
|
|
14672
15397
|
Log.verbose(logLevel, "Lazily found mfra atom.");
|
|
14673
15398
|
result = boxes;
|
|
@@ -14708,7 +15433,8 @@ var isoBaseMediaState = ({
|
|
|
14708
15433
|
controller,
|
|
14709
15434
|
readerInterface,
|
|
14710
15435
|
src,
|
|
14711
|
-
logLevel
|
|
15436
|
+
logLevel,
|
|
15437
|
+
prefetchCache
|
|
14712
15438
|
}) => {
|
|
14713
15439
|
return {
|
|
14714
15440
|
flatSamples: cachedSamplePositionsState(),
|
|
@@ -14718,7 +15444,8 @@ var isoBaseMediaState = ({
|
|
|
14718
15444
|
controller,
|
|
14719
15445
|
readerInterface,
|
|
14720
15446
|
src,
|
|
14721
|
-
logLevel
|
|
15447
|
+
logLevel,
|
|
15448
|
+
prefetchCache
|
|
14722
15449
|
}),
|
|
14723
15450
|
moof: precomputedMoofState(),
|
|
14724
15451
|
tfra: precomputedTfraState()
|
|
@@ -14735,6 +15462,7 @@ var keyframesState = () => {
|
|
|
14735
15462
|
keyframes.push(keyframe);
|
|
14736
15463
|
};
|
|
14737
15464
|
const getKeyframes2 = () => {
|
|
15465
|
+
keyframes.sort((a, b) => a.positionInBytes - b.positionInBytes);
|
|
14738
15466
|
return keyframes;
|
|
14739
15467
|
};
|
|
14740
15468
|
const setFromSeekingHints = (keyframesFromHints) => {
|
|
@@ -14757,8 +15485,11 @@ var sampleSorter = ({
|
|
|
14757
15485
|
const streamsWithTracks = [];
|
|
14758
15486
|
const audioCallbacks = {};
|
|
14759
15487
|
const videoCallbacks = {};
|
|
14760
|
-
|
|
15488
|
+
let latestSample = {};
|
|
14761
15489
|
return {
|
|
15490
|
+
clearSamples: () => {
|
|
15491
|
+
latestSample = {};
|
|
15492
|
+
},
|
|
14762
15493
|
addToStreamWithTrack: (src) => {
|
|
14763
15494
|
streamsWithTracks.push(src);
|
|
14764
15495
|
},
|
|
@@ -14831,6 +15562,8 @@ var m3uState = (logLevel) => {
|
|
|
14831
15562
|
const hasEmittedAudioTrack = {};
|
|
14832
15563
|
const hasEmittedDoneWithTracks = {};
|
|
14833
15564
|
let hasFinishedManifest = false;
|
|
15565
|
+
const seekToSecondsToProcess = {};
|
|
15566
|
+
const nextSeekShouldSubtractChunks = {};
|
|
14834
15567
|
let readyToIterateOverM3u = false;
|
|
14835
15568
|
const allChunksProcessed = {};
|
|
14836
15569
|
const m3uStreamRuns = {};
|
|
@@ -14892,6 +15625,11 @@ var m3uState = (logLevel) => {
|
|
|
14892
15625
|
setAllChunksProcessed: (src) => {
|
|
14893
15626
|
allChunksProcessed[src] = true;
|
|
14894
15627
|
},
|
|
15628
|
+
clearAllChunksProcessed: () => {
|
|
15629
|
+
Object.keys(allChunksProcessed).forEach((key) => {
|
|
15630
|
+
delete allChunksProcessed[key];
|
|
15631
|
+
});
|
|
15632
|
+
},
|
|
14895
15633
|
getAllChunksProcessedForPlaylist,
|
|
14896
15634
|
getAllChunksProcessedOverall: () => {
|
|
14897
15635
|
if (!selectedMainPlaylist) {
|
|
@@ -14919,6 +15657,11 @@ var m3uState = (logLevel) => {
|
|
|
14919
15657
|
getTrackDone: (playlistUrl) => {
|
|
14920
15658
|
return tracksDone[playlistUrl];
|
|
14921
15659
|
},
|
|
15660
|
+
clearTracksDone: () => {
|
|
15661
|
+
Object.keys(tracksDone).forEach((key) => {
|
|
15662
|
+
delete tracksDone[key];
|
|
15663
|
+
});
|
|
15664
|
+
},
|
|
14922
15665
|
getM3uStreamRun: (playlistUrl) => m3uStreamRuns[playlistUrl] ?? null,
|
|
14923
15666
|
abortM3UStreamRuns: () => {
|
|
14924
15667
|
const values = Object.values(m3uStreamRuns);
|
|
@@ -14937,7 +15680,15 @@ var m3uState = (logLevel) => {
|
|
|
14937
15680
|
getSelectedPlaylists,
|
|
14938
15681
|
sampleSorter: sampleSorter({ logLevel, getAllChunksProcessedForPlaylist }),
|
|
14939
15682
|
setMp4HeaderSegment,
|
|
14940
|
-
getMp4HeaderSegment
|
|
15683
|
+
getMp4HeaderSegment,
|
|
15684
|
+
setSeekToSecondsToProcess: (playlistUrl, m3uSeek) => {
|
|
15685
|
+
seekToSecondsToProcess[playlistUrl] = m3uSeek;
|
|
15686
|
+
},
|
|
15687
|
+
getSeekToSecondsToProcess: (playlistUrl) => seekToSecondsToProcess[playlistUrl] ?? null,
|
|
15688
|
+
setNextSeekShouldSubtractChunks: (playlistUrl, chunks) => {
|
|
15689
|
+
nextSeekShouldSubtractChunks[playlistUrl] = chunks;
|
|
15690
|
+
},
|
|
15691
|
+
getNextSeekShouldSubtractChunks: (playlistUrl) => nextSeekShouldSubtractChunks[playlistUrl] ?? 0
|
|
14941
15692
|
};
|
|
14942
15693
|
};
|
|
14943
15694
|
|
|
@@ -14986,12 +15737,15 @@ var fetchWebmCues = async ({
|
|
|
14986
15737
|
readerInterface,
|
|
14987
15738
|
controller,
|
|
14988
15739
|
position,
|
|
14989
|
-
logLevel
|
|
15740
|
+
logLevel,
|
|
15741
|
+
prefetchCache
|
|
14990
15742
|
}) => {
|
|
14991
15743
|
const result = await readerInterface.read({
|
|
14992
15744
|
controller,
|
|
14993
15745
|
range: position,
|
|
14994
|
-
src
|
|
15746
|
+
src,
|
|
15747
|
+
logLevel,
|
|
15748
|
+
prefetchCache
|
|
14995
15749
|
});
|
|
14996
15750
|
const { value } = await result.reader.reader.read();
|
|
14997
15751
|
if (!value) {
|
|
@@ -15018,7 +15772,8 @@ var lazyCuesFetch = ({
|
|
|
15018
15772
|
controller,
|
|
15019
15773
|
logLevel,
|
|
15020
15774
|
readerInterface,
|
|
15021
|
-
src
|
|
15775
|
+
src,
|
|
15776
|
+
prefetchCache
|
|
15022
15777
|
}) => {
|
|
15023
15778
|
let prom = null;
|
|
15024
15779
|
let sOffset = null;
|
|
@@ -15040,7 +15795,8 @@ var lazyCuesFetch = ({
|
|
|
15040
15795
|
logLevel,
|
|
15041
15796
|
position,
|
|
15042
15797
|
readerInterface,
|
|
15043
|
-
src
|
|
15798
|
+
src,
|
|
15799
|
+
prefetchCache
|
|
15044
15800
|
}).then((cues) => {
|
|
15045
15801
|
Log.verbose(logLevel, "Cues loaded");
|
|
15046
15802
|
result = cues;
|
|
@@ -15102,7 +15858,8 @@ var webmState = ({
|
|
|
15102
15858
|
controller,
|
|
15103
15859
|
logLevel,
|
|
15104
15860
|
readerInterface,
|
|
15105
|
-
src
|
|
15861
|
+
src,
|
|
15862
|
+
prefetchCache
|
|
15106
15863
|
}) => {
|
|
15107
15864
|
const trackEntries = {};
|
|
15108
15865
|
const onTrackEntrySegment = (trackEntry2) => {
|
|
@@ -15163,7 +15920,8 @@ var webmState = ({
|
|
|
15163
15920
|
controller,
|
|
15164
15921
|
logLevel,
|
|
15165
15922
|
readerInterface,
|
|
15166
|
-
src
|
|
15923
|
+
src,
|
|
15924
|
+
prefetchCache
|
|
15167
15925
|
});
|
|
15168
15926
|
const getTimeStampMapForSeekingHints = () => {
|
|
15169
15927
|
return timestampMap;
|
|
@@ -15244,13 +16002,16 @@ var fetchIdx1 = async ({
|
|
|
15244
16002
|
readerInterface,
|
|
15245
16003
|
controller,
|
|
15246
16004
|
position,
|
|
15247
|
-
logLevel
|
|
16005
|
+
logLevel,
|
|
16006
|
+
prefetchCache
|
|
15248
16007
|
}) => {
|
|
15249
16008
|
Log.verbose(logLevel, "Making request to fetch idx1 from ", src, "position", position);
|
|
15250
16009
|
const result = await readerInterface.read({
|
|
15251
16010
|
controller,
|
|
15252
16011
|
range: position,
|
|
15253
|
-
src
|
|
16012
|
+
src,
|
|
16013
|
+
logLevel,
|
|
16014
|
+
prefetchCache
|
|
15254
16015
|
});
|
|
15255
16016
|
const iterator = getArrayBufferIterator(new Uint8Array, Infinity);
|
|
15256
16017
|
while (true) {
|
|
@@ -15281,7 +16042,8 @@ var lazyIdx1Fetch = ({
|
|
|
15281
16042
|
controller,
|
|
15282
16043
|
logLevel,
|
|
15283
16044
|
readerInterface,
|
|
15284
|
-
src
|
|
16045
|
+
src,
|
|
16046
|
+
prefetchCache
|
|
15285
16047
|
}) => {
|
|
15286
16048
|
let prom = null;
|
|
15287
16049
|
let result = null;
|
|
@@ -15297,7 +16059,8 @@ var lazyIdx1Fetch = ({
|
|
|
15297
16059
|
logLevel,
|
|
15298
16060
|
position,
|
|
15299
16061
|
readerInterface,
|
|
15300
|
-
src
|
|
16062
|
+
src,
|
|
16063
|
+
prefetchCache
|
|
15301
16064
|
}).then((entries) => {
|
|
15302
16065
|
prom = null;
|
|
15303
16066
|
result = entries;
|
|
@@ -15418,7 +16181,8 @@ var riffSpecificState = ({
|
|
|
15418
16181
|
controller,
|
|
15419
16182
|
logLevel,
|
|
15420
16183
|
readerInterface,
|
|
15421
|
-
src
|
|
16184
|
+
src,
|
|
16185
|
+
prefetchCache
|
|
15422
16186
|
}) => {
|
|
15423
16187
|
let avcProfile = null;
|
|
15424
16188
|
let nextTrackIndex = 0;
|
|
@@ -15437,7 +16201,8 @@ var riffSpecificState = ({
|
|
|
15437
16201
|
controller,
|
|
15438
16202
|
logLevel,
|
|
15439
16203
|
readerInterface,
|
|
15440
|
-
src
|
|
16204
|
+
src,
|
|
16205
|
+
prefetchCache
|
|
15441
16206
|
});
|
|
15442
16207
|
const sampleCounter = riffSampleCounter();
|
|
15443
16208
|
return {
|
|
@@ -15458,7 +16223,7 @@ var riffSpecificState = ({
|
|
|
15458
16223
|
};
|
|
15459
16224
|
|
|
15460
16225
|
// src/state/sample-callbacks.ts
|
|
15461
|
-
var
|
|
16226
|
+
var callbacksState = ({
|
|
15462
16227
|
controller,
|
|
15463
16228
|
hasAudioTrackHandlers,
|
|
15464
16229
|
hasVideoTrackHandlers,
|
|
@@ -15765,14 +16530,15 @@ var makeParserState = ({
|
|
|
15765
16530
|
onDiscardedData,
|
|
15766
16531
|
selectM3uStreamFn,
|
|
15767
16532
|
selectM3uAssociatedPlaylistsFn,
|
|
15768
|
-
|
|
16533
|
+
m3uPlaylistContext,
|
|
15769
16534
|
contentType,
|
|
15770
16535
|
name,
|
|
15771
16536
|
callbacks,
|
|
15772
16537
|
fieldsInReturnValue,
|
|
15773
16538
|
mimeType,
|
|
15774
16539
|
initialReaderInstance,
|
|
15775
|
-
makeSamplesStartAtZero
|
|
16540
|
+
makeSamplesStartAtZero,
|
|
16541
|
+
prefetchCache
|
|
15776
16542
|
}) => {
|
|
15777
16543
|
let skippedBytes = 0;
|
|
15778
16544
|
const returnValue = {};
|
|
@@ -15804,22 +16570,35 @@ var makeParserState = ({
|
|
|
15804
16570
|
callbacks
|
|
15805
16571
|
});
|
|
15806
16572
|
return {
|
|
15807
|
-
riff: riffSpecificState({
|
|
16573
|
+
riff: riffSpecificState({
|
|
16574
|
+
controller,
|
|
16575
|
+
logLevel,
|
|
16576
|
+
readerInterface,
|
|
16577
|
+
src,
|
|
16578
|
+
prefetchCache
|
|
16579
|
+
}),
|
|
15808
16580
|
transportStream: transportStreamState(),
|
|
15809
|
-
webm: webmState({
|
|
16581
|
+
webm: webmState({
|
|
16582
|
+
controller,
|
|
16583
|
+
logLevel,
|
|
16584
|
+
readerInterface,
|
|
16585
|
+
src,
|
|
16586
|
+
prefetchCache
|
|
16587
|
+
}),
|
|
15810
16588
|
iso: isoBaseMediaState({
|
|
15811
16589
|
contentLength,
|
|
15812
16590
|
controller,
|
|
15813
16591
|
readerInterface,
|
|
15814
16592
|
src,
|
|
15815
|
-
logLevel
|
|
16593
|
+
logLevel,
|
|
16594
|
+
prefetchCache
|
|
15816
16595
|
}),
|
|
15817
16596
|
mp3,
|
|
15818
16597
|
aac: aacState(),
|
|
15819
16598
|
flac: flacState(),
|
|
15820
16599
|
m3u: m3uState(logLevel),
|
|
15821
16600
|
timings,
|
|
15822
|
-
callbacks:
|
|
16601
|
+
callbacks: callbacksState({
|
|
15823
16602
|
controller,
|
|
15824
16603
|
hasAudioTrackHandlers,
|
|
15825
16604
|
hasVideoTrackHandlers,
|
|
@@ -15857,7 +16636,7 @@ var makeParserState = ({
|
|
|
15857
16636
|
discardReadBytes,
|
|
15858
16637
|
selectM3uStreamFn,
|
|
15859
16638
|
selectM3uAssociatedPlaylistsFn,
|
|
15860
|
-
|
|
16639
|
+
m3uPlaylistContext,
|
|
15861
16640
|
contentType,
|
|
15862
16641
|
name,
|
|
15863
16642
|
returnValue,
|
|
@@ -15867,7 +16646,8 @@ var makeParserState = ({
|
|
|
15867
16646
|
errored,
|
|
15868
16647
|
currentReader: currentReaderState,
|
|
15869
16648
|
seekInfiniteLoop,
|
|
15870
|
-
makeSamplesStartAtZero
|
|
16649
|
+
makeSamplesStartAtZero,
|
|
16650
|
+
prefetchCache
|
|
15871
16651
|
};
|
|
15872
16652
|
};
|
|
15873
16653
|
|
|
@@ -15946,7 +16726,7 @@ var internalParseMedia = async function({
|
|
|
15946
16726
|
apiName,
|
|
15947
16727
|
selectM3uStream: selectM3uStreamFn,
|
|
15948
16728
|
selectM3uAssociatedPlaylists: selectM3uAssociatedPlaylistsFn,
|
|
15949
|
-
|
|
16729
|
+
m3uPlaylistContext,
|
|
15950
16730
|
makeSamplesStartAtZero,
|
|
15951
16731
|
seekingHints,
|
|
15952
16732
|
...more
|
|
@@ -15958,6 +16738,7 @@ var internalParseMedia = async function({
|
|
|
15958
16738
|
apiName
|
|
15959
16739
|
});
|
|
15960
16740
|
Log.verbose(logLevel, `Reading ${typeof src === "string" ? src : src instanceof URL ? src.toString() : src instanceof File ? src.name : src.toString()}`);
|
|
16741
|
+
const prefetchCache = new Map;
|
|
15961
16742
|
const {
|
|
15962
16743
|
reader: readerInstance,
|
|
15963
16744
|
contentLength,
|
|
@@ -15965,7 +16746,13 @@ var internalParseMedia = async function({
|
|
|
15965
16746
|
contentType,
|
|
15966
16747
|
supportsContentRange,
|
|
15967
16748
|
needsContentRange
|
|
15968
|
-
} = await readerInterface.read({
|
|
16749
|
+
} = await readerInterface.read({
|
|
16750
|
+
src,
|
|
16751
|
+
range: null,
|
|
16752
|
+
controller,
|
|
16753
|
+
logLevel,
|
|
16754
|
+
prefetchCache
|
|
16755
|
+
});
|
|
15969
16756
|
if (contentLength === null) {
|
|
15970
16757
|
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.`);
|
|
15971
16758
|
}
|
|
@@ -15988,14 +16775,15 @@ var internalParseMedia = async function({
|
|
|
15988
16775
|
onDiscardedData,
|
|
15989
16776
|
selectM3uStreamFn,
|
|
15990
16777
|
selectM3uAssociatedPlaylistsFn,
|
|
15991
|
-
|
|
16778
|
+
m3uPlaylistContext,
|
|
15992
16779
|
contentType,
|
|
15993
16780
|
name,
|
|
15994
16781
|
callbacks: more,
|
|
15995
16782
|
fieldsInReturnValue: _fieldsInReturnValue ?? {},
|
|
15996
16783
|
mimeType: contentType,
|
|
15997
16784
|
initialReaderInstance: readerInstance,
|
|
15998
|
-
makeSamplesStartAtZero
|
|
16785
|
+
makeSamplesStartAtZero,
|
|
16786
|
+
prefetchCache
|
|
15999
16787
|
});
|
|
16000
16788
|
if (seekingHints) {
|
|
16001
16789
|
setSeekingHints({ hints: seekingHints, state });
|
|
@@ -16005,7 +16793,7 @@ var internalParseMedia = async function({
|
|
|
16005
16793
|
keyframesState: state.keyframes,
|
|
16006
16794
|
webmState: state.webm,
|
|
16007
16795
|
structureState: state.structure,
|
|
16008
|
-
|
|
16796
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
16009
16797
|
mediaSectionState: state.mediaSection,
|
|
16010
16798
|
isoState: state.iso,
|
|
16011
16799
|
transportStream: state.transportStream,
|
|
@@ -16034,6 +16822,7 @@ var internalParseMedia = async function({
|
|
|
16034
16822
|
state.iterator?.destroy();
|
|
16035
16823
|
state.callbacks.tracks.ensureHasTracksAtEnd(state.fields);
|
|
16036
16824
|
state.m3u.abortM3UStreamRuns();
|
|
16825
|
+
prefetchCache.clear();
|
|
16037
16826
|
if (state.errored) {
|
|
16038
16827
|
throw state.errored;
|
|
16039
16828
|
}
|
|
@@ -16051,7 +16840,7 @@ var forwardMediaParserControllerToWorker = (controller) => {
|
|
|
16051
16840
|
return;
|
|
16052
16841
|
}
|
|
16053
16842
|
if (message.type === "request-seek") {
|
|
16054
|
-
controller.
|
|
16843
|
+
controller.seek(message.payload);
|
|
16055
16844
|
return;
|
|
16056
16845
|
}
|
|
16057
16846
|
if (message.type === "request-get-seeking-hints") {
|
|
@@ -16132,6 +16921,22 @@ var serializeError = ({
|
|
|
16132
16921
|
seekingHints
|
|
16133
16922
|
};
|
|
16134
16923
|
}
|
|
16924
|
+
if (error.name === "AbortError") {
|
|
16925
|
+
return {
|
|
16926
|
+
type: "response-error",
|
|
16927
|
+
errorName: "AbortError",
|
|
16928
|
+
errorMessage: error.message,
|
|
16929
|
+
errorStack: error.stack ?? ""
|
|
16930
|
+
};
|
|
16931
|
+
}
|
|
16932
|
+
if (error.name === "NotReadableError") {
|
|
16933
|
+
return {
|
|
16934
|
+
type: "response-error",
|
|
16935
|
+
errorName: "NotReadableError",
|
|
16936
|
+
errorMessage: error.message,
|
|
16937
|
+
errorStack: error.stack ?? ""
|
|
16938
|
+
};
|
|
16939
|
+
}
|
|
16135
16940
|
if (error.name !== "Error") {
|
|
16136
16941
|
Log.warn(logLevel, `Original error was of type ${error.name} did not properly propagate`);
|
|
16137
16942
|
}
|
|
@@ -16181,7 +16986,7 @@ var startParsing = async (message, reader) => {
|
|
|
16181
16986
|
acknowledgeRemotionLicense,
|
|
16182
16987
|
logLevel: userLogLevel,
|
|
16183
16988
|
progressIntervalInMs,
|
|
16184
|
-
|
|
16989
|
+
m3uPlaylistContext,
|
|
16185
16990
|
seekingHints,
|
|
16186
16991
|
makeSamplesStartAtZero
|
|
16187
16992
|
} = payload;
|
|
@@ -16417,7 +17222,7 @@ var startParsing = async (message, reader) => {
|
|
|
16417
17222
|
}
|
|
16418
17223
|
return res.value;
|
|
16419
17224
|
} : defaultSelectM3uStreamFn,
|
|
16420
|
-
|
|
17225
|
+
m3uPlaylistContext: m3uPlaylistContext ?? null,
|
|
16421
17226
|
selectM3uAssociatedPlaylists: postM3uAssociatedPlaylistsSelection ? async (playlists) => {
|
|
16422
17227
|
const res = await executeCallback({
|
|
16423
17228
|
callbackType: "m3u-associated-playlists-selection",
|