avbridge 2.11.0 → 2.12.0

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.
Files changed (72) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/{avi-B5CQYB7L.cjs → avi-EQE6AR75.cjs} +4 -4
  3. package/dist/{avi-2ILLBNPQ.cjs.map → avi-EQE6AR75.cjs.map} +1 -1
  4. package/dist/{avi-RWWPN2PR.js → avi-NNHH4AAA.js} +3 -3
  5. package/dist/{avi-JXU4GQL2.js.map → avi-NNHH4AAA.js.map} +1 -1
  6. package/dist/{avi-JXU4GQL2.js → avi-S7EY54YA.js} +3 -3
  7. package/dist/{avi-RWWPN2PR.js.map → avi-S7EY54YA.js.map} +1 -1
  8. package/dist/{avi-2ILLBNPQ.cjs → avi-Y3N325WZ.cjs} +4 -4
  9. package/dist/{avi-B5CQYB7L.cjs.map → avi-Y3N325WZ.cjs.map} +1 -1
  10. package/dist/{chunk-GYIJU44C.js → chunk-2LNXMGT6.js} +5 -5
  11. package/dist/{chunk-GYIJU44C.js.map → chunk-2LNXMGT6.js.map} +1 -1
  12. package/dist/{chunk-DCSOQH2N.js → chunk-3AI5WFFN.js} +40 -16
  13. package/dist/chunk-3AI5WFFN.js.map +1 -0
  14. package/dist/{chunk-2NSOOMXW.js → chunk-3YKWU4FM.js} +3 -3
  15. package/dist/{chunk-2NSOOMXW.js.map → chunk-3YKWU4FM.js.map} +1 -1
  16. package/dist/{chunk-CL6UEUQF.js → chunk-5Y5BTB5D.js} +5 -5
  17. package/dist/{chunk-CL6UEUQF.js.map → chunk-5Y5BTB5D.js.map} +1 -1
  18. package/dist/{chunk-37UOSAVI.cjs → chunk-7EF4VTUS.cjs} +23 -23
  19. package/dist/{chunk-IHNHHEA2.js.map → chunk-7EF4VTUS.cjs.map} +1 -1
  20. package/dist/{chunk-OTFS7DC4.cjs → chunk-GJBNLPGI.cjs} +14 -14
  21. package/dist/{chunk-OTFS7DC4.cjs.map → chunk-GJBNLPGI.cjs.map} +1 -1
  22. package/dist/{chunk-BYGZN4Z5.cjs → chunk-HBHSUGNI.cjs} +5 -5
  23. package/dist/{chunk-BYGZN4Z5.cjs.map → chunk-HBHSUGNI.cjs.map} +1 -1
  24. package/dist/{chunk-L7A3ECI2.cjs → chunk-HZUVMXBN.cjs} +4 -4
  25. package/dist/{chunk-L7A3ECI2.cjs.map → chunk-HZUVMXBN.cjs.map} +1 -1
  26. package/dist/{chunk-Z33SBWL5.cjs → chunk-YPZFGJV3.cjs} +40 -16
  27. package/dist/chunk-YPZFGJV3.cjs.map +1 -0
  28. package/dist/{chunk-IHNHHEA2.js → chunk-Z26PXRUY.js} +9 -9
  29. package/dist/chunk-Z26PXRUY.js.map +1 -0
  30. package/dist/element-browser.js +42 -18
  31. package/dist/element-browser.js.map +1 -1
  32. package/dist/element.cjs +5 -5
  33. package/dist/element.d.cts +1 -1
  34. package/dist/element.d.ts +1 -1
  35. package/dist/element.js +4 -4
  36. package/dist/index.cjs +21 -21
  37. package/dist/index.d.cts +2 -2
  38. package/dist/index.d.ts +2 -2
  39. package/dist/index.js +9 -9
  40. package/dist/{libav-demux-3N5Y3VQA.cjs → libav-demux-575OYCT2.cjs} +9 -9
  41. package/dist/{libav-demux-3N5Y3VQA.cjs.map → libav-demux-575OYCT2.cjs.map} +1 -1
  42. package/dist/{libav-demux-JXD4OTLM.js → libav-demux-SXZDLC7W.js} +4 -4
  43. package/dist/{libav-demux-JXD4OTLM.js.map → libav-demux-SXZDLC7W.js.map} +1 -1
  44. package/dist/libav-http-reader-2S5HAHW4.js +3 -0
  45. package/dist/{libav-http-reader-WXG3Z7AI.js.map → libav-http-reader-2S5HAHW4.js.map} +1 -1
  46. package/dist/libav-http-reader-Q356EO2K.cjs +16 -0
  47. package/dist/{libav-http-reader-AZLE7YFS.cjs.map → libav-http-reader-Q356EO2K.cjs.map} +1 -1
  48. package/dist/{player-DDdNVFDv.d.cts → player-bQ6n4hVp.d.cts} +15 -0
  49. package/dist/{player-DDdNVFDv.d.ts → player-bQ6n4hVp.d.ts} +15 -0
  50. package/dist/player.cjs +60 -15
  51. package/dist/player.cjs.map +1 -1
  52. package/dist/player.d.cts +21 -0
  53. package/dist/player.d.ts +21 -0
  54. package/dist/player.js +60 -15
  55. package/dist/player.js.map +1 -1
  56. package/dist/remux-7TA4FKTY.js +10 -0
  57. package/dist/{remux-56V7LDAD.js.map → remux-7TA4FKTY.js.map} +1 -1
  58. package/dist/remux-VPKCLHHM.cjs +35 -0
  59. package/dist/{remux-KUS5GIL6.cjs.map → remux-VPKCLHHM.cjs.map} +1 -1
  60. package/package.json +1 -1
  61. package/src/element/avbridge-player.ts +36 -8
  62. package/src/element/player-styles.ts +13 -1
  63. package/src/player.ts +3 -3
  64. package/src/types.ts +15 -0
  65. package/src/util/libav-http-reader.ts +58 -19
  66. package/dist/chunk-37UOSAVI.cjs.map +0 -1
  67. package/dist/chunk-DCSOQH2N.js.map +0 -1
  68. package/dist/chunk-Z33SBWL5.cjs.map +0 -1
  69. package/dist/libav-http-reader-AZLE7YFS.cjs +0 -16
  70. package/dist/libav-http-reader-WXG3Z7AI.js +0 -3
  71. package/dist/remux-56V7LDAD.js +0 -10
  72. package/dist/remux-KUS5GIL6.cjs +0 -35
