avbridge 2.2.1 → 2.5.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 (165) hide show
  1. package/CHANGELOG.md +153 -1
  2. package/NOTICE.md +2 -2
  3. package/README.md +2 -3
  4. package/THIRD_PARTY_LICENSES.md +2 -2
  5. package/dist/avi-2JPBSHGA.js +183 -0
  6. package/dist/avi-2JPBSHGA.js.map +1 -0
  7. package/dist/avi-F6WZJK5T.cjs +185 -0
  8. package/dist/avi-F6WZJK5T.cjs.map +1 -0
  9. package/dist/{avi-GCGM7OJI.js → avi-NJXAXUXK.js} +9 -3
  10. package/dist/avi-NJXAXUXK.js.map +1 -0
  11. package/dist/{avi-6SJLWIWW.cjs → avi-W6L3BTWU.cjs} +10 -4
  12. package/dist/avi-W6L3BTWU.cjs.map +1 -0
  13. package/dist/chunk-2IJ66NTD.cjs +212 -0
  14. package/dist/chunk-2IJ66NTD.cjs.map +1 -0
  15. package/dist/{chunk-ILKDNBSE.js → chunk-2XW2O3YI.cjs} +55 -10
  16. package/dist/chunk-2XW2O3YI.cjs.map +1 -0
  17. package/dist/chunk-5KVLE6YI.js +167 -0
  18. package/dist/chunk-5KVLE6YI.js.map +1 -0
  19. package/dist/chunk-5YAWWKA3.js +18 -0
  20. package/dist/chunk-5YAWWKA3.js.map +1 -0
  21. package/dist/chunk-CPJLFFCC.js +189 -0
  22. package/dist/chunk-CPJLFFCC.js.map +1 -0
  23. package/dist/chunk-CPZ7PXAM.cjs +240 -0
  24. package/dist/chunk-CPZ7PXAM.cjs.map +1 -0
  25. package/dist/{chunk-WD2ZNQA7.js → chunk-DCSOQH2N.js} +7 -4
  26. package/dist/chunk-DCSOQH2N.js.map +1 -0
  27. package/dist/{chunk-HZLQNKFN.cjs → chunk-E76AMWI4.js} +40 -15
  28. package/dist/chunk-E76AMWI4.js.map +1 -0
  29. package/dist/chunk-F3LQJKXK.cjs +20 -0
  30. package/dist/chunk-F3LQJKXK.cjs.map +1 -0
  31. package/dist/chunk-IAYKFGFG.js +200 -0
  32. package/dist/chunk-IAYKFGFG.js.map +1 -0
  33. package/dist/{chunk-DMWARSEF.js → chunk-KY2GPCT7.js} +788 -697
  34. package/dist/chunk-KY2GPCT7.js.map +1 -0
  35. package/dist/chunk-LUFA47FP.js +19 -0
  36. package/dist/chunk-LUFA47FP.js.map +1 -0
  37. package/dist/chunk-NNVOHKXJ.cjs +204 -0
  38. package/dist/chunk-NNVOHKXJ.cjs.map +1 -0
  39. package/dist/chunk-Q2VUO52Z.cjs +374 -0
  40. package/dist/chunk-Q2VUO52Z.cjs.map +1 -0
  41. package/dist/chunk-QDJLQR53.cjs +22 -0
  42. package/dist/chunk-QDJLQR53.cjs.map +1 -0
  43. package/dist/chunk-S4WAZC2T.cjs +173 -0
  44. package/dist/chunk-S4WAZC2T.cjs.map +1 -0
  45. package/dist/chunk-SMH6IOP2.js +368 -0
  46. package/dist/chunk-SMH6IOP2.js.map +1 -0
  47. package/dist/chunk-SR3MPV4D.js +237 -0
  48. package/dist/chunk-SR3MPV4D.js.map +1 -0
  49. package/dist/{chunk-UF2N5L63.cjs → chunk-TBW26OPP.cjs} +800 -710
  50. package/dist/chunk-TBW26OPP.cjs.map +1 -0
  51. package/dist/chunk-X2K3GIWE.js +235 -0
  52. package/dist/chunk-X2K3GIWE.js.map +1 -0
  53. package/dist/{chunk-L4NPOJ36.cjs → chunk-Z33SBWL5.cjs} +7 -4
  54. package/dist/chunk-Z33SBWL5.cjs.map +1 -0
  55. package/dist/chunk-ZCUXHW55.cjs +242 -0
  56. package/dist/chunk-ZCUXHW55.cjs.map +1 -0
  57. package/dist/element-browser.js +1282 -503
  58. package/dist/element-browser.js.map +1 -1
  59. package/dist/element.cjs +59 -5
  60. package/dist/element.cjs.map +1 -1
  61. package/dist/element.d.cts +39 -1
  62. package/dist/element.d.ts +39 -1
  63. package/dist/element.js +58 -4
  64. package/dist/element.js.map +1 -1
  65. package/dist/index.cjs +605 -327
  66. package/dist/index.cjs.map +1 -1
  67. package/dist/index.d.cts +48 -4
  68. package/dist/index.d.ts +48 -4
  69. package/dist/index.js +528 -319
  70. package/dist/index.js.map +1 -1
  71. package/dist/libav-demux-H2GS46GH.cjs +27 -0
  72. package/dist/{libav-http-reader-NQJVY273.js.map → libav-demux-H2GS46GH.cjs.map} +1 -1
  73. package/dist/libav-demux-OWZ4T2YW.js +6 -0
  74. package/dist/{libav-http-reader-FPYDBMYK.cjs.map → libav-demux-OWZ4T2YW.js.map} +1 -1
  75. package/dist/libav-http-reader-AZLE7YFS.cjs +16 -0
  76. package/dist/libav-http-reader-AZLE7YFS.cjs.map +1 -0
  77. package/dist/libav-http-reader-WXG3Z7AI.js +3 -0
  78. package/dist/libav-http-reader-WXG3Z7AI.js.map +1 -0
  79. package/dist/{libav-import-GST2AMPL.cjs → libav-import-2ZVKV2E7.cjs} +2 -2
  80. package/dist/{libav-import-GST2AMPL.cjs.map → libav-import-2ZVKV2E7.cjs.map} +1 -1
  81. package/dist/{libav-import-2JURFHEW.js → libav-import-6MGLCXVQ.js} +2 -2
  82. package/dist/{libav-import-2JURFHEW.js.map → libav-import-6MGLCXVQ.js.map} +1 -1
  83. package/dist/{player-U2NPmFvA.d.cts → player-B6WB74RD.d.cts} +62 -3
  84. package/dist/{player-U2NPmFvA.d.ts → player-B6WB74RD.d.ts} +62 -3
  85. package/dist/player.cjs +5631 -0
  86. package/dist/player.cjs.map +1 -0
  87. package/dist/player.d.cts +699 -0
  88. package/dist/player.d.ts +699 -0
  89. package/dist/player.js +5629 -0
  90. package/dist/player.js.map +1 -0
  91. package/dist/remux-OBSMIENG.cjs +35 -0
  92. package/dist/remux-OBSMIENG.cjs.map +1 -0
  93. package/dist/remux-WBYIZBBX.js +10 -0
  94. package/dist/remux-WBYIZBBX.js.map +1 -0
  95. package/dist/source-4TZ6KMNV.js +4 -0
  96. package/dist/{source-FFZ7TW2B.js.map → source-4TZ6KMNV.js.map} +1 -1
  97. package/dist/source-7YLO6E7X.cjs +29 -0
  98. package/dist/{source-CN43EI7Z.cjs.map → source-7YLO6E7X.cjs.map} +1 -1
  99. package/dist/source-MTX5ELUZ.js +4 -0
  100. package/dist/source-MTX5ELUZ.js.map +1 -0
  101. package/dist/source-VFLXLOCN.cjs +29 -0
  102. package/dist/source-VFLXLOCN.cjs.map +1 -0
  103. package/dist/subtitles-4T74JRGT.js +4 -0
  104. package/dist/subtitles-4T74JRGT.js.map +1 -0
  105. package/dist/subtitles-QUH4LPI4.cjs +29 -0
  106. package/dist/subtitles-QUH4LPI4.cjs.map +1 -0
  107. package/dist/variant-routing-434STYAB.js +3 -0
  108. package/dist/{variant-routing-JOBWXYKD.js.map → variant-routing-434STYAB.js.map} +1 -1
  109. package/dist/variant-routing-HONNAA6R.cjs +12 -0
  110. package/dist/{variant-routing-GOHB2RZN.cjs.map → variant-routing-HONNAA6R.cjs.map} +1 -1
  111. package/package.json +9 -1
  112. package/src/classify/rules.ts +27 -5
  113. package/src/convert/remux.ts +9 -35
  114. package/src/convert/transcode-libav.ts +691 -0
  115. package/src/convert/transcode.ts +53 -12
  116. package/src/element/avbridge-player.ts +861 -0
  117. package/src/element/avbridge-video.ts +54 -0
  118. package/src/element/player-icons.ts +25 -0
  119. package/src/element/player-styles.ts +472 -0
  120. package/src/errors.ts +53 -0
  121. package/src/index.ts +23 -0
  122. package/src/player-element.ts +18 -0
  123. package/src/player.ts +118 -27
  124. package/src/plugins/builtin.ts +2 -2
  125. package/src/probe/avi.ts +4 -0
  126. package/src/probe/index.ts +40 -10
  127. package/src/strategies/fallback/audio-output.ts +31 -0
  128. package/src/strategies/fallback/decoder.ts +179 -175
  129. package/src/strategies/fallback/index.ts +48 -6
  130. package/src/strategies/fallback/libav-import.ts +9 -1
  131. package/src/strategies/fallback/variant-routing.ts +7 -13
  132. package/src/strategies/fallback/video-renderer.ts +231 -32
  133. package/src/strategies/hybrid/decoder.ts +219 -200
  134. package/src/strategies/hybrid/index.ts +48 -7
  135. package/src/strategies/native.ts +6 -3
  136. package/src/strategies/remux/index.ts +14 -2
  137. package/src/strategies/remux/mse.ts +12 -2
  138. package/src/strategies/remux/pipeline.ts +72 -12
  139. package/src/subtitles/index.ts +7 -3
  140. package/src/subtitles/render.ts +8 -0
  141. package/src/types.ts +53 -1
  142. package/src/util/libav-demux.ts +405 -0
  143. package/src/util/libav-http-reader.ts +5 -1
  144. package/src/util/source.ts +28 -8
  145. package/src/util/transport.ts +26 -0
  146. package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.mjs +1 -1
  147. package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.wasm +0 -0
  148. package/dist/avi-6SJLWIWW.cjs.map +0 -1
  149. package/dist/avi-GCGM7OJI.js.map +0 -1
  150. package/dist/chunk-DMWARSEF.js.map +0 -1
  151. package/dist/chunk-HZLQNKFN.cjs.map +0 -1
  152. package/dist/chunk-ILKDNBSE.js.map +0 -1
  153. package/dist/chunk-J5MCMN3S.js +0 -27
  154. package/dist/chunk-J5MCMN3S.js.map +0 -1
  155. package/dist/chunk-L4NPOJ36.cjs.map +0 -1
  156. package/dist/chunk-NZU7W256.cjs +0 -29
  157. package/dist/chunk-NZU7W256.cjs.map +0 -1
  158. package/dist/chunk-UF2N5L63.cjs.map +0 -1
  159. package/dist/chunk-WD2ZNQA7.js.map +0 -1
  160. package/dist/libav-http-reader-FPYDBMYK.cjs +0 -16
  161. package/dist/libav-http-reader-NQJVY273.js +0 -3
  162. package/dist/source-CN43EI7Z.cjs +0 -28
  163. package/dist/source-FFZ7TW2B.js +0 -3
  164. package/dist/variant-routing-GOHB2RZN.cjs +0 -12
  165. package/dist/variant-routing-JOBWXYKD.js +0 -3
