{"version":3,"sources":["../src/probe/mediabunny.ts","../src/probe/index.ts"],"names":["normalizeSource","sniffNormalizedSource","AvbridgeError","ERR_PROBE_FAILED","ERR_PROBE_UNKNOWN_CONTAINER","ERR_LIBAV_NOT_REACHABLE"],"mappings":";;;;;AAwBA,eAAsB,mBAAA,CACpB,QACA,gBAAA,EACuB;AACvB,EAAA,MAAM,EAAA,GAAK,MAAM,OAAO,YAAY,CAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,IAAI,EAAA,CAAG,KAAA,CAAM;AAAA,IACzB,MAAA,EAAQ,MAAM,qBAAA,CAAsB,EAAA,EAAI,MAAM,CAAA;AAAA,IAC9C,SAAS,EAAA,CAAG;AAAA,GACb,CAAA;AAED,EAAA,MAAM,SAAA,GAAY,MAAM,KAAA,CAAM,SAAA,EAAU;AACxC,EAAA,MAAM,WAAW,MAAM,UAAA,CAAW,MAAM,KAAA,CAAM,iBAAiB,CAAA;AAE/D,EAAA,MAAM,cAAgC,EAAC;AACvC,EAAA,MAAM,cAAgC,EAAC;AAEvC,EAAA,KAAA,MAAW,SAAS,SAAA,EAAW;AAC7B,IAAA,IAAI,KAAA,CAAM,cAAa,EAAG;AACxB,MAAA,MAAM,aAAa,MAAM,IAAA,CAAK,MAAM,KAAA,CAAM,yBAAyB,CAAA;AACnE,MAAA,WAAA,CAAY,IAAA,CAAK;AAAA,QACf,IAAI,KAAA,CAAM,EAAA;AAAA,QACV,KAAA,EAAO,yBAAA,CAA0B,KAAA,CAAM,KAAK,CAAA;AAAA,QAC5C,KAAA,EAAO,KAAA,CAAM,YAAA,IAAgB,KAAA,CAAM,UAAA,IAAc,CAAA;AAAA,QACjD,MAAA,EAAQ,KAAA,CAAM,aAAA,IAAiB,KAAA,CAAM,WAAA,IAAe,CAAA;AAAA,QACpD,aAAa,UAAA,IAAc;AAAA,OAC5B,CAAA;AAAA,IACH,CAAA,MAAA,IAAW,KAAA,CAAM,YAAA,EAAa,EAAG;AAC/B,MAAA,MAAM,aAAa,MAAM,IAAA,CAAK,MAAM,KAAA,CAAM,yBAAyB,CAAA;AACnE,MAAA,WAAA,CAAY,IAAA,CAAK;AAAA,QACf,IAAI,KAAA,CAAM,EAAA;AAAA,QACV,KAAA,EAAO,yBAAA,CAA0B,KAAA,CAAM,KAAK,CAAA;AAAA,QAC5C,QAAA,EAAU,MAAM,gBAAA,IAAoB,CAAA;AAAA,QACpC,UAAA,EAAY,MAAM,UAAA,IAAc,CAAA;AAAA,QAChC,UAAU,KAAA,CAAM,YAAA;AAAA,QAChB,aAAa,UAAA,IAAc;AAAA,OAC5B,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,MAAM,SAAS,MAAM,IAAA,CAAK,MAAM,KAAA,CAAM,WAAW,CAAA;AACjD,EAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,MAAA,EAAQ,IAAA,EAAM,gBAAgB,CAAA;AAEjE,EAAA,OAAO;AAAA,IACL,QAAQ,MAAA,CAAO,QAAA;AAAA,IACf,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,SAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,gBAAgB,EAAC;AAAA,IACjB,QAAA,EAAU,YAAA;AAAA,IACV;AAAA,GACF;AACF;AASA,eAAsB,qBAAA,CACpB,IACA,MAAA,EACiF;AACjF,EAAA,IAAI,MAAA,CAAO,SAAS,KAAA,EAAO;AACzB,IAAA,OAAO,IAAI,EAAA,CAAG,SAAA,CAAU,MAAA,CAAO,GAAG,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,IAAI,EAAA,CAAG,UAAA,CAAW,MAAA,CAAO,IAAI,CAAA;AACtC;AAWA,eAAsB,8BAAA,CACpB,IACA,MAAA,EACiF;AACjF,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,SAAiB,IAAI,EAAA,CAAG,UAAU,MAAM,CAAA;AAC9D,EAAA,IAAI,MAAA,YAAkB,KAAK,OAAO,IAAI,GAAG,SAAA,CAAU,MAAA,CAAO,UAAU,CAAA;AACpE,EAAA,IAAI,kBAAkB,IAAA,EAAM,OAAO,IAAI,EAAA,CAAG,WAAW,MAAM,CAAA;AAC3D,EAAA,IAAI,MAAA,YAAkB,WAAA,EAAa,OAAO,IAAI,EAAA,CAAG,UAAA,CAAW,IAAI,IAAA,CAAK,CAAC,MAAM,CAAC,CAAC,CAAA;AAC9E,EAAA,IAAI,MAAA,YAAkB,UAAA,EAAY,OAAO,IAAI,EAAA,CAAG,UAAA,CAAW,IAAI,IAAA,CAAK,CAAC,MAAkB,CAAC,CAAC,CAAA;AACzF,EAAA,MAAM,IAAI,UAAU,wCAAwC,CAAA;AAC9D;AAEA,SAAS,gBAAA,CAAiB,YAAgC,OAAA,EAAuC;AAC/F,EAAA,MAAM,IAAA,GAAA,CAAQ,UAAA,IAAc,EAAA,EAAI,WAAA,EAAY;AAC5C,EAAA,IAAI,IAAA,CAAK,SAAS,UAAU,CAAA,IAAK,KAAK,QAAA,CAAS,KAAK,GAAG,OAAO,KAAA;AAC9D,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG,OAAO,MAAA;AAClC,EAAA,IAAI,IAAA,CAAK,SAAS,KAAK,CAAA,IAAK,KAAK,QAAA,CAAS,MAAM,GAAG,OAAO,KAAA;AAC1D,EAAA,IAAI,IAAA,CAAK,SAAS,KAAK,CAAA,IAAK,KAAK,QAAA,CAAS,WAAW,GAAG,OAAO,KAAA;AAC/D,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,KAAA;AACjC,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,KAAA;AACjC,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG,OAAO,MAAA;AAClC,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,KAAA;AACjC,EAAA,IAAI,IAAA,CAAK,SAAS,MAAM,CAAA,IAAK,KAAK,QAAA,CAAS,KAAK,GAAG,OAAO,MAAA;AAC1D,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,QAAQ,CAAA,IAAK,IAAA,CAAK,QAAA,CAAS,SAAS,CAAA,IAAK,IAAA,CAAK,QAAA,CAAS,WAAW,CAAA,EAAG,OAAO,QAAA;AAC9F,EAAA,OAAO,OAAA;AACT;AAGO,SAAS,0BAA0B,CAAA,EAA0C;AAClF,EAAA,QAAQ,CAAA;AAAG,IACT,KAAK,KAAA;AAAQ,MAAA,OAAO,MAAA;AAAA,IACpB,KAAK,MAAA;AAAQ,MAAA,OAAO,MAAA;AAAA,IACpB,KAAK,KAAA;AAAQ,MAAA,OAAO,KAAA;AAAA,IACpB,KAAK,KAAA;AAAQ,MAAA,OAAO,KAAA;AAAA,IACpB,KAAK,KAAA;AAAQ,MAAA,OAAO,KAAA;AAAA,IACpB;AAME,MAAA,OAAO,IAAK,CAAA,GAAmB,SAAA;AAAA;AAErC;AAGO,SAAS,0BAA0B,CAAA,EAA8D;AACtG,EAAA,QAAQ,CAAA;AAAG,IACT,KAAK,MAAA;AAAQ,MAAA,OAAO,KAAA;AAAA,IACpB,KAAK,MAAA;AAAQ,MAAA,OAAO,MAAA;AAAA,IACpB,KAAK,KAAA;AAAQ,MAAA,OAAO,KAAA;AAAA,IACpB,KAAK,KAAA;AAAQ,MAAA,OAAO,KAAA;AAAA,IACpB,KAAK,KAAA;AAAQ,MAAA,OAAO,KAAA;AAAA,IACpB;AAAa,MAAA,OAAO,IAAA;AAAA;AAExB;AAEO,SAAS,0BAA0B,CAAA,EAA0C;AAClF,EAAA,QAAQ,CAAA;AAAG,IACT,KAAK,KAAA;AAAU,MAAA,OAAO,KAAA;AAAA,IACtB,KAAK,KAAA;AAAU,MAAA,OAAO,KAAA;AAAA,IACtB,KAAK,MAAA;AAAU,MAAA,OAAO,MAAA;AAAA,IACtB,KAAK,QAAA;AAAU,MAAA,OAAO,QAAA;AAAA,IACtB,KAAK,MAAA;AAAU,MAAA,OAAO,MAAA;AAAA,IACtB,KAAK,KAAA;AAAU,MAAA,OAAO,KAAA;AAAA,IACtB,KAAK,MAAA;AAAU,MAAA,OAAO,MAAA;AAAA,IACtB;AAAe,MAAA,OAAO,IAAK,CAAA,GAAmB,SAAA;AAAA;AAElD;AAEO,SAAS,0BAA0B,CAAA,EAA8B;AACtE,EAAA,QAAQ,CAAA;AAAG,IACT,KAAK,KAAA;AAAU,MAAA,OAAO,KAAA;AAAA,IACtB,KAAK,KAAA;AAAU,MAAA,OAAO,KAAA;AAAA,IACtB,KAAK,MAAA;AAAU,MAAA,OAAO,MAAA;AAAA,IACtB,KAAK,QAAA;AAAU,MAAA,OAAO,QAAA;AAAA,IACtB,KAAK,MAAA;AAAU,MAAA,OAAO,MAAA;AAAA,IACtB,KAAK,KAAA;AAAU,MAAA,OAAO,KAAA;AAAA,IACtB,KAAK,MAAA;AAAU,MAAA,OAAO,MAAA;AAAA,IACtB;AAAe,MAAA,OAAO,IAAA;AAAA;AAE1B;AAEA,eAAe,WAAW,EAAA,EAAiE;AACzF,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAI,MAAM,EAAA,EAAG;AACnB,IAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,QAAA,CAAS,CAAC,IAAI,CAAA,GAAI,KAAA,CAAA;AAAA,EAC3D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,eAAe,KAAQ,EAAA,EAAkD;AACvE,EAAA,IAAI;AAAE,IAAA,OAAO,MAAM,EAAA,EAAG;AAAA,EAAG,CAAA,CAAA,MAAQ;AAAE,IAAA,OAAO,MAAA;AAAA,EAAW;AACvD;;;ACjMA,IAAM,qBAAA,uBAA4B,GAAA,CAAmB;AAAA,EACnD,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAC,CAAA;AAkBD,eAAsB,KAAA,CACpB,QACA,SAAA,EACuB;AACvB,EAAA,MAAM,UAAA,GAAa,MAAMA,iCAAA,CAAgB,MAAA,EAAQ,SAAS,CAAA;AAC1D,EAAA,MAAM,OAAA,GAAU,MAAMC,uCAAA,CAAsB,UAAU,CAAA;AAEtD,EAAA,IAAI,qBAAA,CAAsB,GAAA,CAAI,OAAO,CAAA,EAAG;AACtC,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,mBAAA,CAAoB,UAAA,EAAY,OAAO,CAAA;AAI5D,MAAA,MAAM,kBACJ,MAAA,CAAO,WAAA,CAAY,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,KAAA,KAAU,SAAS,CAAA,IACpD,OAAO,WAAA,CAAY,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,SAAS,CAAA;AACtD,MAAA,IAAI,eAAA,EAAiB;AACnB,QAAA,IAAI;AACF,UAAA,MAAM,EAAE,cAAA,EAAe,GAAI,MAAM,OAAO,oBAAU,CAAA;AAClD,UAAA,OAAO,MAAM,cAAA,CAAe,UAAA,EAAY,OAAO,CAAA;AAAA,QACjD,CAAA,CAAA,MAAQ;AAGN,UAAA,OAAO,MAAA;AAAA,QACT;AAAA,MACF;AACA,MAAA,OAAO,MAAA;AAAA,IACT,SAAS,aAAA,EAAe;AAOtB,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,kCAAkC,OAAO,CAAA,6BAAA,CAAA;AAAA,QACxC,aAAA,CAAwB;AAAA,OAC3B;AACA,MAAA,IAAI;AACF,QAAA,MAAM,EAAE,cAAA,EAAe,GAAI,MAAM,OAAO,oBAAU,CAAA;AAClD,QAAA,OAAO,MAAM,cAAA,CAAe,UAAA,EAAY,OAAO,CAAA;AAAA,MACjD,SAAS,QAAA,EAAU;AACjB,QAAA,MAAM,KAAA,GAAS,aAAA,CAAwB,OAAA,IAAW,MAAA,CAAO,aAAa,CAAA;AACtE,QAAA,MAAM,QAAQ,QAAA,YAAoB,KAAA,GAAQ,QAAA,CAAS,OAAA,GAAU,OAAO,QAAQ,CAAA;AAC5E,QAAA,MAAM,IAAIC,+BAAA;AAAA,UACRC,kCAAA;AAAA,UACA,mBAAmB,OAAA,CAAQ,WAAA,EAAa,CAAA,mBAAA,EAAsB,KAAK,YAAY,KAAK,CAAA,CAAA,CAAA;AAAA,UACpF;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,cAAA,EAAe,GAAI,MAAM,OAAO,oBAAU,CAAA;AAClD,IAAA,OAAO,MAAM,cAAA,CAAe,UAAA,EAAY,OAAO,CAAA;AAAA,EACjD,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,QAAQ,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAE7D,IAAA,OAAA,CAAQ,KAAA,CAAM,mCAAA,EAAqC,OAAA,EAAS,OAAA,EAAS,GAAG,CAAA;AACxE,IAAA,IAAI,YAAY,SAAA,EAAW;AACzB,MAAA,MAAM,IAAID,+BAAA;AAAA,QACRE,6CAAA;AAAA,QACA,CAAA,kFAAA,EAAqF,SAAS,cAAc,CAAA,CAAA;AAAA,QAC5G;AAAA,OACF;AAAA,IACF;AACA,IAAA,MAAM,IAAIF,+BAAA;AAAA,MACRG,yCAAA;AAAA,MACA,GAAG,OAAA,CAAQ,WAAA,EAAa,CAAA,+CAAA,EAAkD,SAAS,cAAc,CAAA,CAAA;AAAA,MACjG;AAAA,KACF;AAAA,EACF;AACF","file":"chunk-VLI3Y6IJ.cjs","sourcesContent":["import type {\n  AudioCodec,\n  AudioTrackInfo,\n  ContainerKind,\n  MediaContext,\n  VideoCodec,\n  VideoTrackInfo,\n} from \"../types.js\";\nimport type { NormalizedSource } from \"../util/source.js\";\n\n/**\n * Probe via mediabunny. Built against the real (typed) API exported by\n * `mediabunny.d.ts`:\n *\n * - `Input.getTracks()` returns `InputTrack[]`; each track has `isVideoTrack()`\n *   / `isAudioTrack()` type guards plus a `codec` getter that returns one of\n *   the enum strings (`\"avc\"|\"hevc\"|\"vp9\"|\"vp8\"|\"av1\"` for video,\n *   `\"aac\"|\"opus\"|...` for audio).\n * - For decoder metadata + codec parameter strings we call\n *   `getDecoderConfig()` and `getCodecParameterString()` on the typed track.\n *\n * The bridging back to avbridge's own codec naming (`h264` instead of mediabunny's\n * `avc`) happens here so the rest of the codebase keeps a single vocabulary.\n */\nexport async function probeWithMediabunny(\n  source: NormalizedSource,\n  sniffedContainer: ContainerKind,\n): Promise<MediaContext> {\n  const mb = await import(\"mediabunny\");\n  const input = new mb.Input({\n    source: await buildMediabunnySource(mb, source),\n    formats: mb.ALL_FORMATS,\n  });\n\n  const allTracks = await input.getTracks();\n  const duration = await safeNumber(() => input.computeDuration());\n\n  const videoTracks: VideoTrackInfo[] = [];\n  const audioTracks: AudioTrackInfo[] = [];\n\n  for (const track of allTracks) {\n    if (track.isVideoTrack()) {\n      const codecParam = await safe(() => track.getCodecParameterString());\n      videoTracks.push({\n        id: track.id,\n        codec: mediabunnyVideoToAvbridge(track.codec),\n        width: track.displayWidth ?? track.codedWidth ?? 0,\n        height: track.displayHeight ?? track.codedHeight ?? 0,\n        codecString: codecParam ?? undefined,\n      });\n    } else if (track.isAudioTrack()) {\n      const codecParam = await safe(() => track.getCodecParameterString());\n      audioTracks.push({\n        id: track.id,\n        codec: mediabunnyAudioToAvbridge(track.codec),\n        channels: track.numberOfChannels ?? 0,\n        sampleRate: track.sampleRate ?? 0,\n        language: track.languageCode,\n        codecString: codecParam ?? undefined,\n      });\n    }\n  }\n\n  const format = await safe(() => input.getFormat());\n  const container = resolveContainer(format?.name, sniffedContainer);\n\n  return {\n    source: source.original,\n    name: source.name,\n    byteLength: source.byteLength,\n    container,\n    videoTracks,\n    audioTracks,\n    subtitleTracks: [],\n    probedBy: \"mediabunny\",\n    duration,\n  };\n}\n\n/**\n * Build the right mediabunny `Source` for a normalized input. URL sources\n * use `UrlSource` (Range requests, prefetch, parallelism) so we don't\n * buffer the whole file into memory. Blob/File sources use `BlobSource`.\n *\n * Exported so the remux strategy can use the same routing logic.\n */\nexport async function buildMediabunnySource(\n  mb: typeof import(\"mediabunny\"),\n  source: NormalizedSource,\n): Promise<InstanceType<typeof mb.BlobSource> | InstanceType<typeof mb.UrlSource>> {\n  if (source.kind === \"url\") {\n    return new mb.UrlSource(source.url);\n  }\n  return new mb.BlobSource(source.blob);\n}\n\n/**\n * Build a mediabunny `Source` directly from a raw `MediaInput`, bypassing\n * `normalizeSource`. Used by strategies that already have the original\n * input on hand (via `MediaContext.source`) and don't need a sniff window.\n *\n * This is the routing point that decides \"stream from URL via Range\n * requests\" vs \"wrap in-memory bytes as BlobSource\". Always prefer\n * `UrlSource` for URL inputs so we don't accidentally buffer the file.\n */\nexport async function buildMediabunnySourceFromInput(\n  mb: typeof import(\"mediabunny\"),\n  source: import(\"../types.js\").MediaInput,\n): Promise<InstanceType<typeof mb.BlobSource> | InstanceType<typeof mb.UrlSource>> {\n  if (typeof source === \"string\") return new mb.UrlSource(source);\n  if (source instanceof URL) return new mb.UrlSource(source.toString());\n  if (source instanceof Blob) return new mb.BlobSource(source);\n  if (source instanceof ArrayBuffer) return new mb.BlobSource(new Blob([source]));\n  if (source instanceof Uint8Array) return new mb.BlobSource(new Blob([source as BlobPart]));\n  throw new TypeError(\"unsupported source type for mediabunny\");\n}\n\nfunction resolveContainer(formatName: string | undefined, sniffed: ContainerKind): ContainerKind {\n  const name = (formatName ?? \"\").toLowerCase();\n  if (name.includes(\"matroska\") || name.includes(\"mkv\")) return \"mkv\";\n  if (name.includes(\"webm\")) return \"webm\";\n  if (name.includes(\"mp4\") || name.includes(\"isom\")) return \"mp4\";\n  if (name.includes(\"mov\") || name.includes(\"quicktime\")) return \"mov\";\n  if (name.includes(\"ogg\")) return \"ogg\";\n  if (name.includes(\"wav\")) return \"wav\";\n  if (name.includes(\"flac\")) return \"flac\";\n  if (name.includes(\"mp3\")) return \"mp3\";\n  if (name.includes(\"adts\") || name.includes(\"aac\")) return \"adts\";\n  if (name.includes(\"mpegts\") || name.includes(\"mpeg-ts\") || name.includes(\"transport\")) return \"mpegts\";\n  return sniffed;\n}\n\n/** Mediabunny video codec → avbridge video codec. */\nexport function mediabunnyVideoToAvbridge(c: string | null | undefined): VideoCodec {\n  switch (c) {\n    case \"avc\":  return \"h264\";\n    case \"hevc\": return \"h265\";\n    case \"vp8\":  return \"vp8\";\n    case \"vp9\":  return \"vp9\";\n    case \"av1\":  return \"av1\";\n    default:\n      // Preserve the original codec string when mediabunny gave us something\n      // we don't recognize. The classifier checks `NATIVE_VIDEO_CODECS.has()`\n      // and routes anything outside that set through the fallback chain — so\n      // returning the unknown name (instead of silently relabeling it as\n      // \"h264\") gets correct routing AND honest diagnostics.\n      return c ? (c as VideoCodec) : \"unknown\";\n  }\n}\n\n/** avbridge video codec → mediabunny video codec (for output sources). */\nexport function avbridgeVideoToMediabunny(c: VideoCodec): \"avc\" | \"hevc\" | \"vp9\" | \"vp8\" | \"av1\" | null {\n  switch (c) {\n    case \"h264\": return \"avc\";\n    case \"h265\": return \"hevc\";\n    case \"vp8\":  return \"vp8\";\n    case \"vp9\":  return \"vp9\";\n    case \"av1\":  return \"av1\";\n    default:     return null;\n  }\n}\n\nexport function mediabunnyAudioToAvbridge(c: string | null | undefined): AudioCodec {\n  switch (c) {\n    case \"aac\":    return \"aac\";\n    case \"mp3\":    return \"mp3\";\n    case \"opus\":   return \"opus\";\n    case \"vorbis\": return \"vorbis\";\n    case \"flac\":   return \"flac\";\n    case \"ac3\":    return \"ac3\";\n    case \"eac3\":   return \"eac3\";\n    default:       return c ? (c as AudioCodec) : \"unknown\";\n  }\n}\n\nexport function avbridgeAudioToMediabunny(c: AudioCodec): string | null {\n  switch (c) {\n    case \"aac\":    return \"aac\";\n    case \"mp3\":    return \"mp3\";\n    case \"opus\":   return \"opus\";\n    case \"vorbis\": return \"vorbis\";\n    case \"flac\":   return \"flac\";\n    case \"ac3\":    return \"ac3\";\n    case \"eac3\":   return \"eac3\";\n    default:       return null;\n  }\n}\n\nasync function safeNumber(fn: () => Promise<number> | number): Promise<number | undefined> {\n  try {\n    const v = await fn();\n    return typeof v === \"number\" && Number.isFinite(v) ? v : undefined;\n  } catch {\n    return undefined;\n  }\n}\n\nasync function safe<T>(fn: () => Promise<T> | T): Promise<T | undefined> {\n  try { return await fn(); } catch { return undefined; }\n}\n","import type { ContainerKind, MediaContext, MediaInput, TransportConfig } from \"../types.js\";\nimport { normalizeSource, sniffNormalizedSource } from \"../util/source.js\";\nimport { probeWithMediabunny } from \"./mediabunny.js\";\nimport { AvbridgeError, ERR_PROBE_FAILED, ERR_PROBE_UNKNOWN_CONTAINER, ERR_LIBAV_NOT_REACHABLE } from \"../errors.js\";\n\n/** Containers mediabunny can demux. Sniff results outside this set go straight to libav. */\nconst MEDIABUNNY_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 * Probe a source and produce a {@link MediaContext}.\n *\n * Routing:\n * 1. Sniff the magic header. Cheap, deterministic, ignores file extensions.\n * 2. If the container is one mediabunny supports → try mediabunny first\n *    (fast path — it's a single pass of WASM-free JS parsing). If mediabunny\n *    throws (e.g. an assertion on an unsupported sample entry like `mp4v`\n *    for MPEG-4 Part 2 in ISOBMFF, or an exotic MKV codec), fall through to\n *    libav.js which handles the long tail of codecs mediabunny doesn't.\n *    The combined-error case surfaces *both* failures so the user sees\n *    which path each step took.\n * 3. If sniffing identifies AVI/ASF/FLV (or `unknown`) → libav.js directly.\n *    mediabunny can't read those containers at all, so there's no fast path\n *    to try.\n */\nexport async function probe(\n  source: MediaInput,\n  transport?: TransportConfig,\n): Promise<MediaContext> {\n  const normalized = await normalizeSource(source, transport);\n  const sniffed = await sniffNormalizedSource(normalized);\n\n  if (MEDIABUNNY_CONTAINERS.has(sniffed)) {\n    try {\n      const result = await probeWithMediabunny(normalized, sniffed);\n      // If mediabunny returned unknown codecs, try libav which recognizes\n      // a wider range (DTS, TrueHD, etc.). Only escalate if there ARE\n      // tracks with unknown codecs — otherwise mediabunny's result is fine.\n      const hasUnknownCodec =\n        result.videoTracks.some((t) => t.codec === \"unknown\") ||\n        result.audioTracks.some((t) => t.codec === \"unknown\");\n      if (hasUnknownCodec) {\n        try {\n          const { probeWithLibav } = await import(\"./avi.js\");\n          return await probeWithLibav(normalized, sniffed);\n        } catch {\n          // libav also failed — return mediabunny's result (unknown codecs\n          // are better than no result at all)\n          return result;\n        }\n      }\n      return result;\n    } catch (mediabunnyErr) {\n      // mediabunny rejected the file. Before giving up, try libav — it can\n      // demux a much wider range of codec combinations in ISOBMFF/MKV/etc.\n      // than mediabunny's pure-JS parser (e.g. mp4v, wmv3-in-asf, flac in\n      // an MP4 container). This is \"escalation\", not \"masking\": if libav\n      // also fails we surface both errors below.\n      // eslint-disable-next-line no-console\n      console.warn(\n        `[avbridge] mediabunny rejected ${sniffed} file, falling back to libav:`,\n        (mediabunnyErr as Error).message,\n      );\n      try {\n        const { probeWithLibav } = await import(\"./avi.js\");\n        return await probeWithLibav(normalized, sniffed);\n      } catch (libavErr) {\n        const mbMsg = (mediabunnyErr as Error).message || String(mediabunnyErr);\n        const lvMsg = libavErr instanceof Error ? libavErr.message : String(libavErr);\n        throw new AvbridgeError(\n          ERR_PROBE_FAILED,\n          `Failed to probe ${sniffed.toUpperCase()} file. mediabunny: ${mbMsg}. libav: ${lvMsg}.`,\n          \"The file may be corrupt, truncated, or in an unsupported format. Enable AVBRIDGE_DEBUG for detailed logs.\",\n        );\n      }\n    }\n  }\n\n  // sniffed === avi | asf | flv | unknown — try libav.\n  try {\n    const { probeWithLibav } = await import(\"./avi.js\");\n    return await probeWithLibav(normalized, sniffed);\n  } catch (err) {\n    const inner = err instanceof Error ? err.message : String(err);\n    // eslint-disable-next-line no-console\n    console.error(\"[avbridge] libav probe failed for\", sniffed, \"file:\", err);\n    if (sniffed === \"unknown\") {\n      throw new AvbridgeError(\n        ERR_PROBE_UNKNOWN_CONTAINER,\n        `Unable to probe source: container format could not be identified. libav fallback: ${inner || \"(no details)\"}`,\n        \"The file may be corrupt or in a format avbridge doesn't recognize. Check the file plays in VLC or ffprobe.\",\n      );\n    }\n    throw new AvbridgeError(\n      ERR_LIBAV_NOT_REACHABLE,\n      `${sniffed.toUpperCase()} files require libav.js, which failed to load: ${inner || \"(no details)\"}`,\n      \"Install @libav.js/variant-webcodecs, or check that AVBRIDGE_LIBAV_BASE points to the correct path.\",\n    );\n  }\n}\n"]}