@@ -3,11 +3,13 @@
3
3
  // src/util/libav-http-reader.ts
4
4
  var MIN_READ = 256 * 1024;
5
5
  var MAX_READ = 1 * 1024 * 1024;
6
+ var DEFAULT_CACHE_BYTES = 8 * 1024 * 1024;
6
7
  async function prepareLibavInput(libav, filename, source, transport) {
7
8
  if (source.kind === "url") {
8
9
  const handle = await attachLibavHttpReader(libav, filename, source.url, {
9
10
  requestInit: transport?.requestInit,
10
- fetchFn: transport?.fetchFn
11
+ fetchFn: transport?.fetchFn,
12
+ cacheBytes: transport?.cacheBytes
11
13
  });
12
14
  return {
13
15
  filename,
@@ -69,7 +71,9 @@ async function attachLibavHttpReader(libav, filename, url, options = {}) {
69
71
  }
70
72
  await libav.mkblockreaderdev(filename, size);
71
73
  let detached = false;
72
- let cached = null;
74
+ const cache = /* @__PURE__ */ new Map();
75
+ let cacheBytes = 0;
76
+ const cacheBudget = Math.max(0, options.cacheBytes ?? DEFAULT_CACHE_BYTES);
73
77
  let inflight = null;
74
78
  function clampReadLength(requested) {
75
79
  const doubled = requested * 2;
@@ -77,14 +81,33 @@ async function attachLibavHttpReader(libav, filename, url, options = {}) {
77
81
  if (doubled > MAX_READ) return MAX_READ;
78
82
  return doubled;
79
83
  }
80
- function cacheCovers(pos, length) {
81
- if (!cached) return false;
82
- return pos >= cached.pos && pos + length <= cached.pos + cached.bytes.byteLength;
84
+ function cacheLookup(pos, length) {
85
+ for (const [blockPos, bytes] of cache) {
86
+ if (pos >= blockPos && pos + length <= blockPos + bytes.byteLength) {
87
+ cache.delete(blockPos);
88
+ cache.set(blockPos, bytes);
89
+ const offset = pos - blockPos;
90
+ return bytes.subarray(offset, offset + length);
91
+ }
92
+ }
93
+ return null;
83
94
  }
84
- function sliceFromCache(pos, length) {
85
- if (!cached) throw new Error("sliceFromCache called with no cache");
86
- const offset = pos - cached.pos;
87
- return cached.bytes.subarray(offset, offset + length);
95
+ function cacheInsert(pos, bytes) {
96
+ const existing = cache.get(pos);
97
+ if (existing) {
98
+ cacheBytes -= existing.byteLength;
99
+ cache.delete(pos);
100
+ }
101
+ cache.set(pos, bytes);
102
+ cacheBytes += bytes.byteLength;
103
+ while (cacheBytes > cacheBudget && cache.size > 0) {
104
+ const oldestKey = cache.keys().next().value;
105
+ if (oldestKey === void 0) break;
106
+ const oldest = cache.get(oldestKey);
107
+ if (!oldest) break;
108
+ cache.delete(oldestKey);
109
+ cacheBytes -= oldest.byteLength;
110
+ }
88
111
  }
89
112
  async function fetchRange(pos, length) {
90
113
  const end = Math.min(pos + length - 1, size - 1);
@@ -101,7 +124,7 @@ async function attachLibavHttpReader(libav, filename, url, options = {}) {
101
124
  );
102
125
  }
103
126
  const buf = new Uint8Array(await res.arrayBuffer());
104
- cached = { pos, bytes: buf };
127
+ cacheInsert(pos, buf);
105
128
  return buf;
106
129
  }
107
130
  async function handleRead(name, pos, length) {
@@ -112,10 +135,10 @@ async function attachLibavHttpReader(libav, filename, url, options = {}) {
112
135
  }
113
136
  }
114
137
  if (detached) return;
115
- if (cacheCovers(pos, length)) {
116
- const data = sliceFromCache(pos, length);
138
+ const hit = cacheLookup(pos, length);
139
+ if (hit) {
117
140
  try {
118
- await libav.ff_block_reader_dev_send(name, pos, data);
141
+ await libav.ff_block_reader_dev_send(name, pos, hit);
119
142
  } catch {
120
143
  }
121
144
  return;
@@ -168,7 +191,8 @@ async function attachLibavHttpReader(libav, filename, url, options = {}) {
168
191
  } catch {
169
192
  }
170
193
  }
171
- cached = null;
194
+ cache.clear();
195
+ cacheBytes = 0;
172
196
  try {
173
197
  await libav.unlinkreadaheadfile(filename);
174
198
  } catch {
@@ -179,5 +203,5 @@ async function attachLibavHttpReader(libav, filename, url, options = {}) {
179
203
 
180
204
  exports.attachLibavHttpReader = attachLibavHttpReader;
181
205
  exports.prepareLibavInput = prepareLibavInput;
182
- //# sourceMappingURL=chunk-Z33SBWL5.cjs.map
183
- //# sourceMappingURL=chunk-Z33SBWL5.cjs.map
206
+ //# sourceMappingURL=chunk-YPZFGJV3.cjs.map
207
+ //# sourceMappingURL=chunk-YPZFGJV3.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/util/libav-http-reader.ts"],"names":[],"mappings":"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","file":"chunk-YPZFGJV3.cjs","sourcesContent":["/**\n * libav.js HTTP block reader.\n *\n * Wraps `libav.mkblockreaderdev` + `libav.onblockread` +\n * `libav.ff_block_reader_dev_send` so that libav can demux a remote file\n * via HTTP Range requests instead of needing the entire file in memory.\n *\n * Used by the AVI/ASF/FLV probe path and the libav-backed playback /\n * conversion strategies whenever the source is a URL.\n *\n * Design notes:\n *\n * - **Range support detection** is done by issuing a `Range: bytes=0-0`\n * probe request. We do NOT trust `Accept-Ranges` headers — some servers\n * support ranges but don't advertise them, others advertise but don't.\n * The probe request is the canonical signal: a `206 Partial Content`\n * response means we can stream; anything else fails fast with a clear\n * error. We never silently fall back to a full download.\n *\n * - **Sequential reads.** libav can issue overlapping `onblockread`\n * callbacks. The reader serializes them through a single async queue\n * so a) `ff_block_reader_dev_send` calls are well-ordered and b) we\n * never have two in-flight fetches for unrelated reads. Throughput\n * for v1 is \"good enough\"; correctness > parallelism.\n *\n * - **In-flight dedup.** If libav asks for `(pos=1000, len=4096)` twice\n * in a row before the first request resolves, the second call awaits\n * the first instead of issuing a duplicate fetch. This handles the\n * \"demuxer re-reads the same header\" pattern cheaply.\n *\n * - **Read-ahead clamp.** libav's requested length is doubled, then\n * clamped to `[256 KB, 1 MB]`. Small reads get amortized; pathological\n * large requests don't OOM us.\n *\n * - **LRU block cache.** Fetched blocks are kept in a Map keyed by start\n * position, bounded by a byte budget (default 8 MB, configurable via\n * `cacheBytes`). Map insertion order doubles as recency; re-accessing\n * a block promotes it via delete+set. Eviction walks oldest-first\n * until total bytes fit the budget. Typical seek pattern has three\n * hot regions — header/moov at the front, index at the tail, current\n * read position — all of which fit comfortably under the default.\n *\n * - **Safe detach.** `detach()` clears `libav.onblockread`, sets a\n * destroyed flag, and ignores any in-flight fetch resolutions so we\n * never write into a torn-down demuxer.\n */\n\nconst MIN_READ = 256 * 1024;\nconst MAX_READ = 1 * 1024 * 1024;\nconst DEFAULT_CACHE_BYTES = 8 * 1024 * 1024;\n\ninterface LibavLike {\n mkblockreaderdev(name: string, size: number): Promise<void>;\n unlinkreadaheadfile(name: string): Promise<void>;\n ff_block_reader_dev_send(\n name: string,\n pos: number,\n data: Uint8Array | null,\n opts?: { errorCode?: number; error?: unknown },\n ): Promise<void>;\n onblockread?: (filename: string, pos: number, length: number) => void;\n}\n\nexport interface LibavHttpReaderHandle {\n /** Total file size (bytes) reported by the server. */\n readonly size: number;\n /** Always `\"http-range\"` for now. Reserved for future transports. */\n readonly transport: \"http-range\";\n /** Stop serving reads, clear the libav callback, and ignore late fetches. */\n detach(): Promise<void>;\n}\n\nexport interface AttachLibavHttpReaderOptions {\n /** Optional `RequestInit` extras (mode, credentials, headers, etc.). */\n requestInit?: RequestInit;\n /** Override fetch (for testing). Defaults to globalThis.fetch. */\n fetchFn?: typeof fetch;\n /**\n * Byte budget for the LRU block cache. Defaults to 8 MB. Set to `0`\n * to disable caching. Raise this (e.g. 32 MB) for apps that play\n * seek-heavy legacy-container media over the network.\n */\n cacheBytes?: number;\n}\n\n/**\n * Result of preparing a libav-readable file from a normalized source.\n * Either an in-memory Blob (created via `mkreadaheadfile`) or a streaming\n * HTTP reader (created via `attachLibavHttpReader`). Callers should\n * `await detach()` when done so resources are cleaned up symmetrically.\n */\nexport interface LibavInputHandle {\n /** The virtual filename libav sees — pass to `ff_init_demuxer_file`. */\n readonly filename: string;\n /** \"blob\" for in-memory, \"http-range\" for streaming URL. */\n readonly transport: \"blob\" | \"http-range\";\n /** Total file size in bytes if known, otherwise undefined. */\n readonly size: number | undefined;\n /** Tear down the virtual file (and any HTTP reader state). */\n detach(): Promise<void>;\n}\n\ninterface LibavLikeWithBlob extends LibavLike {\n mkreadaheadfile(name: string, blob: Blob): Promise<void>;\n}\n\n/**\n * Convenience for the libav-backed strategies. Given a normalized source,\n * either creates an in-memory readahead file (for Blob inputs) or attaches\n * the HTTP block reader (for URL inputs). Returns a handle the caller\n * should detach when done.\n */\nexport async function prepareLibavInput(\n libav: LibavLikeWithBlob,\n filename: string,\n source: import(\"./source.js\").NormalizedSource,\n transport?: import(\"../types.js\").TransportConfig,\n): Promise<LibavInputHandle> {\n if (source.kind === \"url\") {\n const handle = await attachLibavHttpReader(libav, filename, source.url, {\n requestInit: transport?.requestInit,\n fetchFn: transport?.fetchFn,\n cacheBytes: transport?.cacheBytes,\n });\n return {\n filename,\n transport: \"http-range\",\n size: handle.size,\n detach: () => handle.detach(),\n };\n }\n await libav.mkreadaheadfile(filename, source.blob);\n return {\n filename,\n transport: \"blob\",\n size: source.byteLength,\n detach: async () => {\n try { await libav.unlinkreadaheadfile(filename); } catch { /* ignore */ }\n },\n };\n}\n\n/**\n * Attach an HTTP block reader to a libav.js instance. After this resolves,\n * libav can `ff_init_demuxer_file(filename)` and the demuxer will pull\n * bytes via Range requests instead of needing a Blob.\n *\n * Fails fast (before any libav setup) if the server doesn't support\n * Range requests.\n */\nexport async function attachLibavHttpReader(\n libav: LibavLike,\n filename: string,\n url: string,\n options: AttachLibavHttpReaderOptions = {},\n): Promise<LibavHttpReaderHandle> {\n const fetchFn = options.fetchFn ?? fetch;\n\n // 1. Probe the server with a single-byte Range request.\n let probeRes: Response;\n try {\n probeRes = await fetchFn(url, {\n ...options.requestInit,\n headers: {\n ...(options.requestInit?.headers ?? {}),\n Range: \"bytes=0-0\",\n },\n });\n } catch (err) {\n throw new Error(\n `libav HTTP reader: failed to reach ${url}: ${(err as Error).message}`,\n );\n }\n if (probeRes.status !== 206) {\n // 200 means the server ignored Range and would have sent the whole\n // file. We refuse to silently slurp gigabytes.\n throw new Error(\n `libav HTTP reader: ${url} does not support HTTP Range requests ` +\n `(server returned ${probeRes.status} for a Range probe; need 206 Partial Content). ` +\n `Remote AVI/ASF/FLV playback requires a server that honors byte-range requests.`,\n );\n }\n\n // 2. Parse total file size from Content-Range: \"bytes 0-0/12345678\"\n const contentRange = probeRes.headers.get(\"content-range\") ?? \"\";\n const sizeMatch = contentRange.match(/\\/(\\d+)$/);\n if (!sizeMatch) {\n throw new Error(\n `libav HTTP reader: ${url} returned 206 but no parseable Content-Range header (got: \"${contentRange}\")`,\n );\n }\n const size = parseInt(sizeMatch[1], 10);\n if (!Number.isFinite(size) || size <= 0) {\n throw new Error(\n `libav HTTP reader: ${url} reported invalid file size ${size}`,\n );\n }\n\n // Drain the probe body so the connection can be reused.\n try { await probeRes.arrayBuffer(); } catch { /* ignore */ }\n\n // 3. Create the virtual file libav will read from.\n await libav.mkblockreaderdev(filename, size);\n\n // ── State ───────────────────────────────────────────────────────────────\n\n let detached = false;\n // LRU cache of fetched blocks, keyed by start position. Map insertion\n // order = recency. Bounded by `cacheBudget` bytes; evicts oldest-first\n // on overflow. Set budget to 0 to disable caching.\n const cache = new Map<number, Uint8Array>();\n let cacheBytes = 0;\n const cacheBudget = Math.max(0, options.cacheBytes ?? DEFAULT_CACHE_BYTES);\n // The currently in-flight fetch, if any. Used both for serialization\n // (we await this before starting another) and for in-flight dedup.\n let inflight: Promise<void> | null = null;\n\n function clampReadLength(requested: number): number {\n const doubled = requested * 2;\n if (doubled < MIN_READ) return MIN_READ;\n if (doubled > MAX_READ) return MAX_READ;\n return doubled;\n }\n\n /**\n * Look up a cached block that fully covers `[pos, pos+length)`. On hit,\n * promote the block to most-recent and return the slice. On miss, null.\n */\n function cacheLookup(pos: number, length: number): Uint8Array | null {\n for (const [blockPos, bytes] of cache) {\n if (pos >= blockPos && pos + length <= blockPos + bytes.byteLength) {\n cache.delete(blockPos);\n cache.set(blockPos, bytes);\n const offset = pos - blockPos;\n return bytes.subarray(offset, offset + length);\n }\n }\n return null;\n }\n\n /** Insert a fetched block; evict least-recently-used until under budget. */\n function cacheInsert(pos: number, bytes: Uint8Array): void {\n const existing = cache.get(pos);\n if (existing) {\n cacheBytes -= existing.byteLength;\n cache.delete(pos);\n }\n cache.set(pos, bytes);\n cacheBytes += bytes.byteLength;\n while (cacheBytes > cacheBudget && cache.size > 0) {\n const oldestKey = cache.keys().next().value as number | undefined;\n if (oldestKey === undefined) break;\n const oldest = cache.get(oldestKey);\n if (!oldest) break;\n cache.delete(oldestKey);\n cacheBytes -= oldest.byteLength;\n }\n }\n\n /** Fetch one Range and update the cache. */\n async function fetchRange(pos: number, length: number): Promise<Uint8Array> {\n const end = Math.min(pos + length - 1, size - 1);\n const res = await fetchFn(url, {\n ...options.requestInit,\n headers: {\n ...(options.requestInit?.headers ?? {}),\n Range: `bytes=${pos}-${end}`,\n },\n });\n if (res.status !== 206 && res.status !== 200) {\n throw new Error(\n `libav HTTP reader: Range request bytes=${pos}-${end} returned ${res.status}`,\n );\n }\n const buf = new Uint8Array(await res.arrayBuffer());\n cacheInsert(pos, buf);\n return buf;\n }\n\n /**\n * Handle a single libav read request. Serializes against any in-flight\n * read by chaining off `inflight`. Honors `detached` at every async\n * boundary so a torn-down reader never writes back into libav.\n */\n async function handleRead(name: string, pos: number, length: number): Promise<void> {\n // Wait for any preceding read to finish so we don't interleave.\n if (inflight) {\n try { await inflight; } catch { /* ignore — that read's own caller handled it */ }\n }\n if (detached) return;\n\n // Cache hit — reply directly without a network round-trip.\n const hit = cacheLookup(pos, length);\n if (hit) {\n try { await libav.ff_block_reader_dev_send(name, pos, hit); } catch { /* ignore — libav may have torn down */ }\n return;\n }\n\n // Cache miss — fetch via Range. Read-ahead amortizes small reads.\n const fetchLen = clampReadLength(length);\n const fetched = (async () => {\n try {\n const buf = await fetchRange(pos, fetchLen);\n if (detached) return;\n // Slice exactly what libav asked for and send it back.\n const reply = buf.subarray(0, Math.min(length, buf.byteLength));\n try { await libav.ff_block_reader_dev_send(name, pos, reply); } catch { /* ignore */ }\n } catch (err) {\n if (detached) return;\n // Signal EOF + error code to libav so the demuxer surfaces it.\n try {\n await libav.ff_block_reader_dev_send(name, pos, null, {\n error: err,\n });\n } catch { /* ignore */ }\n }\n })();\n inflight = fetched;\n try { await fetched; } finally { if (inflight === fetched) inflight = null; }\n }\n\n // 4. Wire the callback. The signature accepts `(name, pos, length)` and\n // we hand it to handleRead which does all the work asynchronously.\n // Note: libav.js dispatches this synchronously from a worker message,\n // so we kick off handleRead but don't await — the queue inside handleRead\n // serializes things.\n const previousCallback = libav.onblockread;\n libav.onblockread = (name: string, pos: number, length: number) => {\n if (detached || name !== filename) {\n // Forward to any previous callback (e.g. another reader on the same\n // libav instance). This is rare in practice but cheap to support.\n previousCallback?.(name, pos, length);\n return;\n }\n void handleRead(name, pos, length);\n };\n\n return {\n size,\n transport: \"http-range\",\n async detach() {\n if (detached) return;\n detached = true;\n // Restore the previous callback (if any) so we don't break unrelated\n // readers on the same libav instance.\n libav.onblockread = previousCallback;\n // Wait for the last in-flight read to settle so we don't tear down\n // the virtual file while libav is still expecting a response.\n if (inflight) {\n try { await inflight; } catch { /* ignore */ }\n }\n // Drop the cache and unlink the virtual file.\n cache.clear();\n cacheBytes = 0;\n try { await libav.unlinkreadaheadfile(filename); } catch { /* ignore */ }\n },\n };\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { SubtitleResourceBag, discoverSidecars, attachSubtitleTracks, SubtitleOverlay } from './chunk-EDDWAN2L.js';
2
- import { probe, avbridgeVideoToMediabunny, buildMediabunnySourceFromInput, avbridgeAudioToMediabunny } from './chunk-GYIJU44C.js';
2
+ import { probe, avbridgeVideoToMediabunny, buildMediabunnySourceFromInput, avbridgeAudioToMediabunny } from './chunk-2LNXMGT6.js';
3
3
  import { AvbridgeError, ERR_ALL_STRATEGIES_EXHAUSTED, ERR_PLAYER_NOT_READY, ERR_MSE_NOT_SUPPORTED, ERR_MSE_CODEC_NOT_SUPPORTED } from './chunk-CPJLFFCC.js';
4
- import { packetPtsSec, sanitizePacketTimestamp, sanitizeFrameTimestamp, libavFrameToInterleavedFloat32 } from './chunk-2NSOOMXW.js';
4
+ import { packetPtsSec, sanitizePacketTimestamp, sanitizeFrameTimestamp, libavFrameToInterleavedFloat32 } from './chunk-3YKWU4FM.js';
5
5
  import { dbg, loadLibav } from './chunk-5DMTJVIU.js';
6
6
  import { pickLibavVariant } from './chunk-5YAWWKA3.js';
7
7
 
@@ -1610,7 +1610,7 @@ async function startHybridDecoder(opts) {
1610
1610
  const variant = pickLibavVariant(opts.context);
1611
1611
  const libav = await loadLibav(variant);
1612
1612
  const bridge = await loadBridge();
1613
- const { prepareLibavInput } = await import('./libav-http-reader-WXG3Z7AI.js');
1613
+ const { prepareLibavInput } = await import('./libav-http-reader-2S5HAHW4.js');
1614
1614
  const inputHandle = await prepareLibavInput(libav, opts.filename, opts.source, opts.transport);
1615
1615
  const readPkt = await libav.av_packet_alloc();
1616
1616
  const [fmt_ctx, streams] = await libav.ff_init_demuxer_file(opts.filename);
@@ -2280,7 +2280,7 @@ async function startDecoder(opts) {
2280
2280
  const variant = "avbridge";
2281
2281
  const libav = await loadLibav(variant);
2282
2282
  const bridge = await loadBridge2();
2283
- const { prepareLibavInput } = await import('./libav-http-reader-WXG3Z7AI.js');
2283
+ const { prepareLibavInput } = await import('./libav-http-reader-2S5HAHW4.js');
2284
2284
  const inputHandle = await prepareLibavInput(libav, opts.filename, opts.source, opts.transport);
2285
2285
  const readPkt = await libav.av_packet_alloc();
2286
2286
  const [fmt_ctx, streams] = await libav.ff_init_demuxer_file(opts.filename);
@@ -3009,9 +3009,9 @@ var UnifiedPlayer = class _UnifiedPlayer {
3009
3009
  constructor(options, registry) {
3010
3010
  this.options = options;
3011
3011
  this.registry = registry;
3012
- const { requestInit, fetchFn } = options;
3013
- if (requestInit || fetchFn) {
3014
- this.transport = { requestInit, fetchFn };
3012
+ const { requestInit, fetchFn, cacheBytes } = options;
3013
+ if (requestInit || fetchFn || cacheBytes !== void 0) {
3014
+ this.transport = { requestInit, fetchFn, cacheBytes };
3015
3015
  }
3016
3016
  }
3017
3017
  options;
@@ -3543,5 +3543,5 @@ function defaultFallbackChain(strategy) {
3543
3543
  }
3544
3544
 
3545
3545
  export { FALLBACK_AUDIO_CODECS, FALLBACK_VIDEO_CODECS, NATIVE_AUDIO_CODECS, NATIVE_VIDEO_CODECS, UnifiedPlayer, classifyContext, createPlayer };
3546
- //# sourceMappingURL=chunk-IHNHHEA2.js.map
3547
- //# sourceMappingURL=chunk-IHNHHEA2.js.map
3546
+ //# sourceMappingURL=chunk-Z26PXRUY.js.map
3547
+ //# sourceMappingURL=chunk-Z26PXRUY.js.map