avbridge 2.12.0 → 2.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/dist/{avi-EQE6AR75.cjs → avi-32UABODO.cjs} +12 -4
- package/dist/avi-32UABODO.cjs.map +1 -0
- package/dist/{avi-Y3N325WZ.cjs → avi-5BPR6QUX.cjs} +12 -4
- package/dist/avi-5BPR6QUX.cjs.map +1 -0
- package/dist/{avi-NNHH4AAA.js → avi-BLIH7KKV.js} +12 -4
- package/dist/avi-BLIH7KKV.js.map +1 -0
- package/dist/{avi-S7EY54YA.js → avi-GX2H34IQ.js} +12 -4
- package/dist/avi-GX2H34IQ.js.map +1 -0
- package/dist/{chunk-2LNXMGT6.js → chunk-5CX7BVVV.js} +5 -5
- package/dist/{chunk-2LNXMGT6.js.map → chunk-5CX7BVVV.js.map} +1 -1
- package/dist/{chunk-5Y5BTB5D.js → chunk-B76QWPFM.js} +3 -3
- package/dist/{chunk-5Y5BTB5D.js.map → chunk-B76QWPFM.js.map} +1 -1
- package/dist/{chunk-Z26PXRUY.js → chunk-BN7BRTLY.js} +137 -26
- package/dist/chunk-BN7BRTLY.js.map +1 -0
- package/dist/{chunk-GJBNLPGI.cjs → chunk-E5MAM2P4.cjs} +9 -9
- package/dist/{chunk-GJBNLPGI.cjs.map → chunk-E5MAM2P4.cjs.map} +1 -1
- package/dist/{chunk-7EF4VTUS.cjs → chunk-UM6WCSGL.cjs} +141 -30
- package/dist/chunk-UM6WCSGL.cjs.map +1 -0
- package/dist/{chunk-HBHSUGNI.cjs → chunk-VLI3Y6IJ.cjs} +5 -5
- package/dist/{chunk-HBHSUGNI.cjs.map → chunk-VLI3Y6IJ.cjs.map} +1 -1
- package/dist/element-browser.js +144 -25
- package/dist/element-browser.js.map +1 -1
- package/dist/element.cjs +3 -3
- package/dist/element.js +2 -2
- package/dist/index.cjs +18 -18
- package/dist/index.js +6 -6
- package/dist/player.cjs +207 -41
- package/dist/player.cjs.map +1 -1
- package/dist/player.d.cts +1 -0
- package/dist/player.d.ts +1 -0
- package/dist/player.js +207 -41
- package/dist/player.js.map +1 -1
- package/dist/{remux-VPKCLHHM.cjs → remux-NSBJFMLG.cjs} +9 -9
- package/dist/{remux-VPKCLHHM.cjs.map → remux-NSBJFMLG.cjs.map} +1 -1
- package/dist/{remux-7TA4FKTY.js → remux-PHUHO3VV.js} +4 -4
- package/dist/{remux-7TA4FKTY.js.map → remux-PHUHO3VV.js.map} +1 -1
- package/package.json +1 -1
- package/src/element/avbridge-player.ts +87 -15
- package/src/probe/avi.ts +34 -2
- package/src/strategies/fallback/decoder.ts +148 -19
- package/src/strategies/fallback/video-renderer.ts +41 -3
- package/src/strategies/hybrid/decoder.ts +34 -9
- package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.mjs +1 -1
- package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.wasm +0 -0
- package/vendor/libav/avbridge/libav-avbridge.mjs +1 -1
- package/dist/avi-EQE6AR75.cjs.map +0 -1
- package/dist/avi-NNHH4AAA.js.map +0 -1
- package/dist/avi-S7EY54YA.js.map +0 -1
- package/dist/avi-Y3N325WZ.cjs.map +0 -1
- package/dist/chunk-7EF4VTUS.cjs.map +0 -1
- package/dist/chunk-Z26PXRUY.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/strategies/remux/annexb.ts","../src/convert/remux.ts"],"names":[],"mappings":"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","file":"chunk-5Y5BTB5D.js","sourcesContent":["/**\n * H.264/HEVC bitstream conversion helpers.\n *\n * Demuxers from MP4-family containers (mediabunny) hand us packets in **AVCC**\n * format: each NAL unit prefixed with a 4-byte big-endian length.\n *\n * Demuxers from elementary-stream/AVI/TS hand us **Annex B**: NAL units\n * separated by `00 00 00 01` (or `00 00 01`) start codes.\n *\n * MSE expects AVCC inside fragmented MP4. So when the source side emits Annex\n * B, we need to convert before muxing. Going the other way (AVCC → Annex B) is\n * useful for feeding `VideoDecoder` configured with `description` omitted.\n */\n\nconst START_CODE_4 = new Uint8Array([0, 0, 0, 1]);\n\n/** True if the bytes look like Annex B (start with `00 00 00 01` or `00 00 01`). */\nexport function isAnnexB(bytes: Uint8Array): boolean {\n if (bytes.length < 3) return false;\n if (bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 1) return true;\n if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 0 && bytes[3] === 1) return true;\n return false;\n}\n\n/**\n * Walk an Annex B byte stream and yield each NAL unit (without start code).\n * This is the standard byte-by-byte scan; no SIMD tricks because the typical\n * frame is small.\n */\nexport function* iterateAnnexBNalus(bytes: Uint8Array): Generator<Uint8Array> {\n const length = bytes.length;\n let i = 0;\n let nalStart = -1;\n\n while (i < length) {\n // Look for start code at position i\n let scLen = 0;\n if (i + 3 < length && bytes[i] === 0 && bytes[i + 1] === 0 && bytes[i + 2] === 0 && bytes[i + 3] === 1) {\n scLen = 4;\n } else if (i + 2 < length && bytes[i] === 0 && bytes[i + 1] === 0 && bytes[i + 2] === 1) {\n scLen = 3;\n }\n\n if (scLen > 0) {\n if (nalStart >= 0) {\n yield bytes.subarray(nalStart, i);\n }\n nalStart = i + scLen;\n i += scLen;\n } else {\n i += 1;\n }\n }\n\n if (nalStart >= 0 && nalStart < length) {\n yield bytes.subarray(nalStart, length);\n }\n}\n\n/**\n * Convert an Annex B byte stream to AVCC. Each NALU is prefixed with its\n * 4-byte big-endian length.\n */\nexport function annexBToAvcc(annexB: Uint8Array): Uint8Array {\n const nalus: Uint8Array[] = [];\n let total = 0;\n for (const nal of iterateAnnexBNalus(annexB)) {\n nalus.push(nal);\n total += 4 + nal.length;\n }\n const out = new Uint8Array(total);\n let off = 0;\n for (const nal of nalus) {\n const len = nal.length;\n out[off++] = (len >>> 24) & 0xff;\n out[off++] = (len >>> 16) & 0xff;\n out[off++] = (len >>> 8) & 0xff;\n out[off++] = len & 0xff;\n out.set(nal, off);\n off += len;\n }\n return out;\n}\n\n/**\n * Convert AVCC (4-byte length-prefixed) NALUs to Annex B. Each NALU is\n * prefixed with `00 00 00 01`.\n */\nexport function avccToAnnexB(avcc: Uint8Array): Uint8Array {\n const out: Uint8Array[] = [];\n let total = 0;\n let i = 0;\n while (i + 4 <= avcc.length) {\n const len =\n (avcc[i] << 24) | (avcc[i + 1] << 16) | (avcc[i + 2] << 8) | avcc[i + 3];\n i += 4;\n if (i + len > avcc.length) {\n throw new Error(`avccToAnnexB: NAL length ${len} overflows buffer at offset ${i}`);\n }\n out.push(START_CODE_4);\n out.push(avcc.subarray(i, i + len));\n total += 4 + len;\n i += len;\n }\n const merged = new Uint8Array(total);\n let off = 0;\n for (const chunk of out) {\n merged.set(chunk, off);\n off += chunk.length;\n }\n return merged;\n}\n","/**\n * Standalone remux function: repackage media into a modern container without\n * re-encoding. Input can be any format avbridge can probe; output is a\n * finalized downloadable file (MP4, WebM, or MKV).\n *\n * Two internal paths:\n * - **Path A** (mediabunny-readable containers): wraps mediabunny's Conversion\n * class for MP4/MKV/WebM/OGG/MOV/WAV/MP3/FLAC/ADTS sources.\n * - **Path B** (AVI/ASF/FLV): libav.js demux + mediabunny mux via manual\n * packet pump. Lazy-loads libav.js — zero cost if unused.\n */\n\nimport { probe } from \"../probe/index.js\";\nimport { isAnnexB, annexBToAvcc } from \"../strategies/remux/annexb.js\";\nimport {\n avbridgeVideoToMediabunny,\n avbridgeAudioToMediabunny,\n buildMediabunnySourceFromInput,\n} from \"../probe/mediabunny.js\";\nimport { normalizeSource } from \"../util/source.js\";\nimport { sanitizePacketTimestamp } from \"../util/libav-demux.js\";\nimport { prepareLibavInput, type LibavInputHandle } from \"../util/libav-http-reader.js\";\nimport type {\n MediaInput,\n MediaContext,\n ConvertOptions,\n ConvertResult,\n OutputFormat,\n} from \"../types.js\";\n\n/** Containers mediabunny can read (and therefore use Conversion for). */\nconst MEDIABUNNY_CONTAINERS = new Set([\n \"mp4\", \"mov\", \"mkv\", \"webm\", \"ogg\", \"wav\", \"mp3\", \"flac\", \"adts\",\n]);\n\n/**\n * Remux a media source into a modern container format without re-encoding.\n *\n * @throws When the source codecs cannot be remuxed (e.g. WMV3 — use `transcode()` instead).\n * @throws When an AVI/ASF/FLV source is provided but libav.js is not installed.\n */\nexport async function remux(\n source: MediaInput,\n options: ConvertOptions = {},\n): Promise<ConvertResult> {\n const outputFormat = options.outputFormat ?? \"mp4\";\n options.signal?.throwIfAborted();\n\n // Probe the source\n const ctx = await probe(source);\n options.signal?.throwIfAborted();\n\n // Validate remux eligibility: all codecs must map to mediabunny output codecs\n validateRemuxEligibility(ctx, options.strict ?? false);\n\n // Route to the appropriate path\n if (MEDIABUNNY_CONTAINERS.has(ctx.container)) {\n return remuxViaMediAbunny(ctx, outputFormat, options);\n }\n return remuxViaLibav(ctx, outputFormat, options);\n}\n\n// ── Eligibility validation ──────────────────────────────────────────────────\n\n/** @internal Exported for testing. */\nexport function validateRemuxEligibility(ctx: MediaContext, strict: boolean): void {\n const video = ctx.videoTracks[0];\n const audio = ctx.audioTracks[0];\n\n if (video) {\n const mbCodec = avbridgeVideoToMediabunny(video.codec);\n if (!mbCodec) {\n throw new Error(\n `Cannot remux: video codec \"${video.codec}\" is not supported for remuxing. ` +\n `Use transcode() to re-encode to a modern codec.`,\n );\n }\n }\n\n if (audio) {\n const mbCodec = avbridgeAudioToMediabunny(audio.codec);\n if (!mbCodec) {\n throw new Error(\n `Cannot remux: audio codec \"${audio.codec}\" is not supported for remuxing. ` +\n `Use transcode() to re-encode to a modern codec.`,\n );\n }\n }\n\n if (strict && video?.codec === \"h264\" && audio?.codec === \"mp3\") {\n throw new Error(\n `Cannot remux in strict mode: H.264 + MP3 is a best-effort combination ` +\n `that may produce playback issues in some browsers. ` +\n `Set strict: false to allow, or use transcode() to re-encode audio to AAC.`,\n );\n }\n\n if (!video && !audio) {\n throw new Error(\"Cannot remux: source has no video or audio tracks.\");\n }\n}\n\n// ── Path A: mediabunny Conversion ───────────────────────────────────────────\n\nasync function remuxViaMediAbunny(\n ctx: MediaContext,\n outputFormat: OutputFormat,\n options: ConvertOptions,\n): Promise<ConvertResult> {\n const mb = await import(\"mediabunny\");\n\n const input = new mb.Input({\n source: await buildMediabunnySourceFromInput(mb, ctx.source),\n formats: mb.ALL_FORMATS,\n });\n\n const target = new mb.BufferTarget();\n const output = new mb.Output({\n format: createOutputFormat(mb, outputFormat),\n target,\n });\n\n const conversion = await mb.Conversion.init({\n input,\n output,\n showWarnings: false,\n });\n\n if (!conversion.isValid) {\n const reasons = conversion.discardedTracks\n .map((d) => `${d.track.type} track discarded: ${d.reason}`)\n .join(\"; \");\n throw new Error(`Cannot remux: mediabunny rejected the conversion. ${reasons}`);\n }\n\n // Wire progress\n if (options.onProgress) {\n const onProgress = options.onProgress;\n conversion.onProgress = (p) => {\n onProgress({ percent: p * 100, bytesWritten: 0 });\n };\n }\n\n // Wire cancellation\n let abortHandler: (() => void) | undefined;\n if (options.signal) {\n options.signal.throwIfAborted();\n abortHandler = () => void conversion.cancel();\n options.signal.addEventListener(\"abort\", abortHandler, { once: true });\n }\n\n try {\n await conversion.execute();\n } finally {\n if (abortHandler && options.signal) {\n options.signal.removeEventListener(\"abort\", abortHandler);\n }\n }\n\n if (!target.buffer) {\n throw new Error(\"Remux failed: mediabunny produced no output buffer.\");\n }\n\n const mimeType = mimeForFormat(outputFormat);\n const blob = new Blob([target.buffer], { type: mimeType });\n const filename = generateFilename(ctx.name, outputFormat);\n\n options.onProgress?.({ percent: 100, bytesWritten: blob.size });\n\n return {\n blob,\n mimeType,\n container: outputFormat,\n videoCodec: ctx.videoTracks[0]?.codec,\n audioCodec: ctx.audioTracks[0]?.codec,\n duration: ctx.duration,\n filename,\n };\n}\n\n// ── Path B: libav.js demux + mediabunny mux (AVI/ASF/FLV) ──────────────────\n\nasync function remuxViaLibav(\n ctx: MediaContext,\n outputFormat: OutputFormat,\n options: ConvertOptions,\n): Promise<ConvertResult> {\n // Lazy-load libav\n let loadLibav: typeof import(\"../strategies/fallback/libav-loader.js\").loadLibav;\n let pickLibavVariant: typeof import(\"../strategies/fallback/variant-routing.js\").pickLibavVariant;\n try {\n const loader = await import(\"../strategies/fallback/libav-loader.js\");\n const routing = await import(\"../strategies/fallback/variant-routing.js\");\n loadLibav = loader.loadLibav;\n pickLibavVariant = routing.pickLibavVariant;\n } catch {\n throw new Error(\n `Cannot remux ${ctx.container.toUpperCase()} source: libav.js is not available. ` +\n `Install @libav.js/variant-webcodecs and libavjs-webcodecs-bridge, ` +\n `or build the custom avbridge variant with scripts/build-libav.sh.`,\n );\n }\n\n const variant = pickLibavVariant(ctx);\n const libav = await loadLibav(variant) as unknown as LibavRuntime;\n\n // For Blob/File inputs, libav reads from an in-memory readahead file.\n // For URL inputs, libav demuxes via HTTP Range requests through the\n // block reader — no full download.\n const normalized = await normalizeSource(ctx.source);\n const filename = ctx.name ?? `remux-input-${Date.now()}`;\n const handle: LibavInputHandle = await prepareLibavInput(libav as unknown as Parameters<typeof prepareLibavInput>[0], filename, normalized);\n\n try {\n return await doLibavRemux(libav, filename, ctx, outputFormat, options);\n } finally {\n await handle.detach().catch(() => {});\n }\n}\n\nasync function doLibavRemux(\n libav: LibavRuntime,\n filename: string,\n ctx: MediaContext,\n outputFormat: OutputFormat,\n options: ConvertOptions,\n): Promise<ConvertResult> {\n const mb = await import(\"mediabunny\");\n\n const readPkt = await libav.av_packet_alloc();\n const [fmt_ctx, streams] = await libav.ff_init_demuxer_file(filename);\n const videoStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_VIDEO) ?? null;\n const audioStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO) ?? null;\n\n // Map codecs to mediabunny output\n const videoTrackInfo = ctx.videoTracks[0];\n const audioTrackInfo = ctx.audioTracks[0];\n const mbVideoCodec = videoTrackInfo ? avbridgeVideoToMediabunny(videoTrackInfo.codec) : null;\n const mbAudioCodec = audioTrackInfo ? avbridgeAudioToMediabunny(audioTrackInfo.codec) : null;\n\n // Set up mediabunny output with BufferTarget\n const target = new mb.BufferTarget();\n const output = new mb.Output({\n format: createOutputFormat(mb, outputFormat),\n target,\n });\n\n let videoSource: InstanceType<typeof mb.EncodedVideoPacketSource> | null = null;\n let audioSource: InstanceType<typeof mb.EncodedAudioPacketSource> | null = null;\n\n if (mbVideoCodec && videoStream) {\n videoSource = new mb.EncodedVideoPacketSource(mbVideoCodec);\n output.addVideoTrack(videoSource);\n }\n if (mbAudioCodec && audioStream) {\n type AudioCodecArg = ConstructorParameters<typeof mb.EncodedAudioPacketSource>[0];\n audioSource = new mb.EncodedAudioPacketSource(mbAudioCodec as AudioCodecArg);\n output.addAudioTrack(audioSource);\n }\n\n await output.start();\n\n // Timestamp tracking for synthetic timestamps\n const videoFps = videoTrackInfo?.fps && videoTrackInfo.fps > 0 ? videoTrackInfo.fps : 30;\n const videoFrameStepUs = Math.max(1, Math.round(1_000_000 / videoFps));\n let syntheticVideoUs = 0;\n let syntheticAudioUs = 0;\n\n const videoTimeBase: [number, number] | undefined =\n videoStream?.time_base_num && videoStream?.time_base_den\n ? [videoStream.time_base_num, videoStream.time_base_den]\n : undefined;\n const audioTimeBase: [number, number] | undefined =\n audioStream?.time_base_num && audioStream?.time_base_den\n ? [audioStream.time_base_num, audioStream.time_base_den]\n : undefined;\n\n let totalPackets = 0;\n const durationUs = ctx.duration ? ctx.duration * 1_000_000 : 0;\n let firstVideoMeta = true;\n let firstAudioMeta = true;\n\n // Pump loop: read packets from libav, feed to mediabunny output\n while (true) {\n options.signal?.throwIfAborted();\n\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: 64 * 1024,\n });\n } catch (err) {\n throw new Error(`libav demux failed: ${(err as Error).message}`);\n }\n\n const videoPackets = videoStream ? packets[videoStream.index] ?? [] : [];\n const audioPackets = audioStream ? packets[audioStream.index] ?? [] : [];\n\n // Feed video packets\n if (videoSource) {\n for (const pkt of videoPackets) {\n sanitizePacketTimestamp(pkt, () => {\n const ts = syntheticVideoUs;\n syntheticVideoUs += videoFrameStepUs;\n return ts;\n }, videoTimeBase);\n\n // libav demuxes AVI/ASF/FLV H.264 as Annex B (start-code framed),\n // but mediabunny's fMP4 muxer expects AVCC (length-prefixed). Convert\n // on the fly. The check is cheap: isAnnexB reads 4 bytes at the head.\n if (videoTrackInfo && (videoTrackInfo.codec === \"h264\" || videoTrackInfo.codec === \"h265\") && isAnnexB(pkt.data)) {\n pkt.data = annexBToAvcc(pkt.data);\n }\n\n const mbPacket = libavPacketToMediAbunny(mb, pkt);\n await videoSource.add(\n mbPacket,\n firstVideoMeta ? { decoderConfig: buildVideoDecoderConfig(videoTrackInfo!) } : undefined,\n );\n firstVideoMeta = false;\n }\n }\n\n // Feed audio packets\n if (audioSource) {\n for (const pkt of audioPackets) {\n sanitizePacketTimestamp(pkt, () => {\n const ts = syntheticAudioUs;\n const sampleRate = audioTrackInfo?.sampleRate ?? 44100;\n syntheticAudioUs += Math.round(1024 * 1_000_000 / sampleRate);\n return ts;\n }, audioTimeBase);\n\n const mbPacket = libavPacketToMediAbunny(mb, pkt);\n await audioSource.add(\n mbPacket,\n firstAudioMeta ? { decoderConfig: buildAudioDecoderConfig(audioTrackInfo!) } : undefined,\n );\n firstAudioMeta = false;\n }\n }\n\n totalPackets += videoPackets.length + audioPackets.length;\n\n // Report progress\n if (options.onProgress && durationUs > 0) {\n const lastVideoTs = videoPackets.length > 0 ? videoPackets[videoPackets.length - 1].pts ?? 0 : 0;\n const lastAudioTs = audioPackets.length > 0 ? audioPackets[audioPackets.length - 1].pts ?? 0 : 0;\n const currentUs = Math.max(lastVideoTs, lastAudioTs);\n const percent = Math.min(99, (currentUs / durationUs) * 100);\n options.onProgress({ percent, bytesWritten: 0 });\n }\n\n if (readErr === libav.AVERROR_EOF) break;\n if (readErr && readErr !== 0 && readErr !== -libav.EAGAIN) {\n console.warn(\"[avbridge] remux: ff_read_frame_multi returned\", readErr);\n break;\n }\n }\n\n await output.finalize();\n\n // Cleanup libav resources\n try { await libav.av_packet_free?.(readPkt); } catch { /* ignore */ }\n try { await libav.avformat_close_input_js(fmt_ctx); } catch { /* ignore */ }\n\n if (!target.buffer) {\n throw new Error(\"Remux failed: mediabunny produced no output buffer.\");\n }\n\n const mimeType = mimeForFormat(outputFormat);\n const blob = new Blob([target.buffer], { type: mimeType });\n const outputFilename = generateFilename(ctx.name, outputFormat);\n\n options.onProgress?.({ percent: 100, bytesWritten: blob.size });\n\n return {\n blob,\n mimeType,\n container: outputFormat,\n videoCodec: videoTrackInfo?.codec,\n audioCodec: audioTrackInfo?.codec,\n duration: ctx.duration,\n filename: outputFilename,\n };\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\n/** @internal Exported for use by transcode(). */\nexport function createOutputFormat(\n mb: typeof import(\"mediabunny\"),\n format: OutputFormat,\n) {\n switch (format) {\n case \"mp4\": return new mb.Mp4OutputFormat({ fastStart: \"in-memory\" });\n case \"webm\": return new mb.WebMOutputFormat();\n case \"mkv\": return new mb.MkvOutputFormat();\n default: return new mb.Mp4OutputFormat({ fastStart: \"in-memory\" });\n }\n}\n\n/** @internal Exported for testing. */\nexport function mimeForFormat(format: OutputFormat): string {\n switch (format) {\n case \"mp4\": return \"video/mp4\";\n case \"webm\": return \"video/webm\";\n case \"mkv\": return \"video/x-matroska\";\n default: return \"application/octet-stream\";\n }\n}\n\n/** @internal Exported for testing. */\nexport function generateFilename(originalName: string | undefined, format: OutputFormat): string {\n const ext = format === \"mkv\" ? \"mkv\" : format;\n if (!originalName) return `output.${ext}`;\n const base = originalName.replace(/\\.[^.]+$/, \"\");\n return `${base}.${ext}`;\n}\n\n/** Sequence counter for decode-order numbering in mediabunny packets. */\nlet _seqCounter = 0;\n\n/**\n * Convert a libav packet to a mediabunny EncodedPacket.\n * Timestamps from libav are in microseconds (after sanitization); mediabunny wants seconds.\n */\nfunction libavPacketToMediAbunny(\n mb: typeof import(\"mediabunny\"),\n pkt: LibavPacket,\n): InstanceType<typeof mb.EncodedPacket> {\n const KEY_FRAME_FLAG = 0x0001;\n const timestampSec = (pkt.pts ?? 0) / 1_000_000;\n const durationSec = (pkt.duration ?? 0) / 1_000_000;\n const type = (pkt.flags & KEY_FRAME_FLAG) ? \"key\" as const : \"delta\" as const;\n return new mb.EncodedPacket(pkt.data, type, timestampSec, durationSec, _seqCounter++);\n}\n\nfunction buildVideoDecoderConfig(track: { codec: string; width: number; height: number; codecString?: string }) {\n return {\n codec: track.codecString ?? track.codec,\n codedWidth: track.width,\n codedHeight: track.height,\n };\n}\n\nfunction buildAudioDecoderConfig(track: { codec: string; channels: number; sampleRate: number; codecString?: string }) {\n return {\n codec: track.codecString ?? track.codec,\n numberOfChannels: track.channels,\n sampleRate: track.sampleRate,\n };\n}\n\n// ── Structural types ────────────────────────────────────────────────────────\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 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 LibavRuntime {\n AVMEDIA_TYPE_VIDEO: number;\n AVMEDIA_TYPE_AUDIO: number;\n AVERROR_EOF: number;\n EAGAIN: 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 av_packet_alloc(): Promise<number>;\n av_packet_free?(pkt: number): Promise<void>;\n avformat_close_input_js(ctx: number): Promise<void>;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/strategies/remux/annexb.ts","../src/convert/remux.ts"],"names":[],"mappings":"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","file":"chunk-B76QWPFM.js","sourcesContent":["/**\n * H.264/HEVC bitstream conversion helpers.\n *\n * Demuxers from MP4-family containers (mediabunny) hand us packets in **AVCC**\n * format: each NAL unit prefixed with a 4-byte big-endian length.\n *\n * Demuxers from elementary-stream/AVI/TS hand us **Annex B**: NAL units\n * separated by `00 00 00 01` (or `00 00 01`) start codes.\n *\n * MSE expects AVCC inside fragmented MP4. So when the source side emits Annex\n * B, we need to convert before muxing. Going the other way (AVCC → Annex B) is\n * useful for feeding `VideoDecoder` configured with `description` omitted.\n */\n\nconst START_CODE_4 = new Uint8Array([0, 0, 0, 1]);\n\n/** True if the bytes look like Annex B (start with `00 00 00 01` or `00 00 01`). */\nexport function isAnnexB(bytes: Uint8Array): boolean {\n if (bytes.length < 3) return false;\n if (bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 1) return true;\n if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 0 && bytes[3] === 1) return true;\n return false;\n}\n\n/**\n * Walk an Annex B byte stream and yield each NAL unit (without start code).\n * This is the standard byte-by-byte scan; no SIMD tricks because the typical\n * frame is small.\n */\nexport function* iterateAnnexBNalus(bytes: Uint8Array): Generator<Uint8Array> {\n const length = bytes.length;\n let i = 0;\n let nalStart = -1;\n\n while (i < length) {\n // Look for start code at position i\n let scLen = 0;\n if (i + 3 < length && bytes[i] === 0 && bytes[i + 1] === 0 && bytes[i + 2] === 0 && bytes[i + 3] === 1) {\n scLen = 4;\n } else if (i + 2 < length && bytes[i] === 0 && bytes[i + 1] === 0 && bytes[i + 2] === 1) {\n scLen = 3;\n }\n\n if (scLen > 0) {\n if (nalStart >= 0) {\n yield bytes.subarray(nalStart, i);\n }\n nalStart = i + scLen;\n i += scLen;\n } else {\n i += 1;\n }\n }\n\n if (nalStart >= 0 && nalStart < length) {\n yield bytes.subarray(nalStart, length);\n }\n}\n\n/**\n * Convert an Annex B byte stream to AVCC. Each NALU is prefixed with its\n * 4-byte big-endian length.\n */\nexport function annexBToAvcc(annexB: Uint8Array): Uint8Array {\n const nalus: Uint8Array[] = [];\n let total = 0;\n for (const nal of iterateAnnexBNalus(annexB)) {\n nalus.push(nal);\n total += 4 + nal.length;\n }\n const out = new Uint8Array(total);\n let off = 0;\n for (const nal of nalus) {\n const len = nal.length;\n out[off++] = (len >>> 24) & 0xff;\n out[off++] = (len >>> 16) & 0xff;\n out[off++] = (len >>> 8) & 0xff;\n out[off++] = len & 0xff;\n out.set(nal, off);\n off += len;\n }\n return out;\n}\n\n/**\n * Convert AVCC (4-byte length-prefixed) NALUs to Annex B. Each NALU is\n * prefixed with `00 00 00 01`.\n */\nexport function avccToAnnexB(avcc: Uint8Array): Uint8Array {\n const out: Uint8Array[] = [];\n let total = 0;\n let i = 0;\n while (i + 4 <= avcc.length) {\n const len =\n (avcc[i] << 24) | (avcc[i + 1] << 16) | (avcc[i + 2] << 8) | avcc[i + 3];\n i += 4;\n if (i + len > avcc.length) {\n throw new Error(`avccToAnnexB: NAL length ${len} overflows buffer at offset ${i}`);\n }\n out.push(START_CODE_4);\n out.push(avcc.subarray(i, i + len));\n total += 4 + len;\n i += len;\n }\n const merged = new Uint8Array(total);\n let off = 0;\n for (const chunk of out) {\n merged.set(chunk, off);\n off += chunk.length;\n }\n return merged;\n}\n","/**\n * Standalone remux function: repackage media into a modern container without\n * re-encoding. Input can be any format avbridge can probe; output is a\n * finalized downloadable file (MP4, WebM, or MKV).\n *\n * Two internal paths:\n * - **Path A** (mediabunny-readable containers): wraps mediabunny's Conversion\n * class for MP4/MKV/WebM/OGG/MOV/WAV/MP3/FLAC/ADTS sources.\n * - **Path B** (AVI/ASF/FLV): libav.js demux + mediabunny mux via manual\n * packet pump. Lazy-loads libav.js — zero cost if unused.\n */\n\nimport { probe } from \"../probe/index.js\";\nimport { isAnnexB, annexBToAvcc } from \"../strategies/remux/annexb.js\";\nimport {\n avbridgeVideoToMediabunny,\n avbridgeAudioToMediabunny,\n buildMediabunnySourceFromInput,\n} from \"../probe/mediabunny.js\";\nimport { normalizeSource } from \"../util/source.js\";\nimport { sanitizePacketTimestamp } from \"../util/libav-demux.js\";\nimport { prepareLibavInput, type LibavInputHandle } from \"../util/libav-http-reader.js\";\nimport type {\n MediaInput,\n MediaContext,\n ConvertOptions,\n ConvertResult,\n OutputFormat,\n} from \"../types.js\";\n\n/** Containers mediabunny can read (and therefore use Conversion for). */\nconst MEDIABUNNY_CONTAINERS = new Set([\n \"mp4\", \"mov\", \"mkv\", \"webm\", \"ogg\", \"wav\", \"mp3\", \"flac\", \"adts\",\n]);\n\n/**\n * Remux a media source into a modern container format without re-encoding.\n *\n * @throws When the source codecs cannot be remuxed (e.g. WMV3 — use `transcode()` instead).\n * @throws When an AVI/ASF/FLV source is provided but libav.js is not installed.\n */\nexport async function remux(\n source: MediaInput,\n options: ConvertOptions = {},\n): Promise<ConvertResult> {\n const outputFormat = options.outputFormat ?? \"mp4\";\n options.signal?.throwIfAborted();\n\n // Probe the source\n const ctx = await probe(source);\n options.signal?.throwIfAborted();\n\n // Validate remux eligibility: all codecs must map to mediabunny output codecs\n validateRemuxEligibility(ctx, options.strict ?? false);\n\n // Route to the appropriate path\n if (MEDIABUNNY_CONTAINERS.has(ctx.container)) {\n return remuxViaMediAbunny(ctx, outputFormat, options);\n }\n return remuxViaLibav(ctx, outputFormat, options);\n}\n\n// ── Eligibility validation ──────────────────────────────────────────────────\n\n/** @internal Exported for testing. */\nexport function validateRemuxEligibility(ctx: MediaContext, strict: boolean): void {\n const video = ctx.videoTracks[0];\n const audio = ctx.audioTracks[0];\n\n if (video) {\n const mbCodec = avbridgeVideoToMediabunny(video.codec);\n if (!mbCodec) {\n throw new Error(\n `Cannot remux: video codec \"${video.codec}\" is not supported for remuxing. ` +\n `Use transcode() to re-encode to a modern codec.`,\n );\n }\n }\n\n if (audio) {\n const mbCodec = avbridgeAudioToMediabunny(audio.codec);\n if (!mbCodec) {\n throw new Error(\n `Cannot remux: audio codec \"${audio.codec}\" is not supported for remuxing. ` +\n `Use transcode() to re-encode to a modern codec.`,\n );\n }\n }\n\n if (strict && video?.codec === \"h264\" && audio?.codec === \"mp3\") {\n throw new Error(\n `Cannot remux in strict mode: H.264 + MP3 is a best-effort combination ` +\n `that may produce playback issues in some browsers. ` +\n `Set strict: false to allow, or use transcode() to re-encode audio to AAC.`,\n );\n }\n\n if (!video && !audio) {\n throw new Error(\"Cannot remux: source has no video or audio tracks.\");\n }\n}\n\n// ── Path A: mediabunny Conversion ───────────────────────────────────────────\n\nasync function remuxViaMediAbunny(\n ctx: MediaContext,\n outputFormat: OutputFormat,\n options: ConvertOptions,\n): Promise<ConvertResult> {\n const mb = await import(\"mediabunny\");\n\n const input = new mb.Input({\n source: await buildMediabunnySourceFromInput(mb, ctx.source),\n formats: mb.ALL_FORMATS,\n });\n\n const target = new mb.BufferTarget();\n const output = new mb.Output({\n format: createOutputFormat(mb, outputFormat),\n target,\n });\n\n const conversion = await mb.Conversion.init({\n input,\n output,\n showWarnings: false,\n });\n\n if (!conversion.isValid) {\n const reasons = conversion.discardedTracks\n .map((d) => `${d.track.type} track discarded: ${d.reason}`)\n .join(\"; \");\n throw new Error(`Cannot remux: mediabunny rejected the conversion. ${reasons}`);\n }\n\n // Wire progress\n if (options.onProgress) {\n const onProgress = options.onProgress;\n conversion.onProgress = (p) => {\n onProgress({ percent: p * 100, bytesWritten: 0 });\n };\n }\n\n // Wire cancellation\n let abortHandler: (() => void) | undefined;\n if (options.signal) {\n options.signal.throwIfAborted();\n abortHandler = () => void conversion.cancel();\n options.signal.addEventListener(\"abort\", abortHandler, { once: true });\n }\n\n try {\n await conversion.execute();\n } finally {\n if (abortHandler && options.signal) {\n options.signal.removeEventListener(\"abort\", abortHandler);\n }\n }\n\n if (!target.buffer) {\n throw new Error(\"Remux failed: mediabunny produced no output buffer.\");\n }\n\n const mimeType = mimeForFormat(outputFormat);\n const blob = new Blob([target.buffer], { type: mimeType });\n const filename = generateFilename(ctx.name, outputFormat);\n\n options.onProgress?.({ percent: 100, bytesWritten: blob.size });\n\n return {\n blob,\n mimeType,\n container: outputFormat,\n videoCodec: ctx.videoTracks[0]?.codec,\n audioCodec: ctx.audioTracks[0]?.codec,\n duration: ctx.duration,\n filename,\n };\n}\n\n// ── Path B: libav.js demux + mediabunny mux (AVI/ASF/FLV) ──────────────────\n\nasync function remuxViaLibav(\n ctx: MediaContext,\n outputFormat: OutputFormat,\n options: ConvertOptions,\n): Promise<ConvertResult> {\n // Lazy-load libav\n let loadLibav: typeof import(\"../strategies/fallback/libav-loader.js\").loadLibav;\n let pickLibavVariant: typeof import(\"../strategies/fallback/variant-routing.js\").pickLibavVariant;\n try {\n const loader = await import(\"../strategies/fallback/libav-loader.js\");\n const routing = await import(\"../strategies/fallback/variant-routing.js\");\n loadLibav = loader.loadLibav;\n pickLibavVariant = routing.pickLibavVariant;\n } catch {\n throw new Error(\n `Cannot remux ${ctx.container.toUpperCase()} source: libav.js is not available. ` +\n `Install @libav.js/variant-webcodecs and libavjs-webcodecs-bridge, ` +\n `or build the custom avbridge variant with scripts/build-libav.sh.`,\n );\n }\n\n const variant = pickLibavVariant(ctx);\n const libav = await loadLibav(variant) as unknown as LibavRuntime;\n\n // For Blob/File inputs, libav reads from an in-memory readahead file.\n // For URL inputs, libav demuxes via HTTP Range requests through the\n // block reader — no full download.\n const normalized = await normalizeSource(ctx.source);\n const filename = ctx.name ?? `remux-input-${Date.now()}`;\n const handle: LibavInputHandle = await prepareLibavInput(libav as unknown as Parameters<typeof prepareLibavInput>[0], filename, normalized);\n\n try {\n return await doLibavRemux(libav, filename, ctx, outputFormat, options);\n } finally {\n await handle.detach().catch(() => {});\n }\n}\n\nasync function doLibavRemux(\n libav: LibavRuntime,\n filename: string,\n ctx: MediaContext,\n outputFormat: OutputFormat,\n options: ConvertOptions,\n): Promise<ConvertResult> {\n const mb = await import(\"mediabunny\");\n\n const readPkt = await libav.av_packet_alloc();\n const [fmt_ctx, streams] = await libav.ff_init_demuxer_file(filename);\n const videoStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_VIDEO) ?? null;\n const audioStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO) ?? null;\n\n // Map codecs to mediabunny output\n const videoTrackInfo = ctx.videoTracks[0];\n const audioTrackInfo = ctx.audioTracks[0];\n const mbVideoCodec = videoTrackInfo ? avbridgeVideoToMediabunny(videoTrackInfo.codec) : null;\n const mbAudioCodec = audioTrackInfo ? avbridgeAudioToMediabunny(audioTrackInfo.codec) : null;\n\n // Set up mediabunny output with BufferTarget\n const target = new mb.BufferTarget();\n const output = new mb.Output({\n format: createOutputFormat(mb, outputFormat),\n target,\n });\n\n let videoSource: InstanceType<typeof mb.EncodedVideoPacketSource> | null = null;\n let audioSource: InstanceType<typeof mb.EncodedAudioPacketSource> | null = null;\n\n if (mbVideoCodec && videoStream) {\n videoSource = new mb.EncodedVideoPacketSource(mbVideoCodec);\n output.addVideoTrack(videoSource);\n }\n if (mbAudioCodec && audioStream) {\n type AudioCodecArg = ConstructorParameters<typeof mb.EncodedAudioPacketSource>[0];\n audioSource = new mb.EncodedAudioPacketSource(mbAudioCodec as AudioCodecArg);\n output.addAudioTrack(audioSource);\n }\n\n await output.start();\n\n // Timestamp tracking for synthetic timestamps\n const videoFps = videoTrackInfo?.fps && videoTrackInfo.fps > 0 ? videoTrackInfo.fps : 30;\n const videoFrameStepUs = Math.max(1, Math.round(1_000_000 / videoFps));\n let syntheticVideoUs = 0;\n let syntheticAudioUs = 0;\n\n const videoTimeBase: [number, number] | undefined =\n videoStream?.time_base_num && videoStream?.time_base_den\n ? [videoStream.time_base_num, videoStream.time_base_den]\n : undefined;\n const audioTimeBase: [number, number] | undefined =\n audioStream?.time_base_num && audioStream?.time_base_den\n ? [audioStream.time_base_num, audioStream.time_base_den]\n : undefined;\n\n let totalPackets = 0;\n const durationUs = ctx.duration ? ctx.duration * 1_000_000 : 0;\n let firstVideoMeta = true;\n let firstAudioMeta = true;\n\n // Pump loop: read packets from libav, feed to mediabunny output\n while (true) {\n options.signal?.throwIfAborted();\n\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: 64 * 1024,\n });\n } catch (err) {\n throw new Error(`libav demux failed: ${(err as Error).message}`);\n }\n\n const videoPackets = videoStream ? packets[videoStream.index] ?? [] : [];\n const audioPackets = audioStream ? packets[audioStream.index] ?? [] : [];\n\n // Feed video packets\n if (videoSource) {\n for (const pkt of videoPackets) {\n sanitizePacketTimestamp(pkt, () => {\n const ts = syntheticVideoUs;\n syntheticVideoUs += videoFrameStepUs;\n return ts;\n }, videoTimeBase);\n\n // libav demuxes AVI/ASF/FLV H.264 as Annex B (start-code framed),\n // but mediabunny's fMP4 muxer expects AVCC (length-prefixed). Convert\n // on the fly. The check is cheap: isAnnexB reads 4 bytes at the head.\n if (videoTrackInfo && (videoTrackInfo.codec === \"h264\" || videoTrackInfo.codec === \"h265\") && isAnnexB(pkt.data)) {\n pkt.data = annexBToAvcc(pkt.data);\n }\n\n const mbPacket = libavPacketToMediAbunny(mb, pkt);\n await videoSource.add(\n mbPacket,\n firstVideoMeta ? { decoderConfig: buildVideoDecoderConfig(videoTrackInfo!) } : undefined,\n );\n firstVideoMeta = false;\n }\n }\n\n // Feed audio packets\n if (audioSource) {\n for (const pkt of audioPackets) {\n sanitizePacketTimestamp(pkt, () => {\n const ts = syntheticAudioUs;\n const sampleRate = audioTrackInfo?.sampleRate ?? 44100;\n syntheticAudioUs += Math.round(1024 * 1_000_000 / sampleRate);\n return ts;\n }, audioTimeBase);\n\n const mbPacket = libavPacketToMediAbunny(mb, pkt);\n await audioSource.add(\n mbPacket,\n firstAudioMeta ? { decoderConfig: buildAudioDecoderConfig(audioTrackInfo!) } : undefined,\n );\n firstAudioMeta = false;\n }\n }\n\n totalPackets += videoPackets.length + audioPackets.length;\n\n // Report progress\n if (options.onProgress && durationUs > 0) {\n const lastVideoTs = videoPackets.length > 0 ? videoPackets[videoPackets.length - 1].pts ?? 0 : 0;\n const lastAudioTs = audioPackets.length > 0 ? audioPackets[audioPackets.length - 1].pts ?? 0 : 0;\n const currentUs = Math.max(lastVideoTs, lastAudioTs);\n const percent = Math.min(99, (currentUs / durationUs) * 100);\n options.onProgress({ percent, bytesWritten: 0 });\n }\n\n if (readErr === libav.AVERROR_EOF) break;\n if (readErr && readErr !== 0 && readErr !== -libav.EAGAIN) {\n console.warn(\"[avbridge] remux: ff_read_frame_multi returned\", readErr);\n break;\n }\n }\n\n await output.finalize();\n\n // Cleanup libav resources\n try { await libav.av_packet_free?.(readPkt); } catch { /* ignore */ }\n try { await libav.avformat_close_input_js(fmt_ctx); } catch { /* ignore */ }\n\n if (!target.buffer) {\n throw new Error(\"Remux failed: mediabunny produced no output buffer.\");\n }\n\n const mimeType = mimeForFormat(outputFormat);\n const blob = new Blob([target.buffer], { type: mimeType });\n const outputFilename = generateFilename(ctx.name, outputFormat);\n\n options.onProgress?.({ percent: 100, bytesWritten: blob.size });\n\n return {\n blob,\n mimeType,\n container: outputFormat,\n videoCodec: videoTrackInfo?.codec,\n audioCodec: audioTrackInfo?.codec,\n duration: ctx.duration,\n filename: outputFilename,\n };\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\n/** @internal Exported for use by transcode(). */\nexport function createOutputFormat(\n mb: typeof import(\"mediabunny\"),\n format: OutputFormat,\n) {\n switch (format) {\n case \"mp4\": return new mb.Mp4OutputFormat({ fastStart: \"in-memory\" });\n case \"webm\": return new mb.WebMOutputFormat();\n case \"mkv\": return new mb.MkvOutputFormat();\n default: return new mb.Mp4OutputFormat({ fastStart: \"in-memory\" });\n }\n}\n\n/** @internal Exported for testing. */\nexport function mimeForFormat(format: OutputFormat): string {\n switch (format) {\n case \"mp4\": return \"video/mp4\";\n case \"webm\": return \"video/webm\";\n case \"mkv\": return \"video/x-matroska\";\n default: return \"application/octet-stream\";\n }\n}\n\n/** @internal Exported for testing. */\nexport function generateFilename(originalName: string | undefined, format: OutputFormat): string {\n const ext = format === \"mkv\" ? \"mkv\" : format;\n if (!originalName) return `output.${ext}`;\n const base = originalName.replace(/\\.[^.]+$/, \"\");\n return `${base}.${ext}`;\n}\n\n/** Sequence counter for decode-order numbering in mediabunny packets. */\nlet _seqCounter = 0;\n\n/**\n * Convert a libav packet to a mediabunny EncodedPacket.\n * Timestamps from libav are in microseconds (after sanitization); mediabunny wants seconds.\n */\nfunction libavPacketToMediAbunny(\n mb: typeof import(\"mediabunny\"),\n pkt: LibavPacket,\n): InstanceType<typeof mb.EncodedPacket> {\n const KEY_FRAME_FLAG = 0x0001;\n const timestampSec = (pkt.pts ?? 0) / 1_000_000;\n const durationSec = (pkt.duration ?? 0) / 1_000_000;\n const type = (pkt.flags & KEY_FRAME_FLAG) ? \"key\" as const : \"delta\" as const;\n return new mb.EncodedPacket(pkt.data, type, timestampSec, durationSec, _seqCounter++);\n}\n\nfunction buildVideoDecoderConfig(track: { codec: string; width: number; height: number; codecString?: string }) {\n return {\n codec: track.codecString ?? track.codec,\n codedWidth: track.width,\n codedHeight: track.height,\n };\n}\n\nfunction buildAudioDecoderConfig(track: { codec: string; channels: number; sampleRate: number; codecString?: string }) {\n return {\n codec: track.codecString ?? track.codec,\n numberOfChannels: track.channels,\n sampleRate: track.sampleRate,\n };\n}\n\n// ── Structural types ────────────────────────────────────────────────────────\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 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 LibavRuntime {\n AVMEDIA_TYPE_VIDEO: number;\n AVMEDIA_TYPE_AUDIO: number;\n AVERROR_EOF: number;\n EAGAIN: 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 av_packet_alloc(): Promise<number>;\n av_packet_free?(pkt: number): Promise<void>;\n avformat_close_input_js(ctx: number): Promise<void>;\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SubtitleResourceBag, discoverSidecars, attachSubtitleTracks, SubtitleOverlay } from './chunk-EDDWAN2L.js';
|
|
2
|
-
import { probe, avbridgeVideoToMediabunny, buildMediabunnySourceFromInput, avbridgeAudioToMediabunny } from './chunk-
|
|
2
|
+
import { probe, avbridgeVideoToMediabunny, buildMediabunnySourceFromInput, avbridgeAudioToMediabunny } from './chunk-5CX7BVVV.js';
|
|
3
3
|
import { AvbridgeError, ERR_ALL_STRATEGIES_EXHAUSTED, ERR_PLAYER_NOT_READY, ERR_MSE_NOT_SUPPORTED, ERR_MSE_CODEC_NOT_SUPPORTED } from './chunk-CPJLFFCC.js';
|
|
4
4
|
import { packetPtsSec, sanitizePacketTimestamp, sanitizeFrameTimestamp, libavFrameToInterleavedFloat32 } from './chunk-3YKWU4FM.js';
|
|
5
5
|
import { dbg, loadLibav } from './chunk-5DMTJVIU.js';
|
|
@@ -1102,10 +1102,20 @@ var VideoRenderer = class {
|
|
|
1102
1102
|
/** Resolves once the first decoded frame has been enqueued. */
|
|
1103
1103
|
firstFrameReady;
|
|
1104
1104
|
resolveFirstFrame;
|
|
1105
|
-
/**
|
|
1105
|
+
/**
|
|
1106
|
+
* True once at least one frame has been enqueued *since the last flush*.
|
|
1107
|
+
* Used by `readyState` — initial cold-start reports HAVE_NOTHING until
|
|
1108
|
+
* any frame has arrived, and after a seek we want the same semantics
|
|
1109
|
+
* (HAVE_NOTHING until post-seek frames arrive), so the cumulative
|
|
1110
|
+
* `framesPainted > 0` that used to live here was wrong: it kept the
|
|
1111
|
+
* state "true forever" after the first frame ever, so post-seek
|
|
1112
|
+
* `waitForBuffer()` would exit immediately with an empty queue and
|
|
1113
|
+
* leave video frozen while audio kept going.
|
|
1114
|
+
*/
|
|
1106
1115
|
hasFrames() {
|
|
1107
|
-
return this.queue.length > 0 || this.
|
|
1116
|
+
return this.queue.length > 0 || this.hasEverEnqueuedSinceFlush;
|
|
1108
1117
|
}
|
|
1118
|
+
hasEverEnqueuedSinceFlush = false;
|
|
1109
1119
|
/** Current depth of the frame queue. Used by the decoder for backpressure. */
|
|
1110
1120
|
queueDepth() {
|
|
1111
1121
|
return this.queue.length;
|
|
@@ -1124,6 +1134,7 @@ var VideoRenderer = class {
|
|
|
1124
1134
|
return;
|
|
1125
1135
|
}
|
|
1126
1136
|
this.queue.push(frame);
|
|
1137
|
+
this.hasEverEnqueuedSinceFlush = true;
|
|
1127
1138
|
if (this.queue.length === 1 && this.framesPainted === 0) {
|
|
1128
1139
|
this.resolveFirstFrame();
|
|
1129
1140
|
}
|
|
@@ -1257,7 +1268,8 @@ var VideoRenderer = class {
|
|
|
1257
1268
|
}
|
|
1258
1269
|
return;
|
|
1259
1270
|
}
|
|
1260
|
-
const
|
|
1271
|
+
const _relaxDrop = globalThis.AVBRIDGE_RELAX_DROP === true;
|
|
1272
|
+
const dropThresholdUs = _relaxDrop ? audioNowUs - 60 * 1e6 : audioNowUs - frameDurationUs * 2;
|
|
1261
1273
|
let dropped = 0;
|
|
1262
1274
|
while (bestIdx > 0) {
|
|
1263
1275
|
const ts = this.queue[0].timestamp ?? 0;
|
|
@@ -1318,16 +1330,28 @@ var VideoRenderer = class {
|
|
|
1318
1330
|
while (this.queue.length > 0) this.queue.shift()?.close();
|
|
1319
1331
|
this.prerolled = false;
|
|
1320
1332
|
this.ptsCalibrated = false;
|
|
1333
|
+
this.hasEverEnqueuedSinceFlush = false;
|
|
1321
1334
|
if (isDebug() && count > 0) {
|
|
1322
1335
|
console.log(`[avbridge:renderer] FLUSH discarded=${count} painted=${this.framesPainted} drops=${this.framesDroppedLate}`);
|
|
1323
1336
|
}
|
|
1324
1337
|
}
|
|
1325
1338
|
stats() {
|
|
1339
|
+
let queueSpanMs = 0;
|
|
1340
|
+
let queueHeadMs = 0;
|
|
1341
|
+
let queueTailMs = 0;
|
|
1342
|
+
if (this.queue.length > 0) {
|
|
1343
|
+
queueHeadMs = Math.round((this.queue[0].timestamp ?? 0) / 1e3);
|
|
1344
|
+
queueTailMs = Math.round((this.queue[this.queue.length - 1].timestamp ?? 0) / 1e3);
|
|
1345
|
+
queueSpanMs = Math.max(0, queueTailMs - queueHeadMs);
|
|
1346
|
+
}
|
|
1326
1347
|
return {
|
|
1327
1348
|
framesPainted: this.framesPainted,
|
|
1328
1349
|
framesDroppedLate: this.framesDroppedLate,
|
|
1329
1350
|
framesDroppedOverflow: this.framesDroppedOverflow,
|
|
1330
|
-
queueDepth: this.queue.length
|
|
1351
|
+
queueDepth: this.queue.length,
|
|
1352
|
+
queueHeadMs,
|
|
1353
|
+
queueTailMs,
|
|
1354
|
+
queueSpanMs
|
|
1331
1355
|
};
|
|
1332
1356
|
}
|
|
1333
1357
|
destroy() {
|
|
@@ -1685,6 +1709,7 @@ async function startHybridDecoder(opts) {
|
|
|
1685
1709
|
}
|
|
1686
1710
|
let bsfCtx = null;
|
|
1687
1711
|
let bsfPkt = null;
|
|
1712
|
+
let bsfRequiredButMissing = false;
|
|
1688
1713
|
if (videoStream && opts.context.videoTracks[0]?.codec === "mpeg4") {
|
|
1689
1714
|
try {
|
|
1690
1715
|
bsfCtx = await libav.av_bsf_list_parse_str_js("mpeg4_unpack_bframes");
|
|
@@ -1695,13 +1720,19 @@ async function startHybridDecoder(opts) {
|
|
|
1695
1720
|
bsfPkt = await libav.av_packet_alloc();
|
|
1696
1721
|
dbg.info("bsf", "mpeg4_unpack_bframes BSF active (hybrid)");
|
|
1697
1722
|
} else {
|
|
1698
|
-
|
|
1723
|
+
bsfRequiredButMissing = true;
|
|
1699
1724
|
bsfCtx = null;
|
|
1700
1725
|
}
|
|
1701
1726
|
} catch (err) {
|
|
1702
|
-
|
|
1727
|
+
bsfRequiredButMissing = true;
|
|
1703
1728
|
bsfCtx = null;
|
|
1704
1729
|
bsfPkt = null;
|
|
1730
|
+
dbg.warn("bsf", `hybrid: mpeg4_unpack_bframes BSF init failed: ${err.message}`);
|
|
1731
|
+
}
|
|
1732
|
+
if (bsfRequiredButMissing) {
|
|
1733
|
+
console.error(
|
|
1734
|
+
"[avbridge] MPEG-4 Part 2 (DivX/Xvid) detected but mpeg4_unpack_bframes BSF is unavailable in this libav variant. Files with packed B-frames will play with incorrect frame ordering. Rebuild the libav variant with the `avbsf` fragment included."
|
|
1735
|
+
);
|
|
1705
1736
|
}
|
|
1706
1737
|
}
|
|
1707
1738
|
async function applyBSF(packets) {
|
|
@@ -1711,7 +1742,6 @@ async function startHybridDecoder(opts) {
|
|
|
1711
1742
|
await libav.ff_copyin_packet(bsfPkt, pkt);
|
|
1712
1743
|
const sendErr = await libav.av_bsf_send_packet(bsfCtx, bsfPkt);
|
|
1713
1744
|
if (sendErr < 0) {
|
|
1714
|
-
out.push(pkt);
|
|
1715
1745
|
continue;
|
|
1716
1746
|
}
|
|
1717
1747
|
while (true) {
|
|
@@ -1725,10 +1755,13 @@ async function startHybridDecoder(opts) {
|
|
|
1725
1755
|
async function flushBSF() {
|
|
1726
1756
|
if (!bsfCtx || !bsfPkt) return;
|
|
1727
1757
|
try {
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1758
|
+
if (libav.av_bsf_flush) {
|
|
1759
|
+
await libav.av_bsf_flush(bsfCtx);
|
|
1760
|
+
} else {
|
|
1761
|
+
while (true) {
|
|
1762
|
+
const err = await libav.av_bsf_receive_packet(bsfCtx, bsfPkt);
|
|
1763
|
+
if (err < 0) break;
|
|
1764
|
+
}
|
|
1732
1765
|
}
|
|
1733
1766
|
} catch {
|
|
1734
1767
|
}
|
|
@@ -2040,6 +2073,7 @@ async function startHybridDecoder(opts) {
|
|
|
2040
2073
|
videoChunksFed,
|
|
2041
2074
|
audioFramesDecoded,
|
|
2042
2075
|
bsfApplied: bsfCtx ? ["mpeg4_unpack_bframes"] : [],
|
|
2076
|
+
bsfMissing: bsfRequiredButMissing ? ["mpeg4_unpack_bframes"] : [],
|
|
2043
2077
|
videoDecodeQueueSize: videoDecoder?.decodeQueueSize ?? 0,
|
|
2044
2078
|
// Confirmed transport info — see fallback decoder for the pattern.
|
|
2045
2079
|
_transport: inputHandle.transport === "http-range" ? "http-range" : "memory",
|
|
@@ -2339,6 +2373,7 @@ async function startDecoder(opts) {
|
|
|
2339
2373
|
}
|
|
2340
2374
|
let bsfCtx = null;
|
|
2341
2375
|
let bsfPkt = null;
|
|
2376
|
+
let bsfRequiredButMissing = false;
|
|
2342
2377
|
if (videoStream && opts.context.videoTracks[0]?.codec === "mpeg4") {
|
|
2343
2378
|
try {
|
|
2344
2379
|
bsfCtx = await libav.av_bsf_list_parse_str_js("mpeg4_unpack_bframes");
|
|
@@ -2349,13 +2384,19 @@ async function startDecoder(opts) {
|
|
|
2349
2384
|
bsfPkt = await libav.av_packet_alloc();
|
|
2350
2385
|
dbg.info("bsf", "mpeg4_unpack_bframes BSF active");
|
|
2351
2386
|
} else {
|
|
2352
|
-
|
|
2387
|
+
bsfRequiredButMissing = true;
|
|
2353
2388
|
bsfCtx = null;
|
|
2354
2389
|
}
|
|
2355
2390
|
} catch (err) {
|
|
2356
|
-
|
|
2391
|
+
bsfRequiredButMissing = true;
|
|
2357
2392
|
bsfCtx = null;
|
|
2358
2393
|
bsfPkt = null;
|
|
2394
|
+
dbg.warn("bsf", `mpeg4_unpack_bframes BSF init failed: ${err.message}`);
|
|
2395
|
+
}
|
|
2396
|
+
if (bsfRequiredButMissing) {
|
|
2397
|
+
console.error(
|
|
2398
|
+
"[avbridge] MPEG-4 Part 2 (DivX/Xvid) detected but mpeg4_unpack_bframes BSF is unavailable in this libav variant. Files with packed B-frames will play with incorrect frame ordering (backwards PTS jumps, heavy late-drop stuttering). Rebuild the libav variant with the `avbsf` fragment included. See docs/dev/POSTMORTEMS.md for details."
|
|
2399
|
+
);
|
|
2359
2400
|
}
|
|
2360
2401
|
}
|
|
2361
2402
|
async function applyBSF(packets) {
|
|
@@ -2365,7 +2406,6 @@ async function startDecoder(opts) {
|
|
|
2365
2406
|
await libav.ff_copyin_packet(bsfPkt, pkt);
|
|
2366
2407
|
const sendErr = await libav.av_bsf_send_packet(bsfCtx, bsfPkt);
|
|
2367
2408
|
if (sendErr < 0) {
|
|
2368
|
-
out.push(pkt);
|
|
2369
2409
|
continue;
|
|
2370
2410
|
}
|
|
2371
2411
|
while (true) {
|
|
@@ -2379,10 +2419,13 @@ async function startDecoder(opts) {
|
|
|
2379
2419
|
async function flushBSF() {
|
|
2380
2420
|
if (!bsfCtx || !bsfPkt) return;
|
|
2381
2421
|
try {
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2422
|
+
if (libav.av_bsf_flush) {
|
|
2423
|
+
await libav.av_bsf_flush(bsfCtx);
|
|
2424
|
+
} else {
|
|
2425
|
+
while (true) {
|
|
2426
|
+
const err = await libav.av_bsf_receive_packet(bsfCtx, bsfPkt);
|
|
2427
|
+
if (err < 0) break;
|
|
2428
|
+
}
|
|
2386
2429
|
}
|
|
2387
2430
|
} catch {
|
|
2388
2431
|
}
|
|
@@ -2400,6 +2443,19 @@ async function startDecoder(opts) {
|
|
|
2400
2443
|
let watchdogOverflowWarned = false;
|
|
2401
2444
|
let syntheticVideoUs = 0;
|
|
2402
2445
|
let syntheticAudioUs = 0;
|
|
2446
|
+
let videoDecodeMsTotal = 0;
|
|
2447
|
+
let audioDecodeMsTotal = 0;
|
|
2448
|
+
let videoDecodeBatches = 0;
|
|
2449
|
+
let audioDecodeBatches = 0;
|
|
2450
|
+
let readMsTotal = 0;
|
|
2451
|
+
let readBatches = 0;
|
|
2452
|
+
let pumpThrottleMsTotal = 0;
|
|
2453
|
+
let pumpThrottleEntries = 0;
|
|
2454
|
+
let slowestVideoBatchMs = 0;
|
|
2455
|
+
let newestVideoPtsUs = 0;
|
|
2456
|
+
let lastEmittedPtsUs = -1;
|
|
2457
|
+
let ptsRegressions = 0;
|
|
2458
|
+
let worstPtsRegressionMs = 0;
|
|
2403
2459
|
const videoTrackInfo = opts.context.videoTracks.find((t) => t.id === videoStream?.index);
|
|
2404
2460
|
const videoFps = videoTrackInfo?.fps && videoTrackInfo.fps > 0 ? videoTrackInfo.fps : 30;
|
|
2405
2461
|
const videoFrameStepUs = Math.max(1, Math.round(1e6 / videoFps));
|
|
@@ -2408,9 +2464,12 @@ async function startDecoder(opts) {
|
|
|
2408
2464
|
let readErr;
|
|
2409
2465
|
let packets;
|
|
2410
2466
|
try {
|
|
2467
|
+
const _readStart = performance.now();
|
|
2411
2468
|
[readErr, packets] = await libav.ff_read_frame_multi(fmt_ctx, readPkt, {
|
|
2412
2469
|
limit: 16 * 1024
|
|
2413
2470
|
});
|
|
2471
|
+
readMsTotal += performance.now() - _readStart;
|
|
2472
|
+
readBatches++;
|
|
2414
2473
|
} catch (err) {
|
|
2415
2474
|
console.error("[avbridge] ff_read_frame_multi failed:", err);
|
|
2416
2475
|
return;
|
|
@@ -2472,8 +2531,17 @@ async function startDecoder(opts) {
|
|
|
2472
2531
|
}
|
|
2473
2532
|
}
|
|
2474
2533
|
}
|
|
2475
|
-
|
|
2476
|
-
|
|
2534
|
+
{
|
|
2535
|
+
const _throttleStart = performance.now();
|
|
2536
|
+
let _throttled = false;
|
|
2537
|
+
while (!destroyed && myToken === pumpToken && (opts.audio.bufferAhead() > 2 || opts.renderer.queueDepth() >= opts.renderer.queueHighWater)) {
|
|
2538
|
+
_throttled = true;
|
|
2539
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
2540
|
+
}
|
|
2541
|
+
if (_throttled) {
|
|
2542
|
+
pumpThrottleMsTotal += performance.now() - _throttleStart;
|
|
2543
|
+
pumpThrottleEntries++;
|
|
2544
|
+
}
|
|
2477
2545
|
}
|
|
2478
2546
|
if (readErr === libav.AVERROR_EOF) {
|
|
2479
2547
|
if (videoDec) await decodeVideoBatch(
|
|
@@ -2499,6 +2567,7 @@ async function startDecoder(opts) {
|
|
|
2499
2567
|
async function decodeVideoBatch(pkts, myToken, flush = false) {
|
|
2500
2568
|
if (!videoDec || destroyed || myToken !== pumpToken) return;
|
|
2501
2569
|
let frames;
|
|
2570
|
+
const _t0 = performance.now();
|
|
2502
2571
|
try {
|
|
2503
2572
|
frames = await libav.ff_decode_multi(
|
|
2504
2573
|
videoDec.c,
|
|
@@ -2511,18 +2580,38 @@ async function startDecoder(opts) {
|
|
|
2511
2580
|
console.error("[avbridge] video decode batch failed:", err);
|
|
2512
2581
|
return;
|
|
2513
2582
|
}
|
|
2583
|
+
{
|
|
2584
|
+
const _dt = performance.now() - _t0;
|
|
2585
|
+
videoDecodeMsTotal += _dt;
|
|
2586
|
+
videoDecodeBatches++;
|
|
2587
|
+
if (_dt > slowestVideoBatchMs) slowestVideoBatchMs = _dt;
|
|
2588
|
+
}
|
|
2514
2589
|
if (myToken !== pumpToken || destroyed) return;
|
|
2515
2590
|
for (const f of frames) {
|
|
2516
2591
|
if (myToken !== pumpToken || destroyed) return;
|
|
2517
2592
|
sanitizeFrameTimestamp(
|
|
2518
2593
|
f,
|
|
2519
2594
|
() => {
|
|
2520
|
-
const
|
|
2521
|
-
syntheticVideoUs
|
|
2522
|
-
return
|
|
2595
|
+
const base = lastEmittedPtsUs >= 0 ? lastEmittedPtsUs + videoFrameStepUs : syntheticVideoUs;
|
|
2596
|
+
syntheticVideoUs = base + videoFrameStepUs;
|
|
2597
|
+
return base;
|
|
2523
2598
|
},
|
|
2524
2599
|
videoTimeBase
|
|
2525
2600
|
);
|
|
2601
|
+
const _fPts = (f.ptshi ?? 0) * 4294967296 + (f.pts ?? 0);
|
|
2602
|
+
if (_fPts > newestVideoPtsUs) newestVideoPtsUs = _fPts;
|
|
2603
|
+
if (lastEmittedPtsUs >= 0 && _fPts < lastEmittedPtsUs) {
|
|
2604
|
+
ptsRegressions++;
|
|
2605
|
+
const regressMs = (lastEmittedPtsUs - _fPts) / 1e3;
|
|
2606
|
+
if (regressMs > worstPtsRegressionMs) worstPtsRegressionMs = regressMs;
|
|
2607
|
+
if (ptsRegressions <= 10) {
|
|
2608
|
+
console.warn(
|
|
2609
|
+
`[avbridge:decoder] dropped out-of-order frame #${ptsRegressions}: pts=${(_fPts / 1e3).toFixed(1)}ms < previous=${(lastEmittedPtsUs / 1e3).toFixed(1)}ms (regression=${regressMs.toFixed(1)}ms). Typically a post-seek B-frame reorder tail.`
|
|
2610
|
+
);
|
|
2611
|
+
}
|
|
2612
|
+
continue;
|
|
2613
|
+
}
|
|
2614
|
+
lastEmittedPtsUs = _fPts;
|
|
2526
2615
|
try {
|
|
2527
2616
|
const vf = bridge.laFrameToVideoFrame(f, { timeBase: [1, 1e6] });
|
|
2528
2617
|
opts.renderer.enqueue(vf);
|
|
@@ -2537,6 +2626,7 @@ async function startDecoder(opts) {
|
|
|
2537
2626
|
async function decodeAudioBatch(pkts, myToken, flush = false) {
|
|
2538
2627
|
if (!audioDec || destroyed || myToken !== pumpToken) return;
|
|
2539
2628
|
let frames;
|
|
2629
|
+
const _t0 = performance.now();
|
|
2540
2630
|
try {
|
|
2541
2631
|
frames = await libav.ff_decode_multi(
|
|
2542
2632
|
audioDec.c,
|
|
@@ -2549,6 +2639,8 @@ async function startDecoder(opts) {
|
|
|
2549
2639
|
console.error("[avbridge] audio decode batch failed:", err);
|
|
2550
2640
|
return;
|
|
2551
2641
|
}
|
|
2642
|
+
audioDecodeMsTotal += performance.now() - _t0;
|
|
2643
|
+
audioDecodeBatches++;
|
|
2552
2644
|
if (myToken !== pumpToken || destroyed) return;
|
|
2553
2645
|
for (const f of frames) {
|
|
2554
2646
|
if (myToken !== pumpToken || destroyed) return;
|
|
@@ -2670,6 +2762,7 @@ async function startDecoder(opts) {
|
|
|
2670
2762
|
await flushBSF();
|
|
2671
2763
|
syntheticVideoUs = Math.round(timeSec * 1e6);
|
|
2672
2764
|
syntheticAudioUs = Math.round(timeSec * 1e6);
|
|
2765
|
+
lastEmittedPtsUs = -1;
|
|
2673
2766
|
pumpRunning = pumpLoop(newToken).catch(
|
|
2674
2767
|
(err) => console.error("[avbridge] fallback pump failed (post-setAudioTrack):", err)
|
|
2675
2768
|
);
|
|
@@ -2707,6 +2800,7 @@ async function startDecoder(opts) {
|
|
|
2707
2800
|
await flushBSF();
|
|
2708
2801
|
syntheticVideoUs = Math.round(timeSec * 1e6);
|
|
2709
2802
|
syntheticAudioUs = Math.round(timeSec * 1e6);
|
|
2803
|
+
lastEmittedPtsUs = -1;
|
|
2710
2804
|
pumpRunning = pumpLoop(newToken).catch(
|
|
2711
2805
|
(err) => console.error("[avbridge] decoder pump failed (post-seek):", err)
|
|
2712
2806
|
);
|
|
@@ -2720,7 +2814,24 @@ async function startDecoder(opts) {
|
|
|
2720
2814
|
packetsRead,
|
|
2721
2815
|
videoFramesDecoded,
|
|
2722
2816
|
audioFramesDecoded,
|
|
2817
|
+
// Throughput instrumentation — the stats panel turns these into
|
|
2818
|
+
// "decode fps actual / realtime target" and shows slowest batch
|
|
2819
|
+
// + producer throttle share.
|
|
2820
|
+
videoDecodeMsTotal,
|
|
2821
|
+
videoDecodeBatches,
|
|
2822
|
+
audioDecodeMsTotal,
|
|
2823
|
+
audioDecodeBatches,
|
|
2824
|
+
readMsTotal,
|
|
2825
|
+
readBatches,
|
|
2826
|
+
pumpThrottleMsTotal,
|
|
2827
|
+
pumpThrottleEntries,
|
|
2828
|
+
slowestVideoBatchMs,
|
|
2829
|
+
newestVideoPtsMs: Math.round(newestVideoPtsUs / 1e3),
|
|
2830
|
+
ptsRegressions,
|
|
2831
|
+
worstPtsRegressionMs,
|
|
2832
|
+
sourceFps: videoFps,
|
|
2723
2833
|
bsfApplied: bsfCtx ? ["mpeg4_unpack_bframes"] : [],
|
|
2834
|
+
bsfMissing: bsfRequiredButMissing ? ["mpeg4_unpack_bframes"] : [],
|
|
2724
2835
|
// Confirmed transport info: once prepareLibavInput returns
|
|
2725
2836
|
// successfully, we *know* whether the source is http-range (probe
|
|
2726
2837
|
// succeeded and returned 206) or in-memory blob. Diagnostics hoists
|
|
@@ -3543,5 +3654,5 @@ function defaultFallbackChain(strategy) {
|
|
|
3543
3654
|
}
|
|
3544
3655
|
|
|
3545
3656
|
export { FALLBACK_AUDIO_CODECS, FALLBACK_VIDEO_CODECS, NATIVE_AUDIO_CODECS, NATIVE_VIDEO_CODECS, UnifiedPlayer, classifyContext, createPlayer };
|
|
3546
|
-
//# sourceMappingURL=chunk-
|
|
3547
|
-
//# sourceMappingURL=chunk-
|
|
3657
|
+
//# sourceMappingURL=chunk-BN7BRTLY.js.map
|
|
3658
|
+
//# sourceMappingURL=chunk-BN7BRTLY.js.map
|