mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
44 lines
1.7 KiB
JavaScript
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
|