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 @@
1
+ {"version":3,"sources":["../src/util/codec-strings.ts","../src/classify/rules.ts","../src/events.ts","../src/diagnostics.ts","../src/plugins/registry.ts","../src/strategies/native.ts","../src/strategies/remux/mse.ts","../src/strategies/remux/pipeline.ts","../src/strategies/remux/index.ts","../src/strategies/fallback/video-renderer.ts","../src/strategies/fallback/audio-output.ts","../src/strategies/hybrid/decoder.ts","../src/strategies/hybrid/index.ts","../src/strategies/fallback/decoder.ts","../src/strategies/fallback/index.ts","../src/plugins/builtin.ts","../src/player.ts"],"names":["AvbridgeError","ERR_MSE_NOT_SUPPORTED","ERR_MSE_CODEC_NOT_SUPPORTED","avbridgeVideoToMediabunny","buildMediabunnySourceFromInput","avbridgeAudioToMediabunny","SubtitleOverlay","wallNow","frame","drain","pickLibavVariant","loadLibav","dbg","sanitizePacketTimestamp","frames","sanitizeFrameTimestamp","samples","libavFrameToInterleavedFloat32","loadBridge","READY_AUDIO_BUFFER_SECONDS","READY_TIMEOUT_SECONDS","SubtitleResourceBag","probe","discoverSidecars","attachSubtitleTracks","ERR_ALL_STRATEGIES_EXHAUSTED","ERR_PLAYER_NOT_READY"],"mappings":"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","file":"chunk-TBW26OPP.cjs","sourcesContent":["import type { AudioTrackInfo, VideoTrackInfo } from \"../types.js\";\n\n/**\n * Build an RFC 6381 codec string for use with `MediaSource.isTypeSupported`\n * and `<source type=...>`. Returns null when we don't have enough info to\n * compose one — callers should treat that as \"ask the browser at runtime via\n * a different channel\" rather than guessing.\n */\nexport function videoCodecString(track: VideoTrackInfo): string | null {\n if (track.codecString) return track.codecString;\n switch (track.codec) {\n case \"h264\": {\n // avc1.PPCCLL — profile (1B), constraint (1B), level (1B). Default to\n // High Profile @ 4.0 if we don't know — common on real-world content.\n const profileHex = profileToHex(track.profile) ?? \"64\"; // 0x64 = High\n const constraint = \"00\";\n const level = ((track.level ?? 40) & 0xff).toString(16).padStart(2, \"0\");\n return `avc1.${profileHex}${constraint}${level}`;\n }\n case \"h265\":\n // Default Main Profile @ Level 4.1 (0x5d = 93) — `hvc1.1.6.L93.B0`.\n return \"hvc1.1.6.L93.B0\";\n case \"vp8\":\n return \"vp8\";\n case \"vp9\":\n return \"vp09.00.10.08\";\n case \"av1\":\n return \"av01.0.04M.08\";\n default:\n return null;\n }\n}\n\nfunction profileToHex(profile?: string): string | null {\n if (!profile) return null;\n const p = profile.toLowerCase();\n if (p.includes(\"baseline\")) return \"42\";\n if (p.includes(\"main\")) return \"4d\";\n if (p.includes(\"high 10\")) return \"6e\";\n if (p.includes(\"high 4:2:2\")) return \"7a\";\n if (p.includes(\"high 4:4:4\")) return \"f4\";\n if (p.includes(\"high\")) return \"64\";\n return null;\n}\n\nexport function audioCodecString(track: AudioTrackInfo): string | null {\n if (track.codecString) return track.codecString;\n switch (track.codec) {\n case \"aac\":\n return \"mp4a.40.2\"; // AAC-LC\n case \"mp3\":\n return \"mp4a.40.34\";\n case \"opus\":\n return \"opus\";\n case \"vorbis\":\n return \"vorbis\";\n case \"flac\":\n return \"flac\";\n default:\n return null;\n }\n}\n\n/**\n * Compose a `video/mp4; codecs=\"...\"` MIME for MSE. Returns null if either\n * codec string can't be produced — caller should fall back to remux refusal.\n */\nexport function mp4MimeFor(video: VideoTrackInfo, audio?: AudioTrackInfo): string | null {\n const v = videoCodecString(video);\n if (!v) return null;\n const codecs = audio ? `${v},${audioCodecString(audio) ?? \"\"}`.replace(/,$/, \"\") : v;\n return `video/mp4; codecs=\"${codecs}\"`;\n}\n\n/**\n * Wrap `MediaSource.isTypeSupported` so it returns false (instead of throwing)\n * in environments without MSE — e.g. jsdom under vitest.\n */\nexport function mseSupports(mime: string): boolean {\n if (typeof MediaSource === \"undefined\") return false;\n try {\n return MediaSource.isTypeSupported(mime);\n } catch {\n return false;\n }\n}\n","import type {\n AudioCodec,\n AudioTrackInfo,\n Classification,\n ContainerKind,\n MediaContext,\n VideoCodec,\n VideoTrackInfo,\n} from \"../types.js\";\nimport { mp4MimeFor, mseSupports } from \"../util/codec-strings.js\";\n\n/**\n * Codecs we know `<video>` and MSE support across modern desktop + Android.\n * The decision to remux instead of decode hinges on this list.\n */\n/** Codecs the browser can decode natively (also the set WebCodecs can transcode). */\nexport const NATIVE_VIDEO_CODECS = new Set<VideoCodec>([\"h264\", \"h265\", \"vp8\", \"vp9\", \"av1\"]);\nexport const NATIVE_AUDIO_CODECS = new Set<AudioCodec>([\n \"aac\",\n \"mp3\",\n \"opus\",\n \"vorbis\",\n \"flac\",\n]);\n\n/**\n * Codecs no major browser plays, period. These force the WASM fallback.\n */\nexport const FALLBACK_VIDEO_CODECS = new Set<VideoCodec>([\n \"wmv3\", \"vc1\", \"mpeg4\",\n \"rv10\", \"rv20\", \"rv30\", \"rv40\",\n \"mpeg2\", \"mpeg1\", \"theora\",\n]);\nexport const FALLBACK_AUDIO_CODECS = new Set<AudioCodec>([\n \"wmav2\", \"wmapro\", \"ac3\", \"eac3\",\n \"cook\", \"ra_144\", \"ra_288\", \"sipr\", \"atrac3\",\n \"dts\", \"truehd\",\n]);\n\n/**\n * Containers `<video>` plays directly. Anything else with otherwise-supported\n * codecs is a remux candidate — IF mediabunny can read the container.\n */\nconst NATIVE_CONTAINERS = new Set<ContainerKind>([\n \"mp4\",\n \"mov\",\n \"webm\",\n \"ogg\",\n \"wav\",\n \"mp3\",\n \"flac\",\n \"adts\",\n]);\n\n/**\n * Containers mediabunny can demux. The remux strategy feeds the source through\n * mediabunny → fMP4 → MSE, so the source container must be one mediabunny\n * understands. AVI, ASF, FLV are NOT in this set — mediabunny rejects them\n * with \"unsupported or unrecognizable format\". Files in those containers with\n * otherwise-native codecs (e.g. AVI + H.264 + MP3) must go to the fallback\n * strategy even though the *codecs* are browser-supported.\n *\n * MPEG-TS is in this set: mediabunny demuxes it natively, but browsers\n * cannot play `<video src=\"*.ts\">` directly (MPEG-TS is HLS-only), so even\n * a TS file with H.264 + AAC has to go through the remux path.\n */\nconst REMUXABLE_CONTAINERS = new Set<ContainerKind>([\n \"mp4\",\n \"mov\",\n \"mkv\",\n \"webm\",\n \"ogg\",\n \"wav\",\n \"mp3\",\n \"flac\",\n \"adts\",\n \"mpegts\",\n]);\n\n/**\n * Pure classification — no I/O, no async. Test-friendly.\n */\nexport function classifyContext(ctx: MediaContext): Classification {\n const video = ctx.videoTracks[0];\n const audio = ctx.audioTracks[0];\n\n // Audio-only files: mediabunny handles all the common ones natively.\n if (!video) {\n if (NATIVE_CONTAINERS.has(ctx.container) && (!audio || NATIVE_AUDIO_CODECS.has(audio.codec))) {\n return {\n class: \"NATIVE\",\n strategy: \"native\",\n reason: `audio-only ${ctx.container} with native codec`,\n };\n }\n if (audio && FALLBACK_AUDIO_CODECS.has(audio.codec)) {\n return {\n class: \"FALLBACK_REQUIRED\",\n strategy: \"fallback\",\n reason: `audio codec \"${audio.codec}\" requires WASM decode`,\n };\n }\n if (REMUXABLE_CONTAINERS.has(ctx.container)) {\n return {\n class: \"REMUX_CANDIDATE\",\n strategy: \"remux\",\n reason: `audio-only file in non-native container \"${ctx.container}\"`,\n };\n }\n return {\n class: \"FALLBACK_REQUIRED\",\n strategy: \"fallback\",\n reason: `audio-only file in \"${ctx.container}\" (not remuxable by mediabunny)`,\n };\n }\n\n // Video paths.\n if (FALLBACK_VIDEO_CODECS.has(video.codec)) {\n return {\n class: \"FALLBACK_REQUIRED\",\n strategy: \"fallback\",\n reason: `video codec \"${video.codec}\" has no browser decoder; WASM fallback required`,\n };\n }\n // Audio codec needs WASM decode — either it's in the known fallback set\n // or it's unrecognized (\"unknown\" / not in native set). Unknown codecs\n // definitely can't play natively, so they get the same treatment.\n const audioNeedsFallback = audio && (\n FALLBACK_AUDIO_CODECS.has(audio.codec) ||\n !NATIVE_AUDIO_CODECS.has(audio.codec)\n );\n if (audioNeedsFallback) {\n // If the VIDEO codec is native, prefer hybrid (WebCodecs hardware video\n // decode + libav software audio decode) over full WASM fallback. This is\n // critical for Blu-ray MKVs: H.264 1080p in WASM is unwatchably slow,\n // but WebCodecs decodes it at full speed while libav handles the DTS/AC3\n // audio in software.\n if (NATIVE_VIDEO_CODECS.has(video.codec) && webCodecsAvailable()) {\n return {\n class: \"HYBRID_CANDIDATE\",\n strategy: \"hybrid\",\n reason: `video \"${video.codec}\" is hardware-decodable via WebCodecs; audio \"${audio.codec}\" decoded in software by libav`,\n fallbackChain: [\"fallback\"],\n };\n }\n return {\n class: \"FALLBACK_REQUIRED\",\n strategy: \"fallback\",\n reason: `audio codec \"${audio.codec}\" has no browser decoder; WASM fallback required`,\n };\n }\n\n if (!NATIVE_VIDEO_CODECS.has(video.codec)) {\n return {\n class: \"FALLBACK_REQUIRED\",\n strategy: \"fallback\",\n reason: `unknown video codec \"${video.codec}\", routing to fallback`,\n };\n }\n\n // Codecs are native. Now decide between NATIVE and REMUX based on the\n // container and codec quirks.\n const isNativeContainer = NATIVE_CONTAINERS.has(ctx.container);\n\n if (isNativeContainer && isSafeNativeCombo(video, audio)) {\n // Confirm with the browser when we have access to MediaSource.\n const mime = mp4MimeFor(video, audio);\n if (mime && mseSupports(mime)) {\n return {\n class: \"NATIVE\",\n strategy: \"native\",\n reason: `${ctx.container} + ${video.codec}${audio ? \"/\" + audio.codec : \"\"} plays natively`,\n };\n }\n if (mime == null || typeof MediaSource === \"undefined\") {\n // No MSE in this environment (e.g. tests) — trust the heuristic.\n return {\n class: \"NATIVE\",\n strategy: \"native\",\n reason: `${ctx.container} + ${video.codec}${audio ? \"/\" + audio.codec : \"\"} (heuristic native)`,\n };\n }\n }\n\n if (isNativeContainer && isRiskyNative(video)) {\n return {\n class: \"RISKY_NATIVE\",\n strategy: \"native\",\n reason: `${video.codec} ${video.profile ?? \"\"} ${video.bitDepth ?? 8}-bit may stutter on mobile; will escalate to remux on stall`,\n fallbackChain: [\"remux\", \"hybrid\", \"fallback\"],\n };\n }\n\n // Codecs are native but the container isn't. Can we remux?\n // Remuxing goes through mediabunny, which only supports certain containers.\n // AVI/ASF/FLV are NOT in that set — mediabunny rejects them at Input().\n if (REMUXABLE_CONTAINERS.has(ctx.container)) {\n return {\n class: \"REMUX_CANDIDATE\",\n strategy: \"remux\",\n reason: `${ctx.container} container with native-supported codecs — remux to fragmented MP4 for reliable playback`,\n };\n }\n\n // Container is unreadable by mediabunny (AVI, ASF, FLV, etc.) but codecs\n // are browser-supported. Use the hybrid strategy (libav demux + WebCodecs\n // hardware decode) when WebCodecs is available; otherwise full WASM decode.\n if (webCodecsAvailable()) {\n return {\n class: \"HYBRID_CANDIDATE\",\n strategy: \"hybrid\",\n reason: `${ctx.container} container requires libav demux; codecs (${video.codec}${audio ? \"/\" + audio.codec : \"\"}) are hardware-decodable via WebCodecs`,\n fallbackChain: [\"fallback\"],\n };\n }\n return {\n class: \"FALLBACK_REQUIRED\",\n strategy: \"fallback\",\n reason: `${ctx.container} container cannot be remuxed by mediabunny; falling back to WASM decode (${video.codec}${audio ? \"/\" + audio.codec : \"\"})`,\n };\n}\n\nfunction webCodecsAvailable(): boolean {\n return typeof globalThis.VideoDecoder !== \"undefined\";\n}\n\nfunction isSafeNativeCombo(video: VideoTrackInfo, audio?: AudioTrackInfo): boolean {\n if (video.codec === \"h264\") {\n // 8-bit yuv420p H.264 is the safe combo. Hi10P / 4:2:2 / 4:4:4 are not.\n if (video.bitDepth && video.bitDepth > 8) return false;\n if (video.pixelFormat && !/yuv420p$/.test(video.pixelFormat)) return false;\n }\n if (audio && !NATIVE_AUDIO_CODECS.has(audio.codec)) return false;\n return true;\n}\n\nfunction isRiskyNative(video: VideoTrackInfo): boolean {\n if (video.bitDepth && video.bitDepth > 8) return true;\n if (video.pixelFormat && /yuv4(2[24]|44)/.test(video.pixelFormat)) return true;\n if (video.width > 3840 || video.height > 2160) return true;\n if (video.fps && video.fps > 60) return true;\n return false;\n}\n","/**\n * Tiny strongly-typed event emitter. We avoid pulling in eventemitter3 / mitt\n * because we only need a handful of methods and want zero deps.\n *\n * Supports \"sticky\" events via {@link TypedEmitter.emitSticky}: the last value\n * for that event is remembered, and any future `on()` subscriber receives it\n * immediately. This is the right pattern for one-shot state-snapshot events\n * like \"strategy chosen\" or \"player ready\" — callers that subscribe after the\n * event has already fired still need to react to it.\n */\n\nexport type Listener<T> = (payload: T) => void;\n\nexport class TypedEmitter<EventMap> {\n private listeners: { [K in keyof EventMap]?: Set<Listener<EventMap[K]>> } = {};\n private sticky: { [K in keyof EventMap]?: EventMap[K] } = {};\n\n on<K extends keyof EventMap>(event: K, fn: Listener<EventMap[K]>): () => void {\n let set = this.listeners[event];\n if (!set) {\n set = new Set();\n this.listeners[event] = set;\n }\n set.add(fn);\n\n // Replay any sticky value that's already been emitted for this event.\n if (Object.prototype.hasOwnProperty.call(this.sticky, event)) {\n try {\n fn(this.sticky[event] as EventMap[K]);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(\"[avbridge] listener threw replaying sticky value:\", err);\n }\n }\n\n return () => this.off(event, fn);\n }\n\n off<K extends keyof EventMap>(event: K, fn: Listener<EventMap[K]>): void {\n this.listeners[event]?.delete(fn);\n }\n\n emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n const set = this.listeners[event];\n if (!set) return;\n // Snapshot so listeners can unsubscribe themselves.\n for (const fn of [...set]) {\n try {\n fn(payload);\n } catch (err) {\n // Don't let one bad listener break the others.\n // eslint-disable-next-line no-console\n console.error(\"[avbridge] listener threw:\", err);\n }\n }\n }\n\n /**\n * Like {@link emit} but also remembers the value so future subscribers\n * receive it on `on()`. Use for one-shot state-snapshot events.\n */\n emitSticky<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n this.sticky[event] = payload;\n this.emit(event, payload);\n }\n\n removeAll(): void {\n this.listeners = {};\n this.sticky = {};\n }\n}\n","import type {\n Classification,\n DiagnosticsSnapshot,\n MediaContext,\n StrategyName,\n} from \"./types.js\";\n\n/**\n * Accumulates diagnostic info as the player walks probe → classify → play.\n * `snapshot()` produces an immutable view shaped exactly like the example in\n * design doc §12.\n */\nexport class Diagnostics {\n private container: DiagnosticsSnapshot[\"container\"] = \"unknown\";\n private videoCodec?: DiagnosticsSnapshot[\"videoCodec\"];\n private audioCodec?: DiagnosticsSnapshot[\"audioCodec\"];\n private width?: number;\n private height?: number;\n private fps?: number;\n private duration?: number;\n private strategy: DiagnosticsSnapshot[\"strategy\"] = \"pending\";\n private strategyClass: DiagnosticsSnapshot[\"strategyClass\"] = \"pending\";\n private reason = \"\";\n private probedBy?: DiagnosticsSnapshot[\"probedBy\"];\n private sourceType?: DiagnosticsSnapshot[\"sourceType\"];\n private transport?: DiagnosticsSnapshot[\"transport\"];\n private rangeSupported?: DiagnosticsSnapshot[\"rangeSupported\"];\n private runtime: Record<string, unknown> = {};\n private lastError?: Error;\n private strategyHistory: Array<{ strategy: StrategyName; reason: string; at: number }> = [];\n\n recordProbe(ctx: MediaContext): void {\n this.container = ctx.container;\n this.probedBy = ctx.probedBy;\n this.duration = ctx.duration;\n const v = ctx.videoTracks[0];\n if (v) {\n this.videoCodec = v.codec;\n this.width = v.width;\n this.height = v.height;\n this.fps = v.fps;\n }\n const a = ctx.audioTracks[0];\n if (a) this.audioCodec = a.codec;\n // Source-type detection. For blob inputs we know the transport with\n // certainty. For URL inputs we know the *intended* transport but not\n // whether the server actually honors Range — that's confirmed later by\n // the strategy that fetches the bytes (via {@link recordTransport}).\n const src = ctx.source;\n if (typeof src === \"string\" || src instanceof URL) {\n this.sourceType = \"url\";\n this.transport = \"http-range\";\n // Intentionally NOT setting rangeSupported here. Inferring \"true\" from\n // input type was misleading: native/remux URL paths rely on the\n // browser's or mediabunny's own Range handling and don't fail-fast on\n // a non-supporting server. Strategies that prove Range support call\n // recordTransport() once they have a confirmed answer.\n this.rangeSupported = undefined;\n } else {\n this.sourceType = \"blob\";\n this.transport = \"memory\";\n this.rangeSupported = false;\n }\n }\n\n /**\n * Called by a strategy once it has a confirmed answer about how the\n * source bytes are actually flowing (e.g. after the libav HTTP block\n * reader's initial Range probe succeeded). Lets diagnostics report the\n * truth instead of an input-type heuristic.\n */\n recordTransport(\n transport: NonNullable<DiagnosticsSnapshot[\"transport\"]>,\n rangeSupported: boolean,\n ): void {\n this.transport = transport;\n this.rangeSupported = rangeSupported;\n }\n\n recordClassification(c: Classification): void {\n this.strategy = c.strategy;\n this.strategyClass = c.class;\n this.reason = c.reason;\n }\n\n recordRuntime(stats: Record<string, unknown>): void {\n // Strategies can surface confirmed transport info in their runtime\n // stats under the well-known `_transport` / `_rangeSupported` keys.\n // When present, they're hoisted to the typed fields via\n // recordTransport() and stripped from the generic runtime bag so they\n // don't duplicate.\n const {\n _transport,\n _rangeSupported,\n ...rest\n } = stats as Record<string, unknown> & {\n _transport?: NonNullable<DiagnosticsSnapshot[\"transport\"]>;\n _rangeSupported?: boolean;\n };\n if (_transport != null && typeof _rangeSupported === \"boolean\") {\n this.recordTransport(_transport, _rangeSupported);\n }\n this.runtime = { ...this.runtime, ...rest };\n }\n\n recordStrategySwitch(strategy: StrategyName, reason: string): void {\n this.strategy = strategy;\n this.reason = reason;\n this.strategyHistory.push({ strategy, reason, at: Date.now() });\n }\n\n recordError(err: Error): void {\n this.lastError = err;\n }\n\n snapshot(): DiagnosticsSnapshot {\n const snap: DiagnosticsSnapshot = {\n container: this.container,\n videoCodec: this.videoCodec,\n audioCodec: this.audioCodec,\n width: this.width,\n height: this.height,\n fps: this.fps,\n duration: this.duration,\n strategy: this.strategy,\n strategyClass: this.strategyClass,\n reason: this.reason,\n probedBy: this.probedBy,\n sourceType: this.sourceType,\n transport: this.transport,\n rangeSupported: this.rangeSupported,\n runtime: { ...this.runtime, ...(this.lastError ? { error: this.lastError.message } : {}) },\n strategyHistory: this.strategyHistory.length > 0 ? [...this.strategyHistory] : undefined,\n };\n return Object.freeze(snap);\n }\n}\n","import type { MediaContext, Plugin, StrategyName } from \"../types.js\";\n\n/**\n * Plugin registry. Built-in strategies are registered as plugins so that\n * user-supplied plugins can preempt them. The registry is consulted twice:\n * once by the player layer to find a plugin matching the picked strategy, and\n * (optionally) by classification to ask plugins what they support.\n */\nexport class PluginRegistry {\n private plugins: Plugin[] = [];\n\n register(plugin: Plugin, prepend = false): void {\n if (prepend) this.plugins.unshift(plugin);\n else this.plugins.push(plugin);\n }\n\n all(): readonly Plugin[] {\n return this.plugins;\n }\n\n /**\n * Find the first plugin that claims this context AND its name matches the\n * strategy. Built-in strategy plugins are named exactly `\"native\"`,\n * `\"remux\"`, `\"fallback\"`.\n */\n findFor(context: MediaContext, strategy: StrategyName): Plugin | null {\n for (const p of this.plugins) {\n if (p.name === strategy && p.canHandle(context)) return p;\n }\n return null;\n }\n}\n","import type { MediaContext, PlaybackSession } from \"../types.js\";\n\n/**\n * Simplest strategy: hand the source to the browser. Works for any\n * MP4/WebM/MP3/etc. that the user agent already plays.\n *\n * The only complexity is that the source might be a `File`/`Blob` (use\n * `URL.createObjectURL`), an `ArrayBuffer`/`Uint8Array` (wrap in a Blob first),\n * or a string URL (assign directly).\n */\nexport async function createNativeSession(\n context: MediaContext,\n video: HTMLVideoElement,\n): Promise<PlaybackSession> {\n const { url, revoke } = sourceToVideoUrl(context.source);\n video.src = url;\n\n // Wait for metadata so the player resolves only once playback is actually\n // ready. We expose errors via the player's \"error\" event, not by throwing\n // here, because failure here often means we should escalate to remux.\n await new Promise<void>((resolve, reject) => {\n const onMeta = () => {\n cleanup();\n resolve();\n };\n const onError = () => {\n cleanup();\n reject(new Error(`<video> failed to load: ${video.error?.message ?? \"unknown\"}`));\n };\n const cleanup = () => {\n video.removeEventListener(\"loadedmetadata\", onMeta);\n video.removeEventListener(\"error\", onError);\n };\n video.addEventListener(\"loadedmetadata\", onMeta);\n video.addEventListener(\"error\", onError);\n });\n\n let stats = { framesDecoded: 0, framesDropped: 0 };\n\n return {\n strategy: \"native\",\n async play() {\n await video.play();\n },\n pause() {\n video.pause();\n },\n async seek(time) {\n video.currentTime = time;\n },\n async setAudioTrack(id) {\n // HTMLMediaElement.audioTracks isn't exposed on all browsers (Chrome\n // needs the MediaCapabilities flag for many containers). Best-effort:\n // try by string id match first, then by index. If the list doesn't\n // exist, silently no-op — the user will still hear whatever track the\n // browser picked by default.\n const tracks = (video as unknown as { audioTracks?: { length: number; [i: number]: { id: string; enabled: boolean } } }).audioTracks;\n if (!tracks || tracks.length === 0) return;\n for (let i = 0; i < tracks.length; i++) {\n tracks[i].enabled = tracks[i].id === String(id) || i === id;\n }\n },\n async setSubtitleTrack(id) {\n const tracks = video.textTracks;\n for (let i = 0; i < tracks.length; i++) {\n tracks[i].mode = i === id ? \"showing\" : \"disabled\";\n }\n },\n async destroy() {\n video.pause();\n video.removeAttribute(\"src\");\n video.load();\n revoke?.();\n },\n getCurrentTime() {\n return video.currentTime || 0;\n },\n getRuntimeStats() {\n // getVideoPlaybackQuality is the standard hook; not all UAs implement it.\n const q = (video as unknown as { getVideoPlaybackQuality?: () => VideoPlaybackQuality }).getVideoPlaybackQuality?.();\n if (q) {\n stats = {\n framesDecoded: q.totalVideoFrames,\n framesDropped: q.droppedVideoFrames,\n };\n }\n return { ...stats, decoderType: \"native\" };\n },\n };\n}\n\nfunction sourceToVideoUrl(source: unknown): { url: string; revoke?: () => void } {\n if (source instanceof Blob) {\n const url = URL.createObjectURL(source);\n return { url, revoke: () => URL.revokeObjectURL(url) };\n }\n if (source instanceof ArrayBuffer || source instanceof Uint8Array) {\n const blob = new Blob([source as BlobPart]);\n const url = URL.createObjectURL(blob);\n return { url, revoke: () => URL.revokeObjectURL(url) };\n }\n if (typeof source === \"string\") return { url: source };\n if (source instanceof URL) return { url: source.toString() };\n throw new TypeError(\"native strategy: unsupported source type\");\n}\n\ninterface VideoPlaybackQuality {\n totalVideoFrames: number;\n droppedVideoFrames: number;\n}\n","/**\n * MediaSource Extensions plumbing. Wraps a `MediaSource` + single\n * `SourceBuffer` with an append queue that respects `updateend` backpressure.\n */\n\nimport { AvbridgeError, ERR_MSE_NOT_SUPPORTED, ERR_MSE_CODEC_NOT_SUPPORTED } from \"../../errors.js\";\n\nexport interface MseSinkOptions {\n mime: string;\n video: HTMLVideoElement;\n /** Called once the MediaSource is open and ready for appends. */\n onReady?: () => void;\n}\n\nexport class MseSink {\n private mediaSource: MediaSource;\n private sourceBuffer: SourceBuffer | null = null;\n private queue: ArrayBuffer[] = [];\n private endOfStreamCalled = false;\n private destroyed = false;\n private readyPromise: Promise<void>;\n private resolveReady!: () => void;\n private rejectReady!: (err: Error) => void;\n private objectUrl: string;\n\n constructor(private readonly options: MseSinkOptions) {\n if (typeof MediaSource === \"undefined\") {\n throw new AvbridgeError(\n ERR_MSE_NOT_SUPPORTED,\n \"MediaSource Extensions (MSE) are not supported in this environment.\",\n \"MSE is required for the remux strategy. Use a browser that supports MSE, or try the fallback strategy.\",\n );\n }\n if (!MediaSource.isTypeSupported(options.mime)) {\n throw new AvbridgeError(\n ERR_MSE_CODEC_NOT_SUPPORTED,\n `This browser's MSE does not support \"${options.mime}\".`,\n \"The codec combination can't be played via remux in this browser. The player will try the next strategy automatically.\",\n );\n }\n\n this.mediaSource = new MediaSource();\n this.objectUrl = URL.createObjectURL(this.mediaSource);\n options.video.src = this.objectUrl;\n\n this.readyPromise = new Promise((resolve, reject) => {\n this.resolveReady = resolve;\n this.rejectReady = reject;\n });\n\n this.mediaSource.addEventListener(\"sourceopen\", () => {\n try {\n this.sourceBuffer = this.mediaSource.addSourceBuffer(options.mime);\n this.sourceBuffer.mode = \"segments\";\n this.sourceBuffer.addEventListener(\"updateend\", () => this.pump());\n this.resolveReady();\n options.onReady?.();\n } catch (err) {\n this.rejectReady(err instanceof Error ? err : new Error(String(err)));\n }\n });\n }\n\n ready(): Promise<void> {\n return this.readyPromise;\n }\n\n /** Queue a chunk of fMP4 bytes (init segment or media segment). */\n append(chunk: ArrayBuffer | Uint8Array): void {\n if (this.destroyed) return;\n const ab = chunk instanceof Uint8Array\n ? (chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength) as ArrayBuffer)\n : chunk;\n this.queue.push(ab);\n this.pump();\n }\n\n private pump(): void {\n const sb = this.sourceBuffer;\n if (!sb || sb.updating) return;\n\n // Apply deferred actions once the SourceBuffer has any data. Deferred\n // seek and deferred autoplay are independent — both can fire here, or\n // either alone. Setting `currentTime` before data exists causes the\n // browser to snap back to the nearest buffered range; calling `play()`\n // before data exists puts the video into a stuck waiting state.\n if (sb.buffered.length > 0) {\n if (this.pendingSeekTime !== null) {\n this.options.video.currentTime = this.pendingSeekTime;\n this.pendingSeekTime = null;\n } else if (!this.hasSnappedToFirstBuffered) {\n // First data arrival with no pending seek. If currentTime is\n // outside the first buffered range (typical for MPEG-TS sources\n // whose PTS doesn't start at 0), snap into the buffered range\n // so the video element doesn't wait forever for nonexistent data.\n const v = this.options.video;\n const firstStart = sb.buffered.start(0);\n const firstEnd = sb.buffered.end(0);\n if (v.currentTime < firstStart || v.currentTime > firstEnd) {\n v.currentTime = firstStart;\n }\n this.hasSnappedToFirstBuffered = true;\n }\n if (this.playOnSeek) {\n this.playOnSeek = false;\n this.options.video.play().catch(() => { /* ignore — autoplay may be blocked */ });\n }\n }\n\n const next = this.queue.shift();\n if (!next) return;\n try {\n sb.appendBuffer(next);\n } catch (err) {\n // QuotaExceededError → evict the oldest few seconds and retry once.\n if ((err as DOMException).name === \"QuotaExceededError\") {\n this.evict();\n try {\n sb.appendBuffer(next);\n return;\n } catch {\n /* fall through to error */\n }\n }\n this.rejectReady(err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n private evict(): void {\n const sb = this.sourceBuffer;\n if (!sb || sb.buffered.length === 0) return;\n const start = sb.buffered.start(0);\n const current = this.options.video.currentTime;\n // Drop everything that's at least 10s behind the current position.\n if (current - start > 10) {\n try {\n sb.remove(start, current - 10);\n } catch {\n /* ignore */\n }\n }\n }\n\n /** Indicate the source is finished. Future seeks past the end will fail. */\n endOfStream(): void {\n if (this.endOfStreamCalled || this.destroyed) return;\n this.endOfStreamCalled = true;\n const tryEnd = () => {\n if (this.queue.length > 0 || this.sourceBuffer?.updating) {\n // Wait for the queue to drain.\n this.sourceBuffer?.addEventListener(\"updateend\", tryEnd, { once: true });\n return;\n }\n try {\n if (this.mediaSource.readyState === \"open\") {\n this.mediaSource.endOfStream();\n }\n } catch {\n /* ignore */\n }\n };\n tryEnd();\n }\n\n /** Seconds of media buffered ahead of the current playback position. */\n bufferedAhead(): number {\n const sb = this.sourceBuffer;\n if (!sb || sb.buffered.length === 0) return 0;\n const current = this.options.video.currentTime;\n for (let i = 0; i < sb.buffered.length; i++) {\n if (sb.buffered.start(i) <= current && sb.buffered.end(i) > current) {\n return sb.buffered.end(i) - current;\n }\n }\n return 0;\n }\n\n /** Total seconds of media buffered across all ranges. */\n totalBuffered(): number {\n const sb = this.sourceBuffer;\n if (!sb || sb.buffered.length === 0) return 0;\n let total = 0;\n for (let i = 0; i < sb.buffered.length; i++) {\n total += sb.buffered.end(i) - sb.buffered.start(i);\n }\n return total;\n }\n\n /** Number of chunks waiting in the append queue. */\n queueLength(): number {\n return this.queue.length;\n }\n\n /** Time to seek to once the SourceBuffer has data at this position. */\n private pendingSeekTime: number | null = null;\n /** Whether to resume playback after the deferred seek completes. */\n private playOnSeek = false;\n /**\n * On the very first data arrival, if `currentTime` falls outside the first\n * buffered range, snap it to the start of that range. MPEG-TS sources\n * commonly start their PTS at a non-zero value (e.g. ~1.5s); without this\n * snap, the video element sits at `currentTime=0` waiting forever for\n * data that doesn't exist.\n */\n private hasSnappedToFirstBuffered = false;\n\n /** Request that playback resumes automatically once the deferred seek fires. */\n setPlayOnSeek(play: boolean): void {\n this.playOnSeek = play;\n }\n\n /**\n * Discard all buffered media and schedule a deferred seek. The actual\n * `video.currentTime` assignment happens in `pump()` once the SourceBuffer\n * has data at the target position — setting it earlier causes the browser\n * to snap back to the nearest buffered range.\n */\n invalidate(seekTime: number): void {\n const sb = this.sourceBuffer;\n // Clear the pending queue — stale fragments from the old pump position.\n this.queue = [];\n this.pendingSeekTime = seekTime;\n this.hasSnappedToFirstBuffered = true; // explicit seek overrides the auto-snap\n if (!sb || sb.buffered.length === 0) return;\n try {\n const start = sb.buffered.start(0);\n const end = sb.buffered.end(sb.buffered.length - 1);\n sb.remove(start, end);\n } catch {\n /* ignore — sourcebuffer may be in updating state */\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n this.queue = [];\n try {\n if (this.mediaSource.readyState === \"open\") this.mediaSource.endOfStream();\n } catch {\n /* ignore */\n }\n URL.revokeObjectURL(this.objectUrl);\n }\n}\n","import type { MediaContext } from \"../../types.js\";\nimport { MseSink } from \"./mse.js\";\nimport {\n avbridgeVideoToMediabunny,\n avbridgeAudioToMediabunny,\n buildMediabunnySourceFromInput,\n} from \"../../probe/mediabunny.js\";\n\n/**\n * Remux pipeline built against mediabunny's real API.\n *\n * Key design notes:\n *\n * - mediabunny's fMP4 muxer is a streaming muxer that requires monotonically\n * increasing timestamps. It cannot accept out-of-order packets after a seek.\n * Therefore, on each seek we create a **fresh** Output + sources + StreamTarget.\n * The MseSink handles the SourceBuffer reset via `invalidate()`.\n *\n * - Backpressure is enforced at two levels: in the WritableStream write handler\n * (limits append queue depth and total buffered time) and in the pump loop\n * (limits buffered-ahead and total buffered time). Without this, long files\n * dump gigabytes into the SourceBuffer and exhaust memory.\n */\nexport interface RemuxPipeline {\n start(fromTime?: number, autoPlay?: boolean): Promise<void>;\n seek(time: number, autoPlay?: boolean): Promise<void>;\n /** Update the autoplay intent mid-flight — used when play() arrives after seek() but before the MseSink has been constructed. */\n setAutoPlay(autoPlay: boolean): void;\n /**\n * Switch the active audio track. Tears down the current Output, rebuilds\n * with the new audio source, and resumes pumping at the given time.\n */\n setAudioTrack(trackId: number, timeSec: number, autoPlay: boolean): Promise<void>;\n destroy(): Promise<void>;\n stats(): Record<string, unknown>;\n}\n\nexport async function createRemuxPipeline(\n ctx: MediaContext,\n video: HTMLVideoElement,\n): Promise<RemuxPipeline> {\n const mb = await import(\"mediabunny\");\n\n const videoTrackInfo = ctx.videoTracks[0];\n if (!videoTrackInfo) throw new Error(\"remux: source has no video track\");\n\n // Map avbridge codec names back to mediabunny's enum strings.\n const mbVideoCodec = avbridgeVideoToMediabunny(videoTrackInfo.codec);\n if (!mbVideoCodec) {\n throw new Error(`remux: video codec \"${videoTrackInfo.codec}\" is not supported by mediabunny output`);\n }\n\n // Open the input. URL sources go through mediabunny's UrlSource so the\n // muxer streams via Range requests instead of buffering the whole file.\n const input = new mb.Input({\n source: await buildMediabunnySourceFromInput(mb, ctx.source),\n formats: mb.ALL_FORMATS,\n });\n const allTracks = await input.getTracks();\n const inputVideo = allTracks.find((t) => t.id === videoTrackInfo.id && t.isVideoTrack());\n if (!inputVideo || !inputVideo.isVideoTrack()) {\n throw new Error(\"remux: video track not found in input\");\n }\n\n // Pull the video WebCodecs decoder config once — used as `meta` on the\n // first packet after every Output rebuild.\n const videoConfig = await inputVideo.getDecoderConfig();\n\n // Packet sink for video — reused across seeks.\n const videoSink = new mb.EncodedPacketSink(inputVideo);\n\n // Audio selection is mutable: setAudioTrack() can swap it. The selected\n // audio derived state (input track, codec, sink, config) is rebuilt via\n // rebuildAudio() whenever the id changes.\n type InputAudioTrack = InstanceType<typeof mb.InputAudioTrack>;\n type AudioDecCfg = Awaited<ReturnType<InputAudioTrack[\"getDecoderConfig\"]>>;\n\n let selectedAudioTrackId: number | null = ctx.audioTracks[0]?.id ?? null;\n let inputAudio: InputAudioTrack | null = null;\n let mbAudioCodec: ReturnType<typeof avbridgeAudioToMediabunny> | null = null;\n let audioSink: InstanceType<typeof mb.EncodedPacketSink> | null = null;\n let audioConfig: AudioDecCfg | null = null;\n\n async function rebuildAudio(): Promise<void> {\n if (selectedAudioTrackId == null) {\n inputAudio = null;\n mbAudioCodec = null;\n audioSink = null;\n audioConfig = null;\n return;\n }\n const trackInfo = ctx.audioTracks.find((t) => t.id === selectedAudioTrackId);\n if (!trackInfo) {\n throw new Error(`remux: no audio track with id ${selectedAudioTrackId}`);\n }\n const newInput = allTracks.find((t) => t.id === trackInfo.id && t.isAudioTrack());\n if (!newInput || !newInput.isAudioTrack()) {\n throw new Error(\"remux: audio track not found in input\");\n }\n inputAudio = newInput;\n mbAudioCodec = avbridgeAudioToMediabunny(trackInfo.codec);\n audioSink = new mb.EncodedPacketSink(newInput);\n audioConfig = await newInput.getDecoderConfig();\n }\n\n await rebuildAudio();\n\n // MSE sink — created lazily on first output write, reused across seeks.\n let sink: MseSink | null = null;\n const stats = { videoPackets: 0, audioPackets: 0, bytesWritten: 0, fragments: 0 };\n\n let destroyed = false;\n let pumpToken = 0;\n let pendingAutoPlay = false;\n let pendingStartTime = 0;\n\n // The current Output instance. Recreated on each seek because mediabunny's\n // fMP4 muxer requires monotonically increasing timestamps.\n let currentOutput: InstanceType<typeof mb.Output> | null = null;\n\n /**\n * Create a fresh mediabunny Output wired to the MSE sink. Called once at\n * start and again on each seek.\n */\n function createOutput() {\n // Cancel the previous output if it exists.\n if (currentOutput) {\n try { void currentOutput.cancel(); } catch { /* ignore */ }\n }\n\n let mimePromise: Promise<string> | null = null;\n\n const writable = new WritableStream<{\n type: \"write\";\n data: Uint8Array<ArrayBuffer>;\n position: number;\n }>({\n write: async (chunk) => {\n if (destroyed) return;\n if (!sink) {\n const mime = await (mimePromise ??= output.getMimeType());\n sink = new MseSink({ mime, video });\n await sink.ready();\n // Apply deferred seek + autoPlay for the initial start.\n if (pendingStartTime > 0) {\n sink.invalidate(pendingStartTime);\n }\n sink.setPlayOnSeek(pendingAutoPlay);\n }\n // Backpressure: wait for the SourceBuffer append queue to drain.\n while (sink && !destroyed && (sink.queueLength() > 10 || sink.bufferedAhead() > 60 || sink.totalBuffered() > 120)) {\n await new Promise((r) => setTimeout(r, 500));\n }\n if (destroyed) return;\n sink.append(chunk.data);\n stats.bytesWritten += chunk.data.byteLength;\n stats.fragments++;\n },\n });\n\n const target = new mb.StreamTarget(writable);\n const output = new mb.Output({\n format: new mb.Mp4OutputFormat({ fastStart: \"fragmented\" }),\n target,\n });\n\n // Build the output sources.\n const videoSource = new mb.EncodedVideoPacketSource(mbVideoCodec!);\n output.addVideoTrack(videoSource);\n\n type AudioSourceCtorArg = ConstructorParameters<typeof mb.EncodedAudioPacketSource>[0];\n let audioSource: InstanceType<typeof mb.EncodedAudioPacketSource> | null = null;\n if (mbAudioCodec && inputAudio?.isAudioTrack()) {\n audioSource = new mb.EncodedAudioPacketSource(mbAudioCodec as AudioSourceCtorArg);\n output.addAudioTrack(audioSource);\n }\n\n currentOutput = output;\n return { output, videoSource, audioSource };\n }\n\n async function pumpLoop(token: number, fromTime: number) {\n const { output, videoSource, audioSource } = createOutput();\n\n await output.start();\n\n\n // Find the starting key packet so we never push partial GOPs.\n const startVideoPacket =\n fromTime > 0\n ? (await videoSink.getKeyPacket(fromTime)) ?? (await videoSink.getFirstPacket())\n : await videoSink.getFirstPacket();\n if (!startVideoPacket) return;\n\n const startAudioPacket = audioSink\n ? (audioSink && fromTime > 0\n ? (await audioSink.getPacket(fromTime)) ?? (await audioSink.getFirstPacket())\n : await audioSink.getFirstPacket())\n : null;\n\n const videoIter = videoSink.packets(startVideoPacket);\n const audioIter = audioSink && startAudioPacket ? audioSink.packets(startAudioPacket) : null;\n\n let vNext = await videoIter.next();\n let aNext = audioIter ? await audioIter.next() : { done: true as const, value: undefined };\n let firstVideo = true;\n let firstAudio = true;\n\n while (!destroyed && pumpToken === token && (!vNext.done || !aNext.done)) {\n // Backpressure: pause pumping when we've buffered enough.\n while (\n !destroyed &&\n pumpToken === token &&\n sink &&\n (sink.bufferedAhead() > 30 || sink.queueLength() > 20 || sink.totalBuffered() > 90)\n ) {\n await new Promise((r) => setTimeout(r, 500));\n }\n if (destroyed || pumpToken !== token) break;\n\n const vTs = !vNext.done ? vNext.value.timestamp : Number.POSITIVE_INFINITY;\n const aTs = !aNext.done ? aNext.value.timestamp : Number.POSITIVE_INFINITY;\n\n // Mediabunny's muxer requires the first packet on a fresh Output to\n // be a key packet. We fetched `startVideoPacket` via\n // `videoSink.getKeyPacket(fromTime)` so the first video packet is\n // guaranteed to be a keyframe — but a demuxer can hand us an audio\n // packet with a lower timestamp, which mediabunny rejects with\n // \"First packet must be a key packet.\" Force the first video\n // packet out before we let any audio through.\n const forceVideoFirst = firstVideo && !vNext.done;\n\n if (!vNext.done && (forceVideoFirst || vTs <= aTs)) {\n await videoSource.add(\n vNext.value,\n firstVideo && videoConfig ? { decoderConfig: videoConfig } : undefined,\n );\n firstVideo = false;\n stats.videoPackets++;\n vNext = await videoIter.next();\n } else if (audioIter && audioSource && !aNext.done) {\n await audioSource.add(\n aNext.value,\n firstAudio && audioConfig ? { decoderConfig: audioConfig } : undefined,\n );\n firstAudio = false;\n stats.audioPackets++;\n aNext = await audioIter.next();\n } else {\n break;\n }\n }\n\n if (!destroyed && pumpToken === token) {\n await output.finalize();\n sink?.endOfStream();\n }\n }\n\n return {\n async start(fromTime = 0, autoPlay = false) {\n // Store autoPlay/seekTime so the MseSink (created lazily on first\n // write) can apply the deferred seek and auto-play.\n pendingAutoPlay = autoPlay;\n pendingStartTime = fromTime;\n pumpLoop(++pumpToken, fromTime).catch((err) => {\n // eslint-disable-next-line no-console\n console.error(\"[avbridge] remux pipeline failed:\", err);\n try { sink?.destroy(); } catch { /* ignore */ }\n });\n },\n async seek(time, autoPlay = false) {\n if (sink) {\n sink.setPlayOnSeek(autoPlay);\n sink.invalidate(time);\n } else {\n pendingAutoPlay = autoPlay;\n pendingStartTime = time;\n }\n pumpLoop(++pumpToken, time).catch((err) => {\n // eslint-disable-next-line no-console\n console.error(\"[avbridge] remux pipeline reseek failed:\", err);\n });\n },\n setAutoPlay(autoPlay) {\n pendingAutoPlay = autoPlay;\n if (sink) sink.setPlayOnSeek(autoPlay);\n },\n async setAudioTrack(trackId, time, autoPlay) {\n if (selectedAudioTrackId === trackId) return;\n if (!ctx.audioTracks.some((t) => t.id === trackId)) {\n console.warn(\"[avbridge] remux: setAudioTrack — unknown track id\", trackId);\n return;\n }\n // Stop the current pump. The next pumpLoop() will build a fresh\n // Output that uses the newly-selected audio source.\n pumpToken++;\n selectedAudioTrackId = trackId;\n await rebuildAudio().catch((err) => {\n console.warn(\"[avbridge] remux: rebuildAudio failed:\", (err as Error).message);\n });\n // Tear down the existing MseSink — the audio codec may have changed,\n // and the SourceBuffer's mime is fixed at construction time. The next\n // createOutput will recompute `getMimeType()` and the write handler\n // will lazily build a new sink.\n if (sink) {\n try { sink.destroy(); } catch { /* ignore */ }\n sink = null;\n }\n pendingAutoPlay = autoPlay;\n pendingStartTime = time;\n pumpLoop(++pumpToken, time).catch((err) => {\n // eslint-disable-next-line no-console\n console.error(\"[avbridge] remux pipeline setAudioTrack pump failed:\", err);\n });\n },\n async destroy() {\n destroyed = true;\n pumpToken++;\n try { if (currentOutput) await currentOutput.cancel(); } catch { /* ignore */ }\n try { await input.dispose(); } catch { /* ignore */ }\n sink?.destroy();\n },\n stats() {\n return { ...stats, decoderType: \"remux\" };\n },\n };\n}\n\n","import type { MediaContext, PlaybackSession } from \"../../types.js\";\nimport { createRemuxPipeline, type RemuxPipeline } from \"./pipeline.js\";\n\n/**\n * Strategy entry: build the remux pipeline, then expose a {@link PlaybackSession}\n * that delegates to the underlying `<video>` element for playback control and\n * to the pipeline for source-side seek invalidation.\n */\nexport async function createRemuxSession(\n context: MediaContext,\n video: HTMLVideoElement,\n): Promise<PlaybackSession> {\n let pipeline: RemuxPipeline;\n try {\n pipeline = await createRemuxPipeline(context, video);\n } catch (err) {\n throw new Error(\n `remux strategy failed to start: ${(err as Error).message}. The container or codec combination is not supported by mediabunny + MSE on this browser.`,\n );\n }\n\n // Don't pump yet — wait for the first play() or seek() to start from the\n // right position. The player's strategy-switch flow calls seek(currentTime)\n // immediately after creation, so pumping from 0 here would be wasted work.\n let started = false;\n let wantPlay = false;\n\n return {\n strategy: \"remux\",\n async play() {\n wantPlay = true;\n if (!started) {\n // First play — start the pump. The deferred seek in MseSink will\n // call video.play() once data is available (via autoPlay flag).\n started = true;\n await pipeline.start(video.currentTime || 0, true);\n return;\n }\n // seek() may have already started the pump with autoPlay=false\n // (strategy-switch flow calls seek before play). Flip the pipeline's\n // pending autoPlay so the MseSink fires video.play() once buffered\n // data lands, and also attempt an immediate video.play() in case the\n // sink is already wired up. The immediate call can reject when\n // video.src hasn't been set yet — that's fine, the deferred path will\n // catch it.\n pipeline.setAutoPlay(true);\n try {\n await video.play();\n } catch {\n /* sink not ready yet; setAutoPlay will handle playback on first buffered write */\n }\n },\n pause() {\n wantPlay = false;\n video.pause();\n },\n async seek(time) {\n if (!started) {\n started = true;\n // autoPlay=true so playback starts as soon as data arrives at\n // the seek target (handles the strategy-switch case where play()\n // is called right after seek()).\n await pipeline.seek(time, wantPlay);\n return;\n }\n const wasPlaying = !video.paused;\n await pipeline.seek(time, wasPlaying || wantPlay);\n },\n async setAudioTrack(id) {\n if (!context.audioTracks.some((t) => t.id === id)) {\n console.warn(\"[avbridge] remux: setAudioTrack — unknown track id\", id);\n return;\n }\n const wasPlaying = !video.paused;\n const time = video.currentTime || 0;\n // Not yet started? Just note the selection and let play()/seek() drive.\n if (!started) {\n started = true;\n await pipeline.setAudioTrack(id, time, wantPlay || wasPlaying);\n return;\n }\n await pipeline.setAudioTrack(id, time, wasPlaying || wantPlay);\n },\n async setSubtitleTrack(id) {\n const tracks = video.textTracks;\n for (let i = 0; i < tracks.length; i++) {\n tracks[i].mode = i === id ? \"showing\" : \"disabled\";\n }\n },\n getCurrentTime() {\n return video.currentTime || 0;\n },\n async destroy() {\n video.pause();\n await pipeline.destroy();\n video.removeAttribute(\"src\");\n video.load();\n },\n getRuntimeStats() {\n return pipeline.stats();\n },\n };\n}\n","import type { ClockSource } from \"./audio-output.js\";\nimport { SubtitleOverlay } from \"../../subtitles/render.js\";\n\n/**\n * Renders decoded `VideoFrame`s into a 2D canvas overlaid on the user's\n * `<video>` element. The fallback strategy never assigns a src to the video,\n * so we hide it and put the canvas in its place visually.\n *\n * The renderer has two modes:\n *\n * 1. **Pre-roll** — `clock.isPlaying()` is false. The very first decoded\n * frame is painted as a \"poster\" so the user sees something while audio\n * buffers; subsequent frames stay queued without being dropped.\n *\n * 2. **Synced** — `clock.isPlaying()` is true. On each rAF tick, find the\n * latest frame whose timestamp ≤ `clock.now() + lookahead` and paint it.\n * Drop any older frames as \"late.\"\n *\n * The pre-roll behavior is what fixes the cold-start \"first minute is all\n * dropped\" problem: without it, the wall clock raced ahead while the\n * decoder was still warming up, and every frame was already in the past by\n * the time it landed in the queue.\n */\n// Periodic debug log — throttled to once per second so it doesn't\n// flood the console at 60Hz rAF rate.\nfunction isDebug(): boolean {\n return typeof globalThis !== \"undefined\" && !!(globalThis as Record<string, unknown>).AVBRIDGE_DEBUG;\n}\nlet lastDebugLog = 0;\n\nexport class VideoRenderer {\n private canvas: HTMLCanvasElement;\n private ctx: CanvasRenderingContext2D;\n private queue: VideoFrame[] = [];\n private rafHandle: number | null = null;\n private destroyed = false;\n\n private framesPainted = 0;\n private framesDroppedLate = 0;\n private framesDroppedOverflow = 0;\n private prerolled = false;\n /** Wall-clock time of the last paint, in ms (performance.now()). */\n private lastPaintWall = 0;\n /** Minimum ms between paints — paces video at roughly source fps. */\n private paintIntervalMs: number;\n /** Cumulative count of frames skipped because all PTS are in the future. */\n private ticksWaiting = 0;\n /** Cumulative count of ticks where PTS mode painted a frame. */\n private ticksPainted = 0;\n\n /**\n * Subtitle overlay div attached to the stage wrapper alongside the\n * canvas. Created lazily when subtitle tracks are attached via the\n * target's `<track>` children. Canvas strategies (hybrid, fallback)\n * hide the <video>, so we can't rely on the browser's native cue\n * rendering; we read TextTrack.cues and render into this overlay.\n */\n private subtitleOverlay: SubtitleOverlay | null = null;\n private subtitleTrack: TextTrack | null = null;\n\n /**\n * Calibration offset (microseconds) between video PTS and audio clock.\n * Video PTS and AudioContext.currentTime can drift ~0.1% relative to\n * each other (different clock domains). Over 45 minutes that's 2.6s.\n * We measure the offset on the first painted frame and update it\n * periodically so the PTS comparison stays calibrated.\n */\n private ptsCalibrationUs = 0;\n private ptsCalibrated = false;\n private lastCalibrationWall = 0;\n\n /** Resolves once the first decoded frame has been enqueued. */\n readonly firstFrameReady: Promise<void>;\n private resolveFirstFrame!: () => void;\n\n constructor(\n private readonly target: HTMLVideoElement,\n private readonly clock: ClockSource,\n fps = 30,\n ) {\n this.paintIntervalMs = Math.max(1, 1000 / fps);\n this.firstFrameReady = new Promise<void>((resolve) => {\n this.resolveFirstFrame = resolve;\n });\n\n this.canvas = document.createElement(\"canvas\");\n // object-fit:contain letterboxes the canvas bitmap (sized to\n // frame.displayWidth × displayHeight in paint()) inside the stage so\n // portrait / non-stage-aspect content isn't stretched. Canvas is a\n // replaced element, so object-fit applies.\n this.canvas.style.cssText =\n \"position:absolute;left:0;top:0;width:100%;height:100%;background:black;object-fit:contain;\";\n\n // Attach the canvas next to the video. When the video lives inside an\n // `<avbridge-video>` shadow root, `target.parentElement` is the\n // positioned `<div part=\"stage\">` wrapper the element created\n // precisely for this purpose. When the video is used standalone\n // (legacy `createPlayer({ target: videoEl })` path), we fall back to\n // `parentNode` — which handles plain Elements, and also ShadowRoots\n // if someone inserts a bare <video> inside their own shadow DOM\n // without a wrapper.\n const parent: ParentNode | null =\n (target.parentElement as ParentNode | null) ?? target.parentNode;\n if (parent && parent instanceof HTMLElement) {\n if (getComputedStyle(parent).position === \"static\") {\n parent.style.position = \"relative\";\n }\n }\n if (parent) {\n parent.insertBefore(this.canvas, target);\n } else {\n // No parent at all — the target is detached. Fall back to appending\n // the canvas to document.body so at least the frames are visible\n // somewhere while the consumer fixes their DOM layout. This is a\n // loud fallback: log a warning so the misuse is obvious.\n // eslint-disable-next-line no-console\n console.warn(\n \"[avbridge] fallback renderer: target <video> has no parent; \" +\n \"appending canvas to document.body as a fallback.\",\n );\n document.body.appendChild(this.canvas);\n }\n target.style.visibility = \"hidden\";\n\n // Create a subtitle overlay on the same parent as the canvas so cues\n // appear over the rendered video. Shows nothing until a TextTrack\n // gets attached via attachSubtitleTracks.\n const overlayParent = parent instanceof HTMLElement ? parent : document.body;\n this.subtitleOverlay = new SubtitleOverlay(overlayParent);\n // Watch for <track> children on the target <video>. When one is\n // added, grab its TextTrack and poll cues from it each tick.\n this.watchTextTracks(target);\n\n const ctx = this.canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"video renderer: failed to acquire 2D context\");\n this.ctx = ctx;\n\n this.tick = this.tick.bind(this);\n this.rafHandle = requestAnimationFrame(this.tick);\n }\n\n /** True once at least one frame has been enqueued. */\n hasFrames(): boolean {\n return this.queue.length > 0 || this.framesPainted > 0;\n }\n\n /** Current depth of the frame queue. Used by the decoder for backpressure. */\n queueDepth(): number {\n return this.queue.length;\n }\n\n /**\n * Soft cap for decoder backpressure. The decoder pump throttles when\n * `queueDepth() >= queueHighWater`. Set high enough that normal decode\n * bursts don't trigger the renderer's overflow-drop loop (which runs at\n * every paint), but low enough that the decoder doesn't run unboundedly\n * ahead. The hard cap in `enqueue()` is 64.\n */\n readonly queueHighWater = 30;\n\n enqueue(frame: VideoFrame): void {\n if (this.destroyed) {\n frame.close();\n return;\n }\n this.queue.push(frame);\n if (this.queue.length === 1 && this.framesPainted === 0) {\n this.resolveFirstFrame();\n }\n // Hard cap. Should rarely trigger because the decoder backs off at\n // queueHighWater (30) and the drift correction trims gently. This is\n // the last-resort defense against runaway producers.\n while (this.queue.length > 60) {\n this.queue.shift()?.close();\n this.framesDroppedOverflow++;\n }\n }\n\n /**\n * Watch the target <video>'s textTracks list. When a track is added,\n * grab it and start polling cues on each render tick. Existing tracks\n * (if any) are picked up immediately.\n */\n private watchTextTracks(target: HTMLVideoElement): void {\n const pick = () => {\n if (this.subtitleTrack) return;\n const tracks = target.textTracks;\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[avbridge:subs] watchTextTracks pick() — ${tracks.length} tracks`);\n }\n for (let i = 0; i < tracks.length; i++) {\n const t = tracks[i];\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[avbridge:subs] track ${i}: kind=${t.kind} mode=${t.mode} cues=${t.cues?.length ?? 0}`);\n }\n if (t.kind === \"subtitles\" || t.kind === \"captions\") {\n this.subtitleTrack = t;\n t.mode = \"hidden\"; // hidden means \"cues available via API, don't render\"\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[avbridge:subs] picked track, mode=hidden`);\n }\n // Listen for cue load completion\n const trackEl = target.querySelector(`track[srclang=\"${t.language}\"]`) as HTMLTrackElement | null;\n if (trackEl) {\n trackEl.addEventListener(\"load\", () => {\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[avbridge:subs] track element loaded, cues=${t.cues?.length ?? 0}`);\n }\n });\n trackEl.addEventListener(\"error\", (ev) => {\n // eslint-disable-next-line no-console\n console.warn(`[avbridge:subs] track element error:`, ev);\n });\n }\n break;\n }\n }\n };\n pick();\n if (typeof target.textTracks.addEventListener === \"function\") {\n target.textTracks.addEventListener(\"addtrack\", (e) => {\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(\"[avbridge:subs] addtrack event fired\");\n }\n void e;\n pick();\n });\n }\n }\n\n private _loggedCues = false;\n\n /** Find the active cue (if any) for the given media time. */\n private updateSubtitles(): void {\n if (!this.subtitleOverlay || !this.subtitleTrack) return;\n const cues = this.subtitleTrack.cues;\n if (!cues || cues.length === 0) return;\n if (isDebug() && !this._loggedCues) {\n this._loggedCues = true;\n // eslint-disable-next-line no-console\n console.log(`[avbridge:subs] cues available: ${cues.length}, first start=${cues[0].startTime}, last end=${cues[cues.length-1].endTime}`);\n }\n const t = this.clock.now();\n let activeText = \"\";\n for (let i = 0; i < cues.length; i++) {\n const c = cues[i];\n if (t >= c.startTime && t <= c.endTime) {\n const vttCue = c as VTTCue & { text?: string };\n activeText = vttCue.text ?? \"\";\n break;\n }\n }\n // Strip VTT tags for plain rendering (e.g. <c.en> voice tags)\n this.subtitleOverlay.setText(activeText.replace(/<[^>]+>/g, \"\"));\n }\n\n private tick(): void {\n if (this.destroyed) return;\n this.rafHandle = requestAnimationFrame(this.tick);\n\n this.updateSubtitles();\n\n if (this.queue.length === 0) return;\n\n const playing = this.clock.isPlaying();\n\n // Pre-roll: paint the very first frame as a poster while audio buffers.\n if (!playing) {\n if (!this.prerolled) {\n const head = this.queue.shift()!;\n this.paint(head);\n head.close();\n this.prerolled = true;\n this.lastPaintWall = performance.now();\n }\n return;\n }\n\n // PTS-based painting: find the latest frame whose presentation time\n // has arrived (timestamp ≤ audio clock), paint it, and discard any\n // older frames. This produces correct cadence at any display refresh\n // rate and any source fps — no 3:2 pulldown artifacts.\n //\n // Fallback: if frame timestamps are unreliable (all zero, synthetic),\n // fall back to wall-clock pacing as before.\n const rawAudioNowUs = this.clock.now() * 1_000_000;\n const headTs = this.queue[0].timestamp ?? 0;\n const hasPts = headTs > 0 || this.queue.length > 1;\n\n if (hasPts) {\n // Calibration: video PTS and audio clock (AudioContext.currentTime)\n // live in different clock domains with a fixed offset (different epoch)\n // plus a small rate drift (~7ms/s). We snap the offset on first paint\n // and re-snap every 10 seconds. Between snaps, max drift is ~70ms\n // (under 2 frames at 24fps, below lip-sync perception threshold).\n const wallNow = performance.now();\n if (!this.ptsCalibrated || wallNow - this.lastCalibrationWall > 10_000) {\n this.ptsCalibrationUs = headTs - rawAudioNowUs;\n this.ptsCalibrated = true;\n this.lastCalibrationWall = wallNow;\n }\n\n const audioNowUs = rawAudioNowUs + this.ptsCalibrationUs;\n const frameDurationUs = this.paintIntervalMs * 1000;\n const deadlineUs = audioNowUs + frameDurationUs;\n\n let bestIdx = -1;\n for (let i = 0; i < this.queue.length; i++) {\n const ts = this.queue[i].timestamp ?? 0;\n if (ts <= deadlineUs) {\n bestIdx = i;\n } else {\n break;\n }\n }\n\n if (bestIdx < 0) {\n this.ticksWaiting++;\n if (isDebug()) {\n const now = performance.now();\n if (now - lastDebugLog > 1000) {\n const headPtsMs = (headTs / 1000).toFixed(1);\n const audioMs = (audioNowUs / 1000).toFixed(1);\n const rawDriftMs = ((headTs - rawAudioNowUs) / 1000).toFixed(1);\n const calibMs = (this.ptsCalibrationUs / 1000).toFixed(1);\n // eslint-disable-next-line no-console\n console.log(\n `[avbridge:renderer] WAIT q=${this.queue.length} headPTS=${headPtsMs}ms calibAudio=${audioMs}ms ` +\n `rawDrift=${rawDriftMs}ms calib=${calibMs}ms painted=${this.framesPainted} dropped=${this.framesDroppedLate}`,\n );\n lastDebugLog = now;\n }\n }\n return;\n }\n\n // Only drop frames that are more than 2 frame-durations behind.\n const dropThresholdUs = audioNowUs - frameDurationUs * 2;\n let dropped = 0;\n while (bestIdx > 0) {\n const ts = this.queue[0].timestamp ?? 0;\n if (ts < dropThresholdUs) {\n this.queue.shift()?.close();\n this.framesDroppedLate++;\n bestIdx--;\n dropped++;\n } else {\n break;\n }\n }\n\n this.ticksPainted++;\n\n if (isDebug()) {\n const now = performance.now();\n if (now - lastDebugLog > 1000) {\n const paintedTs = (this.queue[0]?.timestamp ?? 0);\n const audioMs = (audioNowUs / 1000).toFixed(1);\n const ptsMs = (paintedTs / 1000).toFixed(1);\n const rawDriftMs = ((paintedTs - rawAudioNowUs) / 1000).toFixed(1);\n const calibMs = (this.ptsCalibrationUs / 1000).toFixed(1);\n // eslint-disable-next-line no-console\n console.log(\n `[avbridge:renderer] PAINT q=${this.queue.length} calibAudio=${audioMs}ms nextPTS=${ptsMs}ms ` +\n `rawDrift=${rawDriftMs}ms calib=${calibMs}ms dropped=${dropped} total_drops=${this.framesDroppedLate} painted=${this.framesPainted}`,\n );\n lastDebugLog = now;\n }\n }\n\n const frame = this.queue.shift()!;\n this.paint(frame);\n frame.close();\n this.lastPaintWall = performance.now();\n return;\n }\n\n // Wall-clock fallback: used when timestamps are unreliable (all zero).\n const wallNow = performance.now();\n if (wallNow - this.lastPaintWall < this.paintIntervalMs - 2) return;\n\n const frame = this.queue.shift()!;\n this.paint(frame);\n frame.close();\n this.lastPaintWall = wallNow;\n }\n\n private paint(frame: VideoFrame): void {\n if (\n this.canvas.width !== frame.displayWidth ||\n this.canvas.height !== frame.displayHeight\n ) {\n this.canvas.width = frame.displayWidth;\n this.canvas.height = frame.displayHeight;\n }\n try {\n this.ctx.drawImage(frame, 0, 0, this.canvas.width, this.canvas.height);\n this.framesPainted++;\n } catch (err) {\n // Log only once so a structurally broken frame format doesn't spam\n // the console at 60 Hz, but we still find out about it.\n if (this.framesPainted === 0 && this.framesDroppedLate === 0) {\n // eslint-disable-next-line no-console\n console.warn(\"[avbridge] canvas drawImage failed:\", err);\n }\n }\n }\n\n /** Discard all queued frames. Used by seek to drop stale buffers. */\n flush(): void {\n const count = this.queue.length;\n while (this.queue.length > 0) this.queue.shift()?.close();\n this.prerolled = false;\n this.ptsCalibrated = false; // recalibrate at new seek position\n if (isDebug() && count > 0) {\n // eslint-disable-next-line no-console\n console.log(`[avbridge:renderer] FLUSH discarded=${count} painted=${this.framesPainted} drops=${this.framesDroppedLate}`);\n }\n }\n\n stats(): Record<string, unknown> {\n return {\n framesPainted: this.framesPainted,\n framesDroppedLate: this.framesDroppedLate,\n framesDroppedOverflow: this.framesDroppedOverflow,\n queueDepth: this.queue.length,\n };\n }\n\n destroy(): void {\n this.destroyed = true;\n if (this.rafHandle != null) cancelAnimationFrame(this.rafHandle);\n this.flush();\n if (this.subtitleOverlay) { this.subtitleOverlay.destroy(); this.subtitleOverlay = null; }\n this.subtitleTrack = null;\n this.canvas.remove();\n this.target.style.visibility = \"\";\n }\n}\n","/**\n * Web Audio output for the fallback strategy.\n *\n * Owns the **media-time clock** for fallback playback. Audio is the master:\n * decoded video frames are presented based on what `now()` returns here.\n *\n * State machine:\n *\n * ┌──────┐ schedule() ┌──────┐ ┌────────┐\n * │ idle │ ───────────▶ │ idle │ ── start() ──▶│ playing│\n * └──────┘ (queues) └──────┘ └────┬───┘\n * ▲ │\n * │ │ pause()\n * │ ▼\n * │ ┌────────┐\n * └────────────── reset(t) ─────────────── ── │ paused │\n * └────────┘\n *\n * - **idle**: AudioContext is suspended (no playback). `schedule()` queues\n * samples in `pendingQueue`; `now()` returns `mediaTimeOfAnchor`.\n * - **playing**: AudioContext is running. `schedule()` writes directly to\n * the audio graph at the right time. `now()` advances with `ctx.currentTime`.\n * - **paused**: AudioContext is suspended. `now()` returns the media time\n * captured at pause. `start()` resumes.\n *\n * Key invariant: between any two `start()` calls, `mediaTimeOfNext` (the\n * media time of the next sample to be scheduled) must equal the media time\n * the playback is at. This is what makes the cold-start race go away — we\n * never schedule audio with a stale wall-clock anchor.\n */\n\ninterface PendingChunk {\n samples: Float32Array;\n channels: number;\n sampleRate: number;\n frameCount: number;\n durationSec: number;\n}\n\nexport interface ClockSource {\n /** Current media time in seconds. */\n now(): number;\n /** True if media is currently playing (audio scheduler is running). */\n isPlaying(): boolean;\n}\n\nexport class AudioOutput implements ClockSource {\n private ctx: AudioContext;\n private gain: GainNode;\n\n private state: \"idle\" | \"playing\" | \"paused\" = \"idle\";\n\n /**\n * Wall-clock fallback mode. When true, this output behaves as if audio\n * is unavailable — `now()` advances from `performance.now()` instead of\n * the audio context, `schedule()` is a no-op, and `bufferAhead()` returns\n * Infinity so the session's `waitForBuffer()` doesn't block on audio.\n *\n * Set by the decoder via {@link setNoAudio} when audio decode init fails.\n * This is what lets video play even when the audio codec isn't supported\n * by the loaded libav variant.\n */\n private noAudio = false;\n /** Wall-clock anchor (ms from `performance.now()`) for noAudio mode. */\n private wallAnchorMs = 0;\n\n /** Media time at which the next sample will be scheduled. */\n private mediaTimeOfNext = 0;\n\n /** Anchor: media time `mediaTimeOfAnchor` corresponds to ctx time `ctxTimeAtAnchor`. */\n private mediaTimeOfAnchor = 0;\n private ctxTimeAtAnchor = 0;\n\n private pendingQueue: PendingChunk[] = [];\n\n private framesScheduled = 0;\n private destroyed = false;\n\n /** User-set volume (0..1). Applied to the gain node. */\n private _volume = 1;\n /** User-set muted flag. When true, gain is forced to 0. */\n private _muted = false;\n\n constructor() {\n this.ctx = new AudioContext();\n this.gain = this.ctx.createGain();\n this.gain.connect(this.ctx.destination);\n }\n\n /** Set volume (0..1). Applied immediately to the gain node. */\n setVolume(v: number): void {\n this._volume = Math.max(0, Math.min(1, v));\n this.applyGain();\n }\n\n getVolume(): number {\n return this._volume;\n }\n\n /** Set muted. When true, output is silenced regardless of volume. */\n setMuted(m: boolean): void {\n this._muted = m;\n this.applyGain();\n }\n\n getMuted(): boolean {\n return this._muted;\n }\n\n private applyGain(): void {\n const target = this._muted ? 0 : this._volume;\n try { this.gain.gain.value = target; } catch { /* ignore */ }\n }\n\n /**\n * Switch into wall-clock fallback mode. Called by the decoder when no\n * audio decoder could be initialized for the source. Once set, this\n * output drives playback time from `performance.now()` and ignores\n * any incoming audio samples.\n */\n setNoAudio(): void {\n this.noAudio = true;\n }\n\n // ── ClockSource ────────────────────────────────────────────────────────\n\n now(): number {\n if (this.noAudio) {\n if (this.state === \"playing\") {\n return this.mediaTimeOfAnchor + (performance.now() - this.wallAnchorMs) / 1000;\n }\n return this.mediaTimeOfAnchor;\n }\n if (this.state === \"playing\") {\n return this.mediaTimeOfAnchor + (this.ctx.currentTime - this.ctxTimeAtAnchor);\n }\n return this.mediaTimeOfAnchor;\n }\n\n isPlaying(): boolean {\n return this.state === \"playing\";\n }\n\n // ── Buffering ─────────────────────────────────────────────────────────\n\n /**\n * How many seconds of audio are buffered ahead of the current playback\n * position. While idle, this counts the pending queue. While playing,\n * it counts how far `mediaTimeOfNext` is ahead of `now()`.\n */\n bufferAhead(): number {\n // In wall-clock mode, no samples are ever scheduled — the buffer is\n // genuinely empty. Callers that want to gate cold-start should check\n // {@link isNoAudio} and skip the audio gate entirely instead.\n if (this.noAudio) return 0;\n if (this.state === \"idle\") {\n let sec = 0;\n for (const c of this.pendingQueue) sec += c.durationSec;\n return sec;\n }\n return Math.max(0, this.mediaTimeOfNext - this.now());\n }\n\n /** True if this output is in wall-clock fallback mode (no audio decode). */\n isNoAudio(): boolean {\n return this.noAudio;\n }\n\n /**\n * Schedule a chunk of decoded samples. Queues internally while idle (cold\n * start or post-seek), schedules directly to the audio graph while playing.\n * In wall-clock mode, samples are silently discarded.\n */\n schedule(samples: Float32Array, channels: number, sampleRate: number): void {\n if (this.destroyed || this.noAudio) return;\n const frameCount = samples.length / channels;\n const durationSec = frameCount / sampleRate;\n\n if (this.state === \"idle\" || this.state === \"paused\") {\n this.pendingQueue.push({ samples, channels, sampleRate, frameCount, durationSec });\n return;\n }\n\n this.scheduleNow(samples, channels, sampleRate, frameCount);\n }\n\n private scheduleNow(\n samples: Float32Array,\n channels: number,\n sampleRate: number,\n frameCount: number,\n ): void {\n const buffer = this.ctx.createBuffer(channels, frameCount, sampleRate);\n for (let ch = 0; ch < channels; ch++) {\n const channelData = buffer.getChannelData(ch);\n for (let i = 0; i < frameCount; i++) {\n channelData[i] = samples[i * channels + ch];\n }\n }\n const node = this.ctx.createBufferSource();\n node.buffer = buffer;\n node.connect(this.gain);\n\n // Convert media time → ctx time using the anchor.\n let ctxStart = this.ctxTimeAtAnchor + (this.mediaTimeOfNext - this.mediaTimeOfAnchor);\n\n // When the decoder is slower than realtime, `ctxStart` falls into\n // the past (ctx.currentTime has already passed it). Clamping each\n // sample to `ctx.currentTime` individually (the old behavior)\n // caused every stale sample in a burst to start at *the same\n // instant*, stacking them on top of each other — the audible\n // symptom was a series of clicks / a chord of stuttering cook\n // packets.\n //\n // Correct behavior: when the first sample of a burst is behind,\n // *rebase the anchor forward* so ctxStart = ctx.currentTime now.\n // Subsequent samples in the same burst then schedule at\n // ctxStart + offset as usual, laying out sequentially on the\n // timeline instead of piling up. The downside is a visible jump\n // in the audio clock — but the alternative was silent corruption.\n // `now()` readers (the video renderer) just see the clock step\n // forward and drop any frames older than the new time.\n if (ctxStart < this.ctx.currentTime) {\n this.ctxTimeAtAnchor = this.ctx.currentTime;\n this.mediaTimeOfAnchor = this.mediaTimeOfNext;\n ctxStart = this.ctx.currentTime;\n }\n\n node.start(ctxStart);\n\n this.mediaTimeOfNext += frameCount / sampleRate;\n this.framesScheduled++;\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────\n\n /**\n * Start (or resume) playback. On a cold start (or after a reset), drains\n * the pending queue scheduling all queued samples to play starting at\n * `ctx.currentTime + STARTUP_DELAY`. On resume from pause, just re-anchors\n * the media↔ctx time mapping and unsuspends the context.\n */\n async start(): Promise<void> {\n if (this.destroyed || this.state === \"playing\") return;\n\n // Wall-clock mode: no audio context involved. Anchor to performance.now()\n // and let `now()` advance from there. The renderer's tick loop will see\n // `isPlaying() === true` and start painting frames.\n if (this.noAudio) {\n this.wallAnchorMs = performance.now();\n this.state = \"playing\";\n return;\n }\n\n if (this.ctx.state === \"suspended\") {\n await this.ctx.resume();\n }\n\n if (this.state === \"paused\") {\n // Resume: media time should continue from where we paused. ctx.currentTime\n // is preserved across suspend/resume, so re-anchoring it to \"now\" with\n // the same mediaTimeOfAnchor gives a continuous clock.\n this.ctxTimeAtAnchor = this.ctx.currentTime;\n this.state = \"playing\";\n // Drain anything that was scheduled while paused.\n const drain = this.pendingQueue;\n this.pendingQueue = [];\n for (const c of drain) {\n this.scheduleNow(c.samples, c.channels, c.sampleRate, c.frameCount);\n }\n return;\n }\n\n // Cold start (or post-seek). Anchor: the first sample we scheduled lands\n // at ctxTimeAtAnchor (a tiny bit in the future), and that ctx time\n // corresponds to media time mediaTimeOfAnchor.\n const STARTUP_DELAY = 0.05;\n this.ctxTimeAtAnchor = this.ctx.currentTime + STARTUP_DELAY;\n this.mediaTimeOfNext = this.mediaTimeOfAnchor;\n this.state = \"playing\";\n\n const drain = this.pendingQueue;\n this.pendingQueue = [];\n for (const c of drain) {\n this.scheduleNow(c.samples, c.channels, c.sampleRate, c.frameCount);\n }\n }\n\n /** Pause playback. Suspends the audio context. */\n async pause(): Promise<void> {\n if (this.state !== \"playing\") return;\n this.mediaTimeOfAnchor = this.now();\n this.state = \"paused\";\n if (this.noAudio) return;\n if (this.ctx.state === \"running\") {\n await this.ctx.suspend();\n }\n }\n\n /**\n * Reset to a new media time. Discards all queued and scheduled audio,\n * disconnects the gain node so any in-flight scheduled buffers are cut\n * off, and returns to the idle state. Used by `seek()`.\n *\n * After reset, callers should re-buffer audio (the decoder will start\n * supplying new samples) and then call `start()` to resume playback.\n */\n async reset(newMediaTime: number): Promise<void> {\n if (this.noAudio) {\n this.pendingQueue = [];\n this.mediaTimeOfAnchor = newMediaTime;\n this.wallAnchorMs = performance.now();\n this.state = \"idle\";\n return;\n }\n\n try { this.gain.disconnect(); } catch { /* ignore */ }\n this.gain = this.ctx.createGain();\n this.gain.connect(this.ctx.destination);\n this.applyGain();\n\n this.pendingQueue = [];\n this.mediaTimeOfAnchor = newMediaTime;\n this.mediaTimeOfNext = newMediaTime;\n this.ctxTimeAtAnchor = this.ctx.currentTime;\n this.state = \"idle\";\n\n if (this.ctx.state === \"running\") {\n await this.ctx.suspend();\n }\n }\n\n stats(): Record<string, unknown> {\n return {\n framesScheduled: this.framesScheduled,\n bufferAhead: this.bufferAhead(),\n audioState: this.state,\n clockMode: this.noAudio ? \"wall\" : \"audio\",\n };\n }\n\n destroy(): void {\n this.destroyed = true;\n try { this.ctx.close(); } catch { /* ignore */ }\n }\n}\n","/**\n * Hybrid decoder: libav.js demux + WebCodecs VideoDecoder + libav audio decode.\n *\n * This is the hardware-accelerated path for files in containers mediabunny\n * can't read (AVI, ASF, FLV) but whose codecs ARE browser-supported.\n * libav.js handles demuxing, then:\n *\n * - **Video**: bridge.packetToEncodedVideoChunk → VideoDecoder (hardware)\n * - **Audio**: libav ff_decode_multi (software). Chrome's AudioDecoder\n * rejects raw MP3 packets from AVI, and audio decode is cheap enough\n * that software decode is fine.\n *\n * The demux pump loop, seek handling, and synthetic timestamp logic mirror\n * fallback/decoder.ts. The key difference is the video decode path.\n */\n\nimport { loadLibav, type LibavVariant } from \"../fallback/libav-loader.js\";\nimport { VideoRenderer } from \"../fallback/video-renderer.js\";\nimport { AudioOutput } from \"../fallback/audio-output.js\";\nimport type { MediaContext } from \"../../types.js\";\nimport { dbg } from \"../../util/debug.js\";\nimport { pickLibavVariant } from \"../fallback/variant-routing.js\";\nimport {\n sanitizePacketTimestamp,\n sanitizeFrameTimestamp,\n libavFrameToInterleavedFloat32,\n} from \"../../util/libav-demux.js\";\n\nexport interface HybridDecoderHandles {\n destroy(): Promise<void>;\n seek(timeSec: number): Promise<void>;\n /** Swap the active audio track — rebuilds the libav audio decoder + reseeks. */\n setAudioTrack(trackId: number, timeSec: number): Promise<void>;\n stats(): Record<string, unknown>;\n onFatalError(handler: (reason: string) => void): void;\n}\n\nexport interface StartHybridDecoderOptions {\n /** Normalized source — either a Blob in memory or a URL we'll stream via Range requests. */\n source: import(\"../../util/source.js\").NormalizedSource;\n filename: string;\n context: MediaContext;\n renderer: VideoRenderer;\n audio: AudioOutput;\n transport?: import(\"../../types.js\").TransportConfig;\n}\n\nexport async function startHybridDecoder(opts: StartHybridDecoderOptions): Promise<HybridDecoderHandles> {\n const variant: LibavVariant = pickLibavVariant(opts.context);\n const libav = (await loadLibav(variant)) as unknown as LibavRuntime;\n const bridge = await loadBridge();\n\n // For URL sources, prepareLibavInput attaches an HTTP block reader so\n // libav demuxes via Range requests. For Blob sources, it falls back to\n // mkreadaheadfile (in-memory). The returned handle owns cleanup.\n const { prepareLibavInput } = await import(\"../../util/libav-http-reader.js\");\n const inputHandle = await prepareLibavInput(libav as unknown as Parameters<typeof prepareLibavInput>[0], opts.filename, opts.source, opts.transport);\n\n const readPkt = await libav.av_packet_alloc();\n const [fmt_ctx, streams] = await libav.ff_init_demuxer_file(opts.filename);\n const videoStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_VIDEO) ?? null;\n // Audio stream is mutable (setAudioTrack swaps it). Prefer the id the\n // probe layer listed first so both entry points agree.\n const firstAudioTrackId = opts.context.audioTracks[0]?.id;\n let audioStream: LibavStream | null =\n (firstAudioTrackId != null\n ? streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO && s.index === firstAudioTrackId)\n : undefined) ??\n streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO) ?? null;\n\n if (!videoStream && !audioStream) {\n throw new Error(\"hybrid decoder: file has no decodable streams\");\n }\n\n // ── Fatal error callback ──────────────────────────────────────────────\n let fatalHandler: ((reason: string) => void) | null = null;\n let fatalFired = false;\n\n function fireFatal(reason: string): void {\n if (fatalFired) return;\n fatalFired = true;\n fatalHandler?.(reason);\n }\n\n // ── WebCodecs VideoDecoder ────────────────────────────────────────────\n let videoDecoder: VideoDecoder | null = null;\n let videoTimeBase: [number, number] | undefined;\n\n if (videoStream) {\n try {\n const config = await bridge.videoStreamToConfig(libav, videoStream);\n if (!config) throw new Error(\"bridge returned null config\");\n\n const supported = await VideoDecoder.isConfigSupported(config);\n if (!supported.supported) throw new Error(`VideoDecoder does not support config: ${JSON.stringify(config)}`);\n\n videoDecoder = new VideoDecoder({\n output: (frame: VideoFrame) => {\n opts.renderer.enqueue(frame);\n videoFramesDecoded++;\n },\n error: (err: DOMException) => {\n console.error(\"[avbridge] WebCodecs VideoDecoder error:\", err);\n fireFatal(`WebCodecs VideoDecoder error: ${err.message}`);\n },\n });\n videoDecoder.configure(config);\n\n if (videoStream.time_base_num && videoStream.time_base_den) {\n videoTimeBase = [videoStream.time_base_num, videoStream.time_base_den];\n }\n } catch (err) {\n console.error(\"[avbridge] hybrid: failed to init WebCodecs VideoDecoder:\", err);\n fireFatal(`WebCodecs VideoDecoder init failed: ${(err as Error).message}`);\n // Clean up and throw — the player will escalate to fallback\n await inputHandle.detach().catch(() => {});\n throw err;\n }\n }\n\n // ── libav software AudioDecoder ───────────────────────────────────────\n let audioDec: SoftDecoder | null = null;\n let audioTimeBase: [number, number] | undefined;\n\n if (audioStream) {\n try {\n const [, c, pkt, frame] = await libav.ff_init_decoder(audioStream.codec_id, {\n codecpar: audioStream.codecpar,\n });\n audioDec = { c, pkt, frame };\n if (audioStream.time_base_num && audioStream.time_base_den) {\n audioTimeBase = [audioStream.time_base_num, audioStream.time_base_den];\n }\n } catch (err) {\n console.warn(\n \"[avbridge] hybrid: audio decoder unavailable for this codec — playing video with wall-clock timing:\",\n (err as Error).message,\n );\n }\n }\n\n // No audio decoder? Switch the audio output into wall-clock mode so the\n // video renderer doesn't stall waiting for an audio clock that never starts.\n if (!audioDec) {\n opts.audio.setNoAudio();\n }\n\n if (!videoDecoder && !audioDec) {\n await inputHandle.detach().catch(() => {});\n throw new Error(\"hybrid decoder: could not initialize any decoders\");\n }\n\n // ── Bitstream filter for MPEG-4 Part 2 packed B-frames ───────────────\n let bsfCtx: number | null = null;\n let bsfPkt: number | null = null;\n if (videoStream && opts.context.videoTracks[0]?.codec === \"mpeg4\") {\n try {\n bsfCtx = await libav.av_bsf_list_parse_str_js(\"mpeg4_unpack_bframes\");\n if (bsfCtx != null && bsfCtx >= 0) {\n const parIn = await libav.AVBSFContext_par_in(bsfCtx);\n await libav.avcodec_parameters_copy(parIn, videoStream.codecpar);\n await libav.av_bsf_init(bsfCtx);\n bsfPkt = await libav.av_packet_alloc();\n dbg.info(\"bsf\", \"mpeg4_unpack_bframes BSF active (hybrid)\");\n } else {\n // eslint-disable-next-line no-console\n console.warn(\"[avbridge] mpeg4_unpack_bframes BSF not available in hybrid decoder\");\n bsfCtx = null;\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn(\"[avbridge] hybrid: failed to init BSF:\", (err as Error).message);\n bsfCtx = null;\n bsfPkt = null;\n }\n }\n\n async function applyBSF(packets: LibavPacket[]): Promise<LibavPacket[]> {\n if (!bsfCtx || !bsfPkt) return packets;\n const out: LibavPacket[] = [];\n for (const pkt of packets) {\n await libav.ff_copyin_packet(bsfPkt, pkt);\n const sendErr = await libav.av_bsf_send_packet(bsfCtx, bsfPkt);\n if (sendErr < 0) { out.push(pkt); continue; }\n while (true) {\n const recvErr = await libav.av_bsf_receive_packet(bsfCtx, bsfPkt);\n if (recvErr < 0) break;\n out.push(await libav.ff_copyout_packet(bsfPkt));\n }\n }\n return out;\n }\n\n async function flushBSF(): Promise<void> {\n if (!bsfCtx || !bsfPkt) return;\n try {\n await libav.av_bsf_send_packet(bsfCtx, 0);\n while (true) {\n const err = await libav.av_bsf_receive_packet(bsfCtx, bsfPkt);\n if (err < 0) break;\n }\n } catch { /* ignore */ }\n }\n\n // ── Mutable state ─────────────────────────────────────────────────────\n let destroyed = false;\n let pumpToken = 0;\n let pumpRunning: Promise<void> | null = null;\n\n let packetsRead = 0;\n let videoFramesDecoded = 0;\n let audioFramesDecoded = 0;\n let videoChunksFed = 0;\n\n let syntheticVideoUs = 0;\n let syntheticAudioUs = 0;\n\n const videoTrackInfo = opts.context.videoTracks.find((t) => t.id === videoStream?.index);\n const videoFps = videoTrackInfo?.fps && videoTrackInfo.fps > 0 ? videoTrackInfo.fps : 30;\n const videoFrameStepUs = Math.max(1, Math.round(1_000_000 / videoFps));\n\n // ── Pump loop ─────────────────────────────────────────────────────────\n\n async function pumpLoop(myToken: number): Promise<void> {\n while (!destroyed && myToken === pumpToken) {\n let readErr: number;\n let packets: Record<number, LibavPacket[]>;\n try {\n [readErr, packets] = await libav.ff_read_frame_multi(fmt_ctx, readPkt, {\n limit: 16 * 1024,\n });\n } catch (err) {\n console.error(\"[avbridge] hybrid ff_read_frame_multi failed:\", err);\n return;\n }\n\n if (myToken !== pumpToken || destroyed) return;\n\n const videoPackets = videoStream ? packets[videoStream.index] : undefined;\n const audioPackets = audioStream ? packets[audioStream.index] : undefined;\n\n // Decode audio BEFORE video. Same rationale as fallback decoder\n // (POSTMORTEMS.md entry 1, fix #2): audio decode via libav's\n // ff_decode_multi is a blocking WASM call that prevents rAF from\n // firing. For heavy codecs like DTS, a single batch can take\n // 10-50 ms. Processing audio first ensures the audio scheduler is\n // fed before video decode starts, reducing perceived stutter.\n if (audioDec && audioPackets && audioPackets.length > 0) {\n await decodeAudioBatch(audioPackets, myToken);\n }\n if (myToken !== pumpToken || destroyed) return;\n\n // Yield to the event loop so the video renderer's rAF callback\n // can fire between the audio decode (blocking) and the video feed\n // (async). Without this, the renderer starves during DTS decode.\n await new Promise((r) => setTimeout(r, 0));\n if (myToken !== pumpToken || destroyed) return;\n\n // Feed video packets to WebCodecs VideoDecoder (after BSF if applicable)\n if (videoDecoder && videoPackets && videoPackets.length > 0) {\n const processed = await applyBSF(videoPackets);\n for (const pkt of processed) {\n if (myToken !== pumpToken || destroyed) return;\n sanitizePacketTimestamp(pkt, () => {\n const ts = syntheticVideoUs;\n syntheticVideoUs += videoFrameStepUs;\n return ts;\n }, videoTimeBase);\n try {\n const chunk = bridge.packetToEncodedVideoChunk(pkt, videoStream);\n videoDecoder.decode(chunk);\n videoChunksFed++;\n } catch (err) {\n if (videoChunksFed === 0) {\n console.warn(\"[avbridge] hybrid: packetToEncodedVideoChunk failed:\", err);\n fireFatal(`WebCodecs chunk creation failed: ${(err as Error).message}`);\n return;\n }\n }\n }\n }\n\n packetsRead += (videoPackets?.length ?? 0) + (audioPackets?.length ?? 0);\n\n // Backpressure: WebCodecs decodeQueueSize + audio buffer + renderer queue\n while (\n !destroyed &&\n myToken === pumpToken &&\n ((videoDecoder && videoDecoder.decodeQueueSize > 10) ||\n opts.audio.bufferAhead() > 2.0 ||\n opts.renderer.queueDepth() >= opts.renderer.queueHighWater)\n ) {\n await new Promise((r) => setTimeout(r, 50));\n }\n\n if (readErr === libav.AVERROR_EOF) {\n // Flush WebCodecs decoder\n if (videoDecoder && videoDecoder.state === \"configured\") {\n try { await videoDecoder.flush(); } catch { /* ignore */ }\n }\n // Flush libav audio decoder\n if (audioDec) await decodeAudioBatch([], myToken, true);\n return;\n }\n if (readErr && readErr !== 0 && readErr !== -libav.EAGAIN) {\n console.warn(\"[avbridge] hybrid ff_read_frame_multi returned\", readErr);\n return;\n }\n }\n }\n\n async function decodeAudioBatch(pkts: LibavPacket[], myToken: number, flush = false) {\n if (!audioDec || destroyed || myToken !== pumpToken) return;\n\n // For heavy codecs (DTS, AC3), decode in small sub-batches and yield\n // between them so the event loop can run rAF for video painting.\n // Each ff_decode_multi call is a blocking WASM invocation.\n const AUDIO_SUB_BATCH = 4; // packets per sub-batch\n let allFrames: LibavFrame[] = [];\n\n for (let i = 0; i < pkts.length; i += AUDIO_SUB_BATCH) {\n if (myToken !== pumpToken || destroyed) return;\n const slice = pkts.slice(i, i + AUDIO_SUB_BATCH);\n const isLast = i + AUDIO_SUB_BATCH >= pkts.length;\n try {\n const frames = await libav.ff_decode_multi(\n audioDec.c,\n audioDec.pkt,\n audioDec.frame,\n slice,\n isLast && flush ? { fin: true, ignoreErrors: true } : { ignoreErrors: true },\n );\n allFrames = allFrames.concat(frames);\n } catch (err) {\n console.error(\"[avbridge] hybrid audio decode failed:\", err);\n return;\n }\n // Yield between sub-batches so rAF can fire\n if (!isLast) await new Promise((r) => setTimeout(r, 0));\n }\n\n // Handle flush-only call (empty pkts array)\n if (pkts.length === 0 && flush) {\n try {\n allFrames = await libav.ff_decode_multi(\n audioDec.c, audioDec.pkt, audioDec.frame, [],\n { fin: true, ignoreErrors: true },\n );\n } catch (err) {\n console.error(\"[avbridge] hybrid audio flush failed:\", err);\n return;\n }\n }\n\n if (myToken !== pumpToken || destroyed) return;\n const frames = allFrames;\n\n for (const f of frames) {\n if (myToken !== pumpToken || destroyed) return;\n sanitizeFrameTimestamp(\n f,\n () => {\n const ts = syntheticAudioUs;\n const samples = f.nb_samples ?? 1024;\n const sampleRate = f.sample_rate ?? 44100;\n syntheticAudioUs += Math.round((samples * 1_000_000) / sampleRate);\n return ts;\n },\n audioTimeBase,\n );\n const samples = libavFrameToInterleavedFloat32(f);\n if (samples) {\n opts.audio.schedule(samples.data, samples.channels, samples.sampleRate);\n audioFramesDecoded++;\n }\n }\n }\n\n // Kick off initial pump\n pumpToken = 1;\n pumpRunning = pumpLoop(pumpToken).catch((err) =>\n console.error(\"[avbridge] hybrid pump failed:\", err),\n );\n\n return {\n onFatalError(handler: (reason: string) => void): void {\n fatalHandler = handler;\n // If fatal already fired before handler was attached, fire immediately\n if (fatalFired) handler(\"WebCodecs decode failed (error occurred before handler attached)\");\n },\n\n async destroy() {\n destroyed = true;\n pumpToken++;\n try { await pumpRunning; } catch { /* ignore */ }\n try { if (bsfCtx) await libav.av_bsf_free(bsfCtx); } catch { /* ignore */ }\n try { if (bsfPkt) await libav.av_packet_free?.(bsfPkt); } catch { /* ignore */ }\n try { if (videoDecoder && videoDecoder.state !== \"closed\") videoDecoder.close(); } catch { /* ignore */ }\n try { if (audioDec) await libav.ff_free_decoder?.(audioDec.c, audioDec.pkt, audioDec.frame); } catch { /* ignore */ }\n try { await libav.av_packet_free?.(readPkt); } catch { /* ignore */ }\n try { await libav.avformat_close_input_js(fmt_ctx); } catch { /* ignore */ }\n try { await inputHandle.detach(); } catch { /* ignore */ }\n },\n\n async setAudioTrack(trackId, timeSec) {\n if (audioStream && audioStream.index === trackId) return;\n const newStream = streams.find(\n (s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO && s.index === trackId,\n );\n if (!newStream) {\n console.warn(\"[avbridge] hybrid: setAudioTrack — no stream with id\", trackId);\n return;\n }\n\n const newToken = ++pumpToken;\n if (pumpRunning) {\n try { await pumpRunning; } catch { /* ignore */ }\n }\n if (destroyed) return;\n\n // Tear down old audio decoder, build new one.\n if (audioDec) {\n try { await libav.ff_free_decoder?.(audioDec.c, audioDec.pkt, audioDec.frame); } catch { /* ignore */ }\n audioDec = null;\n }\n try {\n const [, c, pkt, frame] = await libav.ff_init_decoder(newStream.codec_id, {\n codecpar: newStream.codecpar,\n });\n audioDec = { c, pkt, frame };\n audioTimeBase = newStream.time_base_num && newStream.time_base_den\n ? [newStream.time_base_num, newStream.time_base_den]\n : undefined;\n } catch (err) {\n console.warn(\n \"[avbridge] hybrid: setAudioTrack init failed — switching to no-audio:\",\n (err as Error).message,\n );\n audioDec = null;\n opts.audio.setNoAudio();\n }\n\n audioStream = newStream;\n\n // Re-seek demuxer to current time for the new track.\n try {\n const tsUs = Math.floor(timeSec * 1_000_000);\n const [tsLo, tsHi] = libav.f64toi64\n ? libav.f64toi64(tsUs)\n : [tsUs | 0, Math.floor(tsUs / 0x100000000)];\n await libav.av_seek_frame(\n fmt_ctx,\n -1,\n tsLo,\n tsHi,\n libav.AVSEEK_FLAG_BACKWARD ?? 0,\n );\n } catch (err) {\n console.warn(\"[avbridge] hybrid: setAudioTrack seek failed:\", err);\n }\n\n // Flush video decoder too — demuxer moved back to a keyframe.\n try {\n if (videoDecoder && videoDecoder.state === \"configured\") {\n await videoDecoder.flush();\n }\n } catch { /* ignore */ }\n await flushBSF();\n\n syntheticVideoUs = Math.round(timeSec * 1_000_000);\n syntheticAudioUs = Math.round(timeSec * 1_000_000);\n\n pumpRunning = pumpLoop(newToken).catch((err) =>\n console.error(\"[avbridge] hybrid pump failed (post-setAudioTrack):\", err),\n );\n },\n\n async seek(timeSec) {\n const newToken = ++pumpToken;\n if (pumpRunning) {\n try { await pumpRunning; } catch { /* ignore */ }\n }\n if (destroyed) return;\n\n try {\n const tsUs = Math.floor(timeSec * 1_000_000);\n const [tsLo, tsHi] = libav.f64toi64\n ? libav.f64toi64(tsUs)\n : [tsUs | 0, Math.floor(tsUs / 0x100000000)];\n await libav.av_seek_frame(\n fmt_ctx,\n -1,\n tsLo,\n tsHi,\n libav.AVSEEK_FLAG_BACKWARD ?? 0,\n );\n } catch (err) {\n console.warn(\"[avbridge] hybrid av_seek_frame failed:\", err);\n }\n\n // Flush WebCodecs VideoDecoder\n try {\n if (videoDecoder && videoDecoder.state === \"configured\") {\n await videoDecoder.flush();\n }\n } catch { /* ignore */ }\n\n // Flush libav audio decoder\n try {\n if (audioDec) await libav.avcodec_flush_buffers?.(audioDec.c);\n } catch { /* ignore */ }\n await flushBSF();\n\n syntheticVideoUs = Math.round(timeSec * 1_000_000);\n syntheticAudioUs = Math.round(timeSec * 1_000_000);\n\n pumpRunning = pumpLoop(newToken).catch((err) =>\n console.error(\"[avbridge] hybrid pump failed (post-seek):\", err),\n );\n },\n\n stats() {\n return {\n decoderType: \"webcodecs-hybrid\",\n packetsRead,\n videoFramesDecoded,\n videoChunksFed,\n audioFramesDecoded,\n bsfApplied: bsfCtx ? [\"mpeg4_unpack_bframes\"] : [],\n videoDecodeQueueSize: videoDecoder?.decodeQueueSize ?? 0,\n // Confirmed transport info — see fallback decoder for the pattern.\n _transport: inputHandle.transport === \"http-range\" ? \"http-range\" : \"memory\",\n _rangeSupported: inputHandle.transport === \"http-range\",\n ...opts.renderer.stats(),\n ...opts.audio.stats(),\n };\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Packet timestamp sanitizer for WebCodecs chunks.\n//\n// AVI packets often have AV_NOPTS_VALUE. The bridge's packetToEncodedVideoChunk\n// uses the packet's pts + time_base. We normalize to microseconds with a 1/1e6\n// time_base to avoid overflow.\n// ─────────────────────────────────────────────────────────────────────────────\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Bridge loader\n// ─────────────────────────────────────────────────────────────────────────────\n\nasync function loadBridge(): Promise<BridgeModule> {\n try {\n const wrapper = await import(\"../fallback/libav-import.js\");\n return wrapper.libavBridge as unknown as BridgeModule;\n } catch (err) {\n throw new Error(\n `failed to load libavjs-webcodecs-bridge: ${(err as Error).message}`,\n );\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Structural types\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface SoftDecoder {\n c: number;\n pkt: number;\n frame: number;\n}\n\ninterface LibavStream {\n index: number;\n codec_type: number;\n codec_id: number;\n codecpar: number;\n time_base_num?: number;\n time_base_den?: number;\n}\n\ninterface LibavPacket {\n data: Uint8Array;\n pts: number;\n ptshi?: number;\n duration?: number;\n durationhi?: number;\n flags: number;\n stream_index: number;\n time_base_num?: number;\n time_base_den?: number;\n}\n\ninterface LibavFrame {\n data: unknown;\n format: number;\n channels?: number;\n ch_layout_nb_channels?: number;\n sample_rate?: number;\n nb_samples?: number;\n pts?: number;\n ptshi?: number;\n width?: number;\n height?: number;\n}\n\ninterface LibavRuntime {\n AVMEDIA_TYPE_VIDEO: number;\n AVMEDIA_TYPE_AUDIO: number;\n AVERROR_EOF: number;\n EAGAIN: number;\n AVSEEK_FLAG_BACKWARD?: number;\n\n mkreadaheadfile(name: string, blob: Blob): Promise<void>;\n unlinkreadaheadfile(name: string): Promise<void>;\n ff_init_demuxer_file(name: string): Promise<[number, LibavStream[]]>;\n ff_read_frame_multi(\n fmt_ctx: number,\n pkt: number,\n opts?: { limit?: number },\n ): Promise<[number, Record<number, LibavPacket[]>]>;\n ff_init_decoder(\n codec: number | string,\n config?: { codecpar?: number; time_base?: [number, number] },\n ): Promise<[number, number, number, number]>;\n ff_decode_multi(\n c: number,\n pkt: number,\n frame: number,\n packets: LibavPacket[],\n opts?: { fin?: boolean; ignoreErrors?: boolean },\n ): Promise<LibavFrame[]>;\n ff_free_decoder?(c: number, pkt: number, frame: number): Promise<void>;\n av_packet_alloc(): Promise<number>;\n av_packet_free?(pkt: number): Promise<void>;\n av_seek_frame(\n fmt_ctx: number,\n stream: number,\n tsLo: number,\n tsHi: number,\n flags: number,\n ): Promise<number>;\n avcodec_flush_buffers?(c: number): Promise<void>;\n avformat_close_input_js(ctx: number): Promise<void>;\n f64toi64?(val: number): [number, number];\n\n // BSF methods\n av_bsf_list_parse_str_js(str: string): Promise<number>;\n AVBSFContext_par_in(ctx: number): Promise<number>;\n avcodec_parameters_copy(dst: number, src: number): Promise<number>;\n av_bsf_init(ctx: number): Promise<number>;\n av_bsf_send_packet(ctx: number, pkt: number): Promise<number>;\n av_bsf_receive_packet(ctx: number, pkt: number): Promise<number>;\n av_bsf_free(ctx: number): Promise<void>;\n ff_copyin_packet(pktPtr: number, packet: LibavPacket): Promise<void>;\n ff_copyout_packet(pkt: number): Promise<LibavPacket>;\n}\n\ninterface BridgeModule {\n videoStreamToConfig(libav: unknown, stream: unknown): Promise<VideoDecoderConfig | null>;\n packetToEncodedVideoChunk(pkt: unknown, stream: unknown): EncodedVideoChunk;\n}\n","import type { MediaContext, PlaybackSession, TransportConfig } from \"../../types.js\";\nimport { VideoRenderer } from \"../fallback/video-renderer.js\";\nimport { AudioOutput } from \"../fallback/audio-output.js\";\nimport { startHybridDecoder, type HybridDecoderHandles } from \"./decoder.js\";\n\n/**\n * Hybrid strategy session.\n *\n * Uses libav.js for demuxing + WebCodecs VideoDecoder for hardware-accelerated\n * video decode + libav.js software decode for audio. Same canvas + Web Audio\n * output as the fallback strategy.\n *\n * Falls back to the pure-WASM fallback strategy if WebCodecs fails (via the\n * onFatalError callback that the player wires to its escalation mechanism).\n */\n\nconst READY_AUDIO_BUFFER_SECONDS = 0.3;\nconst READY_TIMEOUT_SECONDS = 10;\n\nexport async function createHybridSession(\n ctx: MediaContext,\n target: HTMLVideoElement,\n transport?: TransportConfig,\n): Promise<PlaybackSession> {\n // Normalize the source so URL inputs go through the libav HTTP block\n // reader instead of being buffered into memory.\n const { normalizeSource } = await import(\"../../util/source.js\");\n const source = await normalizeSource(ctx.source);\n\n const fps = ctx.videoTracks[0]?.fps ?? 30;\n const audio = new AudioOutput();\n const renderer = new VideoRenderer(target, audio, fps);\n\n let handles: HybridDecoderHandles;\n try {\n handles = await startHybridDecoder({\n source,\n filename: ctx.name ?? \"input.bin\",\n context: ctx,\n renderer,\n audio,\n transport,\n });\n } catch (err) {\n audio.destroy();\n renderer.destroy();\n throw err;\n }\n\n // Patch <video> element for the unified player layer. The underlying\n // <video> never has its own src; all playback state lives in the audio\n // clock + canvas renderer. We expose that state via property getters\n // so standard HTMLMediaElement consumers (like <avbridge-player>'s\n // controls UI) see the real values.\n Object.defineProperty(target, \"currentTime\", {\n configurable: true,\n get: () => audio.now(),\n set: (v: number) => { void doSeek(v); },\n });\n Object.defineProperty(target, \"paused\", {\n configurable: true,\n get: () => !audio.isPlaying(),\n });\n Object.defineProperty(target, \"volume\", {\n configurable: true,\n get: () => audio.getVolume(),\n set: (v: number) => {\n audio.setVolume(v);\n target.dispatchEvent(new Event(\"volumechange\"));\n },\n });\n Object.defineProperty(target, \"muted\", {\n configurable: true,\n get: () => audio.getMuted(),\n set: (m: boolean) => {\n audio.setMuted(m);\n target.dispatchEvent(new Event(\"volumechange\"));\n },\n });\n if (ctx.duration && Number.isFinite(ctx.duration)) {\n Object.defineProperty(target, \"duration\", {\n configurable: true,\n get: () => ctx.duration ?? NaN,\n });\n }\n\n async function waitForBuffer(): Promise<void> {\n const start = performance.now();\n while (true) {\n const audioReady = audio.isNoAudio() || audio.bufferAhead() >= READY_AUDIO_BUFFER_SECONDS;\n if (audioReady && renderer.hasFrames()) {\n return;\n }\n if ((performance.now() - start) / 1000 > READY_TIMEOUT_SECONDS) return;\n await new Promise((r) => setTimeout(r, 50));\n }\n }\n\n async function doSeek(timeSec: number): Promise<void> {\n const wasPlaying = audio.isPlaying();\n await audio.pause().catch(() => {});\n await handles.seek(timeSec).catch((err) =>\n console.warn(\"[avbridge] hybrid decoder seek failed:\", err),\n );\n await audio.reset(timeSec);\n renderer.flush();\n if (wasPlaying) {\n await waitForBuffer();\n await audio.start();\n }\n }\n\n // Store the fatal error handler so the player can wire escalation\n let fatalErrorHandler: ((reason: string) => void) | null = null;\n handles.onFatalError((reason) => fatalErrorHandler?.(reason));\n\n return {\n strategy: \"hybrid\",\n\n async play() {\n if (!audio.isPlaying()) {\n await waitForBuffer();\n await audio.start();\n // Dispatch play/playing events so HTMLMediaElement consumers\n // (e.g. <avbridge-player>'s controls UI) update their state.\n target.dispatchEvent(new Event(\"play\"));\n target.dispatchEvent(new Event(\"playing\"));\n }\n },\n\n pause() {\n void audio.pause();\n target.dispatchEvent(new Event(\"pause\"));\n },\n\n async seek(time) {\n await doSeek(time);\n },\n\n async setAudioTrack(id) {\n if (!ctx.audioTracks.some((t) => t.id === id)) {\n console.warn(\"[avbridge] hybrid: setAudioTrack — unknown track id\", id);\n return;\n }\n const wasPlaying = audio.isPlaying();\n const currentTime = audio.now();\n await audio.pause().catch(() => {});\n await handles.setAudioTrack(id, currentTime).catch((err) =>\n console.warn(\"[avbridge] hybrid: handles.setAudioTrack failed:\", err),\n );\n await audio.reset(currentTime);\n renderer.flush();\n if (wasPlaying) {\n await waitForBuffer();\n await audio.start();\n }\n },\n\n async setSubtitleTrack(_id) {\n // Post-MVP for hybrid strategy\n },\n\n getCurrentTime() {\n return audio.now();\n },\n\n onFatalError(handler: (reason: string) => void) {\n fatalErrorHandler = handler;\n },\n\n async destroy() {\n await handles.destroy();\n renderer.destroy();\n audio.destroy();\n try {\n delete (target as unknown as Record<string, unknown>).currentTime;\n delete (target as unknown as Record<string, unknown>).duration;\n delete (target as unknown as Record<string, unknown>).paused;\n delete (target as unknown as Record<string, unknown>).volume;\n delete (target as unknown as Record<string, unknown>).muted;\n } catch { /* ignore */ }\n },\n\n getRuntimeStats() {\n return handles.stats();\n },\n };\n}\n","/**\n * libav.js demux + decode loop for the fallback strategy.\n *\n * Design:\n *\n * - **Always software decode.** The fallback strategy is only entered when\n * classification has decided no browser decoder will handle the codec set,\n * so the WebCodecs hardware path is dead weight here. Going through libav\n * uniformly also avoids brittleness around `EncodedAudioChunk` framing for\n * codecs like MP3-in-AVI where the browser's AudioDecoder rejects libav's\n * raw demuxed packets.\n *\n * - **Cancellable pump loop.** Each pump iteration is gated on a token that\n * `seek()` increments. When the token changes mid-batch, the loop exits\n * and a fresh one starts at the new position. This is how seek interrupts\n * the decoder cleanly without having to await an arbitrarily long\n * `ff_decode_multi` call.\n *\n * - **Synthetic timestamps.** AVI demuxers report `AV_NOPTS_VALUE` for most\n * packets — they're frame-indexed, not time-indexed. We replace any\n * invalid pts with a per-stream synthetic counter (frame index × 1e6/fps\n * for video; sample-accurate for audio) so the bridge's chunk constructor\n * doesn't overflow int64.\n */\n\nimport { loadLibav, type LibavVariant } from \"./libav-loader.js\";\nimport { VideoRenderer } from \"./video-renderer.js\";\nimport { AudioOutput } from \"./audio-output.js\";\nimport type { MediaContext } from \"../../types.js\";\nimport { pickLibavVariant } from \"./variant-routing.js\";\nimport { dbg } from \"../../util/debug.js\";\nimport {\n sanitizeFrameTimestamp,\n libavFrameToInterleavedFloat32,\n} from \"../../util/libav-demux.js\";\n\nexport interface DecoderHandles {\n destroy(): Promise<void>;\n /** Seek to the given time in seconds. Returns once the new pump has been kicked off. */\n seek(timeSec: number): Promise<void>;\n /**\n * Switch the active audio track. The decoder tears down the current audio\n * decoder, initializes one for the stream whose container id matches\n * `trackId` (== libav `stream.index`), seeks the demuxer to `timeSec`, and\n * restarts the pump. No-op if the track is already active.\n */\n setAudioTrack(trackId: number, timeSec: number): Promise<void>;\n stats(): Record<string, unknown>;\n}\n\nexport interface StartDecoderOptions {\n /** Normalized source — either a Blob in memory or a URL we'll stream via Range requests. */\n source: import(\"../../util/source.js\").NormalizedSource;\n filename: string;\n context: MediaContext;\n renderer: VideoRenderer;\n audio: AudioOutput;\n transport?: import(\"../../types.js\").TransportConfig;\n}\n\nexport async function startDecoder(opts: StartDecoderOptions): Promise<DecoderHandles> {\n const variant: LibavVariant = pickLibavVariant(opts.context);\n const libav = (await loadLibav(variant)) as unknown as LibavRuntime;\n const bridge = await loadBridge();\n\n // For URL sources, prepareLibavInput attaches an HTTP block reader so\n // libav demuxes via Range requests. For Blob sources, it falls back to\n // mkreadaheadfile (in-memory). The returned handle owns cleanup.\n const { prepareLibavInput } = await import(\"../../util/libav-http-reader.js\");\n const inputHandle = await prepareLibavInput(libav as unknown as Parameters<typeof prepareLibavInput>[0], opts.filename, opts.source, opts.transport);\n\n // Pre-allocate one AVPacket for ff_read_frame_multi to reuse.\n const readPkt = await libav.av_packet_alloc();\n\n const [fmt_ctx, streams] = await libav.ff_init_demuxer_file(opts.filename);\n const videoStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_VIDEO) ?? null;\n // Audio stream is mutable so setAudioTrack() can swap it. Default to the\n // track the context picked first (matches probe ordering). We resolve by\n // container id so the selection survives stream reordering.\n const firstAudioTrackId = opts.context.audioTracks[0]?.id;\n let audioStream: LibavStream | null =\n (firstAudioTrackId != null\n ? streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO && s.index === firstAudioTrackId)\n : undefined) ??\n streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO) ?? null;\n\n if (!videoStream && !audioStream) {\n throw new Error(\"fallback decoder: file has no decodable streams\");\n }\n\n // ── Set up software decoders ─────────────────────────────────────────\n let videoDec: SoftDecoder | null = null;\n let audioDec: SoftDecoder | null = null;\n let videoTimeBase: [number, number] | undefined;\n let audioTimeBase: [number, number] | undefined;\n\n if (videoStream) {\n try {\n const [, c, pkt, frame] = await libav.ff_init_decoder(videoStream.codec_id, {\n codecpar: videoStream.codecpar,\n });\n videoDec = { c, pkt, frame };\n if (videoStream.time_base_num && videoStream.time_base_den) {\n videoTimeBase = [videoStream.time_base_num, videoStream.time_base_den];\n }\n } catch (err) {\n console.error(\"[avbridge] failed to init video decoder:\", err);\n }\n }\n\n if (audioStream) {\n try {\n const [, c, pkt, frame] = await libav.ff_init_decoder(audioStream.codec_id, {\n codecpar: audioStream.codecpar,\n });\n audioDec = { c, pkt, frame };\n if (audioStream.time_base_num && audioStream.time_base_den) {\n audioTimeBase = [audioStream.time_base_num, audioStream.time_base_den];\n }\n } catch (err) {\n console.warn(\n \"[avbridge] fallback: audio decoder unavailable — playing video with wall-clock timing:\",\n (err as Error).message,\n );\n }\n }\n\n // No audio decoder? Switch audio output into wall-clock mode so video can\n // play even when the audio codec isn't supported by the loaded libav variant.\n if (!audioDec) {\n opts.audio.setNoAudio();\n }\n\n if (!videoDec && !audioDec) {\n await inputHandle.detach().catch(() => {});\n const codecs = [\n videoStream ? `video: ${opts.context.videoTracks[0]?.codec ?? \"unknown\"}` : null,\n audioStream ? `audio: ${opts.context.audioTracks[0]?.codec ?? \"unknown\"}` : null,\n ].filter(Boolean).join(\", \");\n const hint = variant === \"webcodecs\"\n ? ` The \"${variant}\" libav variant does not include software decoders for these codecs. ` +\n `Try the custom \"avbridge\" variant (scripts/build-libav.sh) for broader codec support, ` +\n `or use a lighter strategy (native, remux, hybrid) instead.`\n : \"\";\n throw new Error(\n `fallback decoder: could not initialize any libav decoders (${codecs}).${hint}`,\n );\n }\n\n // ── Bitstream filter for MPEG-4 Part 2 packed B-frames ───────────────\n // Applied unconditionally for mpeg4 video — the BSF is a no-op when\n // the stream doesn't actually have packed B-frames, so false positives\n // are harmless. Without it, DivX files with packed B-frames produce\n // garbled frame ordering.\n let bsfCtx: number | null = null;\n let bsfPkt: number | null = null;\n if (videoStream && opts.context.videoTracks[0]?.codec === \"mpeg4\") {\n try {\n bsfCtx = await libav.av_bsf_list_parse_str_js(\"mpeg4_unpack_bframes\");\n if (bsfCtx != null && bsfCtx >= 0) {\n const parIn = await libav.AVBSFContext_par_in(bsfCtx);\n await libav.avcodec_parameters_copy(parIn, videoStream.codecpar);\n await libav.av_bsf_init(bsfCtx);\n bsfPkt = await libav.av_packet_alloc();\n dbg.info(\"bsf\", \"mpeg4_unpack_bframes BSF active\");\n } else {\n // eslint-disable-next-line no-console\n console.warn(\"[avbridge] mpeg4_unpack_bframes BSF not available — decoding without it\");\n bsfCtx = null;\n }\n } catch (err) {\n // eslint-disable-next-line no-console\n console.warn(\"[avbridge] failed to init mpeg4_unpack_bframes BSF:\", (err as Error).message);\n bsfCtx = null;\n bsfPkt = null;\n }\n }\n\n /** Run video packets through the BSF. Returns original packets if no BSF active. */\n async function applyBSF(packets: LibavPacket[]): Promise<LibavPacket[]> {\n if (!bsfCtx || !bsfPkt) return packets;\n const out: LibavPacket[] = [];\n for (const pkt of packets) {\n await libav.ff_copyin_packet(bsfPkt, pkt);\n const sendErr = await libav.av_bsf_send_packet(bsfCtx, bsfPkt);\n if (sendErr < 0) {\n out.push(pkt); // BSF rejected — pass through original\n continue;\n }\n while (true) {\n const recvErr = await libav.av_bsf_receive_packet(bsfCtx, bsfPkt);\n if (recvErr < 0) break; // EAGAIN or EOF\n out.push(await libav.ff_copyout_packet(bsfPkt));\n }\n }\n return out;\n }\n\n /** Flush the BSF (on seek or EOF) to drain any internally buffered packets. */\n async function flushBSF(): Promise<void> {\n if (!bsfCtx || !bsfPkt) return;\n try {\n await libav.av_bsf_send_packet(bsfCtx, 0);\n while (true) {\n const err = await libav.av_bsf_receive_packet(bsfCtx, bsfPkt);\n if (err < 0) break;\n }\n } catch { /* ignore flush errors */ }\n }\n\n // ── Mutable state shared across pump loops ───────────────────────────\n let destroyed = false;\n let pumpToken = 0; // bumped on seek; pump loops bail when token changes\n let pumpRunning: Promise<void> | null = null;\n\n let packetsRead = 0;\n let videoFramesDecoded = 0;\n let audioFramesDecoded = 0;\n\n // Decode-rate watchdog. Samples framesDecoded every second and\n // compares against realtime expected frames for the source fps. If\n // the decoder sustains less than 60% of realtime for more than\n // 5 seconds (counting only time since the first frame emerged),\n // emits a one-shot diagnostic so users know why playback is\n // stuttering instead of guessing. A second one-shot fires if the\n // renderer's overflow-drop rate exceeds 10% of decoded frames —\n // that symptom means the decoder is BURSTING faster than the\n // renderer can drain, which is a different bug from \"decoder slow\".\n let watchdogFirstFrameMs = 0;\n let watchdogSlowSinceMs = 0;\n let watchdogSlowWarned = false;\n let watchdogOverflowWarned = false;\n\n // Synthetic timestamp counters. Reset on seek.\n let syntheticVideoUs = 0;\n let syntheticAudioUs = 0;\n\n const videoTrackInfo = opts.context.videoTracks.find((t) => t.id === videoStream?.index);\n const videoFps = videoTrackInfo?.fps && videoTrackInfo.fps > 0 ? videoTrackInfo.fps : 30;\n const videoFrameStepUs = Math.max(1, Math.round(1_000_000 / videoFps));\n\n // ── Pump loop ─────────────────────────────────────────────────────────\n\n async function pumpLoop(myToken: number): Promise<void> {\n while (!destroyed && myToken === pumpToken) {\n let readErr: number;\n let packets: Record<number, LibavPacket[]>;\n try {\n // Batch size tunes the tradeoff between JS↔WASM call overhead\n // (small = more crossings per second) and queue burstiness\n // (large = decoder hands the renderer big bursts at once that\n // can blow past the renderer's 64-frame hard cap before the\n // per-batch `queueHighWater` throttle runs).\n //\n // We tried 64 KB and saw ~30% overflow drops on RMVB:rv40 at\n // 1024x768 because one decode batch regularly produced >30\n // frames. 16 KB keeps each batch ≈ 4-6 video packets at\n // typical bitrates, so the worst-case queue spike stays under\n // `queueHighWater` and the throttle has a chance to apply\n // backpressure *between* batches rather than within one.\n [readErr, packets] = await libav.ff_read_frame_multi(fmt_ctx, readPkt, {\n limit: 16 * 1024,\n });\n } catch (err) {\n console.error(\"[avbridge] ff_read_frame_multi failed:\", err);\n return;\n }\n\n if (myToken !== pumpToken || destroyed) return;\n\n const videoPackets = videoStream ? packets[videoStream.index] : undefined;\n const audioPackets = audioStream ? packets[audioStream.index] : undefined;\n\n // Decode audio BEFORE video. On software-decode-bound content\n // (rv40/mpeg4/wmv3 @ 720p+) a single video batch can take\n // 200-400 ms of wall time; if the scheduler hasn't been fed\n // during that window, audio output runs dry and the user hears\n // clicks/gaps. Audio is time-critical; video can drop a frame\n // and nobody notices. Audio decode is also typically <1 ms per\n // packet for cook/mp3/aac, so doing it first barely delays\n // video decoding at all.\n if (audioDec && audioPackets && audioPackets.length > 0) {\n await decodeAudioBatch(audioPackets, myToken);\n }\n if (myToken !== pumpToken || destroyed) return;\n if (videoDec && videoPackets && videoPackets.length > 0) {\n const processed = await applyBSF(videoPackets);\n await decodeVideoBatch(processed, myToken);\n }\n\n packetsRead += (videoPackets?.length ?? 0) + (audioPackets?.length ?? 0);\n\n // ── Decode-rate watchdog ──────────────────────────────────────\n if (videoFramesDecoded > 0) {\n if (watchdogFirstFrameMs === 0) {\n watchdogFirstFrameMs = performance.now();\n }\n const elapsedSinceFirst = (performance.now() - watchdogFirstFrameMs) / 1000;\n\n // 1. Slow-decode detection (sustained <60% of realtime fps).\n if (elapsedSinceFirst > 1 && !watchdogSlowWarned) {\n const expectedFrames = elapsedSinceFirst * videoFps;\n const ratio = videoFramesDecoded / expectedFrames;\n if (ratio < 0.6) {\n if (watchdogSlowSinceMs === 0) watchdogSlowSinceMs = performance.now();\n if ((performance.now() - watchdogSlowSinceMs) / 1000 > 5) {\n watchdogSlowWarned = true;\n console.warn(\n \"[avbridge:decode-rate]\",\n `decoder is running slower than realtime: ` +\n `${videoFramesDecoded} frames in ${elapsedSinceFirst.toFixed(1)}s ` +\n `(${(videoFramesDecoded / elapsedSinceFirst).toFixed(1)} fps vs ${videoFps} fps source — ` +\n `${(ratio * 100).toFixed(0)}% of realtime). ` +\n `Playback will stutter. Typical causes: software decode of a codec with no WebCodecs support ` +\n `(rv40, mpeg4 @ 720p+, wmv3), or a resolution too large for single-threaded WASM to keep up with.`,\n );\n }\n } else {\n watchdogSlowSinceMs = 0;\n }\n }\n\n // 2. Overflow-drop detection (>10% of decoded frames dropped\n // by the renderer's hard cap). This means the decoder\n // produces BURSTS — it's fast enough on average but one\n // batch delivers >30 frames at a time, overflowing before\n // the queueHighWater throttle can apply backpressure.\n // Symptom is different from \"decoder slow\": here the fps\n // ratio looks fine but the user sees choppy playback.\n if (\n !watchdogOverflowWarned &&\n videoFramesDecoded > 100 // wait for a meaningful sample\n ) {\n const rendererStats = opts.renderer.stats() as { framesDroppedOverflow?: number };\n const overflow = rendererStats.framesDroppedOverflow ?? 0;\n if (overflow / videoFramesDecoded > 0.1) {\n watchdogOverflowWarned = true;\n console.warn(\n \"[avbridge:overflow-drop]\",\n `renderer is dropping ${overflow}/${videoFramesDecoded} frames ` +\n `(${((overflow / videoFramesDecoded) * 100).toFixed(0)}%) because the decoder ` +\n `is producing bursts faster than the canvas can drain. Symptom: choppy ` +\n `playback despite decoder keeping up on average. Fix would be smaller ` +\n `read batches in the pump loop or a lower queueHighWater cap — see ` +\n `src/strategies/fallback/decoder.ts.`,\n );\n }\n }\n }\n\n // Throttle: don't run too far ahead of playback. Two backpressure\n // signals:\n // - Audio buffer (mediaTimeOfNext - now()) > 2 sec — we have\n // plenty of audio scheduled.\n // - Renderer queue depth >= queueHighWater — the canvas can't\n // drain fast enough. Without this, fast software decode of\n // small frames piles up in the renderer and overflows.\n while (\n !destroyed &&\n myToken === pumpToken &&\n (opts.audio.bufferAhead() > 2.0 ||\n opts.renderer.queueDepth() >= opts.renderer.queueHighWater)\n ) {\n await new Promise((r) => setTimeout(r, 50));\n }\n\n if (readErr === libav.AVERROR_EOF) {\n if (videoDec) await decodeVideoBatch([], myToken, /*flush*/ true);\n if (audioDec) await decodeAudioBatch([], myToken, /*flush*/ true);\n return;\n }\n if (readErr && readErr !== 0 && readErr !== -libav.EAGAIN) {\n console.warn(\"[avbridge] ff_read_frame_multi returned\", readErr);\n return;\n }\n }\n }\n\n async function decodeVideoBatch(pkts: LibavPacket[], myToken: number, flush = false) {\n if (!videoDec || destroyed || myToken !== pumpToken) return;\n let frames: LibavFrame[];\n try {\n frames = await libav.ff_decode_multi(\n videoDec.c,\n videoDec.pkt,\n videoDec.frame,\n pkts,\n flush ? { fin: true, ignoreErrors: true } : { ignoreErrors: true },\n );\n } catch (err) {\n console.error(\"[avbridge] video decode batch failed:\", err);\n return;\n }\n if (myToken !== pumpToken || destroyed) return;\n\n for (const f of frames) {\n if (myToken !== pumpToken || destroyed) return;\n sanitizeFrameTimestamp(\n f,\n () => {\n const ts = syntheticVideoUs;\n syntheticVideoUs += videoFrameStepUs;\n return ts;\n },\n videoTimeBase,\n );\n // sanitizeFrameTimestamp normalizes pts to µs, so the bridge can\n // always use the 1/1e6 timebase.\n try {\n const vf = bridge.laFrameToVideoFrame(f, { timeBase: [1, 1_000_000] });\n opts.renderer.enqueue(vf);\n videoFramesDecoded++;\n } catch (err) {\n if (videoFramesDecoded === 0) {\n console.warn(\"[avbridge] laFrameToVideoFrame failed:\", err);\n }\n }\n }\n }\n\n async function decodeAudioBatch(pkts: LibavPacket[], myToken: number, flush = false) {\n if (!audioDec || destroyed || myToken !== pumpToken) return;\n let frames: LibavFrame[];\n try {\n frames = await libav.ff_decode_multi(\n audioDec.c,\n audioDec.pkt,\n audioDec.frame,\n pkts,\n flush ? { fin: true, ignoreErrors: true } : { ignoreErrors: true },\n );\n } catch (err) {\n console.error(\"[avbridge] audio decode batch failed:\", err);\n return;\n }\n if (myToken !== pumpToken || destroyed) return;\n\n for (const f of frames) {\n if (myToken !== pumpToken || destroyed) return;\n sanitizeFrameTimestamp(\n f,\n () => {\n const ts = syntheticAudioUs;\n const samples = f.nb_samples ?? 1024;\n const sampleRate = f.sample_rate ?? 44100;\n syntheticAudioUs += Math.round((samples * 1_000_000) / sampleRate);\n return ts;\n },\n audioTimeBase,\n );\n const samples = libavFrameToInterleavedFloat32(f);\n if (samples) {\n opts.audio.schedule(samples.data, samples.channels, samples.sampleRate);\n audioFramesDecoded++;\n }\n }\n }\n\n // Kick off the initial pump.\n pumpToken = 1;\n pumpRunning = pumpLoop(pumpToken).catch((err) =>\n console.error(\"[avbridge] decoder pump failed:\", err),\n );\n\n return {\n async destroy() {\n destroyed = true;\n pumpToken++;\n try { await pumpRunning; } catch { /* ignore */ }\n try { if (bsfCtx) await libav.av_bsf_free(bsfCtx); } catch { /* ignore */ }\n try { if (bsfPkt) await libav.av_packet_free?.(bsfPkt); } catch { /* ignore */ }\n try { if (videoDec) await libav.ff_free_decoder?.(videoDec.c, videoDec.pkt, videoDec.frame); } catch { /* ignore */ }\n try { if (audioDec) await libav.ff_free_decoder?.(audioDec.c, audioDec.pkt, audioDec.frame); } catch { /* ignore */ }\n try { await libav.av_packet_free?.(readPkt); } catch { /* ignore */ }\n try { await libav.avformat_close_input_js(fmt_ctx); } catch { /* ignore */ }\n try { await inputHandle.detach(); } catch { /* ignore */ }\n },\n\n async setAudioTrack(trackId, timeSec) {\n if (audioStream && audioStream.index === trackId) return;\n const newStream = streams.find(\n (s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO && s.index === trackId,\n );\n if (!newStream) {\n console.warn(\"[avbridge] fallback: setAudioTrack — no stream with id\", trackId);\n return;\n }\n\n // Stop the pump before touching libav state. Same discipline as seek().\n const newToken = ++pumpToken;\n if (pumpRunning) {\n try { await pumpRunning; } catch { /* ignore */ }\n }\n if (destroyed) return;\n\n // Tear down the old audio decoder and init a fresh one for the new stream.\n if (audioDec) {\n try { await libav.ff_free_decoder?.(audioDec.c, audioDec.pkt, audioDec.frame); } catch { /* ignore */ }\n audioDec = null;\n }\n try {\n const [, c, pkt, frame] = await libav.ff_init_decoder(newStream.codec_id, {\n codecpar: newStream.codecpar,\n });\n audioDec = { c, pkt, frame };\n audioTimeBase = newStream.time_base_num && newStream.time_base_den\n ? [newStream.time_base_num, newStream.time_base_den]\n : undefined;\n } catch (err) {\n console.warn(\n \"[avbridge] fallback: setAudioTrack init failed — falling back to no-audio mode:\",\n (err as Error).message,\n );\n audioDec = null;\n opts.audio.setNoAudio();\n }\n\n audioStream = newStream;\n\n // Re-seek so packets resume from the user's current position for the\n // new track (and the same video position).\n try {\n const tsUs = Math.floor(timeSec * 1_000_000);\n const [tsLo, tsHi] = libav.f64toi64\n ? libav.f64toi64(tsUs)\n : [tsUs | 0, Math.floor(tsUs / 0x100000000)];\n await libav.av_seek_frame(\n fmt_ctx,\n -1,\n tsLo,\n tsHi,\n libav.AVSEEK_FLAG_BACKWARD ?? 0,\n );\n } catch (err) {\n console.warn(\"[avbridge] fallback: setAudioTrack seek failed:\", err);\n }\n\n // Flush the video decoder too — we just moved the demuxer back to a\n // keyframe boundary.\n try { if (videoDec) await libav.avcodec_flush_buffers?.(videoDec.c); } catch { /* ignore */ }\n await flushBSF();\n\n syntheticVideoUs = Math.round(timeSec * 1_000_000);\n syntheticAudioUs = Math.round(timeSec * 1_000_000);\n\n pumpRunning = pumpLoop(newToken).catch((err) =>\n console.error(\"[avbridge] fallback pump failed (post-setAudioTrack):\", err),\n );\n },\n\n async seek(timeSec) {\n // Cancel the current pump and wait for it to actually exit before\n // we start moving file pointers around — concurrent ff_decode_multi\n // and av_seek_frame on the same context would be a recipe for memory\n // corruption inside libav.\n const newToken = ++pumpToken;\n if (pumpRunning) {\n try { await pumpRunning; } catch { /* ignore */ }\n }\n if (destroyed) return;\n\n try {\n // libav.js's `av_seek_frame` takes the timestamp as a *split*\n // (lo, hi) int64 pair, NOT a single number. The function signature\n // is: av_seek_frame(s, stream_index, tsLo, tsHi, flags). Passing a\n // single number put AVSEEK_FLAG_BACKWARD (1) into tsHi, which\n // produced a bogus int64 = 4.29e9 + tsLo ≈ 73 min for any small\n // seek target — seeking past EOF and stalling the pump.\n const tsUs = Math.floor(timeSec * 1_000_000);\n const [tsLo, tsHi] = libav.f64toi64\n ? libav.f64toi64(tsUs)\n : [tsUs | 0, Math.floor(tsUs / 0x100000000)];\n await libav.av_seek_frame(\n fmt_ctx,\n -1,\n tsLo,\n tsHi,\n libav.AVSEEK_FLAG_BACKWARD ?? 0,\n );\n } catch (err) {\n console.warn(\"[avbridge] av_seek_frame failed:\", err);\n }\n\n // Reset the decoder state. After the previous pump exited via the\n // EOF path it called ff_decode_multi with `fin: true`, which sends a\n // NULL packet to the decoder and puts it in drain mode — meaning all\n // subsequent decode calls return EOF. `avcodec_flush_buffers` clears\n // that state so a fresh stream of post-seek packets is accepted.\n // Also clears any internal frame reordering buffer, which is what we\n // want anyway since we just changed positions.\n try {\n if (videoDec) await libav.avcodec_flush_buffers?.(videoDec.c);\n } catch { /* ignore */ }\n try {\n if (audioDec) await libav.avcodec_flush_buffers?.(audioDec.c);\n } catch { /* ignore */ }\n await flushBSF();\n\n // Reset synthetic timestamp counters to the seek target so newly\n // decoded frames start at the right media time.\n syntheticVideoUs = Math.round(timeSec * 1_000_000);\n syntheticAudioUs = Math.round(timeSec * 1_000_000);\n\n // The renderer & audio output are reset by the fallback session\n // wrapper that called us — see strategies/fallback/index.ts.\n\n // Start a fresh pump for the new token.\n pumpRunning = pumpLoop(newToken).catch((err) =>\n console.error(\"[avbridge] decoder pump failed (post-seek):\", err),\n );\n },\n\n stats() {\n return {\n decoderType: \"libav-wasm\",\n packetsRead,\n videoFramesDecoded,\n audioFramesDecoded,\n bsfApplied: bsfCtx ? [\"mpeg4_unpack_bframes\"] : [],\n // Confirmed transport info: once prepareLibavInput returns\n // successfully, we *know* whether the source is http-range (probe\n // succeeded and returned 206) or in-memory blob. Diagnostics hoists\n // these `_`-prefixed keys to the typed fields.\n _transport: inputHandle.transport === \"http-range\" ? \"http-range\" : \"memory\",\n _rangeSupported: inputHandle.transport === \"http-range\",\n ...opts.renderer.stats(),\n ...opts.audio.stats(),\n };\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Bridge loader (lazy via the static-import wrapper).\n// ─────────────────────────────────────────────────────────────────────────────\n\nasync function loadBridge(): Promise<BridgeModule> {\n try {\n const wrapper = await import(\"./libav-import.js\");\n return wrapper.libavBridge as unknown as BridgeModule;\n } catch (err) {\n throw new Error(\n `failed to load libavjs-webcodecs-bridge — install the optional peer deps with: ` +\n `npm i libavjs-webcodecs-bridge @libav.js/variant-webcodecs. ` +\n `(${(err as Error).message})`,\n );\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Structural types.\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface SoftDecoder {\n c: number;\n pkt: number;\n frame: number;\n}\n\ninterface LibavStream {\n index: number;\n codec_type: number;\n codec_id: number;\n codecpar: number;\n time_base_num?: number;\n time_base_den?: number;\n}\n\ninterface LibavPacket {\n data: Uint8Array;\n pts: number;\n ptshi?: number;\n duration?: number;\n durationhi?: number;\n flags: number;\n stream_index: number;\n time_base_num?: number;\n time_base_den?: number;\n}\n\ninterface LibavFrame {\n data: unknown;\n format: number;\n channels?: number;\n ch_layout_nb_channels?: number;\n sample_rate?: number;\n nb_samples?: number;\n pts?: number;\n ptshi?: number;\n width?: number;\n height?: number;\n}\n\ninterface LibavRuntime {\n AVMEDIA_TYPE_VIDEO: number;\n AVMEDIA_TYPE_AUDIO: number;\n AVERROR_EOF: number;\n EAGAIN: number;\n AVSEEK_FLAG_BACKWARD?: number;\n\n mkreadaheadfile(name: string, blob: Blob): Promise<void>;\n unlinkreadaheadfile(name: string): Promise<void>;\n ff_init_demuxer_file(name: string): Promise<[number, LibavStream[]]>;\n ff_read_frame_multi(\n fmt_ctx: number,\n pkt: number,\n opts?: { limit?: number },\n ): Promise<[number, Record<number, LibavPacket[]>]>;\n ff_init_decoder(\n codec: number | string,\n config?: { codecpar?: number; time_base?: [number, number] },\n ): Promise<[number, number, number, number]>;\n ff_decode_multi(\n c: number,\n pkt: number,\n frame: number,\n packets: LibavPacket[],\n opts?: { fin?: boolean; ignoreErrors?: boolean },\n ): Promise<LibavFrame[]>;\n ff_free_decoder?(c: number, pkt: number, frame: number): Promise<void>;\n av_packet_alloc(): Promise<number>;\n av_packet_free?(pkt: number): Promise<void>;\n av_seek_frame(\n fmt_ctx: number,\n stream: number,\n tsLo: number,\n tsHi: number,\n flags: number,\n ): Promise<number>;\n avcodec_flush_buffers?(c: number): Promise<void>;\n avformat_close_input_js(ctx: number): Promise<void>;\n /** Sync helper exposed by libav.js: split a JS number into (lo, hi) int64. */\n f64toi64?(val: number): [number, number];\n\n // BSF (bitstream filter) methods — used for mpeg4_unpack_bframes\n av_bsf_list_parse_str_js(str: string): Promise<number>;\n AVBSFContext_par_in(ctx: number): Promise<number>;\n avcodec_parameters_copy(dst: number, src: number): Promise<number>;\n av_bsf_init(ctx: number): Promise<number>;\n av_bsf_send_packet(ctx: number, pkt: number): Promise<number>;\n av_bsf_receive_packet(ctx: number, pkt: number): Promise<number>;\n av_bsf_free(ctx: number): Promise<void>;\n\n // Packet copy helpers — bridge JS packet objects to/from C-level pointers\n ff_copyin_packet(pktPtr: number, packet: LibavPacket): Promise<void>;\n ff_copyout_packet(pkt: number): Promise<LibavPacket>;\n}\n\ninterface BridgeModule {\n laFrameToVideoFrame(\n frame: LibavFrame,\n opts?: { VideoFrame?: unknown; timeBase?: [number, number]; transfer?: boolean },\n ): VideoFrame;\n laFrameToAudioData(\n frame: LibavFrame,\n opts?: { AudioData?: unknown; timeBase?: [number, number] },\n ): AudioData;\n}\n","import type { MediaContext, PlaybackSession, TransportConfig } from \"../../types.js\";\nimport { VideoRenderer } from \"./video-renderer.js\";\nimport { AudioOutput } from \"./audio-output.js\";\nimport { startDecoder, type DecoderHandles } from \"./decoder.js\";\nimport { dbg } from \"../../util/debug.js\";\n\n/**\n * Fallback strategy session.\n *\n * Owns the orchestration between the libav decoder, the audio scheduler,\n * and the canvas renderer. Three things make this non-trivial:\n *\n * 1. **Cold-start ready gate.** When `play()` is called, we wait until the\n * audio scheduler has buffered enough audio (≥ 300 ms) AND the renderer\n * has at least one decoded video frame, before actually telling the\n * audio context to start. Without this gate, audio and the wall clock\n * race ahead of the still-warming-up software decoder, and every video\n * frame lands \"in the past\" and gets dropped.\n *\n * 2. **Pause / resume.** The audio context is suspended on pause and\n * resumed on play. The media-time anchor is preserved across the\n * suspend so the clock is continuous.\n *\n * 3. **Seek.** Pauses the audio scheduler, asks the decoder to cancel its\n * current pump and `av_seek_frame` to the target, resets the audio\n * output's media-time anchor to the seek target, flushes the renderer\n * queue, then re-enters the ready gate. If we were playing before the\n * seek, we automatically resume once the buffer fills.\n *\n * The unified player API on top of this just sees `play() / pause() /\n * seek(t)` — none of the buffering choreography leaks out.\n */\n\n// Gate for cold-start playback. We want to start playing as soon as\n// there's any decoded output — the decoder will keep pumping during\n// playback, so more-is-better buffering only helps for fast decoders.\n//\n// For software-decode-bound content (rv40 / wmv3 / mpeg4 @ 720p+ on\n// single-threaded WASM), the decoder may run *slower* than realtime.\n// Waiting for a large audio-buffer threshold is actively wrong in that\n// case: it will never be reached, so the old gate would sit out its\n// full 10-second timeout before playing anything. An aggressive gate\n// ships the first frame to the screen fast, at the cost of the audio\n// clock racing a little ahead of video in the first few seconds —\n// which is the same situation we'd have been in after the timeout\n// anyway.\n//\n// READY_AUDIO_BUFFER_SECONDS: minimum audio queued before start. Set\n// low enough that a slow decoder still reaches it before the user\n// loses patience; 40 ms ≈ 2 cook packets or ~2 AAC packets.\n// READY_TIMEOUT_SECONDS: hard safety. If even 40 ms of audio can't be\n// produced in 3 s, give up and play whatever we have.\nconst READY_AUDIO_BUFFER_SECONDS = 0.04;\nconst READY_TIMEOUT_SECONDS = 3;\n\nexport async function createFallbackSession(\n ctx: MediaContext,\n target: HTMLVideoElement,\n transport?: TransportConfig,\n): Promise<PlaybackSession> {\n // Normalize the source so URL inputs go through the libav HTTP block\n // reader instead of being buffered into memory.\n const { normalizeSource } = await import(\"../../util/source.js\");\n const source = await normalizeSource(ctx.source);\n\n const fps = ctx.videoTracks[0]?.fps ?? 30;\n const audio = new AudioOutput();\n const renderer = new VideoRenderer(target, audio, fps);\n\n let handles: DecoderHandles;\n try {\n handles = await startDecoder({\n source,\n filename: ctx.name ?? \"input.bin\",\n context: ctx,\n renderer,\n audio,\n transport,\n });\n } catch (err) {\n audio.destroy();\n renderer.destroy();\n throw err;\n }\n\n // Patch the <video> element so the unified player layer (which polls\n // `target.currentTime` for `timeupdate` events and lets users assign to\n // it for seeks) gets the right values from the fallback strategy.\n Object.defineProperty(target, \"currentTime\", {\n configurable: true,\n get: () => audio.now(),\n set: (v: number) => {\n // Fire-and-forget — the user is expected to await player.seek() if\n // they want to know when the seek completes.\n void doSeek(v);\n },\n });\n // Mirror `paused` / `volume` / `muted` from the audio output — the\n // underlying <video> never has its own src, so its native state is\n // meaningless. This lets HTMLMediaElement consumers (<avbridge-player>\n // controls) see the real values and control volume through the audio\n // output's GainNode.\n Object.defineProperty(target, \"paused\", {\n configurable: true,\n get: () => !audio.isPlaying(),\n });\n Object.defineProperty(target, \"volume\", {\n configurable: true,\n get: () => audio.getVolume(),\n set: (v: number) => {\n audio.setVolume(v);\n target.dispatchEvent(new Event(\"volumechange\"));\n },\n });\n Object.defineProperty(target, \"muted\", {\n configurable: true,\n get: () => audio.getMuted(),\n set: (m: boolean) => {\n audio.setMuted(m);\n target.dispatchEvent(new Event(\"volumechange\"));\n },\n });\n // Mirror duration so the demo's controls can use target.duration too.\n if (ctx.duration && Number.isFinite(ctx.duration)) {\n Object.defineProperty(target, \"duration\", {\n configurable: true,\n get: () => ctx.duration ?? NaN,\n });\n }\n\n /**\n * Wait until the decoder has produced enough buffered output to start\n * playback smoothly. Returns early on timeout so we don't hang forever\n * if the decoder is producing nothing (e.g. immediately past EOF after\n * a seek to the end).\n *\n * The gate has three exit paths in order of preference:\n *\n * 1. **Fully ready** — audio buffer ≥ target AND ≥1 video frame.\n * The happy path for fast decoders (native + remux never reach\n * this function; this is fallback only).\n *\n * 2. **Video-ready, audio grace period elapsed** — we have video\n * frames but the audio scheduler is still empty. RM/AVI\n * containers commonly deliver a video GOP before their first\n * audio packet, so \"no audio yet\" ≠ \"no audio coming\". We give\n * the demuxer a 500 ms grace window from first-frame, then\n * start regardless. Audio will be scheduled at its correct\n * media time once its packets arrive.\n *\n * 3. **Hard timeout** — after {@link READY_TIMEOUT_SECONDS} seconds\n * with neither condition met, start anyway and emit an\n * unconditional diagnostic so the specific underflow is visible.\n *\n * Path #2 is what fixed the \"RMVB sits on the play button for 10 s\n * with audio=0ms, frames=N\" case — the gate was waiting on audio\n * packets that were several seconds behind in the file stream, and\n * the timeout was the only way out.\n */\n async function waitForBuffer(): Promise<void> {\n const start = performance.now();\n let firstFrameAtMs = 0;\n dbg.info(\"cold-start\",\n `gate entry: want audio ≥ ${READY_AUDIO_BUFFER_SECONDS * 1000}ms + 1 frame`,\n );\n while (true) {\n const audioAhead = audio.isNoAudio() ? Infinity : audio.bufferAhead();\n const audioReady = audio.isNoAudio() || audioAhead >= READY_AUDIO_BUFFER_SECONDS;\n const hasFrames = renderer.hasFrames();\n const nowMs = performance.now();\n\n if (hasFrames && firstFrameAtMs === 0) firstFrameAtMs = nowMs;\n\n // Happy path: both ready.\n if (audioReady && hasFrames) {\n dbg.info(\"cold-start\",\n `gate satisfied in ${(nowMs - start).toFixed(0)}ms ` +\n `(audio=${(audioAhead * 1000).toFixed(0)}ms, frames=${renderer.queueDepth()})`,\n );\n return;\n }\n\n // Grace path: have video, still waiting for audio that's\n // on its way (first 500 ms after first-frame).\n if (\n hasFrames &&\n firstFrameAtMs > 0 &&\n nowMs - firstFrameAtMs >= 500\n ) {\n dbg.info(\"cold-start\",\n `gate released on video-only grace at ${(nowMs - start).toFixed(0)}ms ` +\n `(frames=${renderer.queueDepth()}, audio=${(audioAhead * 1000).toFixed(0)}ms — ` +\n `demuxer hasn't delivered audio packets yet, starting anyway and letting ` +\n `the audio scheduler catch up at its media-time anchor)`,\n );\n return;\n }\n\n // Hard timeout.\n if ((nowMs - start) / 1000 > READY_TIMEOUT_SECONDS) {\n dbg.diag(\"cold-start\",\n `gate TIMEOUT after ${READY_TIMEOUT_SECONDS}s — ` +\n `audio=${(audioAhead * 1000).toFixed(0)}ms ` +\n `(needed ${READY_AUDIO_BUFFER_SECONDS * 1000}ms), ` +\n `frames=${renderer.queueDepth()} (needed ≥1). ` +\n `Decoder produced nothing in ${READY_TIMEOUT_SECONDS}s — either a corrupt source, ` +\n `a missing codec, or WASM is catastrophically slow on this file. ` +\n `Check getDiagnostics().runtime for decode counters.`,\n );\n return;\n }\n await new Promise((r) => setTimeout(r, 50));\n }\n }\n\n async function doSeek(timeSec: number): Promise<void> {\n const wasPlaying = audio.isPlaying();\n // 1. Stop audio (suspend ctx + capture media time).\n await audio.pause().catch(() => {});\n // 2. Tell the decoder to cancel its pump and seek the demuxer.\n await handles.seek(timeSec).catch((err) =>\n console.warn(\"[avbridge] decoder seek failed:\", err),\n );\n // 3. Reset audio + renderer to the new media time. New samples from\n // the decoder will queue against this anchor.\n await audio.reset(timeSec);\n renderer.flush();\n // 4. If we were playing, wait for the buffer to fill again and then\n // resume. If we were paused, leave it paused at the new position.\n if (wasPlaying) {\n await waitForBuffer();\n await audio.start();\n }\n }\n\n return {\n strategy: \"fallback\",\n\n async play() {\n // Either a cold start (very first play() call) or a resume from\n // pause. AudioOutput.start() handles both.\n if (!audio.isPlaying()) {\n await waitForBuffer();\n await audio.start();\n target.dispatchEvent(new Event(\"play\"));\n target.dispatchEvent(new Event(\"playing\"));\n }\n },\n\n pause() {\n void audio.pause();\n target.dispatchEvent(new Event(\"pause\"));\n },\n\n async seek(time) {\n await doSeek(time);\n },\n\n async setAudioTrack(id) {\n // Verify the id refers to a real track.\n if (!ctx.audioTracks.some((t) => t.id === id)) {\n console.warn(\"[avbridge] fallback: setAudioTrack — unknown track id\", id);\n return;\n }\n const wasPlaying = audio.isPlaying();\n const currentTime = audio.now();\n // Suspend audio, rebuild the decoder + seek, reset audio output, re-gate.\n await audio.pause().catch(() => {});\n await handles.setAudioTrack(id, currentTime).catch((err) =>\n console.warn(\"[avbridge] fallback: handles.setAudioTrack failed:\", err),\n );\n await audio.reset(currentTime);\n renderer.flush();\n if (wasPlaying) {\n await waitForBuffer();\n await audio.start();\n }\n },\n\n async setSubtitleTrack(_id) {\n // Subtitle overlay support is post-MVP for the fallback strategy.\n },\n\n getCurrentTime() {\n return audio.now();\n },\n async destroy() {\n await handles.destroy();\n renderer.destroy();\n audio.destroy();\n try {\n delete (target as unknown as Record<string, unknown>).currentTime;\n delete (target as unknown as Record<string, unknown>).duration;\n delete (target as unknown as Record<string, unknown>).paused;\n delete (target as unknown as Record<string, unknown>).volume;\n delete (target as unknown as Record<string, unknown>).muted;\n } catch { /* ignore */ }\n },\n\n getRuntimeStats() {\n return handles.stats();\n },\n };\n}\n","import type { Plugin } from \"../types.js\";\nimport { createNativeSession } from \"../strategies/native.js\";\nimport { createRemuxSession } from \"../strategies/remux/index.js\";\nimport { createHybridSession } from \"../strategies/hybrid/index.js\";\nimport { createFallbackSession } from \"../strategies/fallback/index.js\";\nimport type { PluginRegistry } from \"./registry.js\";\n\nconst nativePlugin: Plugin = {\n name: \"native\",\n canHandle: () => true,\n execute: (ctx, video) => createNativeSession(ctx, video),\n};\n\nconst remuxPlugin: Plugin = {\n name: \"remux\",\n canHandle: () => true,\n execute: (ctx, video) => createRemuxSession(ctx, video),\n};\n\nconst hybridPlugin: Plugin = {\n name: \"hybrid\",\n canHandle: () => typeof VideoDecoder !== \"undefined\",\n execute: (ctx, video, transport) => createHybridSession(ctx, video, transport),\n};\n\nconst fallbackPlugin: Plugin = {\n name: \"fallback\",\n canHandle: () => true,\n execute: (ctx, video, transport) => createFallbackSession(ctx, video, transport),\n};\n\nexport function registerBuiltins(registry: PluginRegistry): void {\n registry.register(nativePlugin);\n registry.register(remuxPlugin);\n registry.register(hybridPlugin);\n registry.register(fallbackPlugin);\n}\n","import { TypedEmitter } from \"./events.js\";\nimport { probe } from \"./probe/index.js\";\nimport { classify } from \"./classify/index.js\";\nimport { Diagnostics } from \"./diagnostics.js\";\nimport { PluginRegistry } from \"./plugins/registry.js\";\nimport { registerBuiltins } from \"./plugins/builtin.js\";\nimport { discoverSidecars, attachSubtitleTracks, SubtitleResourceBag } from \"./subtitles/index.js\";\nimport { dbg } from \"./util/debug.js\";\nimport type {\n Classification,\n CreatePlayerOptions,\n DiagnosticsSnapshot,\n MediaContext,\n PlaybackSession,\n PlayerEventMap,\n PlayerEventName,\n StrategyName,\n TransportConfig,\n Listener,\n} from \"./types.js\";\nimport { AvbridgeError, ERR_PLAYER_NOT_READY, ERR_ALL_STRATEGIES_EXHAUSTED } from \"./errors.js\";\n\nexport class UnifiedPlayer {\n private emitter = new TypedEmitter<PlayerEventMap>();\n private session: PlaybackSession | null = null;\n private diag = new Diagnostics();\n private timeupdateInterval: ReturnType<typeof setInterval> | null = null;\n\n // Saved from bootstrap for strategy switching\n private mediaContext: MediaContext | null = null;\n private classification: Classification | null = null;\n\n // Stall detection\n private stallTimer: ReturnType<typeof setInterval> | null = null;\n private lastProgressTime = 0;\n private lastProgressPosition = -1;\n private errorListener: (() => void) | null = null;\n\n // Bound so we can removeEventListener in destroy(); without this the\n // listener outlives the player and accumulates on elements that swap\n // source (e.g. <avbridge-video>).\n private endedListener: (() => void) | null = null;\n\n // Background tab handling. userIntent is what the user last asked for\n // (play vs pause) — used to decide whether to auto-resume on visibility\n // return. autoPausedForVisibility tracks whether we paused because the\n // tab was hidden, so we don't resume playback the user deliberately\n // paused (e.g. via media keys while hidden).\n private userIntent: \"play\" | \"pause\" = \"pause\";\n private autoPausedForVisibility = false;\n private visibilityListener: (() => void) | null = null;\n\n // Serializes escalation / setStrategy calls\n private switchingPromise: Promise<void> = Promise.resolve();\n\n // Owns blob URLs created during sidecar discovery + SRT->VTT conversion.\n // Revoked at destroy() so repeated source swaps don't leak.\n private subtitleResources = new SubtitleResourceBag();\n\n // Transport config extracted from CreatePlayerOptions. Threaded to probe,\n // subtitle fetches, and strategy session creators. Not stored on MediaContext\n // because it's runtime config, not media analysis.\n private readonly transport: TransportConfig | undefined;\n\n /**\n * @internal Use {@link createPlayer} or {@link UnifiedPlayer.create} instead.\n */\n private constructor(\n private readonly options: CreatePlayerOptions,\n private readonly registry: PluginRegistry,\n ) {\n const { requestInit, fetchFn } = options;\n if (requestInit || fetchFn) {\n this.transport = { requestInit, fetchFn };\n }\n }\n\n static async create(options: CreatePlayerOptions): Promise<UnifiedPlayer> {\n const registry = new PluginRegistry();\n registerBuiltins(registry);\n if (options.plugins) {\n for (const p of options.plugins) registry.register(p, /* prepend */ true);\n }\n const player = new UnifiedPlayer(options, registry);\n try {\n await player.bootstrap();\n } catch (err) {\n (err as Error & { player?: UnifiedPlayer }).player = player;\n throw err;\n }\n return player;\n }\n\n private async bootstrap(): Promise<void> {\n const bootstrapStart = performance.now();\n try {\n dbg.info(\"bootstrap\", \"start\");\n const ctx = await dbg.timed(\"probe\", \"probe\", 3000, () => probe(this.options.source, this.transport));\n dbg.info(\"probe\",\n `container=${ctx.container} video=${ctx.videoTracks[0]?.codec ?? \"-\"} ` +\n `audio=${ctx.audioTracks[0]?.codec ?? \"-\"} probedBy=${ctx.probedBy}`,\n );\n this.diag.recordProbe(ctx);\n this.mediaContext = ctx;\n\n // Merge sidecar / explicit subtitles\n if (this.options.subtitles) {\n for (const s of this.options.subtitles) {\n ctx.subtitleTracks.push({\n id: ctx.subtitleTracks.length,\n format: s.format ?? (s.url.endsWith(\".srt\") ? \"srt\" : \"vtt\"),\n language: s.language,\n sidecarUrl: s.url,\n });\n }\n }\n if (this.options.directory && this.options.source instanceof File) {\n const found = await discoverSidecars(this.options.source, this.options.directory);\n for (const s of found) {\n // Track every blob URL we adopted from discovery so it gets\n // revoked at destroy() — otherwise repeated source changes leak.\n this.subtitleResources.track(s.url);\n ctx.subtitleTracks.push({\n id: ctx.subtitleTracks.length,\n format: s.format,\n language: s.language,\n sidecarUrl: s.url,\n });\n }\n }\n\n const decision = this.options.initialStrategy\n ? buildInitialDecision(this.options.initialStrategy, ctx)\n : classify(ctx);\n dbg.info(\"classify\",\n `strategy=${decision.strategy} class=${decision.class} reason=\"${decision.reason}\"` +\n (decision.fallbackChain ? ` fallback=${decision.fallbackChain.join(\"→\")}` : \"\"),\n );\n this.classification = decision;\n this.diag.recordClassification(decision);\n\n this.emitter.emitSticky(\"strategy\", {\n strategy: decision.strategy,\n reason: decision.reason,\n });\n\n // Try the primary strategy, falling through the chain on failure\n await this.startSession(decision.strategy, decision.reason);\n\n // Apply subtitles for all strategies. Native/remux render them via\n // the inner <video>'s native text-track engine. Hybrid/fallback\n // hide the <video> and render cues into the canvas overlay — see\n // each session's SubtitleOverlay wiring. The <track> elements are\n // attached in both cases so cues are parsed by the browser.\n await attachSubtitleTracks(\n this.options.target,\n ctx.subtitleTracks,\n this.subtitleResources,\n (err, track) => {\n // eslint-disable-next-line no-console\n console.warn(`[avbridge] subtitle ${track.id} failed: ${err.message}`);\n },\n this.transport,\n );\n\n this.emitter.emitSticky(\"tracks\", {\n video: ctx.videoTracks,\n audio: ctx.audioTracks,\n subtitle: ctx.subtitleTracks,\n });\n\n this.startTimeupdateLoop();\n this.endedListener = () => this.emitter.emit(\"ended\", undefined);\n this.options.target.addEventListener(\"ended\", this.endedListener);\n\n // Auto-pause on background tab (unless explicitly opted out).\n // Chrome throttles rAF and setTimeout in hidden tabs, so playback\n // degrades anyway — better to pause cleanly and resume on return.\n if (this.options.backgroundBehavior !== \"continue\" && typeof document !== \"undefined\") {\n this.visibilityListener = () => this.onVisibilityChange();\n document.addEventListener(\"visibilitychange\", this.visibilityListener);\n }\n\n this.emitter.emitSticky(\"ready\", undefined);\n const bootstrapElapsed = performance.now() - bootstrapStart;\n dbg.info(\"bootstrap\", `ready in ${bootstrapElapsed.toFixed(0)}ms`);\n if (bootstrapElapsed > 5000) {\n // eslint-disable-next-line no-console\n console.warn(\n \"[avbridge:bootstrap]\",\n `total bootstrap time ${bootstrapElapsed.toFixed(0)}ms — unusually slow. ` +\n `Enable globalThis.AVBRIDGE_DEBUG for a per-phase breakdown.`,\n );\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n this.diag.recordError(e);\n this.emitter.emit(\"error\", e);\n throw e;\n }\n }\n\n /**\n * Try to start a session with the given strategy. On failure, walk the\n * fallback chain. Throws only if all strategies are exhausted.\n */\n private async startSession(strategy: StrategyName, reason: string): Promise<void> {\n const plugin = this.registry.findFor(this.mediaContext!, strategy);\n if (!plugin) {\n throw new Error(`no plugin available for strategy \"${strategy}\"`);\n }\n\n try {\n this.session = await plugin.execute(this.mediaContext!, this.options.target, this.transport);\n } catch (err) {\n // Try the fallback chain\n const chain = this.classification?.fallbackChain;\n if (chain && chain.length > 0) {\n const next = chain.shift()!;\n console.warn(`[avbridge] ${strategy} failed (${(err as Error).message}), escalating to ${next}`);\n this.emitter.emit(\"strategychange\", {\n from: strategy,\n to: next,\n reason: `${strategy} failed: ${(err as Error).message}`,\n currentTime: 0,\n });\n this.diag.recordStrategySwitch(next, `${strategy} failed: ${(err as Error).message}`);\n return this.startSession(next, `escalated from ${strategy}`);\n }\n throw err;\n }\n\n // Wire up fatal error handler for hybrid/fallback escalation\n this.session.onFatalError?.((fatalReason) => {\n void this.escalate(fatalReason);\n });\n\n // Attach stall supervisor\n this.attachSupervisor();\n\n // Update sticky strategy event if we ended up on a different strategy\n if (this.session.strategy !== strategy) {\n this.emitter.emitSticky(\"strategy\", {\n strategy: this.session.strategy,\n reason,\n });\n }\n }\n\n // ── Escalation ──────────────────────────────────────────────────────────\n\n private async escalate(reason: string): Promise<void> {\n // Serialize with other switch operations\n this.switchingPromise = this.switchingPromise.then(() =>\n this.doEscalate(reason),\n ).catch((err) => {\n this.emitter.emit(\"error\", err instanceof Error ? err : new Error(String(err)));\n });\n await this.switchingPromise;\n }\n\n private async doEscalate(reason: string): Promise<void> {\n const chain = this.classification?.fallbackChain;\n if (!chain || chain.length === 0) {\n this.emitter.emit(\"error\", new Error(\n `strategy \"${this.session?.strategy}\" failed: ${reason} (no fallback available)`,\n ));\n return;\n }\n\n const currentTime = this.session?.getCurrentTime() ?? 0;\n const wasPlaying = this.session ? !this.options.target.paused : false;\n const fromStrategy = this.session?.strategy ?? \"native\";\n\n // Tear down the current session before walking the chain — once we\n // commit to escalating, the existing session is going away regardless\n // of which fallback step succeeds.\n this.clearSupervisor();\n if (this.session) {\n try { await this.session.destroy(); } catch { /* ignore */ }\n this.session = null;\n }\n\n // Walk every remaining entry in the chain. Previously this method\n // popped exactly one entry and gave up if its plugin failed to start —\n // a recoverable failure in one fallback step blocked later viable\n // strategies (inconsistent with startSession() which already loops).\n const errors: string[] = [];\n while (chain.length > 0) {\n const nextStrategy = chain.shift()!;\n console.warn(`[avbridge] escalating from ${fromStrategy} to ${nextStrategy}: ${reason}`);\n\n this.emitter.emit(\"strategychange\", {\n from: fromStrategy,\n to: nextStrategy,\n reason,\n currentTime,\n });\n this.diag.recordStrategySwitch(nextStrategy, reason);\n\n const plugin = this.registry.findFor(this.mediaContext!, nextStrategy);\n if (!plugin) {\n errors.push(`${nextStrategy}: no plugin available`);\n continue;\n }\n\n try {\n this.session = await plugin.execute(this.mediaContext!, this.options.target, this.transport);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n errors.push(`${nextStrategy}: ${msg}`);\n console.warn(`[avbridge] ${nextStrategy} failed during escalation, trying next: ${msg}`);\n continue;\n }\n\n // Success — finish wiring and restore playback.\n this.emitter.emitSticky(\"strategy\", {\n strategy: nextStrategy,\n reason: `escalated: ${reason}`,\n });\n this.session.onFatalError?.((fatalReason) => {\n void this.escalate(fatalReason);\n });\n this.attachSupervisor();\n try {\n await this.session.seek(currentTime);\n if (wasPlaying) await this.session.play();\n } catch (err) {\n console.warn(\"[avbridge] failed to restore position after escalation:\", err);\n }\n return;\n }\n\n // Chain exhausted with no working strategy.\n this.emitter.emit(\"error\", new AvbridgeError(\n ERR_ALL_STRATEGIES_EXHAUSTED,\n `All playback strategies failed: ${errors.join(\"; \")}`,\n \"This file may require a codec or container that isn't available in this browser. Try the fallback strategy or check browser codec support.\",\n ));\n }\n\n // ── Stall supervision ─────────────────────────────────────────────────\n\n private attachSupervisor(): void {\n this.clearSupervisor();\n if (this.options.autoEscalate === false) return;\n if (!this.classification?.fallbackChain?.length) return;\n\n const strategy = this.session?.strategy;\n if (strategy === \"native\" || strategy === \"remux\") {\n // Monitor currentTime progress\n this.lastProgressPosition = this.options.target.currentTime;\n this.lastProgressTime = performance.now();\n\n this.stallTimer = setInterval(() => {\n const t = this.options.target;\n if (t.paused || t.ended || t.readyState < 2) {\n this.lastProgressPosition = t.currentTime;\n this.lastProgressTime = performance.now();\n return;\n }\n if (t.currentTime !== this.lastProgressPosition) {\n this.lastProgressPosition = t.currentTime;\n this.lastProgressTime = performance.now();\n return;\n }\n if (performance.now() - this.lastProgressTime > 5000) {\n void this.escalate(\n `${strategy} strategy stalled for 5s at ${t.currentTime.toFixed(1)}s`,\n );\n }\n }, 1000);\n\n // Listen for media element errors\n const onError = () => {\n void this.escalate(\n `${strategy} strategy error: ${this.options.target.error?.message ?? \"unknown\"}`,\n );\n };\n this.options.target.addEventListener(\"error\", onError, { once: true });\n this.errorListener = onError;\n }\n // Hybrid/fallback escalation is handled via onFatalError callback\n }\n\n private clearSupervisor(): void {\n if (this.stallTimer) {\n clearInterval(this.stallTimer);\n this.stallTimer = null;\n }\n if (this.errorListener) {\n this.options.target.removeEventListener(\"error\", this.errorListener);\n this.errorListener = null;\n }\n }\n\n // ── Public: manual strategy switch ────────────────────────────────────\n\n /** Manually switch to a different playback strategy. Preserves current position and play/pause state. Concurrent calls are serialized. */\n async setStrategy(strategy: StrategyName, reason?: string): Promise<void> {\n if (!this.mediaContext) throw new AvbridgeError(ERR_PLAYER_NOT_READY, \"Player not ready — wait for the 'ready' event before calling playback methods.\", \"Await the 'ready' event or check player.readyState before calling play/pause/seek.\");\n if (this.session?.strategy === strategy) return;\n\n this.switchingPromise = this.switchingPromise.then(() =>\n this.doSetStrategy(strategy, reason),\n );\n await this.switchingPromise;\n }\n\n private async doSetStrategy(strategy: StrategyName, reason?: string): Promise<void> {\n const currentTime = this.session?.getCurrentTime() ?? 0;\n const wasPlaying = this.session ? !this.options.target.paused : false;\n const fromStrategy = this.session?.strategy ?? \"native\";\n const switchReason = reason ?? `manual switch to ${strategy}`;\n\n this.emitter.emit(\"strategychange\", {\n from: fromStrategy,\n to: strategy,\n reason: switchReason,\n currentTime,\n });\n this.diag.recordStrategySwitch(strategy, switchReason);\n\n this.clearSupervisor();\n if (this.session) {\n try { await this.session.destroy(); } catch { /* ignore */ }\n this.session = null;\n }\n\n const plugin = this.registry.findFor(this.mediaContext!, strategy);\n if (!plugin) throw new Error(`no plugin available for strategy \"${strategy}\"`);\n\n this.session = await plugin.execute(this.mediaContext!, this.options.target, this.transport);\n\n this.emitter.emitSticky(\"strategy\", {\n strategy,\n reason: switchReason,\n });\n\n this.session.onFatalError?.((fatalReason) => {\n void this.escalate(fatalReason);\n });\n this.attachSupervisor();\n\n try {\n await this.session.seek(currentTime);\n if (wasPlaying) await this.session.play();\n } catch (err) {\n console.warn(\"[avbridge] failed to restore position after strategy switch:\", err);\n }\n }\n\n // ── Timeupdate loop ───────────────────────────────────────────────────\n\n private startTimeupdateLoop(): void {\n this.timeupdateInterval = setInterval(() => {\n const t = this.session?.getCurrentTime() ?? this.options.target.currentTime;\n this.emitter.emit(\"timeupdate\", { currentTime: t });\n }, 250);\n }\n\n // ── Public API ────────────────────────────────────────────────────────\n\n /** Subscribe to a player event. Returns an unsubscribe function. Sticky events (strategy, ready, tracks) replay for late subscribers. */\n on<K extends PlayerEventName>(event: K, fn: Listener<PlayerEventMap[K]>): () => void {\n return this.emitter.on(event, fn);\n }\n\n /** Remove a previously registered event listener. */\n off<K extends PlayerEventName>(event: K, fn: Listener<PlayerEventMap[K]>): void {\n this.emitter.off(event, fn);\n }\n\n /** Begin or resume playback. Throws if the player is not ready. */\n async play(): Promise<void> {\n if (!this.session) throw new AvbridgeError(ERR_PLAYER_NOT_READY, \"Player not ready — wait for the 'ready' event before calling playback methods.\", \"Await the 'ready' event or check player.readyState before calling play/pause/seek.\");\n this.userIntent = \"play\";\n this.autoPausedForVisibility = false;\n await this.session.play();\n }\n\n /** Pause playback. No-op if the player is not ready or already paused. */\n pause(): void {\n this.userIntent = \"pause\";\n this.autoPausedForVisibility = false;\n this.session?.pause();\n }\n\n /**\n * Handle browser tab visibility changes. On hide: pause if the user\n * had been playing. On show: resume if we were the one who paused.\n * Skips when `backgroundBehavior: \"continue\"` is set (listener isn't\n * installed in that case).\n */\n private onVisibilityChange(): void {\n if (!this.session) return;\n const action = decideVisibilityAction({\n hidden: document.hidden,\n userIntent: this.userIntent,\n sessionIsPlaying: !this.options.target.paused,\n autoPausedForVisibility: this.autoPausedForVisibility,\n });\n if (action === \"pause\") {\n this.autoPausedForVisibility = true;\n dbg.info(\"visibility\", \"tab hidden — auto-paused\");\n this.session.pause();\n } else if (action === \"resume\") {\n this.autoPausedForVisibility = false;\n dbg.info(\"visibility\", \"tab visible — auto-resuming\");\n void this.session.play().catch((err) => {\n // eslint-disable-next-line no-console\n console.warn(\"[avbridge] auto-resume after tab return failed:\", err);\n });\n }\n }\n\n /** Seek to the given time in seconds. Throws if the player is not ready. */\n async seek(time: number): Promise<void> {\n if (!this.session) throw new AvbridgeError(ERR_PLAYER_NOT_READY, \"Player not ready — wait for the 'ready' event before calling playback methods.\", \"Await the 'ready' event or check player.readyState before calling play/pause/seek.\");\n await this.session.seek(time);\n }\n\n /** Switch the active audio track by track ID. Throws if the player is not ready. */\n async setAudioTrack(id: number): Promise<void> {\n if (!this.session) throw new AvbridgeError(ERR_PLAYER_NOT_READY, \"Player not ready — wait for the 'ready' event before calling playback methods.\", \"Await the 'ready' event or check player.readyState before calling play/pause/seek.\");\n await this.session.setAudioTrack(id);\n }\n\n /** Switch the active subtitle track by track ID, or pass `null` to disable subtitles. */\n async setSubtitleTrack(id: number | null): Promise<void> {\n if (!this.session) throw new AvbridgeError(ERR_PLAYER_NOT_READY, \"Player not ready — wait for the 'ready' event before calling playback methods.\", \"Await the 'ready' event or check player.readyState before calling play/pause/seek.\");\n await this.session.setSubtitleTrack(id);\n }\n\n /** Return a snapshot of current diagnostics: container, codecs, strategy, runtime stats, and strategy history. */\n getDiagnostics(): DiagnosticsSnapshot {\n if (this.session) {\n this.diag.recordRuntime(this.session.getRuntimeStats());\n }\n return this.diag.snapshot();\n }\n\n /** Return the total duration in seconds, or `NaN` if unknown. */\n getDuration(): number {\n const fromDiag = this.diag.snapshot().duration;\n if (typeof fromDiag === \"number\" && Number.isFinite(fromDiag)) return fromDiag;\n const fromVideo = this.options.target.duration;\n return Number.isFinite(fromVideo) ? fromVideo : NaN;\n }\n\n /** Return the current playback position in seconds. */\n getCurrentTime(): number {\n return this.session?.getCurrentTime() ?? this.options.target.currentTime ?? 0;\n }\n\n /** Tear down the player: stop timers, destroy the active session, remove all event listeners. The player is unusable after this call. */\n async destroy(): Promise<void> {\n if (this.timeupdateInterval) {\n clearInterval(this.timeupdateInterval);\n this.timeupdateInterval = null;\n }\n this.clearSupervisor();\n if (this.endedListener) {\n this.options.target.removeEventListener(\"ended\", this.endedListener);\n this.endedListener = null;\n }\n if (this.visibilityListener) {\n document.removeEventListener(\"visibilitychange\", this.visibilityListener);\n this.visibilityListener = null;\n }\n if (this.session) {\n await this.session.destroy();\n this.session = null;\n }\n // Revoke every blob URL we created for sidecar discovery / SRT->VTT\n // conversion. This is the cleanup leg of the leak fix.\n this.subtitleResources.revokeAll();\n this.emitter.removeAll();\n }\n}\n\nexport async function createPlayer(options: CreatePlayerOptions): Promise<UnifiedPlayer> {\n return UnifiedPlayer.create(options);\n}\n\n/**\n * Pure decision function for visibility-change handling. Separated from\n * the class method so it can be unit-tested without a full player\n * instance.\n *\n * @internal — exported for unit tests; not part of the public API.\n */\nexport function decideVisibilityAction(state: {\n hidden: boolean;\n userIntent: \"play\" | \"pause\";\n sessionIsPlaying: boolean;\n autoPausedForVisibility: boolean;\n}): \"pause\" | \"resume\" | \"noop\" {\n if (state.hidden) {\n // Tab hidden: pause if user had been playing and session is active\n if (state.userIntent === \"play\" && state.sessionIsPlaying) return \"pause\";\n return \"noop\";\n }\n // Tab visible: resume only if we're the one who paused\n if (state.autoPausedForVisibility) return \"resume\";\n return \"noop\";\n}\n\n/**\n * Build a synthetic classification for an explicit `initialStrategy` override.\n * The `class` is derived from the chosen strategy so diagnostics and any\n * downstream consumer of `strategyClass` see the real strategy. The fallback\n * chain is inherited from the natural classification but must never contain\n * `initial` itself — otherwise `startSession` would retry the strategy that\n * just failed before escalating.\n *\n * @internal — exported for unit tests; not part of the public API.\n */\nexport function buildInitialDecision(\n initial: StrategyName,\n ctx: MediaContext,\n): Classification {\n const natural = classify(ctx);\n const cls = strategyToClass(initial, natural);\n const inherited = natural.fallbackChain ?? defaultFallbackChain(initial);\n const fallbackChain = inherited.filter((s) => s !== initial);\n return {\n class: cls,\n strategy: initial,\n reason: `initial strategy \"${initial}\" requested via options.initialStrategy`,\n fallbackChain,\n };\n}\n\nfunction strategyToClass(\n strategy: StrategyName,\n natural: Classification,\n): Classification[\"class\"] {\n // If the natural classification picked the same strategy, use its class.\n if (natural.strategy === strategy) return natural.class;\n switch (strategy) {\n case \"native\": return \"NATIVE\";\n case \"remux\": return \"REMUX_CANDIDATE\";\n case \"hybrid\": return \"HYBRID_CANDIDATE\";\n case \"fallback\": return \"FALLBACK_REQUIRED\";\n }\n}\n\nfunction defaultFallbackChain(strategy: StrategyName): StrategyName[] {\n switch (strategy) {\n case \"native\": return [\"remux\", \"hybrid\", \"fallback\"];\n case \"remux\": return [\"hybrid\", \"fallback\"];\n case \"hybrid\": return [\"fallback\"];\n case \"fallback\": return [];\n }\n}\n"]}