Files
v10/dist/dev/playback/primitives/head-peek.js
T

44 lines
1.7 KiB
JavaScript

//#region src/playback/primitives/head-peek.ts
/**
* Eager head-of-stream peek. Pulls chunks from an async byte stream only until
* `tryParse` signals it has read what it needs (or the stream ends), then returns
* a stream that re-emits the pulled head followed by the untouched tail — so
* reading a head-of-stream mp4 box (`mdhd` / `tfdt`) doesn't break streaming of
* the append. Once the caller has what it wants, the rest streams as normal.
*/
function concat(chunks) {
if (chunks.length === 1) return chunks[0];
const total = chunks.reduce((n, c) => n + c.length, 0);
const out = new Uint8Array(total);
let offset = 0;
for (const chunk of chunks) {
out.set(chunk, offset);
offset += chunk.length;
}
return out;
}
/** Re-emit the eagerly-pulled head chunks, then stream the untouched tail. */
async function* reassemble(head, tail) {
yield* head;
for (let next = await tail.next(); !next.done; next = await tail.next()) yield next.value;
}
/**
* Pull chunks until `tryParse(accumulatedHead)` returns `true` — it found and read
* its box — or the stream ends, then return a stream re-emitting the pulled head
* followed by the untouched tail. `tryParse` is called with the growing head after
* each chunk; it performs the side effect (publishing the parsed value) and returns
* whether it's done.
*/
async function peekHead(data, tryParse) {
const iterator = data[Symbol.asyncIterator]();
const head = [];
for (let next = await iterator.next(); !next.done; next = await iterator.next()) {
head.push(next.value);
if (tryParse(concat(head))) break;
}
return reassemble(head, iterator);
}
//#endregion
export { peekHead };
//# sourceMappingURL=head-peek.js.map