avbridge 2.12.0 → 2.13.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.
- package/CHANGELOG.md +177 -0
- package/README.md +33 -0
- package/dist/{avi-EQE6AR75.cjs → avi-32UABODO.cjs} +12 -4
- package/dist/avi-32UABODO.cjs.map +1 -0
- package/dist/{avi-Y3N325WZ.cjs → avi-5BPR6QUX.cjs} +12 -4
- package/dist/avi-5BPR6QUX.cjs.map +1 -0
- package/dist/{avi-NNHH4AAA.js → avi-BLIH7KKV.js} +12 -4
- package/dist/avi-BLIH7KKV.js.map +1 -0
- package/dist/{avi-S7EY54YA.js → avi-GX2H34IQ.js} +12 -4
- package/dist/avi-GX2H34IQ.js.map +1 -0
- package/dist/{chunk-2LNXMGT6.js → chunk-5CX7BVVV.js} +5 -5
- package/dist/{chunk-2LNXMGT6.js.map → chunk-5CX7BVVV.js.map} +1 -1
- package/dist/{chunk-5Y5BTB5D.js → chunk-B76QWPFM.js} +3 -3
- package/dist/{chunk-5Y5BTB5D.js.map → chunk-B76QWPFM.js.map} +1 -1
- package/dist/{chunk-GJBNLPGI.cjs → chunk-E5MAM2P4.cjs} +9 -9
- package/dist/{chunk-GJBNLPGI.cjs.map → chunk-E5MAM2P4.cjs.map} +1 -1
- package/dist/{chunk-7EF4VTUS.cjs → chunk-OFJYEITB.cjs} +489 -113
- package/dist/chunk-OFJYEITB.cjs.map +1 -0
- package/dist/{chunk-HBHSUGNI.cjs → chunk-VLI3Y6IJ.cjs} +5 -5
- package/dist/{chunk-HBHSUGNI.cjs.map → chunk-VLI3Y6IJ.cjs.map} +1 -1
- package/dist/{chunk-Z26PXRUY.js → chunk-VOC24LYF.js} +486 -110
- package/dist/chunk-VOC24LYF.js.map +1 -0
- package/dist/element-browser.js +492 -130
- package/dist/element-browser.js.map +1 -1
- package/dist/element.cjs +3 -3
- package/dist/element.js +2 -2
- package/dist/index.cjs +18 -18
- package/dist/index.js +6 -6
- package/dist/player.cjs +658 -170
- package/dist/player.cjs.map +1 -1
- package/dist/player.d.cts +36 -4
- package/dist/player.d.ts +36 -4
- package/dist/player.js +658 -170
- package/dist/player.js.map +1 -1
- package/dist/{remux-VPKCLHHM.cjs → remux-NSBJFMLG.cjs} +9 -9
- package/dist/{remux-VPKCLHHM.cjs.map → remux-NSBJFMLG.cjs.map} +1 -1
- package/dist/{remux-7TA4FKTY.js → remux-PHUHO3VV.js} +4 -4
- package/dist/{remux-7TA4FKTY.js.map → remux-PHUHO3VV.js.map} +1 -1
- package/package.json +1 -1
- package/src/element/avbridge-player.ts +223 -43
- package/src/probe/avi.ts +34 -2
- package/src/strategies/fallback/audio-output.ts +164 -35
- package/src/strategies/fallback/decoder.ts +467 -60
- package/src/strategies/fallback/video-renderer.ts +209 -29
- package/src/strategies/hybrid/decoder.ts +56 -28
- package/src/strategies/remux/pipeline.ts +12 -3
- package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.mjs +1 -1
- package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.wasm +0 -0
- package/vendor/libav/avbridge/libav-avbridge.mjs +1 -1
- package/dist/avi-EQE6AR75.cjs.map +0 -1
- package/dist/avi-NNHH4AAA.js.map +0 -1
- package/dist/avi-S7EY54YA.js.map +0 -1
- package/dist/avi-Y3N325WZ.cjs.map +0 -1
- package/dist/chunk-7EF4VTUS.cjs.map +0 -1
- package/dist/chunk-Z26PXRUY.js.map +0 -1
|
@@ -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/util/time-ranges.ts","../src/strategies/hybrid/index.ts","../src/strategies/fallback/decoder.ts","../src/strategies/fallback/index.ts","../src/plugins/builtin.ts","../src/player.ts"],"names":["wallNow","frame","isDebug","drain","frames","loadBridge","READY_AUDIO_BUFFER_SECONDS","READY_TIMEOUT_SECONDS"],"mappings":"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","file":"chunk-VOC24LYF.js","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 StrategyName,\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 \"dv\", \"hq_hqa\",\n \"rawvideo\", \"qtrle\", \"png\", \"vp6f\",\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 // Feature-detect: the remux target is fragmented MP4 via MSE. If the\n // browser's MSE can't decode this codec combo (e.g. HEVC on\n // open-source Chromium — no proprietary codecs by design — or\n // future codec/container combos we haven't thought of), remux will\n // stall. Degrade gracefully: try hybrid (WebCodecs hardware decode)\n // or fallback (WASM software decode) without waiting for runtime\n // escalation.\n const mime = mp4MimeFor(video, audio);\n if (mime && typeof MediaSource !== \"undefined\" && !mseSupports(mime)) {\n if (webCodecsAvailable()) {\n return {\n class: \"HYBRID_CANDIDATE\",\n strategy: \"hybrid\",\n reason: `${ctx.container} container with ${video.codec}${audio ? \"/\" + audio.codec : \"\"}; MSE rejects the remux target mime — routing to WebCodecs hardware decode`,\n fallbackChain: [\"fallback\"],\n };\n }\n return {\n class: \"FALLBACK_REQUIRED\",\n strategy: \"fallback\",\n reason: `${ctx.container} container with ${video.codec}${audio ? \"/\" + audio.codec : \"\"}; MSE rejects the remux target mime and WebCodecs is unavailable — falling back to WASM decode`,\n };\n }\n // Give REMUX_CANDIDATE a fallback chain so the runtime stall / decode\n // supervisors have somewhere to escalate to when MSE lies about codec\n // support (the Firefox HEVC case — audio plays, video never paints).\n // The initial pick is still remux; these only engage on stall.\n const fallbackChain: StrategyName[] = webCodecsAvailable()\n ? [\"hybrid\", \"fallback\"]\n : [\"fallback\"];\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 fallbackChain,\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 // Capture the active pump token at the moment this output was created.\n // A subsequent seek bumps `pumpToken`, and any in-flight write from this\n // (now-stale) output must drop its chunk instead of appending to the\n // SourceBuffer — otherwise stale fragments land at their original\n // timestamps, the deferred seek applies against the wrong buffered\n // range, and the video snaps to the end of the stale range.\n const myToken = pumpToken;\n\n const writable = new WritableStream<{\n type: \"write\";\n data: Uint8Array<ArrayBuffer>;\n position: number;\n }>({\n write: async (chunk) => {\n if (destroyed || pumpToken !== myToken) return;\n if (!sink) {\n const mime = await (mimePromise ??= output.getMimeType());\n if (destroyed || pumpToken !== myToken) return;\n sink = new MseSink({ mime, video });\n await sink.ready();\n if (destroyed || pumpToken !== myToken) return;\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 && pumpToken === myToken && (sink.queueLength() > 10 || sink.bufferedAhead() > 60 || sink.totalBuffered() > 120)) {\n await new Promise((r) => setTimeout(r, 500));\n }\n if (destroyed || pumpToken !== myToken) 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 // HTMLMediaElement contract: Firefox + WebKit's MSE doesn't\n // reliably fire `seeked` after a SourceBuffer remove+refill\n // cycle (Chromium does). Dispatch manually so consumers get a\n // consistent signal across browsers. Duplicating a native\n // `seeked` is harmless per spec.\n queueMicrotask(() => {\n try { video.dispatchEvent(new Event(\"seeked\")); } catch { /* ignore */ }\n });\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 /** True once the head frame has been painted as a pre-roll poster\n * since the last flush. Used to ensure pre-roll paints exactly one\n * frame (held static) during the post-seek discard window. */\n private prerolled = false;\n /** PTS (µs) of the most recently painted frame. Used as the calibration\n * reference on the first post-flush snap: the pre-roll path paints one\n * frame *before* PTS-based playback starts, so the queue head's PTS at\n * first PTS-based paint is the *next* frame, off by one frameDur from\n * the actually-displayed frame. Calibrating against the painted frame\n * instead of the queue head removes that one-frame offset and yields\n * calib ≈ 0 instead of +frameDur. */\n private lastPaintedPtsUs = 0;\n private hasLastPaintedPts = false;\n /** Audio-clock reading (ms) at the previous paint, for overlay Δaud. */\n private lastPaintAudMs = 0;\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` is driven by the `--avbridge-fit` custom property so the\n // `<avbridge-video>` element's `fit` attribute can retarget the canvas\n // without reaching into the fallback strategy. Default is `contain` —\n // letterboxes the canvas bitmap (sized to frame.displayWidth ×\n // displayHeight in paint()) inside the stage so portrait / non-stage-aspect\n // content isn't stretched. Canvas is a 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:var(--avbridge-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 /**\n * True once at least one frame has been enqueued *since the last flush*.\n * Used by `readyState` — initial cold-start reports HAVE_NOTHING until\n * any frame has arrived, and after a seek we want the same semantics\n * (HAVE_NOTHING until post-seek frames arrive), so the cumulative\n * `framesPainted > 0` that used to live here was wrong: it kept the\n * state \"true forever\" after the first frame ever, so post-seek\n * `waitForBuffer()` would exit immediately with an empty queue and\n * leave video frozen while audio kept going.\n */\n hasFrames(): boolean {\n return this.queue.length > 0 || this.hasEverEnqueuedSinceFlush;\n }\n\n private hasEverEnqueuedSinceFlush = false;\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 * Cap the decoder may fill the queue up to. Used by the decoder's\n * enqueue-side discard logic (it closes new frames instead of pushing\n * them when this is reached). Sized so a long post-seek catch-up\n * fits — the decoder produces frames at PTS T_kf onwards rapidly\n * while the demuxer is chewing through pre-target audio; if the\n * queue can hold the whole post-seek burst, the renderer plays\n * smoothly from pre-roll without a frozen-video gap when audio.start\n * fires. At ~340 KB per SD frame the cap is ~85 MB peak; at HD it's\n * larger but still bounded.\n */\n readonly queueHighWater = 256;\n\n enqueue(frame: VideoFrame): void {\n if (this.destroyed) {\n frame.close();\n return;\n }\n this.queue.push(frame);\n this.hasEverEnqueuedSinceFlush = true;\n if (this.queue.length === 1 && this.framesPainted === 0) {\n this.resolveFirstFrame();\n }\n // Hard cap. The decoder's enqueue-side discard at `queueHighWater`\n // is the primary defense; this `+8` margin is just safety for a\n // racy producer. Drops the OLDEST frames, which during catch-up\n // would mean losing the frames closest to the seek target — so the\n // decoder should be tuned to never reach this.\n while (this.queue.length > this.queueHighWater + 8) {\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 head frame ONCE as a poster while audio buffers.\n //\n // Safety invariant (load-bearing): with the decoder.ts content-clock\n // fix (POSTMORTEMS 2026-06-01), pre-target frames are discarded at\n // the decoder/enqueue boundary, so queue[0] here is guaranteed to be\n // a near-target frame — never the keyframe-to-target preroll sequence\n // that previously caused the post-seek fast-forward when painted.\n //\n // Paint at most ONE frame and hold it (gate via `prerolled`). Do NOT\n // shift the queue: when audio unfreezes and `playing` becomes true,\n // the regular PTS loop below will paint this same frame again and\n // shift it out. That second paint is a no-op visually (same pixels)\n // so there's no flicker.\n //\n // If the queue is empty (decoder still grinding through the post-seek\n // discard window), just return — last pre-flush frame stays on canvas\n // as the freeze poster, which is the safe fallback.\n if (!playing) {\n if (!this.prerolled && this.queue.length > 0) {\n this.prerolled = true;\n this.paint(this.queue[0]);\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 //\n // Two cases for the *first* snap after flush:\n // - Anchor `rawAudioNowUs` against `clock.now()` (default for the\n // periodic 10s re-snap) drifts with the audio clock — including\n // decode-stall lag accumulated between `audio.start()` and the\n // first frame's arrival. On a slow seek where the first frame\n // lands 1–2s after audio resumed, this captures the lag as a\n // permanent offset and the video stays that far behind audio.\n // - For the *first* snap post-flush we instead use the audio's\n // **anchor time** (`mediaTimeOfAnchor`, == the seek target / 0\n // on cold start). That gives `headTs − seekTarget` ≈ keyframe\n // offset (usually < 100ms), independent of decode delay.\n const wallNow = performance.now();\n // First snap after flush/cold-start anchors against the audio's\n // *master-clock reference* (= `mediaTimeOfAnchor`, == the rebased\n // audio first-chunk PTS), NOT `clock.now()`. `clock.now()` includes\n // wall-clock-drifted elapsed time between `audio.start()` and the\n // first paint — on a slow seek where the first frame lands 1-2 s\n // after audio resumed, that decode delay gets baked into the\n // calibration as a permanent video-lag offset. See POSTMORTEMS.md\n // (2026-04-13). The periodic re-snap continues to use `rawAudioNow`\n // as the original design intended — a stateless independent snap\n // every 10 s bounds drift to ~70 ms at the documented ~7 ms/s rate,\n // below the lip-sync perception threshold. Do *not* introduce a\n // smoothed / EMA / bounded-delta variant here: the measured offset\n // includes the current calibration, which produces a feedback loop\n // (postmortem 2026-04-13, hypothesis 3).\n if (!this.ptsCalibrated) {\n const anchorUs = (this.clock.anchorTime?.() ?? this.clock.now()) * 1_000_000;\n // Reference frame for calibration: prefer the pre-rolled frame's\n // PTS over the queue head, since the pre-rolled frame is what the\n // user is *actually looking at* the moment audio starts. The queue\n // head at this point is the NEXT frame (PTS == prerolled + frameDur),\n // and calibrating against it bakes that one-frame offset into the\n // calibration permanently. With the painted-frame reference, calib\n // ≈ 0 when video keyframe lands at the seek target.\n const referencePtsUs = this.hasLastPaintedPts ? this.lastPaintedPtsUs : headTs;\n this.ptsCalibrationUs = referencePtsUs - anchorUs;\n this.ptsCalibrated = true;\n this.lastCalibrationWall = wallNow;\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(\n `[avbridge:renderer] CALIB-FIRST audioAnchor=${(anchorUs / 1000).toFixed(1)}ms ` +\n `prerolledPTS=${this.hasLastPaintedPts ? (this.lastPaintedPtsUs / 1000).toFixed(1) : \"n/a\"}ms ` +\n `queueHeadPTS=${(headTs / 1000).toFixed(1)}ms ` +\n `rawAudioNow=${(rawAudioNowUs / 1000).toFixed(1)}ms ` +\n `→ calib=${(this.ptsCalibrationUs / 1000).toFixed(1)}ms`,\n );\n }\n } else if (wallNow - this.lastCalibrationWall > 10_000) {\n const oldCalib = this.ptsCalibrationUs;\n this.ptsCalibrationUs = headTs - rawAudioNowUs;\n this.lastCalibrationWall = wallNow;\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(\n `[avbridge:renderer] CALIB-RESNAP ` +\n `headPTS=${(headTs / 1000).toFixed(1)}ms rawAudioNow=${(rawAudioNowUs / 1000).toFixed(1)}ms ` +\n `calib ${(oldCalib / 1000).toFixed(1)}ms → ${(this.ptsCalibrationUs / 1000).toFixed(1)}ms ` +\n `(Δ=${((this.ptsCalibrationUs - oldCalib) / 1000).toFixed(1)}ms after 10s)`,\n );\n }\n }\n\n const audioNowUs = rawAudioNowUs + this.ptsCalibrationUs;\n // Paint the frame whose PTS is at or just before audioNow. A frame\n // at PTS P should be the displayed frame from the moment audio\n // reaches P, *not* from P − frameDur. The previous code used\n // `deadline = audioNow + frameDur`, which painted frames up to one\n // source-frame ahead of audio — a steady ~40 ms video-leads-audio\n // offset that the user perceived as \"fast-forward then normal.\"\n // With `deadline = audioNow`, paints land exactly at the frame's\n // start of display interval; lip sync matches.\n const deadlineUs = audioNowUs;\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 // Audio-sync skip: when `bestIdx > 0` there are multiple frames in\n // the queue whose PTS ≤ deadline. Drop everything before `bestIdx`\n // and paint the latest paintable frame. See POSTMORTEMS.md\n // 2026-05-31 coda for the rationale.\n const _relaxDrop =\n (globalThis as { AVBRIDGE_RELAX_DROP?: boolean }).AVBRIDGE_RELAX_DROP === true;\n let dropped = 0;\n const initialBestIdx = bestIdx;\n if (!_relaxDrop) {\n while (bestIdx > 0) {\n this.queue.shift()?.close();\n this.framesDroppedLate++;\n bestIdx--;\n dropped++;\n }\n }\n const paintTs = this.queue[0]?.timestamp ?? 0;\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[TRACE] PAINT bestIdx_initial=${initialBestIdx} dropped=${dropped} paintPts=${(paintTs / 1000).toFixed(1)}ms audioNow=${(audioNowUs / 1000).toFixed(1)}ms deadline=${(deadlineUs / 1000).toFixed(1)}ms queueLen=${this.queue.length} wall=${performance.now().toFixed(0)}`);\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\n // Debug overlay (gated on AVBRIDGE_DEBUG). Draws frame info on top\n // of the painted frame so the user can SEE what's actually\n // displayed and at what rate. Three time domains:\n // pts — source content time (from frame.timestamp)\n // aud — audio media clock (clock.now() × 1000)\n // wall — performance.now() (monotonic browser clock)\n // Plus the per-paint deltas. If `Δpts > Δwall` sustained across\n // multiple frames, that's real fast-forward; if it alternates\n // 33/50ms on a 25fps source, that's 3:2 pulldown judder. (See\n // POSTMORTEMS 2026-06-01 for why this overlay was load-bearing\n // when diagnosing the post-seek fast-forward.)\n if (isDebug()) {\n const wallNow = performance.now();\n const audNowMs = this.clock.now() * 1000;\n const ptsMs = (frame.timestamp ?? 0) / 1000;\n const dWall = this.lastPaintWall > 0 ? wallNow - this.lastPaintWall : 0;\n const dAud = this.lastPaintAudMs > 0 ? audNowMs - this.lastPaintAudMs : 0;\n const dPts = this.hasLastPaintedPts ? ptsMs - this.lastPaintedPtsUs / 1000 : 0;\n this.ctx.save();\n this.ctx.font = \"bold 18px monospace\";\n const lines = [\n `#${this.framesPainted + 1} pts=${ptsMs.toFixed(0)} aud=${audNowMs.toFixed(0)} wall=${wallNow.toFixed(0)}`,\n `Δpts=${dPts.toFixed(0)} Δaud=${dAud.toFixed(0)} Δwall=${dWall.toFixed(0)}`,\n ];\n const lineHeight = 22;\n const padTop = 6;\n const stripH = padTop + lineHeight * lines.length;\n this.ctx.fillStyle = \"rgba(0,0,0,0.7)\";\n this.ctx.fillRect(0, 0, this.canvas.width, stripH);\n this.ctx.fillStyle = \"#0f0\";\n for (let i = 0; i < lines.length; i++) {\n this.ctx.fillText(lines[i], 8, padTop + lineHeight * (i + 1) - 4);\n }\n this.ctx.restore();\n }\n\n // Record the just-painted frame's PTS so the next paint's overlay\n // Δpts and the next CALIB-RESNAP have a reference. Must run\n // unconditionally — `hasLastPaintedPts`/`lastPaintedPtsUs` are read\n // by the calibration path in tick() too, not just the overlay.\n this.lastPaintedPtsUs = frame.timestamp ?? 0;\n this.hasLastPaintedPts = true;\n this.lastPaintAudMs = this.clock.now() * 1000;\n\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.hasLastPaintedPts = false; // calibration ref doesn't carry across seek\n this.ptsCalibrated = false; // recalibrate at new seek position\n this.hasEverEnqueuedSinceFlush = false; // so waitForBuffer() waits for post-flush frames\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 // Queue span — the gap between the oldest and newest queued frame's\n // PTS, in ms. If this collapses while audio keeps advancing, the\n // producer has stalled. If it stays wide with stale head, the\n // producer is bursting faster than realtime but the renderer can't\n // catch up.\n let queueSpanMs = 0;\n let queueHeadMs = 0;\n let queueTailMs = 0;\n if (this.queue.length > 0) {\n queueHeadMs = Math.round((this.queue[0].timestamp ?? 0) / 1000);\n queueTailMs = Math.round((this.queue[this.queue.length - 1].timestamp ?? 0) / 1000);\n queueSpanMs = Math.max(0, queueTailMs - queueHeadMs);\n }\n return {\n framesPainted: this.framesPainted,\n framesDroppedLate: this.framesDroppedLate,\n framesDroppedOverflow: this.framesDroppedOverflow,\n queueDepth: this.queue.length,\n queueHeadMs,\n queueTailMs,\n queueSpanMs,\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 /** Source-domain content PTS in seconds. `null` for legacy callers\n * that schedule sequentially without PTS information. */\n ptsSec: number | null;\n}\n\n/** True when `globalThis.AVBRIDGE_DEBUG` is set. Used to gate [TRACE-AUD]\n * per-chunk logs that are useful for diagnosing scheduling drift but\n * unreadable in normal use. */\nfunction isDebug(): boolean {\n return typeof globalThis !== \"undefined\"\n && !!(globalThis as Record<string, unknown>).AVBRIDGE_DEBUG;\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 * Media time at which the current playback session was anchored — i.e. the\n * seek target after the most recent `reset()`, or 0 on cold start. Used by\n * the video renderer for post-flush PTS calibration: `now()` includes any\n * decode-stall lag accumulated since playback resumed, but the anchor is\n * a stable reference that maps directly to the user's intended position.\n */\n anchorTime(): number;\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\n /**\n * Ctx time at which the first audible chunk will start playing. `-1`\n * before any chunk has been scheduled successfully (clock is frozen);\n * the actual ctx time once one has. The renderer's `clock.now()` uses\n * this to avoid advancing during the silent-gap window between\n * `audio.start()` and the first chunk that schedules without being\n * dropped — that gap is what produces the \"audio-less fast-forward\"\n * the user sees post-seek when the gate releases on video-only grace.\n */\n private firstAudibleCtxStart = -1;\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 /** Playback rate. Scales the media clock and each AudioBufferSourceNode's\n * playbackRate so audio pitches up/down accordingly (same as native\n * <video>.playbackRate). Default 1. */\n private _rate = 1;\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 /** Set playback rate. Scales the media clock and pitches audio output\n * (same as native <video>.playbackRate — speed without pitch correction).\n * Rebases the anchor so the clock transition is seamless. */\n setPlaybackRate(rate: number): void {\n if (rate === this._rate) return;\n // Rebase anchor at the current media time before changing rate,\n // so the clock doesn't jump.\n const t = this.now();\n this.mediaTimeOfAnchor = t;\n this.ctxTimeAtAnchor = this.ctx.currentTime;\n this.wallAnchorMs = performance.now();\n this._rate = rate;\n }\n\n getPlaybackRate(): number {\n return this._rate;\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 * this._rate;\n }\n return this.mediaTimeOfAnchor;\n }\n if (this.state === \"playing\") {\n // Freeze the clock until the first audio chunk has actually been\n // scheduled. Without this, when `audio.start()` fires before any\n // post-seek audio packets have made it through the decoder (e.g. the\n // gate's \"video-only grace\" path released early), `clock.now()`\n // would advance from `mediaTimeOfAnchor` at 1× wall time while the\n // audio scheduler is dropping every chunk that arrives (their\n // PTS-derived `ctxStart` is already in the past). The renderer would\n // paint frames during that silent window — the user perceives that\n // as a \"fast-forward burst with no audio.\" When the first chunk\n // finally arrives and schedules normally, `firstAudibleCtxStart` is\n // set and the clock unfreezes from there in sync with the audible\n // content's PTS.\n if (this.firstAudibleCtxStart < 0) {\n return this.mediaTimeOfAnchor;\n }\n return this.mediaTimeOfAnchor + (this.ctx.currentTime - this.ctxTimeAtAnchor) * this._rate;\n }\n return this.mediaTimeOfAnchor;\n }\n\n anchorTime(): number {\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 * `ptsSec` is the chunk's source-domain content PTS in seconds, from\n * the demuxer. When provided, the chunk plays at the ctx-time\n * corresponding to that PTS — so pre-target audio after a seek\n * naturally drops (its computed `ctxStart` falls in the past) and\n * post-target audio plays at its true content time, without any\n * external trim or anchor rebase. When `ptsSec` is null (cold start\n * with no PTS yet, or codecs whose packet→frame mapping isn't 1:1),\n * the chunk is scheduled sequentially after `mediaTimeOfNext` — the\n * pre-refactor behavior.\n */\n schedule(\n samples: Float32Array,\n channels: number,\n sampleRate: number,\n ptsSec?: number | null,\n ): void {\n if (this.destroyed || this.noAudio) return;\n const frameCount = samples.length / channels;\n const durationSec = frameCount / sampleRate;\n const hasPts = ptsSec != null && Number.isFinite(ptsSec);\n\n // Pre-target gate: a chunk whose entire PTS span is before the\n // current media anchor will be silently dropped by `scheduleNow`\n // (its `ctxStart` falls in the past). We must apply the same drop\n // here in idle/paused state too — otherwise the chunk sits in\n // `pendingQueue`, `bufferAhead()` reports it as buffered audio,\n // `waitForBuffer()`'s gate releases on a phantom audio buffer, and\n // `audio.start()` fires with a queue full of chunks that immediately\n // drop on drain. The user sees post-seek \"sped up no audio\" while\n // the demuxer slowly chews through pre-target packets — `clock.now()`\n // is advancing on wall time and the renderer paints video against\n // it, but `node.start()` is never being called.\n if (hasPts && (ptsSec as number) + durationSec / this._rate < this.mediaTimeOfAnchor) {\n return;\n }\n\n if (this.state === \"idle\" || this.state === \"paused\") {\n this.pendingQueue.push({\n samples, channels, sampleRate, frameCount, durationSec,\n ptsSec: hasPts ? (ptsSec as number) : null,\n });\n return;\n }\n\n this.scheduleNow(\n samples, channels, sampleRate, frameCount,\n hasPts ? (ptsSec as number) : null,\n );\n }\n\n private scheduleNow(\n samples: Float32Array,\n channels: number,\n sampleRate: number,\n frameCount: number,\n ptsSec: number | null,\n ): void {\n const durationSec = frameCount / sampleRate;\n\n // Compute ctxStart. Two paths:\n //\n // PTS-known: the chunk's content PTS maps to a specific ctx time\n // via (mediaTimeOfAnchor, ctxTimeAtAnchor). If that ctx time is\n // already in the past, the chunk represents audio the user should\n // have heard before now — drop it. After a seek, this is what\n // *automatically* skips pre-target audio packets returned by a\n // keyframe-aligned demuxer seek; no manual trim needed.\n //\n // PTS-unknown (legacy): chain after the last-scheduled sample\n // via `mediaTimeOfNext`. Same behavior as before the refactor.\n let ctxStart: number;\n if (ptsSec != null) {\n ctxStart = this.ctxTimeAtAnchor + (ptsSec - this.mediaTimeOfAnchor) / this._rate;\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[TRACE-AUD] PTS sched #${this.framesScheduled} pts=${ptsSec.toFixed(3)} dur=${durationSec.toFixed(4)} ctxStart=${ctxStart.toFixed(4)} ctxNow=${this.ctx.currentTime.toFixed(4)} anchor=${this.mediaTimeOfAnchor.toFixed(3)} ctxAnchor=${this.ctxTimeAtAnchor.toFixed(4)} mtNext=${this.mediaTimeOfNext.toFixed(3)} rate=${this._rate}`);\n }\n if (ctxStart < this.ctx.currentTime - 0.001) {\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[TRACE-AUD] DROP late chunk pts=${ptsSec.toFixed(3)} ctxStart=${ctxStart.toFixed(4)} < ctxNow=${this.ctx.currentTime.toFixed(4)}`);\n }\n return;\n }\n // First chunk to schedule successfully unfreezes `clock.now()`.\n // We rebase the anchor onto this chunk: when ctx reaches `ctxStart`,\n // clock should equal `ptsSec` (so `audioNow` matches audible content\n // PTS exactly when the chunk plays). The renderer's deadline will\n // then advance from there, in lockstep with what's audible.\n if (this.firstAudibleCtxStart < 0) {\n this.firstAudibleCtxStart = ctxStart;\n this.mediaTimeOfAnchor = ptsSec;\n this.ctxTimeAtAnchor = ctxStart;\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[TRACE-AUD] UNFREEZE clock — first audible chunk pts=${ptsSec.toFixed(3)} ctxStart=${ctxStart.toFixed(4)} → anchor=${this.mediaTimeOfAnchor.toFixed(3)} ctxAnchor=${this.ctxTimeAtAnchor.toFixed(4)}`);\n }\n }\n const endMediaTime = ptsSec + durationSec / this._rate;\n if (endMediaTime > this.mediaTimeOfNext) {\n this.mediaTimeOfNext = endMediaTime;\n }\n } else {\n ctxStart = this.ctxTimeAtAnchor + (this.mediaTimeOfNext - this.mediaTimeOfAnchor) / this._rate;\n // eslint-disable-next-line no-console\n console.warn(`[TRACE-AUD] LEGACY (no PTS) sched dur=${durationSec.toFixed(4)} ctxStart=${ctxStart.toFixed(4)} ctxNow=${this.ctx.currentTime.toFixed(4)}`);\n if (ctxStart < this.ctx.currentTime) {\n // eslint-disable-next-line no-console\n console.warn(`[TRACE-AUD] REBASE anchor was=${this.mediaTimeOfAnchor.toFixed(3)} ctxAnchor was=${this.ctxTimeAtAnchor.toFixed(4)} → anchor=${this.mediaTimeOfNext.toFixed(3)} ctxAnchor=${this.ctx.currentTime.toFixed(4)}`);\n this.ctxTimeAtAnchor = this.ctx.currentTime;\n this.mediaTimeOfAnchor = this.mediaTimeOfNext;\n ctxStart = this.ctx.currentTime;\n }\n this.mediaTimeOfNext += durationSec;\n }\n\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 if (this._rate !== 1) node.playbackRate.value = this._rate;\n node.start(ctxStart);\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 // Reconnect the gain node — pause() disconnects it to cut off\n // in-flight audio instantly. Safe to call even if already connected.\n try { this.gain.connect(this.ctx.destination); } catch { /* ignore */ }\n\n if (this.state === \"paused\") {\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[TRACE-AUD] START(resume) anchor=${this.mediaTimeOfAnchor.toFixed(3)} ctxAnchor=${this.ctxTimeAtAnchor.toFixed(4)} → ctxAnchor=${this.ctx.currentTime.toFixed(4)} ctxNow=${this.ctx.currentTime.toFixed(4)} pendingCount=${this.pendingQueue.length}`);\n }\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, c.ptsSec);\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 if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[TRACE-AUD] START(cold) anchor=${this.mediaTimeOfAnchor.toFixed(3)} ctxAnchor=${this.ctxTimeAtAnchor.toFixed(4)} mtNext=${this.mediaTimeOfNext.toFixed(3)} ctxNow=${this.ctx.currentTime.toFixed(4)} pendingCount=${this.pendingQueue.length}`);\n }\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, c.ptsSec);\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 // Disconnect the gain node immediately so any in-flight scheduled\n // buffers are silenced instantly. ctx.suspend() is async and\n // already-started AudioBufferSourceNodes keep playing until the\n // context actually suspends — without the disconnect, audio bleeds\n // through for ~200ms after pause().\n try { this.gain.disconnect(); } catch { /* ignore */ }\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 (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[TRACE-AUD] RESET to=${newMediaTime.toFixed(3)} prev_anchor=${this.mediaTimeOfAnchor.toFixed(3)} prev_mtNext=${this.mediaTimeOfNext.toFixed(3)} prev_ctxAnchor=${this.ctxTimeAtAnchor.toFixed(4)} ctxNow=${this.ctx.currentTime.toFixed(4)} state=${this.state}`);\n }\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.firstAudibleCtxStart = -1;\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 libavFrameToInterleavedFloat32,\n packetPtsSec,\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 * The demuxer's read-ahead frontier in seconds — the highest pts\n * observed on any packet handed back from `ff_read_frame_multi`.\n * Monotonically non-decreasing: seeks don't reset it, since the\n * frontier represents \"how far we've ever demuxed through this\n * source,\" which matches what a seek-bar buffered indicator should\n * show. Backs `<video>.buffered` on canvas strategies. Returns 0\n * before any valid pts have been seen (some AVI/FLV sources may\n * never reach this — their `buffered` stays empty).\n */\n bufferedUntilSec(): number;\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 let bsfRequiredButMissing = false;\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 bsfRequiredButMissing = true;\n bsfCtx = null;\n }\n } catch (err) {\n bsfRequiredButMissing = true;\n bsfCtx = null;\n bsfPkt = null;\n dbg.warn(\"bsf\", `hybrid: mpeg4_unpack_bframes BSF init failed: ${(err as Error).message}`);\n }\n if (bsfRequiredButMissing) {\n // eslint-disable-next-line no-console\n console.error(\n \"[avbridge] MPEG-4 Part 2 (DivX/Xvid) detected but mpeg4_unpack_bframes \" +\n \"BSF is unavailable in this libav variant. Files with packed B-frames \" +\n \"will play with incorrect frame ordering. Rebuild the libav variant \" +\n \"with the `avbsf` fragment included.\",\n );\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) {\n // BSF rejected — DON'T pass the original through. Its buffer may\n // have been transferred into the worker by ff_copyin_packet, so\n // re-posting it would throw DataCloneError on a detached\n // ArrayBuffer. See fallback/decoder.ts for the full explanation.\n continue;\n }\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 // Use av_bsf_flush to reset the BSF without putting it in EOF mode.\n // See the matching comment in src/strategies/fallback/decoder.ts —\n // sending NULL as the flush signal puts the BSF into EOF state so\n // subsequent sends fail, which corrupts the post-seek pipeline with\n // detached-buffer DataCloneErrors.\n if (libav.av_bsf_flush) {\n await libav.av_bsf_flush(bsfCtx);\n } else {\n while (true) {\n const err = await libav.av_bsf_receive_packet(bsfCtx, bsfPkt);\n if (err < 0) break;\n }\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 let bufferedUntilSec = 0;\n\n // Synthetic video timestamp for packets with AV_NOPTS_VALUE (audio\n // uses the packet PTS directly — see decodeAudioBatch).\n let syntheticVideoUs = 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 // Track how far the demuxer has read through the source — the\n // signal behind `<video>.buffered` on this strategy. Peek at raw\n // packet pts using each stream's native time_base (before the\n // sanitizePacketTimestamp call later in the loop, which\n // overwrites to µs). Monotonic: we never walk it backward.\n if (videoPackets && videoTimeBase) {\n for (const pkt of videoPackets) {\n const sec = packetPtsSec(pkt, videoTimeBase);\n if (sec != null && sec > bufferedUntilSec) bufferedUntilSec = sec;\n }\n }\n if (audioPackets && audioTimeBase) {\n for (const pkt of audioPackets) {\n const sec = packetPtsSec(pkt, audioTimeBase);\n if (sec != null && sec > bufferedUntilSec) bufferedUntilSec = sec;\n }\n }\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, /*flush*/ false, audioTimeBase);\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(\n pkts: LibavPacket[],\n myToken: number,\n flush = false,\n tb?: [number, number],\n ) {\n if (!audioDec || destroyed || myToken !== pumpToken) return;\n\n // Capture packet-level PTS before decode (same rationale as fallback\n // decoder — see POSTMORTEMS.md 2026-05-31: libav's reported\n // `frame.pts` is unreliable for some container/codec combinations;\n // the demuxer's packet PTS is reliable). For mp3/aac the packet→frame\n // mapping is 1:1, so the PTS array aligns with `allFrames`.\n const pktPtsSec: (number | null)[] = pkts.map((p) =>\n tb ? packetPtsSec(p, tb) : null,\n );\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 (let i = 0; i < frames.length; i++) {\n if (myToken !== pumpToken || destroyed) return;\n const f = frames[i];\n const samples = libavFrameToInterleavedFloat32(f);\n if (samples) {\n const pts = pktPtsSec[i] ?? null;\n opts.audio.schedule(samples.data, samples.channels, samples.sampleRate, pts);\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\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\n pumpRunning = pumpLoop(newToken).catch((err) =>\n console.error(\"[avbridge] hybrid pump failed (post-seek):\", err),\n );\n },\n\n bufferedUntilSec() {\n return bufferedUntilSec;\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 bsfMissing: bsfRequiredButMissing ? [\"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_flush?(ctx: number): Promise<void>;\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","/**\n * Synthesize a `TimeRanges`-shaped object for the HTMLMediaElement contract\n * on canvas strategies (hybrid/fallback). The real `TimeRanges` interface\n * is browser-only and not constructable; this object duck-types it.\n *\n * `ranges` is an array of `[start, end]` pairs in seconds, in ascending\n * order. The returned object exposes `length`, `start(i)`, `end(i)` —\n * the full surface consumers actually use.\n *\n * NOTE: Plain objects and real TimeRanges aren't `instanceof`-comparable,\n * but consumer code virtually never checks that. The methods + length\n * property are what matters.\n */\nexport function makeTimeRanges(ranges: Array<[number, number]>): TimeRanges {\n const frozen = ranges.slice();\n const impl = {\n get length(): number {\n return frozen.length;\n },\n start(index: number): number {\n if (index < 0 || index >= frozen.length) {\n throw new DOMException(\n `TimeRanges.start: index ${index} out of range (length=${frozen.length})`,\n \"IndexSizeError\",\n );\n }\n return frozen[index][0];\n },\n end(index: number): number {\n if (index < 0 || index >= frozen.length) {\n throw new DOMException(\n `TimeRanges.end: index ${index} out of range (length=${frozen.length})`,\n \"IndexSizeError\",\n );\n }\n return frozen[index][1];\n },\n };\n return impl as TimeRanges;\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\";\nimport { makeTimeRanges } from \"../../util/time-ranges.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 Object.defineProperty(target, \"playbackRate\", {\n configurable: true,\n get: () => audio.getPlaybackRate(),\n set: (v: number) => {\n audio.setPlaybackRate(v);\n target.dispatchEvent(new Event(\"ratechange\"));\n },\n });\n // HTMLMediaElement parity surfaces — see fallback/index.ts for rationale.\n Object.defineProperty(target, \"readyState\", {\n configurable: true,\n get: (): number => {\n if (!renderer.hasFrames()) return 0;\n if (!audio.isPlaying() && audio.bufferAhead() <= 0 && !audio.isNoAudio()) return 1;\n return 2;\n },\n });\n Object.defineProperty(target, \"seekable\", {\n configurable: true,\n get: () => makeTimeRanges(ctx.duration && Number.isFinite(ctx.duration) && ctx.duration > 0\n ? [[0, ctx.duration]]\n : []),\n });\n Object.defineProperty(target, \"buffered\", {\n configurable: true,\n get: () => {\n const end = handles.bufferedUntilSec();\n return makeTimeRanges(end > 0 ? [[0, end]] : []);\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 // HTMLMediaElement contract — see fallback/index.ts for the why.\n target.dispatchEvent(new Event(\"seeking\"));\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 target.dispatchEvent(new Event(\"seeked\"));\n }\n\n // HTMLMediaElement contract: `loadedmetadata` once the session is\n // ready. The inner <video> never fires this itself on the hybrid\n // path — it has no src.\n queueMicrotask(() => {\n try { target.dispatchEvent(new Event(\"loadedmetadata\")); } catch { /* element torn down */ }\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 delete (target as unknown as Record<string, unknown>).readyState;\n delete (target as unknown as Record<string, unknown>).seekable;\n delete (target as unknown as Record<string, unknown>).playbackRate;\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\";\n\n/** True when `globalThis.AVBRIDGE_DEBUG` is set. Used to gate verbose\n * per-packet / per-frame trace lines that are useful for debugging\n * post-seek pts behavior but unreadable in normal use. */\nfunction isDebug(): boolean {\n return typeof globalThis !== \"undefined\"\n && !!(globalThis as Record<string, unknown>).AVBRIDGE_DEBUG;\n}\nimport {\n libavFrameToInterleavedFloat32,\n packetPtsSec,\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 * The demuxer's read-ahead frontier in seconds. See\n * `HybridDecoderHandles.bufferedUntilSec` for the full contract —\n * same semantics, same consumer (`<video>.buffered` on canvas\n * strategies).\n */\n bufferedUntilSec(): number;\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 // Fallback always does full software decode. The \"webcodecs\" libav\n // variant is trimmed to demuxing + WebCodecs-companion use; it lacks\n // software decoders for codecs whose browsers usually handle them\n // (e.g. h265). When we've reached fallback for those codecs, it's\n // precisely because the browser *can't* decode them — so we need\n // the full \"avbridge\" variant with software decoders. pickLibavVariant\n // is still right for the hybrid strategy (which software-decodes only\n // audio and relies on WebCodecs for video), but not here.\n const variant: LibavVariant = \"avbridge\";\n void pickLibavVariant; // kept in scope for future opt-in use\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 throw new Error(\n `fallback decoder: could not initialize any libav decoders (${codecs}). ` +\n `The \"${variant}\" libav variant lacks software decoders for these codecs — ` +\n `rebuild with scripts/build-libav.sh including the missing decoder, ` +\n `or use a lighter strategy (native, remux, hybrid) instead.`,\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 let bsfRequiredButMissing = false;\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 bsfRequiredButMissing = true;\n bsfCtx = null;\n }\n } catch (err) {\n bsfRequiredButMissing = true;\n bsfCtx = null;\n bsfPkt = null;\n dbg.warn(\"bsf\", `mpeg4_unpack_bframes BSF init failed: ${(err as Error).message}`);\n }\n if (bsfRequiredButMissing) {\n // eslint-disable-next-line no-console\n console.error(\n \"[avbridge] MPEG-4 Part 2 (DivX/Xvid) detected but mpeg4_unpack_bframes \" +\n \"BSF is unavailable in this libav variant. Files with packed B-frames \" +\n \"will play with incorrect frame ordering (backwards PTS jumps, heavy \" +\n \"late-drop stuttering). Rebuild the libav variant with the `avbsf` \" +\n \"fragment included. See docs/dev/POSTMORTEMS.md for details.\",\n );\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 // BSF rejected — DON'T pass the original through. `ff_copyin_packet`\n // above may have transferred pkt.data's ArrayBuffer into the worker,\n // in which case re-posting the same packet to the decoder fails\n // with DataCloneError on a detached buffer. Skipping the packet is\n // safer; the decoder's error recovery will resync at the next\n // keyframe if this was transient.\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 // `av_bsf_flush` resets the BSF state without putting it in EOF\n // mode. The old approach — sending a NULL packet — is the EOF\n // signal; after that every subsequent `av_bsf_send_packet` fails,\n // which made `applyBSF` fall back to pushing the ORIGINAL packet\n // through (with its buffer already transferred to WASM by\n // `ff_copyin_packet`). That detached buffer then failed to\n // `postMessage` into the decoder worker with DataCloneError on\n // the first post-seek batch.\n if (libav.av_bsf_flush) {\n await libav.av_bsf_flush(bsfCtx);\n } else {\n // Fallback for older libav.js variants without av_bsf_flush:\n // drain any internal packets but DON'T send NULL-EOF.\n while (true) {\n const err = await libav.av_bsf_receive_packet(bsfCtx, bsfPkt);\n if (err < 0) break;\n }\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 bufferedUntilSec = 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 // Content clock for video frames. Tracks the last frame's content time\n // in µs. The invariant per emit:\n // - raw libav pts valid → lastContentUs = raw_pts (sync to truth)\n // - raw libav pts NOPTS → lastContentUs += frameStep (extend by one frame)\n // This makes synthetic labels always relative to the *immediately\n // preceding* frame's real content, self-correcting at every valid pts.\n // -1 means \"unanchored\" — pre-anchor NOPTS frames are discarded outright\n // because we don't know where the decoder actually landed. The anchor\n // is established at the first valid raw pts post-seek.\n //\n // This replaced an older \"synthetic counter reset to seekTarget on seek\"\n // path which stamped NOPTS preroll frames with the user's requested seek\n // time — producing labels 4+ seconds ahead of actual content, dropping\n // every valid-pts frame as a \"regression\", and surfacing as a ~2s\n // post-seek fast-forward as the slow-advancing synthetic counter slowly\n // converged with real content. See POSTMORTEMS.md (2026-06-01).\n let lastContentUs = -1;\n let firstValidPtsLoggedSinceSeek = false;\n\n // Diagnostic: first post-seek audio packet's PTS. Logged once per seek\n // so the operator can see the demuxer's actual content alignment vs\n // the user's click. With PTS-based audio scheduling, audio packets\n // with PTS before the seek target *naturally* don't get scheduled\n // (their computed ctxStart falls in the past) — no manual trim needed.\n let seenFirstAudioPacketSinceSeek = false;\n let seekTargetSec = 0;\n // Post-seek diagnostic counters. Capture raw pts/dts/pos for the first\n // ~N packets and frames after each seek so we can tell whether libav\n // hands us a valid pts at seek landing, when (if ever) it becomes\n // valid mid-stream, and whether sanitize's NOPTS fallback is firing.\n let diagPktsLoggedSinceSeek = 0;\n let diagFramesLoggedSinceSeek = 0;\n let diagFrameKeysDumped = false;\n const DIAG_MAX_PKTS = 100;\n const DIAG_MAX_FRAMES = 300;\n\n // Throughput instrumentation — answers \"is the decoder keeping up?\".\n // All counters are cumulative since bootstrap (not reset on seek), so\n // the stats panel can compute rolling deltas. Times are wall-ms spent\n // inside the respective libav call; JS↔WASM boundary is inside the\n // worker so this is the real cost the producer pays per batch.\n let videoDecodeMsTotal = 0;\n let audioDecodeMsTotal = 0;\n let videoDecodeBatches = 0;\n let audioDecodeBatches = 0;\n let readMsTotal = 0;\n let readBatches = 0;\n let pumpThrottleMsTotal = 0;\n let pumpThrottleEntries = 0;\n let slowestVideoBatchMs = 0;\n let newestVideoPtsUs = 0; // set by decodeVideoBatch after each emitted frame\n let lastEmittedPtsUs = -1; // previous emitted frame's pts, for monotonicity check\n let ptsRegressions = 0;\n let worstPtsRegressionMs = 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 const _readStart = performance.now();\n [readErr, packets] = await libav.ff_read_frame_multi(fmt_ctx, readPkt, {\n limit: 16 * 1024,\n });\n readMsTotal += performance.now() - _readStart;\n readBatches++;\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 // Track demuxer read-ahead for <video>.buffered on this strategy.\n // Peek raw pts before sanitizePacketTimestamp (which would\n // clobber to µs and lose the source-native scale). Monotonic;\n // seeks don't reset.\n if (videoPackets && videoTimeBase) {\n for (const pkt of videoPackets) {\n const sec = packetPtsSec(pkt, videoTimeBase);\n if (sec != null && sec > bufferedUntilSec) bufferedUntilSec = sec;\n // [DIAG-PKT] Raw pre-sanitize packet fields for the first N\n // post-seek video packets. Most important question: does the\n // FIRST packet after av_seek_frame carry a valid pts? If yes,\n // we can anchor synthetic counter to that — cheap & robust.\n // If no, fall back to pkt_pos → AVI index → chunk_idx × frameDur.\n if (isDebug() && diagPktsLoggedSinceSeek < DIAG_MAX_PKTS) {\n const rawHi = (pkt as { ptshi?: number }).ptshi ?? 0;\n const rawLo = pkt.pts ?? 0;\n const isInvalidPts = (rawHi === -2147483648 && rawLo === 0);\n const rawPts64 = isInvalidPts ? null : (rawHi * 0x100000000 + rawLo);\n const rawSec = rawPts64 != null && videoTimeBase\n ? (rawPts64 * videoTimeBase[0]) / videoTimeBase[1]\n : null;\n const pktKeys = diagPktsLoggedSinceSeek === 0\n ? `[keys: ${Object.keys(pkt).join(\",\")}]`\n : \"\";\n // eslint-disable-next-line no-console\n console.log(\n `[DIAG-PKT] vidx=${diagPktsLoggedSinceSeek} ` +\n `pts=${isInvalidPts ? \"NOPTS\" : rawPts64} ` +\n `pts_sec=${rawSec != null ? rawSec.toFixed(3) : \"n/a\"} ` +\n `ptshi=${rawHi} ptslo=${rawLo} ` +\n `flags=0x${(pkt.flags ?? 0).toString(16)} ` +\n `keyframe=${((pkt.flags ?? 0) & 1) ? \"Y\" : \"N\"} ` +\n `stream=${pkt.stream_index} ` +\n `dataLen=${pkt.data?.length ?? 0} ` +\n `seekTarget=${seekTargetSec.toFixed(3)} ` +\n pktKeys,\n );\n diagPktsLoggedSinceSeek++;\n }\n }\n }\n if (audioPackets && audioTimeBase) {\n for (const pkt of audioPackets) {\n const sec = packetPtsSec(pkt, audioTimeBase);\n if (sec != null && sec > bufferedUntilSec) bufferedUntilSec = sec;\n }\n // Diagnostic: log the first post-seek audio packet's PTS. With\n // PTS-based scheduling, packets whose PTS is before the seek\n // target won't be played (AudioOutput skips them silently), so\n // this is informational only — it tells you how far off the\n // demuxer's seek granularity is from the user's click.\n if (!seenFirstAudioPacketSinceSeek && audioPackets.length > 0) {\n const firstSec = packetPtsSec(audioPackets[0], audioTimeBase);\n if (firstSec != null && Number.isFinite(firstSec)) {\n seenFirstAudioPacketSinceSeek = true;\n dbg.info(\"av-anchor\",\n `seek-target=${seekTargetSec.toFixed(3)}s, ` +\n `first-audio-pkt-pts=${firstSec.toFixed(3)}s ` +\n `(Δ=${((firstSec - seekTargetSec) * 1000).toFixed(1)}ms — ` +\n `pre-target packets will be skipped by AudioOutput)`,\n );\n }\n }\n }\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, /*flush*/ false, audioTimeBase);\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: only on audio buffer (mediaTimeOfNext - now() > 2 s).\n // Renderer queue backpressure is enforced at the *enqueue* side in\n // `decodeVideoBatch` — when the queue is at `queueHighWater`, the\n // freshly decoded VideoFrame is closed without being enqueued, so\n // the decoder keeps consuming packets in order. That preserves the\n // reference-frame state needed to decode P/B frames cleanly during\n // post-seek catch-up. Throttling the *pump* on queue depth here\n // would block demuxer reads, which would also stall audio packet\n // processing and starve `audio.bufferAhead()`.\n {\n const _throttleStart = performance.now();\n let _throttled = false;\n while (\n !destroyed &&\n myToken === pumpToken &&\n opts.audio.bufferAhead() > 2.0\n ) {\n _throttled = true;\n await new Promise((r) => setTimeout(r, 50));\n }\n if (_throttled) {\n pumpThrottleMsTotal += performance.now() - _throttleStart;\n pumpThrottleEntries++;\n }\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 const _t0 = performance.now();\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 {\n const _dt = performance.now() - _t0;\n videoDecodeMsTotal += _dt;\n videoDecodeBatches++;\n if (_dt > slowestVideoBatchMs) slowestVideoBatchMs = _dt;\n }\n if (myToken !== pumpToken || destroyed) return;\n\n for (const f of frames) {\n if (myToken !== pumpToken || destroyed) return;\n // [DIAG-FRAME] Capture raw pre-sanitize fields. One-shot key dump\n // on first frame post-seek so we can see which fields libav\n // actually exposes (best_effort_timestamp? pkt_dts? pkt_pos?).\n const _diagShouldLog = isDebug() && diagFramesLoggedSinceSeek < DIAG_MAX_FRAMES;\n const _diagRawHi = f.ptshi ?? 0;\n const _diagRawLo = f.pts ?? 0;\n const _diagInvalid = (_diagRawHi === -2147483648 && _diagRawLo === 0);\n const _diagRawPts64 = _diagInvalid ? null : (_diagRawHi * 0x100000000 + _diagRawLo);\n const _diagRawSec = _diagRawPts64 != null && videoTimeBase\n ? (_diagRawPts64 * videoTimeBase[0]) / videoTimeBase[1]\n : null;\n if (_diagShouldLog && !diagFrameKeysDumped) {\n diagFrameKeysDumped = true;\n const allKeys = Object.keys(f);\n const fieldDump: Record<string, unknown> = {};\n for (const k of allKeys) {\n const v = (f as unknown as Record<string, unknown>)[k];\n // Skip the data buffer; everything else is metadata.\n if (k === \"data\") continue;\n if (typeof v === \"object\" && v !== null && \"length\" in (v as object)) continue;\n fieldDump[k] = v;\n }\n // eslint-disable-next-line no-console\n console.log(`[DIAG-FRAME] FIRST FRAME post-seek — all keys: ${allKeys.join(\",\")}`);\n // eslint-disable-next-line no-console\n console.log(`[DIAG-FRAME] FIRST FRAME field dump:`, fieldDump);\n }\n // Convert raw libav pts (in stream timebase) to µs, or null if NOPTS.\n let rawUs: number | null = null;\n if (!_diagInvalid && _diagRawPts64 != null) {\n const tb = videoTimeBase ?? [1, 1_000_000];\n const us = Math.round((_diagRawPts64 * 1_000_000 * tb[0]) / tb[1]);\n if (Number.isFinite(us) && Math.abs(us) <= Number.MAX_SAFE_INTEGER) {\n rawUs = us;\n }\n }\n\n // Forward declare _diagLog so PRE-ANCHOR-DROP can call it.\n // Final pts isn't known until after the anchor/step block, so we pass\n // it as a parameter rather than closing over a `let`.\n const _diagLog = (decision: string, finalPtsUs: number, sanFallback: boolean): void => {\n if (!_diagShouldLog) return;\n const ptsSrc = sanFallback\n ? `SYNTHETIC(${_diagInvalid ? \"NOPTS\" : \"invalid-range\"})`\n : \"LIBAV\";\n // eslint-disable-next-line no-console\n console.log(\n `[DIAG-FRAME] vidx=${diagFramesLoggedSinceSeek} ` +\n `raw_pts=${_diagInvalid ? \"NOPTS\" : _diagRawPts64} ` +\n `raw_pts_sec=${_diagRawSec != null ? _diagRawSec.toFixed(3) : \"n/a\"} ` +\n `pts_src=${ptsSrc} ` +\n `final_pts_us=${finalPtsUs} ` +\n `final_pts_sec=${(finalPtsUs / 1_000_000).toFixed(3)} ` +\n `seekTarget=${seekTargetSec.toFixed(3)} ` +\n `offset_to_target_ms=${((finalPtsUs / 1000) - (seekTargetSec * 1000)).toFixed(1)} ` +\n `lastEmittedPts_us=${lastEmittedPtsUs} ` +\n `decision=${decision}`,\n );\n diagFramesLoggedSinceSeek++;\n };\n\n // Anchor + step invariant.\n // - Unanchored (post-seek, no valid pts seen yet) AND NOPTS frame\n // → discard outright. We don't know where the decoder landed, so\n // stamping a synthetic label would be a lie (this was the source\n // of the post-seek fast-forward bug).\n // - First valid raw pts → anchor `lastContentUs` to it. The pipeline\n // below will then drop this and subsequent frames as pre-target\n // until content reaches seekTarget.\n // - Anchored AND valid → sync `lastContentUs` to truth.\n // - Anchored AND NOPTS → step `lastContentUs += frameStep`.\n let _diagSanFallbackFired = false;\n const seekTargetUs = Math.round(seekTargetSec * 1_000_000);\n if (lastContentUs < 0) {\n if (rawUs == null) {\n // Cold-start keyframe special case. At seekTargetSec === 0 the\n // demuxer guarantees the very first emitted keyframe is content\n // 0 (container start=0.000000). Anchoring there directly avoids\n // discarding the opening I-frame — without this, cold start\n // loses 1-2 frames and the first paint is ~80ms late.\n //\n // STRICTLY gated to seekTarget === 0. The seek path proved\n // correct via the offset-ground-truth experiment (POSTMORTEMS\n // 2026-06-01); this branch must not change its behavior.\n //\n // Why keyframe-pin instead of back-computing from the first\n // valid pts: the I/P/B reorder is densest at the stream head,\n // so `firstValidPts − N × frameStep` is off by however many\n // early B-frames the decoder dropped. The keyframe identity\n // (`f.key_frame === 1`) is the only signal that doesn't depend\n // on frame-spacing assumptions.\n const isColdStartKeyframe =\n seekTargetSec === 0\n && (f as { key_frame?: number }).key_frame === 1;\n if (isColdStartKeyframe) {\n lastContentUs = 0;\n _diagSanFallbackFired = true;\n // Fall through: the frame gets labeled 0 and runs through\n // the regression/pre-target/enqueue pipeline normally.\n } else {\n // Pre-anchor NOPTS: discard. Decoder retains the frame internally\n // as a reference — we just don't expose it to the renderer.\n _diagLog(\"PRE-ANCHOR-DROP\", 0, true);\n continue;\n }\n } else {\n // First valid raw pts post-seek = the anchor.\n lastContentUs = rawUs;\n if (!firstValidPtsLoggedSinceSeek) {\n firstValidPtsLoggedSinceSeek = true;\n if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(\n `[avbridge:decoder] post-seek anchor established: ` +\n `first valid raw pts = ${(rawUs / 1000).toFixed(1)}ms ` +\n `(seekTarget = ${(seekTargetSec * 1000).toFixed(1)}ms, ` +\n `Δ = ${((rawUs - seekTargetUs) / 1000).toFixed(1)}ms)`,\n );\n }\n // Guard: if the first valid pts is at or beyond the seek\n // target, the pre-anchor NOPTS frames we already discarded\n // may have straddled the target. In normal AVI MPEG-4 seeks,\n // the demuxer lands well before the target (previous\n // keyframe), so this shouldn't happen — log a warning if it\n // does so we know to implement a pkt_pos→AVI-index\n // back-computation path. The cold-start case (seekTarget=0)\n // is handled by the keyframe-pin branch above and shouldn't\n // reach this warning.\n if (rawUs >= seekTargetUs) {\n // eslint-disable-next-line no-console\n console.warn(\n `[avbridge:decoder] first valid raw pts ≥ seek target — ` +\n `pre-anchor NOPTS frames may have straddled the target ` +\n `and been mis-discarded. First painted frame may be late ` +\n `by up to one keyframe interval.`,\n );\n }\n }\n }\n } else {\n if (rawUs != null) {\n lastContentUs = rawUs; // sync to truth on every valid pts\n } else {\n lastContentUs += videoFrameStepUs; // extend from last truth\n _diagSanFallbackFired = true;\n }\n }\n // Write the content label into the frame so the bridge sees it.\n f.pts = lastContentUs;\n f.ptshi = lastContentUs < 0 ? -1 : 0;\n const _fPts = lastContentUs;\n if (_fPts > newestVideoPtsUs) newestVideoPtsUs = _fPts;\n if (lastEmittedPtsUs >= 0 && _fPts < lastEmittedPtsUs) {\n _diagLog(\"REGRESSED-DROP\", _fPts, _diagSanFallbackFired);\n // Decoder emitted a frame with lower PTS than the previous\n // output. Dropping out-of-order frames here is the right move:\n // the renderer's paint loop assumes monotonic queue order and\n // breaks (stale frame stuck at head, newer frames drop as late,\n // paint cadence collapses) if we let them through. Two scenarios\n // produce this in practice:\n // - Post-seek tail of a B-frame reorder buffer that survives\n // avcodec_flush_buffers + av_bsf_flush (rare but observed\n // on mpeg4 after large seeks).\n // - A BSF that doesn't repair packed B-frames perfectly and\n // lets a DTS/PTS swap through.\n // The decoder will catch up at the next I-frame.\n ptsRegressions++;\n const regressMs = (lastEmittedPtsUs - _fPts) / 1000;\n if (regressMs > worstPtsRegressionMs) worstPtsRegressionMs = regressMs;\n if (ptsRegressions <= 10) {\n // eslint-disable-next-line no-console\n console.warn(\n `[avbridge:decoder] dropped out-of-order frame #${ptsRegressions}: ` +\n `pts=${(_fPts / 1000).toFixed(1)}ms < previous=${(lastEmittedPtsUs / 1000).toFixed(1)}ms ` +\n `(regression=${regressMs.toFixed(1)}ms). Typically a post-seek B-frame reorder tail.`,\n );\n }\n continue; // skip enqueue\n }\n lastEmittedPtsUs = _fPts;\n // Decode-to-display: after a seek the demuxer lands at the\n // keyframe ≤ click target and the decoder produces frames\n // starting there. Pre-target frames are still DECODED (they're\n // reference frames for later P/B decodes) but they MUST NOT be\n // displayed — otherwise the renderer paints them in a brief\n // fast-forward burst as it catches up to audio (T_click). Drop\n // them at the enqueue boundary; the decoder doesn't care.\n //\n // Tolerance of one frame duration: source frames are quantized\n // (PTS = N × frameStep) but the user's click is arbitrary, so\n // the frame nearest the click is typically a few ms *before* it.\n // Convention (matches `<video>.currentTime = T` and ffplay):\n // display the frame at the largest PTS ≤ T.\n const targetUs = Math.round(seekTargetSec * 1_000_000);\n if (_fPts < targetUs - videoFrameStepUs) {\n _diagLog(\"PRE-TARGET-DROP\", _fPts, _diagSanFallbackFired);\n continue;\n }\n try {\n const vf = bridge.laFrameToVideoFrame(f, { timeBase: [1, 1_000_000] });\n // Renderer-queue backpressure at the enqueue side. Discarding\n // here (rather than throttling the pump on `queueHighWater`)\n // keeps the decoder consuming packets sequentially so its\n // reference-frame state stays intact — essential during\n // post-seek catch-up, when the pump must continue reading\n // packets to advance the demuxer past pre-target audio. Without\n // sequential decode, the next batch's P/B frames decode against\n // a stale reference and produce gray + glitchy output until\n // the next keyframe.\n if (opts.renderer.queueDepth() >= opts.renderer.queueHighWater) {\n vf.close();\n _diagLog(\"OVERFLOW-DROP\", _fPts, _diagSanFallbackFired);\n } else {\n opts.renderer.enqueue(vf);\n _diagLog(\"ENQUEUED\", _fPts, _diagSanFallbackFired);\n }\n videoFramesDecoded++;\n } catch (err) {\n if (videoFramesDecoded === 0) {\n console.warn(\"[avbridge] laFrameToVideoFrame failed:\", err);\n }\n _diagLog(\"BRIDGE-ERROR\", _fPts, _diagSanFallbackFired);\n }\n }\n }\n\n async function decodeAudioBatch(\n pkts: LibavPacket[],\n myToken: number,\n flush = false,\n tb?: [number, number],\n ) {\n if (!audioDec || destroyed || myToken !== pumpToken) return;\n // Capture the packet-level PTS *before* decoding. libav's reported\n // `frame.pts` after decode is unreliable for mp3-in-AVI (returns a\n // value that doesn't agree with the stream's reported time base —\n // see POSTMORTEMS.md 2026-05-31). The demuxer's packet PTS is\n // reliable, and for mp3/aac the packet→frame mapping is 1:1, so we\n // forward each packet's PTS to the matching output frame. For codecs\n // where the mapping isn't 1:1, the trailing frames fall back to a\n // synthetic running counter — same behavior as before this change.\n const pktPtsSec: (number | null)[] = pkts.map((p) =>\n tb ? packetPtsSec(p, tb) : null,\n );\n let frames: LibavFrame[];\n const _t0 = performance.now();\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 audioDecodeMsTotal += performance.now() - _t0;\n audioDecodeBatches++;\n if (myToken !== pumpToken || destroyed) return;\n\n for (let i = 0; i < frames.length; i++) {\n if (myToken !== pumpToken || destroyed) return;\n const f = frames[i];\n const samples = libavFrameToInterleavedFloat32(f);\n if (samples) {\n const pts = pktPtsSec[i] ?? null;\n if (isDebug()) {\n const dur = samples.data.length / samples.channels / samples.sampleRate;\n // Log every frame — we need to see what happens around seeks.\n // Also surface explicitly when the per-frame PTS is null, which\n // would route the chunk to the LEGACY rebase path in AudioOutput.\n // eslint-disable-next-line no-console\n console.log(`[TRACE-DEC] audio frame #${audioFramesDecoded} pts=${pts != null ? pts.toFixed(4) : \"NULL\"} dur=${dur.toFixed(4)} samples=${samples.data.length / samples.channels} sr=${samples.sampleRate} ch=${samples.channels} pktsIn=${pkts.length} framesOut=${frames.length}`);\n }\n opts.audio.schedule(samples.data, samples.channels, samples.sampleRate, pts);\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 lastContentUs = -1;\n lastEmittedPtsUs = -1;\n firstValidPtsLoggedSinceSeek = false;\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 if (isDebug()) {\n // eslint-disable-next-line no-console\n console.log(`[SEEK] target=${timeSec.toFixed(3)}s (${(timeSec * 1000).toFixed(0)}ms) wall=${performance.now().toFixed(0)}`);\n }\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 the content clock to \"unanchored\". The next decode loop\n // will discard NOPTS frames until the first valid libav pts\n // establishes a real anchor, then label every frame relative to\n // truth. Do NOT set anything to seekTarget here — that lie was\n // the post-seek fast-forward bug.\n lastContentUs = -1;\n lastEmittedPtsUs = -1;\n firstValidPtsLoggedSinceSeek = false;\n seenFirstAudioPacketSinceSeek = false;\n seekTargetSec = timeSec;\n diagPktsLoggedSinceSeek = 0;\n diagFramesLoggedSinceSeek = 0;\n diagFrameKeysDumped = false;\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 bufferedUntilSec() {\n return bufferedUntilSec;\n },\n\n stats() {\n return {\n decoderType: \"libav-wasm\",\n packetsRead,\n videoFramesDecoded,\n audioFramesDecoded,\n // Throughput instrumentation — the stats panel turns these into\n // \"decode fps actual / realtime target\" and shows slowest batch\n // + producer throttle share.\n videoDecodeMsTotal,\n videoDecodeBatches,\n audioDecodeMsTotal,\n audioDecodeBatches,\n readMsTotal,\n readBatches,\n pumpThrottleMsTotal,\n pumpThrottleEntries,\n slowestVideoBatchMs,\n newestVideoPtsMs: Math.round(newestVideoPtsUs / 1000),\n ptsRegressions,\n worstPtsRegressionMs,\n sourceFps: videoFps,\n bsfApplied: bsfCtx ? [\"mpeg4_unpack_bframes\"] : [],\n bsfMissing: bsfRequiredButMissing ? [\"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_flush?(ctx: number): Promise<void>;\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\";\nimport { makeTimeRanges } from \"../../util/time-ranges.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 // Playback rate — canvas strategies don't use the real <video>, so the\n // native playbackRate property does nothing. Patch it to drive the\n // AudioOutput clock speed + pitch.\n Object.defineProperty(target, \"playbackRate\", {\n configurable: true,\n get: () => audio.getPlaybackRate(),\n set: (v: number) => {\n audio.setPlaybackRate(v);\n target.dispatchEvent(new Event(\"ratechange\"));\n },\n });\n // Synthesize HTMLMediaElement parity surfaces that the canvas strategies\n // can't otherwise answer truthfully (the inner <video> has no src, so\n // its own readyState/seekable are zero/empty).\n //\n // readyState: HAVE_NOTHING (0) until the first frame lands; then\n // HAVE_CURRENT_DATA (2) once the cold-start gate is released (both\n // audio+video ready). Simplified from the full five-level spec — we\n // don't distinguish HAVE_FUTURE_DATA vs HAVE_ENOUGH_DATA since our\n // pump semantics make those essentially the same state.\n Object.defineProperty(target, \"readyState\", {\n configurable: true,\n get: (): number => {\n if (!renderer.hasFrames()) return 0; // HAVE_NOTHING\n if (!audio.isPlaying() && audio.bufferAhead() <= 0 && !audio.isNoAudio()) return 1; // HAVE_METADATA\n return 2; // HAVE_CURRENT_DATA (or better — but 2 is the honest lower bound)\n },\n });\n // seekable: a progressive source is fully seekable once we have duration.\n Object.defineProperty(target, \"seekable\", {\n configurable: true,\n get: () => makeTimeRanges(ctx.duration && Number.isFinite(ctx.duration) && ctx.duration > 0\n ? [[0, ctx.duration]]\n : []),\n });\n // buffered: demuxer's read-ahead frontier (highest pts pumped from\n // libav). Single [0, end] range — approximation of \"how far we've\n // read through the source,\" the signal the seek-bar buffered\n // indicator wants. Real MSE-style per-range tracking isn't\n // meaningful here since decoded frames are consumed in flight.\n Object.defineProperty(target, \"buffered\", {\n configurable: true,\n get: () => {\n const end = handles.bufferedUntilSec();\n return makeTimeRanges(end > 0 ? [[0, end]] : []);\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 // HTMLMediaElement contract: dispatch `seeking` once the seek\n // operation begins. The inner <video> never fires this itself on\n // canvas strategies (no src), so we dispatch manually to preserve\n // the contract for consumers listening via `<avbridge-video>`.\n target.dispatchEvent(new Event(\"seeking\"));\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 // HTMLMediaElement contract: dispatch `seeked` after the seek has\n // completed (demuxer + renderer reset + optional buffer refill).\n target.dispatchEvent(new Event(\"seeked\"));\n }\n\n // HTMLMediaElement contract: dispatch `loadedmetadata` once the\n // session is ready (duration, dimensions, tracks known via the\n // MediaContext). Dispatched on a microtask so it lands after the\n // session promise resolves and consumers have a chance to attach\n // listeners. The inner <video> never fires this itself here — it\n // has no src.\n queueMicrotask(() => {\n try { target.dispatchEvent(new Event(\"loadedmetadata\")); } catch { /* element torn down */ }\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 delete (target as unknown as Record<string, unknown>).readyState;\n delete (target as unknown as Record<string, unknown>).seekable;\n delete (target as unknown as Record<string, unknown>).playbackRate;\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\n/**\n * Decoded-video-frame counter reader. Prefers the standard\n * `getVideoPlaybackQuality().totalVideoFrames` (all evergreen browsers);\n * falls back to the WebKit-prefixed `webkitDecodedFrameCount` for older\n * Safari. Returns 0 for non-video elements or when nothing exposes the\n * count — the caller treats 0 as \"no signal\" (constant across samples,\n * which is fine).\n */\nexport function readDecodedFrameCount(target: HTMLMediaElement): number {\n if (typeof HTMLVideoElement === \"undefined\" || !(target instanceof HTMLVideoElement)) return 0;\n const vq = (target as HTMLVideoElement & { getVideoPlaybackQuality?: () => { totalVideoFrames: number } }).getVideoPlaybackQuality;\n if (typeof vq === \"function\") {\n try { return vq.call(target).totalVideoFrames; } catch { /* fall through */ }\n }\n const legacy = (target as HTMLVideoElement & { webkitDecodedFrameCount?: number }).webkitDecodedFrameCount;\n return typeof legacy === \"number\" ? legacy : 0;\n}\n\n/**\n * Pure decision function for the stall supervisor. Takes a snapshot of\n * the observable state and returns whether to escalate. Extracted so it\n * can be unit-tested without spinning up a real player / media element.\n *\n * - `time-stall`: `currentTime` hasn't moved for `timeStallThresholdMs`\n * despite the element being in a state where it should be playing.\n * - `silent-video`: the media has a video track, `currentTime` is\n * advancing (audio is playing), but the decoder has produced no new\n * frames for `frameStallThresholdMs`. Catches Firefox-style \"MSE\n * reports codec supported but the decoder can't actually decode it\".\n */\nexport function evaluateDecodeHealth(input: {\n hasVideoTrack: boolean;\n timeAdvanced: boolean;\n framesAdvanced: boolean;\n now: number;\n lastProgressTime: number;\n lastFrameProgressTime: number;\n timeStallThresholdMs?: number;\n frameStallThresholdMs?: number;\n}): { escalate: false } | { escalate: true; kind: \"time-stall\" | \"silent-video\" } {\n const timeThreshold = input.timeStallThresholdMs ?? 5000;\n const frameThreshold = input.frameStallThresholdMs ?? 3000;\n if (!input.timeAdvanced && input.now - input.lastProgressTime > timeThreshold) {\n return { escalate: true, kind: \"time-stall\" };\n }\n if (\n input.hasVideoTrack &&\n input.timeAdvanced &&\n !input.framesAdvanced &&\n input.now - input.lastFrameProgressTime > frameThreshold\n ) {\n return { escalate: true, kind: \"silent-video\" };\n }\n return { escalate: false };\n}\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 /** Last observed `HTMLVideoElement.getVideoPlaybackQuality().totalVideoFrames`\n * (or `webkitDecodedFrameCount` fallback). Used by the silent-video\n * watchdog — catches cases where `currentTime` advances (audio plays)\n * but the decoder produces no frames, e.g. Firefox claiming `hev1.*`\n * via MSE when the decoder actually can't decode HEVC. */\n private lastVideoFrameCount = 0;\n private lastVideoFrameProgressTime = 0;\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, cacheBytes } = options;\n if (requestInit || fetchFn || cacheBytes !== undefined) {\n this.transport = { requestInit, fetchFn, cacheBytes };\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 this.lastVideoFrameCount = readDecodedFrameCount(this.options.target);\n this.lastVideoFrameProgressTime = performance.now();\n\n const hasVideoTrack = (this.mediaContext?.videoTracks.length ?? 0) > 0;\n\n this.stallTimer = setInterval(() => {\n const t = this.options.target;\n const now = performance.now();\n if (t.paused || t.ended || t.readyState < 2) {\n this.lastProgressPosition = t.currentTime;\n this.lastProgressTime = now;\n this.lastVideoFrameCount = readDecodedFrameCount(t);\n this.lastVideoFrameProgressTime = now;\n return;\n }\n const timeAdvanced = t.currentTime !== this.lastProgressPosition;\n const frames = readDecodedFrameCount(t);\n const framesAdvanced = frames > this.lastVideoFrameCount;\n\n const health = evaluateDecodeHealth({\n hasVideoTrack,\n timeAdvanced,\n framesAdvanced,\n now,\n lastProgressTime: this.lastProgressTime,\n lastFrameProgressTime: this.lastVideoFrameProgressTime,\n });\n\n if (timeAdvanced) {\n this.lastProgressPosition = t.currentTime;\n this.lastProgressTime = now;\n }\n if (framesAdvanced) {\n this.lastVideoFrameCount = frames;\n this.lastVideoFrameProgressTime = now;\n }\n\n if (health.escalate) {\n const reason = health.kind === \"time-stall\"\n ? `${strategy} strategy stalled for 5s at ${t.currentTime.toFixed(1)}s`\n : `${strategy} strategy: audio is advancing but the video decoder has produced no new frames for 3s — likely a silent codec failure`;\n void this.escalate(reason);\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"]}
|