@@ -0,0 +1,19 @@
1
+ // src/util/transport.ts
2
+ function mergeFetchInit(base, extra) {
3
+ if (!base && !extra) return void 0;
4
+ return {
5
+ ...base,
6
+ ...extra,
7
+ headers: {
8
+ ...base?.headers ?? {},
9
+ ...extra?.headers ?? {}
10
+ }
11
+ };
12
+ }
13
+ function fetchWith(transport) {
14
+ return transport?.fetchFn ?? globalThis.fetch;
15
+ }
16
+
17
+ export { fetchWith, mergeFetchInit };
18
+ //# sourceMappingURL=chunk-LUFA47FP.js.map
19
+ //# sourceMappingURL=chunk-LUFA47FP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/util/transport.ts"],"names":[],"mappings":";AAOO,SAAS,cAAA,CACd,MACA,KAAA,EACyB;AACzB,EAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,KAAA,EAAO,OAAO,MAAA;AAC5B,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,GAAG,KAAA;AAAA,IACH,OAAA,EAAS;AAAA,MACP,GAAI,IAAA,EAAM,OAAA,IAAiD,EAAC;AAAA,MAC5D,GAAI,KAAA,EAAO,OAAA,IAAiD;AAAC;AAC/D,GACF;AACF;AAGO,SAAS,UAAU,SAAA,EAAsC;AAC9D,EAAA,OAAO,SAAA,EAAW,WAAW,UAAA,CAAW,KAAA;AAC1C","file":"chunk-LUFA47FP.js","sourcesContent":["import type { FetchFn, TransportConfig } from \"../types.js\";\n\n/**\n * Merge two RequestInit objects. Headers are merged (not overwritten) so\n * the caller's auth headers coexist with the player's Range headers.\n * Other fields (credentials, mode, signal, etc.) in `extra` override `base`.\n */\nexport function mergeFetchInit(\n base: RequestInit | undefined,\n extra: RequestInit | undefined,\n): RequestInit | undefined {\n if (!base && !extra) return undefined;\n return {\n ...base,\n ...extra,\n headers: {\n ...(base?.headers as Record<string, string> | undefined ?? {}),\n ...(extra?.headers as Record<string, string> | undefined ?? {}),\n },\n };\n}\n\n/** Return the fetch function from a TransportConfig, falling back to globalThis.fetch. */\nexport function fetchWith(transport?: TransportConfig): FetchFn {\n return transport?.fetchFn ?? globalThis.fetch;\n}\n"]}
@@ -0,0 +1,204 @@
1
+ 'use strict';
2
+
3
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
4
+ // src/util/debug.ts
5
+ function isDebugEnabled() {
6
+ if (typeof globalThis === "undefined") return false;
7
+ const g = globalThis;
8
+ if (g.AVBRIDGE_DEBUG === true) return true;
9
+ if (typeof location !== "undefined" && typeof URLSearchParams !== "undefined") {
10
+ try {
11
+ const p = new URLSearchParams(location.search);
12
+ if (p.has("avbridge_debug")) {
13
+ g.AVBRIDGE_DEBUG = true;
14
+ return true;
15
+ }
16
+ } catch {
17
+ }
18
+ }
19
+ return false;
20
+ }
21
+ function fmt(tag) {
22
+ return `[avbridge:${tag}]`;
23
+ }
24
+ var dbg = {
25
+ /** Verbose — only when debug is enabled. The hot-path normal case. */
26
+ info(tag, ...args) {
27
+ if (isDebugEnabled()) console.info(fmt(tag), ...args);
28
+ },
29
+ /** Warning — only when debug is enabled. Non-fatal oddities. */
30
+ warn(tag, ...args) {
31
+ if (isDebugEnabled()) console.warn(fmt(tag), ...args);
32
+ },
33
+ /**
34
+ * Self-diagnosis warning. **Always** emits regardless of debug flag.
35
+ * Use this only for conditions that mean something is actually wrong
36
+ * or degraded — not for routine chatter.
37
+ */
38
+ diag(tag, ...args) {
39
+ console.warn(fmt(tag), ...args);
40
+ },
41
+ /**
42
+ * Timing helper: wraps an async call and logs its elapsed time when
43
+ * debug is on. The callback runs whether debug is on or off — this is
44
+ * just for the `dbg.info` at the end.
45
+ *
46
+ * Also unconditionally fires `dbg.diag` if the elapsed time exceeds
47
+ * `slowMs`, so "the bootstrap took 8 seconds" shows up even without
48
+ * debug mode enabled.
49
+ */
50
+ async timed(tag, label, slowMs, fn) {
51
+ const start = performance.now();
52
+ try {
53
+ const result = await fn();
54
+ const elapsed = performance.now() - start;
55
+ if (isDebugEnabled()) {
56
+ console.info(fmt(tag), `${label} ${elapsed.toFixed(0)}ms`);
57
+ }
58
+ if (elapsed > slowMs) {
59
+ console.warn(
60
+ fmt(tag),
61
+ `${label} took ${elapsed.toFixed(0)}ms (>${slowMs}ms expected) \u2014 this is unusually slow; possible causes: ${hintForTag(tag)}`
62
+ );
63
+ }
64
+ return result;
65
+ } catch (err) {
66
+ const elapsed = performance.now() - start;
67
+ console.warn(
68
+ fmt(tag),
69
+ `${label} FAILED after ${elapsed.toFixed(0)}ms:`,
70
+ err
71
+ );
72
+ throw err;
73
+ }
74
+ }
75
+ };
76
+ function hintForTag(tag) {
77
+ switch (tag) {
78
+ case "probe":
79
+ return "slow network (range request), large sniff window, or libav cold-start";
80
+ case "libav-load":
81
+ return "large .wasm download, misconfigured AVBRIDGE_LIBAV_BASE, or server-side MIME type";
82
+ case "bootstrap":
83
+ return "probe+classify+strategy-init chain; enable AVBRIDGE_DEBUG for a phase breakdown";
84
+ case "cold-start":
85
+ return "decoder is producing output slower than realtime \u2014 check framesDecoded in getDiagnostics()";
86
+ default:
87
+ return "unknown stage \u2014 enable globalThis.AVBRIDGE_DEBUG for more detail";
88
+ }
89
+ }
90
+
91
+ // src/strategies/fallback/libav-loader.ts
92
+ var cache = /* @__PURE__ */ new Map();
93
+ function cacheKey(variant, threads) {
94
+ return `${variant}:${threads ? "thr" : "wasm"}`;
95
+ }
96
+ function loadLibav(variant = "webcodecs", opts = {}) {
97
+ const env = globalThis;
98
+ const wantThreads = opts.threads !== void 0 ? opts.threads : env.AVBRIDGE_LIBAV_THREADS === true;
99
+ const key = cacheKey(variant, wantThreads);
100
+ let entry = cache.get(key);
101
+ if (!entry) {
102
+ entry = loadVariant(variant, wantThreads);
103
+ cache.set(key, entry);
104
+ }
105
+ return entry;
106
+ }
107
+ async function loadVariant(variant, wantThreads) {
108
+ return dbg.timed(
109
+ "libav-load",
110
+ `load "${variant}" (threads=${wantThreads})`,
111
+ 5e3,
112
+ () => loadVariantInner(variant, wantThreads)
113
+ );
114
+ }
115
+ async function loadVariantInner(variant, wantThreads) {
116
+ const key = cacheKey(variant, wantThreads);
117
+ const base = `${libavBaseUrl()}/${variant}`;
118
+ const variantUrl = `${base}/libav-${variant}.mjs`;
119
+ dbg.info("libav-load", `fetching ${variantUrl}`);
120
+ if (typeof fetch === "function") {
121
+ try {
122
+ const head = await fetch(variantUrl, { method: "GET", headers: { Range: "bytes=0-0" } });
123
+ if (!head.ok && head.status !== 206) {
124
+ throw new Error(
125
+ `HTTP ${head.status} ${head.statusText} \u2014 check that libav files are served at ${base}/ (override via globalThis.AVBRIDGE_LIBAV_BASE)`
126
+ );
127
+ }
128
+ try {
129
+ await head.arrayBuffer();
130
+ } catch {
131
+ }
132
+ } catch (err) {
133
+ cache.delete(key);
134
+ throw chain(
135
+ `libav.js "${variant}" variant not reachable at ${variantUrl}`,
136
+ err
137
+ );
138
+ }
139
+ }
140
+ let mod;
141
+ try {
142
+ const imported = await import(
143
+ /* @vite-ignore */
144
+ variantUrl
145
+ );
146
+ if (!imported || typeof imported.LibAV !== "function") {
147
+ throw new Error(`module at ${variantUrl} did not export LibAV`);
148
+ }
149
+ mod = imported;
150
+ } catch (err) {
151
+ cache.delete(key);
152
+ const hint = variant === "avbridge" ? `The "avbridge" variant is a custom local build. Run \`./scripts/build-libav.sh\` to produce it (requires Emscripten; ~15-30 min the first time).` : `Make sure the variant files are present at ${base}/ (set globalThis.AVBRIDGE_LIBAV_BASE to override the default lookup path).`;
153
+ throw new Error(
154
+ `failed to load libav.js "${variant}" variant from ${variantUrl}. ${hint} Original error: ${err.message || String(err)}`
155
+ );
156
+ }
157
+ try {
158
+ const inst = await mod.LibAV(buildOpts(base, wantThreads));
159
+ await silenceLibavLogs(inst);
160
+ return inst;
161
+ } catch (err) {
162
+ cache.delete(key);
163
+ throw chain(`LibAV() factory failed for "${variant}" variant (threads=${wantThreads})`, err);
164
+ }
165
+ }
166
+ async function silenceLibavLogs(inst) {
167
+ try {
168
+ const setLevel = inst.av_log_set_level;
169
+ if (typeof setLevel === "function") {
170
+ const quiet = inst.AV_LOG_QUIET ?? -8;
171
+ await setLevel(quiet);
172
+ }
173
+ } catch {
174
+ }
175
+ }
176
+ function buildOpts(base, wantThreads) {
177
+ return {
178
+ base,
179
+ nothreads: !wantThreads,
180
+ yesthreads: wantThreads
181
+ };
182
+ }
183
+ function libavBaseUrl() {
184
+ const override = typeof globalThis !== "undefined" ? globalThis.AVBRIDGE_LIBAV_BASE : void 0;
185
+ if (override) return override;
186
+ try {
187
+ return new URL("../vendor/libav", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-NNVOHKXJ.cjs', document.baseURI).href))).href;
188
+ } catch {
189
+ if (typeof location !== "undefined" && location.protocol.startsWith("http")) {
190
+ return `${location.origin}/libav`;
191
+ }
192
+ return "/libav";
193
+ }
194
+ }
195
+ function chain(message, err) {
196
+ const inner = err instanceof Error ? err.message : String(err);
197
+ console.error(`[avbridge] ${message}:`, err);
198
+ return new Error(`${message}: ${inner || "(no message \u2014 see browser console)"}`);
199
+ }
200
+
201
+ exports.dbg = dbg;
202
+ exports.loadLibav = loadLibav;
203
+ //# sourceMappingURL=chunk-NNVOHKXJ.cjs.map
204
+ //# sourceMappingURL=chunk-NNVOHKXJ.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/util/debug.ts","../src/strategies/fallback/libav-loader.ts"],"names":[],"mappings":"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","file":"chunk-NNVOHKXJ.cjs","sourcesContent":["/**\n * Debug + self-diagnosis helper.\n *\n * avbridge has a lot of async stages (probe → classify → libav load →\n * strategy.execute → decoder pump → cold-start gate → first paint) and\n * when something's slow or wrong the symptom — \"it hangs\", \"it stutters\",\n * \"it plays audio without video\" — is usually nowhere near the actual\n * cause. This module gives us two things:\n *\n * 1. **Gated verbose logging.** `dbg.info(tag, ...)` etc. are no-ops\n * unless the consumer sets `globalThis.AVBRIDGE_DEBUG = true` (or\n * uses the matching `?avbridge_debug` URL search param at dev time).\n * When enabled, every log is prefixed with `[avbridge:<tag>]` so the\n * console is filterable.\n *\n * 2. **Unconditional self-diagnosis.** `dbg.warnIf(cond, tag, ...)`\n * always fires when a suspicious condition is detected, even with\n * debug off. These are the things we *know* mean something is\n * broken or degraded and the user would want to know about — e.g.\n * the cold-start gate timing out, the decoder running slower than\n * realtime, a libav variant taking longer to load than any network\n * should take, >20% of packets getting rejected.\n *\n * The guiding principle: **if a symptom caused more than 10 minutes of\n * human debugging once, add a targeted warning so the next instance\n * self-identifies in the console.** This module is where those\n * warnings live.\n */\n\n/** Read the debug flag fresh on every call so it's runtime-toggleable. */\nfunction isDebugEnabled(): boolean {\n if (typeof globalThis === \"undefined\") return false;\n const g = globalThis as { AVBRIDGE_DEBUG?: unknown };\n if (g.AVBRIDGE_DEBUG === true) return true;\n // Convenience: if running in a browser with a `?avbridge_debug` search\n // param, flip the flag on automatically. Useful for demos and quick\n // user reproduction without editing code.\n if (typeof location !== \"undefined\" && typeof URLSearchParams !== \"undefined\") {\n try {\n const p = new URLSearchParams(location.search);\n if (p.has(\"avbridge_debug\")) {\n g.AVBRIDGE_DEBUG = true;\n return true;\n }\n } catch { /* ignore */ }\n }\n return false;\n}\n\nfunction fmt(tag: string): string {\n return `[avbridge:${tag}]`;\n}\n\n/* eslint-disable no-console */\n\nexport const dbg = {\n /** Verbose — only when debug is enabled. The hot-path normal case. */\n info(tag: string, ...args: unknown[]): void {\n if (isDebugEnabled()) console.info(fmt(tag), ...args);\n },\n\n /** Warning — only when debug is enabled. Non-fatal oddities. */\n warn(tag: string, ...args: unknown[]): void {\n if (isDebugEnabled()) console.warn(fmt(tag), ...args);\n },\n\n /**\n * Self-diagnosis warning. **Always** emits regardless of debug flag.\n * Use this only for conditions that mean something is actually wrong\n * or degraded — not for routine chatter.\n */\n diag(tag: string, ...args: unknown[]): void {\n console.warn(fmt(tag), ...args);\n },\n\n /**\n * Timing helper: wraps an async call and logs its elapsed time when\n * debug is on. The callback runs whether debug is on or off — this is\n * just for the `dbg.info` at the end.\n *\n * Also unconditionally fires `dbg.diag` if the elapsed time exceeds\n * `slowMs`, so \"the bootstrap took 8 seconds\" shows up even without\n * debug mode enabled.\n */\n async timed<T>(\n tag: string,\n label: string,\n slowMs: number,\n fn: () => Promise<T>,\n ): Promise<T> {\n const start = performance.now();\n try {\n const result = await fn();\n const elapsed = performance.now() - start;\n if (isDebugEnabled()) {\n console.info(fmt(tag), `${label} ${elapsed.toFixed(0)}ms`);\n }\n if (elapsed > slowMs) {\n console.warn(\n fmt(tag),\n `${label} took ${elapsed.toFixed(0)}ms (>${slowMs}ms expected) — ` +\n `this is unusually slow; possible causes: ${hintForTag(tag)}`,\n );\n }\n return result;\n } catch (err) {\n const elapsed = performance.now() - start;\n console.warn(\n fmt(tag),\n `${label} FAILED after ${elapsed.toFixed(0)}ms:`,\n err,\n );\n throw err;\n }\n },\n};\n\nfunction hintForTag(tag: string): string {\n switch (tag) {\n case \"probe\":\n return \"slow network (range request), large sniff window, or libav cold-start\";\n case \"libav-load\":\n return \"large .wasm download, misconfigured AVBRIDGE_LIBAV_BASE, or server-side MIME type\";\n case \"bootstrap\":\n return \"probe+classify+strategy-init chain; enable AVBRIDGE_DEBUG for a phase breakdown\";\n case \"cold-start\":\n return \"decoder is producing output slower than realtime — check framesDecoded in getDiagnostics()\";\n default:\n return \"unknown stage — enable globalThis.AVBRIDGE_DEBUG for more detail\";\n }\n}\n","/**\n * Lazy libav.js loader supporting multiple variants.\n *\n * avbridge recognises three libav variants:\n *\n * - **webcodecs** — npm `@libav.js/variant-webcodecs`, ~5 MB. Modern formats\n * only (mp4/mkv/webm/ogg/wav/...) — designed to bridge to WebCodecs.\n *\n * - **default** — npm `@libav.js/variant-default`, ~12 MB. Audio-only build\n * (Opus, FLAC, WAV) despite the name. Useful for audio fallback.\n *\n * - **avbridge** — a custom build produced by `scripts/build-libav.sh` and\n * landing in `vendor/libav/`. Includes the AVI/ASF/FLV/MKV demuxers plus\n * the legacy decoders (WMV3, MPEG-4 Part 2, MS-MPEG4 v1/2/3, VC-1, MPEG-1/2,\n * AC-3/E-AC-3, WMAv1/v2/Pro). This is the only variant that can read AVI;\n * the npm variants are intentionally minimal and ship none of the legacy\n * demuxers.\n *\n * Variant resolution always goes through a runtime URL + `/* @vite-ignore *\\/`\n * dynamic import. Static imports trigger Vite's optimized-deps pipeline,\n * which rewrites `import.meta.url` away from the real `dist/` directory and\n * breaks libav's sibling-binary loading.\n */\n\nimport { dbg } from \"../../util/debug.js\";\n\nexport type LibavVariant = \"webcodecs\" | \"default\" | \"avbridge\";\n\nexport interface LoadLibavOptions {\n /**\n * Force threading on/off for this load. If unspecified, defaults to\n * \"true if `crossOriginIsolated`, otherwise false\". Some libav.js code\n * paths (notably the cross-thread reader-device protocol used during\n * `avformat_find_stream_info` for AVI) are unreliable in threaded mode,\n * so probing forces this to `false` while decode keeps it default.\n */\n threads?: boolean;\n}\n\n// Cache key includes both variant and threading mode so probe and decode\n// can run different libav instances of the same variant.\nconst cache: Map<string, Promise<LibavInstance>> = new Map();\n\nfunction cacheKey(variant: LibavVariant, threads: boolean): string {\n return `${variant}:${threads ? \"thr\" : \"wasm\"}`;\n}\n\n/**\n * Load (and cache) a libav.js variant. Pass `\"webcodecs\"` for the small\n * default; pass `\"default\"` for the audio fallback; pass `\"avbridge\"` for the\n * custom build that supports AVI/WMV/legacy codecs.\n */\nexport function loadLibav(\n variant: LibavVariant = \"webcodecs\",\n opts: LoadLibavOptions = {},\n): Promise<LibavInstance> {\n // Threading is OFF by default. The threaded libav.js variant is too\n // fragile in practice for our usage:\n // - Probe (`avformat_find_stream_info` for AVI) throws an `undefined`\n // exception out of `ff_init_demuxer_file`, apparently due to the\n // cross-thread reader-device protocol racing with the main thread.\n // - Decode hits a `TypeError: Cannot read properties of undefined\n // (reading 'apply')` inside libav.js's own worker message handler\n // within seconds of starting — a bug in libav.js's threaded message\n // dispatch that we can't fix from outside.\n //\n // Performance work for the fallback strategy needs to come from elsewhere\n // (WASM SIMD, OffscreenCanvas, larger decode batches) instead of libav's\n // pthreads. Threading can still be force-enabled with\n // `globalThis.AVBRIDGE_LIBAV_THREADS = true` for testing if libav.js fixes\n // those bugs in a future release.\n const env = globalThis as { AVBRIDGE_LIBAV_THREADS?: boolean };\n const wantThreads =\n opts.threads !== undefined\n ? opts.threads\n : env.AVBRIDGE_LIBAV_THREADS === true;\n\n const key = cacheKey(variant, wantThreads);\n let entry = cache.get(key);\n if (!entry) {\n entry = loadVariant(variant, wantThreads);\n cache.set(key, entry);\n }\n return entry;\n}\n\nasync function loadVariant(\n variant: LibavVariant,\n wantThreads: boolean,\n): Promise<LibavInstance> {\n return dbg.timed(\"libav-load\", `load \"${variant}\" (threads=${wantThreads})`, 5000, () =>\n loadVariantInner(variant, wantThreads),\n );\n}\n\nasync function loadVariantInner(\n variant: LibavVariant,\n wantThreads: boolean,\n): Promise<LibavInstance> {\n const key = cacheKey(variant, wantThreads);\n const base = `${libavBaseUrl()}/${variant}`;\n // The custom variant is named `libav-avbridge.mjs`; the npm variants follow\n // the same convention (`libav-webcodecs.mjs`, `libav-default.mjs`).\n const variantUrl = `${base}/libav-${variant}.mjs`;\n dbg.info(\"libav-load\", `fetching ${variantUrl}`);\n\n // Preflight HEAD-ish check: issue a bytes=0-0 range request so a missing\n // file fails fast with a clear error instead of hanging deep inside the\n // dynamic import or inside libav's own WASM instantiation. Surfaces the\n // most common mistake (\"libav base path is wrong\") in <100 ms instead of\n // an indeterminate stall.\n if (typeof fetch === \"function\") {\n try {\n const head = await fetch(variantUrl, { method: \"GET\", headers: { Range: \"bytes=0-0\" } });\n if (!head.ok && head.status !== 206) {\n throw new Error(\n `HTTP ${head.status} ${head.statusText} — check that libav files are served ` +\n `at ${base}/ (override via globalThis.AVBRIDGE_LIBAV_BASE)`,\n );\n }\n // Drain the tiny response so the connection can be reused.\n try { await head.arrayBuffer(); } catch { /* ignore */ }\n } catch (err) {\n cache.delete(key);\n throw chain(\n `libav.js \"${variant}\" variant not reachable at ${variantUrl}`,\n err,\n );\n }\n }\n\n let mod: LoadedVariant;\n try {\n // @ts-ignore runtime URL\n const imported: unknown = await import(/* @vite-ignore */ variantUrl);\n if (!imported || typeof (imported as { LibAV?: unknown }).LibAV !== \"function\") {\n throw new Error(`module at ${variantUrl} did not export LibAV`);\n }\n mod = imported as LoadedVariant;\n } catch (err) {\n cache.delete(key);\n const hint =\n variant === \"avbridge\"\n ? `The \"avbridge\" variant is a custom local build. Run \\`./scripts/build-libav.sh\\` ` +\n `to produce it (requires Emscripten; ~15-30 min the first time).`\n : `Make sure the variant files are present at ${base}/ (set ` +\n `globalThis.AVBRIDGE_LIBAV_BASE to override the default lookup path).`;\n throw new Error(\n `failed to load libav.js \"${variant}\" variant from ${variantUrl}. ${hint} ` +\n `Original error: ${(err as Error).message || String(err)}`,\n );\n }\n\n try {\n const inst = (await mod.LibAV(buildOpts(base, wantThreads))) as LibavInstance;\n await silenceLibavLogs(inst);\n return inst;\n } catch (err) {\n cache.delete(key);\n throw chain(`LibAV() factory failed for \"${variant}\" variant (threads=${wantThreads})`, err);\n }\n}\n\n/**\n * Lower libav's internal log level so the console doesn't get flooded with\n * `[mp3 @ ...] Header missing` and `Video uses a non-standard and wasteful\n * way to store B-frames` warnings on every legacy file. We still get any\n * actual JS-level errors via the normal Error path; this only affects\n * libav's own ffmpeg log channel.\n *\n * AV_LOG_QUIET = -8 (no output at all). If you want to keep fatal errors,\n * use AV_LOG_FATAL = 8 instead.\n */\nasync function silenceLibavLogs(inst: LibavInstance): Promise<void> {\n try {\n const setLevel = (inst as { av_log_set_level?: (n: number) => Promise<void> })\n .av_log_set_level;\n if (typeof setLevel === \"function\") {\n const quiet = (inst as { AV_LOG_QUIET?: number }).AV_LOG_QUIET ?? -8;\n await setLevel(quiet);\n }\n } catch {\n /* not fatal — verbose logs are noise, not an error */\n }\n}\n\nfunction buildOpts(base: string, wantThreads: boolean): Record<string, unknown> {\n // The wantThreads decision is made by `loadLibav()` so callers (probe,\n // decoder) can override per-load. Decode wants pthreads for speed; probe\n // forces them off because libav.js's cross-thread reader-device protocol\n // is unreliable mid-`avformat_find_stream_info` for some AVI files.\n return {\n base,\n nothreads: !wantThreads,\n yesthreads: wantThreads,\n };\n}\n\nfunction libavBaseUrl(): string {\n // Consumer override — the documented \"LGPL replaceability\" hook.\n // Setting `globalThis.AVBRIDGE_LIBAV_BASE = \"/my/path\"` lets anyone swap\n // in a different libav build (custom fragments, security patches, etc.)\n // without rebuilding avbridge.\n const override =\n typeof globalThis !== \"undefined\"\n ? (globalThis as { AVBRIDGE_LIBAV_BASE?: string }).AVBRIDGE_LIBAV_BASE\n : undefined;\n if (override) return override;\n\n // Default: resolve relative to this module's URL. When avbridge is installed\n // under `node_modules/avbridge/`, this module lives at `dist/chunk-*.js` (or\n // `dist/element-browser.js` for the browser entry) and `../vendor/libav`\n // resolves to `node_modules/avbridge/vendor/libav`, where the build step\n // vendored every variant's binaries. That's the zero-config path.\n //\n // `import.meta.url` throws in some synthetic environments (CJS tests, some\n // SSR evaluators). If it fails, fall back to the legacy `/libav` path so\n // consumers who relied on the pre-2.1 behavior still work.\n try {\n return new URL(\"../vendor/libav\", import.meta.url).href;\n } catch {\n if (typeof location !== \"undefined\" && location.protocol.startsWith(\"http\")) {\n return `${location.origin}/libav`;\n }\n return \"/libav\";\n }\n}\n\nfunction chain(message: string, err: unknown): Error {\n const inner = err instanceof Error ? err.message : String(err);\n // eslint-disable-next-line no-console\n console.error(`[avbridge] ${message}:`, err);\n return new Error(`${message}: ${inner || \"(no message — see browser console)\"}`);\n}\n\ninterface LoadedVariant {\n LibAV: (opts?: Record<string, unknown>) => Promise<Record<string, unknown>>;\n}\n\n/** Loose structural type — the AVI probe and the fallback decoder add fields. */\nexport type LibavInstance = Record<string, unknown> & {\n mkreadaheadfile(name: string, blob: Blob): Promise<void>;\n unlinkreadaheadfile(name: string): Promise<void>;\n};\n"]}
@@ -0,0 +1,374 @@
1
+ 'use strict';
2
+
3
+ var chunkZCUXHW55_cjs = require('./chunk-ZCUXHW55.cjs');
4
+ var chunk2IJ66NTD_cjs = require('./chunk-2IJ66NTD.cjs');
5
+ var chunkCPZ7PXAM_cjs = require('./chunk-CPZ7PXAM.cjs');
6
+ var chunkZ33SBWL5_cjs = require('./chunk-Z33SBWL5.cjs');
7
+
8
+ function isAnnexB(bytes) {
9
+ if (bytes.length < 3) return false;
10
+ if (bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 1) return true;
11
+ if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 0 && bytes[3] === 1) return true;
12
+ return false;
13
+ }
14
+ function* iterateAnnexBNalus(bytes) {
15
+ const length = bytes.length;
16
+ let i = 0;
17
+ let nalStart = -1;
18
+ while (i < length) {
19
+ let scLen = 0;
20
+ if (i + 3 < length && bytes[i] === 0 && bytes[i + 1] === 0 && bytes[i + 2] === 0 && bytes[i + 3] === 1) {
21
+ scLen = 4;
22
+ } else if (i + 2 < length && bytes[i] === 0 && bytes[i + 1] === 0 && bytes[i + 2] === 1) {
23
+ scLen = 3;
24
+ }
25
+ if (scLen > 0) {
26
+ if (nalStart >= 0) {
27
+ yield bytes.subarray(nalStart, i);
28
+ }
29
+ nalStart = i + scLen;
30
+ i += scLen;
31
+ } else {
32
+ i += 1;
33
+ }
34
+ }
35
+ if (nalStart >= 0 && nalStart < length) {
36
+ yield bytes.subarray(nalStart, length);
37
+ }
38
+ }
39
+ function annexBToAvcc(annexB) {
40
+ const nalus = [];
41
+ let total = 0;
42
+ for (const nal of iterateAnnexBNalus(annexB)) {
43
+ nalus.push(nal);
44
+ total += 4 + nal.length;
45
+ }
46
+ const out = new Uint8Array(total);
47
+ let off = 0;
48
+ for (const nal of nalus) {
49
+ const len = nal.length;
50
+ out[off++] = len >>> 24 & 255;
51
+ out[off++] = len >>> 16 & 255;
52
+ out[off++] = len >>> 8 & 255;
53
+ out[off++] = len & 255;
54
+ out.set(nal, off);
55
+ off += len;
56
+ }
57
+ return out;
58
+ }
59
+
60
+ // src/convert/remux.ts
61
+ var MEDIABUNNY_CONTAINERS = /* @__PURE__ */ new Set([
62
+ "mp4",
63
+ "mov",
64
+ "mkv",
65
+ "webm",
66
+ "ogg",
67
+ "wav",
68
+ "mp3",
69
+ "flac",
70
+ "adts"
71
+ ]);
72
+ async function remux(source, options = {}) {
73
+ const outputFormat = options.outputFormat ?? "mp4";
74
+ options.signal?.throwIfAborted();
75
+ const ctx = await chunkZCUXHW55_cjs.probe(source);
76
+ options.signal?.throwIfAborted();
77
+ validateRemuxEligibility(ctx, options.strict ?? false);
78
+ if (MEDIABUNNY_CONTAINERS.has(ctx.container)) {
79
+ return remuxViaMediAbunny(ctx, outputFormat, options);
80
+ }
81
+ return remuxViaLibav(ctx, outputFormat, options);
82
+ }
83
+ function validateRemuxEligibility(ctx, strict) {
84
+ const video = ctx.videoTracks[0];
85
+ const audio = ctx.audioTracks[0];
86
+ if (video) {
87
+ const mbCodec = chunkZCUXHW55_cjs.avbridgeVideoToMediabunny(video.codec);
88
+ if (!mbCodec) {
89
+ throw new Error(
90
+ `Cannot remux: video codec "${video.codec}" is not supported for remuxing. Use transcode() to re-encode to a modern codec.`
91
+ );
92
+ }
93
+ }
94
+ if (audio) {
95
+ const mbCodec = chunkZCUXHW55_cjs.avbridgeAudioToMediabunny(audio.codec);
96
+ if (!mbCodec) {
97
+ throw new Error(
98
+ `Cannot remux: audio codec "${audio.codec}" is not supported for remuxing. Use transcode() to re-encode to a modern codec.`
99
+ );
100
+ }
101
+ }
102
+ if (strict && video?.codec === "h264" && audio?.codec === "mp3") {
103
+ throw new Error(
104
+ `Cannot remux in strict mode: H.264 + MP3 is a best-effort combination that may produce playback issues in some browsers. Set strict: false to allow, or use transcode() to re-encode audio to AAC.`
105
+ );
106
+ }
107
+ if (!video && !audio) {
108
+ throw new Error("Cannot remux: source has no video or audio tracks.");
109
+ }
110
+ }
111
+ async function remuxViaMediAbunny(ctx, outputFormat, options) {
112
+ const mb = await import('mediabunny');
113
+ const input = new mb.Input({
114
+ source: await chunkZCUXHW55_cjs.buildMediabunnySourceFromInput(mb, ctx.source),
115
+ formats: mb.ALL_FORMATS
116
+ });
117
+ const target = new mb.BufferTarget();
118
+ const output = new mb.Output({
119
+ format: createOutputFormat(mb, outputFormat),
120
+ target
121
+ });
122
+ const conversion = await mb.Conversion.init({
123
+ input,
124
+ output,
125
+ showWarnings: false
126
+ });
127
+ if (!conversion.isValid) {
128
+ const reasons = conversion.discardedTracks.map((d) => `${d.track.type} track discarded: ${d.reason}`).join("; ");
129
+ throw new Error(`Cannot remux: mediabunny rejected the conversion. ${reasons}`);
130
+ }
131
+ if (options.onProgress) {
132
+ const onProgress = options.onProgress;
133
+ conversion.onProgress = (p) => {
134
+ onProgress({ percent: p * 100, bytesWritten: 0 });
135
+ };
136
+ }
137
+ let abortHandler;
138
+ if (options.signal) {
139
+ options.signal.throwIfAborted();
140
+ abortHandler = () => void conversion.cancel();
141
+ options.signal.addEventListener("abort", abortHandler, { once: true });
142
+ }
143
+ try {
144
+ await conversion.execute();
145
+ } finally {
146
+ if (abortHandler && options.signal) {
147
+ options.signal.removeEventListener("abort", abortHandler);
148
+ }
149
+ }
150
+ if (!target.buffer) {
151
+ throw new Error("Remux failed: mediabunny produced no output buffer.");
152
+ }
153
+ const mimeType = mimeForFormat(outputFormat);
154
+ const blob = new Blob([target.buffer], { type: mimeType });
155
+ const filename = generateFilename(ctx.name, outputFormat);
156
+ options.onProgress?.({ percent: 100, bytesWritten: blob.size });
157
+ return {
158
+ blob,
159
+ mimeType,
160
+ container: outputFormat,
161
+ videoCodec: ctx.videoTracks[0]?.codec,
162
+ audioCodec: ctx.audioTracks[0]?.codec,
163
+ duration: ctx.duration,
164
+ filename
165
+ };
166
+ }
167
+ async function remuxViaLibav(ctx, outputFormat, options) {
168
+ let loadLibav;
169
+ let pickLibavVariant;
170
+ try {
171
+ const loader = await import('./libav-loader-IV4AJ2HW.cjs');
172
+ const routing = await import('./variant-routing-HONNAA6R.cjs');
173
+ loadLibav = loader.loadLibav;
174
+ pickLibavVariant = routing.pickLibavVariant;
175
+ } catch {
176
+ throw new Error(
177
+ `Cannot remux ${ctx.container.toUpperCase()} source: libav.js is not available. Install @libav.js/variant-webcodecs and libavjs-webcodecs-bridge, or build the custom avbridge variant with scripts/build-libav.sh.`
178
+ );
179
+ }
180
+ const variant = pickLibavVariant(ctx);
181
+ const libav = await loadLibav(variant);
182
+ const normalized = await chunk2IJ66NTD_cjs.normalizeSource(ctx.source);
183
+ const filename = ctx.name ?? `remux-input-${Date.now()}`;
184
+ const handle = await chunkZ33SBWL5_cjs.prepareLibavInput(libav, filename, normalized);
185
+ try {
186
+ return await doLibavRemux(libav, filename, ctx, outputFormat, options);
187
+ } finally {
188
+ await handle.detach().catch(() => {
189
+ });
190
+ }
191
+ }
192
+ async function doLibavRemux(libav, filename, ctx, outputFormat, options) {
193
+ const mb = await import('mediabunny');
194
+ const readPkt = await libav.av_packet_alloc();
195
+ const [fmt_ctx, streams] = await libav.ff_init_demuxer_file(filename);
196
+ const videoStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_VIDEO) ?? null;
197
+ const audioStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO) ?? null;
198
+ const videoTrackInfo = ctx.videoTracks[0];
199
+ const audioTrackInfo = ctx.audioTracks[0];
200
+ const mbVideoCodec = videoTrackInfo ? chunkZCUXHW55_cjs.avbridgeVideoToMediabunny(videoTrackInfo.codec) : null;
201
+ const mbAudioCodec = audioTrackInfo ? chunkZCUXHW55_cjs.avbridgeAudioToMediabunny(audioTrackInfo.codec) : null;
202
+ const target = new mb.BufferTarget();
203
+ const output = new mb.Output({
204
+ format: createOutputFormat(mb, outputFormat),
205
+ target
206
+ });
207
+ let videoSource = null;
208
+ let audioSource = null;
209
+ if (mbVideoCodec && videoStream) {
210
+ videoSource = new mb.EncodedVideoPacketSource(mbVideoCodec);
211
+ output.addVideoTrack(videoSource);
212
+ }
213
+ if (mbAudioCodec && audioStream) {
214
+ audioSource = new mb.EncodedAudioPacketSource(mbAudioCodec);
215
+ output.addAudioTrack(audioSource);
216
+ }
217
+ await output.start();
218
+ const videoFps = videoTrackInfo?.fps && videoTrackInfo.fps > 0 ? videoTrackInfo.fps : 30;
219
+ const videoFrameStepUs = Math.max(1, Math.round(1e6 / videoFps));
220
+ let syntheticVideoUs = 0;
221
+ let syntheticAudioUs = 0;
222
+ const videoTimeBase = videoStream?.time_base_num && videoStream?.time_base_den ? [videoStream.time_base_num, videoStream.time_base_den] : void 0;
223
+ const audioTimeBase = audioStream?.time_base_num && audioStream?.time_base_den ? [audioStream.time_base_num, audioStream.time_base_den] : void 0;
224
+ let totalPackets = 0;
225
+ const durationUs = ctx.duration ? ctx.duration * 1e6 : 0;
226
+ let firstVideoMeta = true;
227
+ let firstAudioMeta = true;
228
+ while (true) {
229
+ options.signal?.throwIfAborted();
230
+ let readErr;
231
+ let packets;
232
+ try {
233
+ [readErr, packets] = await libav.ff_read_frame_multi(fmt_ctx, readPkt, {
234
+ limit: 64 * 1024
235
+ });
236
+ } catch (err) {
237
+ throw new Error(`libav demux failed: ${err.message}`);
238
+ }
239
+ const videoPackets = videoStream ? packets[videoStream.index] ?? [] : [];
240
+ const audioPackets = audioStream ? packets[audioStream.index] ?? [] : [];
241
+ if (videoSource) {
242
+ for (const pkt of videoPackets) {
243
+ chunkCPZ7PXAM_cjs.sanitizePacketTimestamp(pkt, () => {
244
+ const ts = syntheticVideoUs;
245
+ syntheticVideoUs += videoFrameStepUs;
246
+ return ts;
247
+ }, videoTimeBase);
248
+ if (videoTrackInfo && (videoTrackInfo.codec === "h264" || videoTrackInfo.codec === "h265") && isAnnexB(pkt.data)) {
249
+ pkt.data = annexBToAvcc(pkt.data);
250
+ }
251
+ const mbPacket = libavPacketToMediAbunny(mb, pkt);
252
+ await videoSource.add(
253
+ mbPacket,
254
+ firstVideoMeta ? { decoderConfig: buildVideoDecoderConfig(videoTrackInfo) } : void 0
255
+ );
256
+ firstVideoMeta = false;
257
+ }
258
+ }
259
+ if (audioSource) {
260
+ for (const pkt of audioPackets) {
261
+ chunkCPZ7PXAM_cjs.sanitizePacketTimestamp(pkt, () => {
262
+ const ts = syntheticAudioUs;
263
+ const sampleRate = audioTrackInfo?.sampleRate ?? 44100;
264
+ syntheticAudioUs += Math.round(1024 * 1e6 / sampleRate);
265
+ return ts;
266
+ }, audioTimeBase);
267
+ const mbPacket = libavPacketToMediAbunny(mb, pkt);
268
+ await audioSource.add(
269
+ mbPacket,
270
+ firstAudioMeta ? { decoderConfig: buildAudioDecoderConfig(audioTrackInfo) } : void 0
271
+ );
272
+ firstAudioMeta = false;
273
+ }
274
+ }
275
+ totalPackets += videoPackets.length + audioPackets.length;
276
+ if (options.onProgress && durationUs > 0) {
277
+ const lastVideoTs = videoPackets.length > 0 ? videoPackets[videoPackets.length - 1].pts ?? 0 : 0;
278
+ const lastAudioTs = audioPackets.length > 0 ? audioPackets[audioPackets.length - 1].pts ?? 0 : 0;
279
+ const currentUs = Math.max(lastVideoTs, lastAudioTs);
280
+ const percent = Math.min(99, currentUs / durationUs * 100);
281
+ options.onProgress({ percent, bytesWritten: 0 });
282
+ }
283
+ if (readErr === libav.AVERROR_EOF) break;
284
+ if (readErr && readErr !== 0 && readErr !== -libav.EAGAIN) {
285
+ console.warn("[avbridge] remux: ff_read_frame_multi returned", readErr);
286
+ break;
287
+ }
288
+ }
289
+ await output.finalize();
290
+ try {
291
+ await libav.av_packet_free?.(readPkt);
292
+ } catch {
293
+ }
294
+ try {
295
+ await libav.avformat_close_input_js(fmt_ctx);
296
+ } catch {
297
+ }
298
+ if (!target.buffer) {
299
+ throw new Error("Remux failed: mediabunny produced no output buffer.");
300
+ }
301
+ const mimeType = mimeForFormat(outputFormat);
302
+ const blob = new Blob([target.buffer], { type: mimeType });
303
+ const outputFilename = generateFilename(ctx.name, outputFormat);
304
+ options.onProgress?.({ percent: 100, bytesWritten: blob.size });
305
+ return {
306
+ blob,
307
+ mimeType,
308
+ container: outputFormat,
309
+ videoCodec: videoTrackInfo?.codec,
310
+ audioCodec: audioTrackInfo?.codec,
311
+ duration: ctx.duration,
312
+ filename: outputFilename
313
+ };
314
+ }
315
+ function createOutputFormat(mb, format) {
316
+ switch (format) {
317
+ case "mp4":
318
+ return new mb.Mp4OutputFormat({ fastStart: "in-memory" });
319
+ case "webm":
320
+ return new mb.WebMOutputFormat();
321
+ case "mkv":
322
+ return new mb.MkvOutputFormat();
323
+ default:
324
+ return new mb.Mp4OutputFormat({ fastStart: "in-memory" });
325
+ }
326
+ }
327
+ function mimeForFormat(format) {
328
+ switch (format) {
329
+ case "mp4":
330
+ return "video/mp4";
331
+ case "webm":
332
+ return "video/webm";
333
+ case "mkv":
334
+ return "video/x-matroska";
335
+ default:
336
+ return "application/octet-stream";
337
+ }
338
+ }
339
+ function generateFilename(originalName, format) {
340
+ const ext = format === "mkv" ? "mkv" : format;
341
+ if (!originalName) return `output.${ext}`;
342
+ const base = originalName.replace(/\.[^.]+$/, "");
343
+ return `${base}.${ext}`;
344
+ }
345
+ var _seqCounter = 0;
346
+ function libavPacketToMediAbunny(mb, pkt) {
347
+ const KEY_FRAME_FLAG = 1;
348
+ const timestampSec = (pkt.pts ?? 0) / 1e6;
349
+ const durationSec = (pkt.duration ?? 0) / 1e6;
350
+ const type = pkt.flags & KEY_FRAME_FLAG ? "key" : "delta";
351
+ return new mb.EncodedPacket(pkt.data, type, timestampSec, durationSec, _seqCounter++);
352
+ }
353
+ function buildVideoDecoderConfig(track) {
354
+ return {
355
+ codec: track.codecString ?? track.codec,
356
+ codedWidth: track.width,
357
+ codedHeight: track.height
358
+ };
359
+ }
360
+ function buildAudioDecoderConfig(track) {
361
+ return {
362
+ codec: track.codecString ?? track.codec,
363
+ numberOfChannels: track.channels,
364
+ sampleRate: track.sampleRate
365
+ };
366
+ }
367
+
368
+ exports.createOutputFormat = createOutputFormat;
369
+ exports.generateFilename = generateFilename;
370
+ exports.mimeForFormat = mimeForFormat;
371
+ exports.remux = remux;
372
+ exports.validateRemuxEligibility = validateRemuxEligibility;
373
+ //# sourceMappingURL=chunk-Q2VUO52Z.cjs.map
374
+ //# sourceMappingURL=chunk-Q2VUO52Z.cjs.map