{"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":["AvbridgeError","ERR_MSE_NOT_SUPPORTED","ERR_MSE_CODEC_NOT_SUPPORTED","avbridgeVideoToMediabunny","buildMediabunnySourceFromInput","avbridgeAudioToMediabunny","SubtitleOverlay","wallNow","frame","isDebug","drain","pickLibavVariant","loadLibav","dbg","packetPtsSec","sanitizePacketTimestamp","frames","libavFrameToInterleavedFloat32","loadBridge","READY_AUDIO_BUFFER_SECONDS","READY_TIMEOUT_SECONDS","SubtitleResourceBag","probe","discoverSidecars","attachSubtitleTracks","ERR_ALL_STRATEGIES_EXHAUSTED","ERR_PLAYER_NOT_READY"],"mappings":"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","file":"chunk-OFJYEITB.cjs","sourcesContent":["import type { AudioTrackInfo, VideoTrackInfo } from \"../types.js\";\n\n/**\n * Build an RFC 6381 codec string for use with `MediaSource.isTypeSupported`\n * and `<source type=...>`. Returns null when we don't have enough info to\n * compose one — callers should treat that as \"ask the browser at runtime via\n * a different channel\" rather than guessing.\n */\nexport function videoCodecString(track: VideoTrackInfo): string | null {\n  if (track.codecString) return track.codecString;\n  switch (track.codec) {\n    case \"h264\": {\n      // avc1.PPCCLL — profile (1B), constraint (1B), level (1B). Default to\n      // High Profile @ 4.0 if we don't know — common on real-world content.\n      const profileHex = profileToHex(track.profile) ?? \"64\"; // 0x64 = High\n      const constraint = \"00\";\n      const level = ((track.level ?? 40) & 0xff).toString(16).padStart(2, \"0\");\n      return `avc1.${profileHex}${constraint}${level}`;\n    }\n    case \"h265\":\n      // Default Main Profile @ Level 4.1 (0x5d = 93) — `hvc1.1.6.L93.B0`.\n      return \"hvc1.1.6.L93.B0\";\n    case \"vp8\":\n      return \"vp8\";\n    case \"vp9\":\n      return \"vp09.00.10.08\";\n    case \"av1\":\n      return \"av01.0.04M.08\";\n    default:\n      return null;\n  }\n}\n\nfunction profileToHex(profile?: string): string | null {\n  if (!profile) return null;\n  const p = profile.toLowerCase();\n  if (p.includes(\"baseline\")) return \"42\";\n  if (p.includes(\"main\")) return \"4d\";\n  if (p.includes(\"high 10\")) return \"6e\";\n  if (p.includes(\"high 4:2:2\")) return \"7a\";\n  if (p.includes(\"high 4:4:4\")) return \"f4\";\n  if (p.includes(\"high\")) return \"64\";\n  return null;\n}\n\nexport function audioCodecString(track: AudioTrackInfo): string | null {\n  if (track.codecString) return track.codecString;\n  switch (track.codec) {\n    case \"aac\":\n      return \"mp4a.40.2\"; // AAC-LC\n    case \"mp3\":\n      return \"mp4a.40.34\";\n    case \"opus\":\n      return \"opus\";\n    case \"vorbis\":\n      return \"vorbis\";\n    case \"flac\":\n      return \"flac\";\n    default:\n      return null;\n  }\n}\n\n/**\n * Compose a `video/mp4; codecs=\"...\"` MIME for MSE. Returns null if either\n * codec string can't be produced — caller should fall back to remux refusal.\n */\nexport function mp4MimeFor(video: VideoTrackInfo, audio?: AudioTrackInfo): string | null {\n  const v = videoCodecString(video);\n  if (!v) return null;\n  const codecs = audio ? `${v},${audioCodecString(audio) ?? \"\"}`.replace(/,$/, \"\") : v;\n  return `video/mp4; codecs=\"${codecs}\"`;\n}\n\n/**\n * Wrap `MediaSource.isTypeSupported` so it returns false (instead of throwing)\n * in environments without MSE — e.g. jsdom under vitest.\n */\nexport function mseSupports(mime: string): boolean {\n  if (typeof MediaSource === \"undefined\") return false;\n  try {\n    return MediaSource.isTypeSupported(mime);\n  } catch {\n    return false;\n  }\n}\n","import type {\n  AudioCodec,\n  AudioTrackInfo,\n  Classification,\n  ContainerKind,\n  MediaContext,\n  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"]}