/** * VideoDecoder - WebCodecs-based video decoder */ import type { VideoTrack } from "../types"; import { WasmBindings } from "../wasm/bindings"; export declare class MoviVideoDecoder { private decoder; private swDecoder; private bindings; private useSoftware; private _configuredCodecString; /** Set when configure() had to drop `prefer-hardware` to get a supported * config — WebCodecs is decoding, but on the CPU. See isSoftwareBacked. */ /** * WHY this decoder is in software, when it is. * * "The picture is being decoded on the CPU" is one fact with two very * different meanings. A codec WebCodecs can do, that this machine's hardware * refused, is a trade the viewer might want a say in — it costs battery and * can stutter, and there may be a lower rung that does decode. A codec * WebCodecs has never heard of (Motion JPEG in an AVI, say) is not a trade at * all: software is the only way it will ever play, and offering "Try Software * Decoding" for it is offering the thing already happening. */ private _softwareReason; /** See _softwareReason. Null when the hardware path is in use. */ get softwareReason(): "unmapped" | "no-webcodecs" | "hardware-refused" | null; private hardwareUnavailable; private pendingFrames; private pendingChunks; private isConfigured; private onFrame; private onError; private waitingForKeyframe; private keyframeWaitSince; onKeyframeWaitChange: ((waiting: boolean) => void) | null; private errorCount; private static MAX_ERRORS; private lastConfig; private currentProfile; private currentTrack; private lastErrorTime; private openGopErrorCount; private _hardRecreateNeeded; private hardwareRetryCount; private lastHardwareRetryTime; private isResurrecting; private forceSoftware; private requiresSoftware; private targetFps; private isRecovering; private lastRecreateTime; private isAnnexBSource; private _loggedConversion; private skippedWhileWaiting; private justFlushed; private skipRaslAfterResume; private _perfSkipNonRef; private postFlushKeyframeRejects; private static POST_FLUSH_REJECT_LIMIT; private static MID_STREAM_OPENGOP_REJECT_LIMIT; private static DISABLE_OPENGOP_SW_FALLBACK; constructor(forceSoftware?: boolean); setBindings(bindings: WasmBindings): void; private setWaitingForKeyframe; /** * Configure the decoder for a specific track */ configure(track: VideoTrack, extradata?: Uint8Array, targetFps?: number): Promise; private initSoftwareDecoder; /** True when video is running through the software (WASM/FFmpeg) decoder * rather than a hardware WebCodecs decoder. */ isUsingSoftware(): boolean; /** * Adaptive load shedding, driven by the renderer when it finds the device * can't sustain the source frame rate. Both paths shed by dropping * non-reference frames: the software decoder via AVDISCARD_NONREF, the * WebCodecs path by dropping disposable packets before they're fed (see the * _perfSkipNonRef check in decode()). Nothing references those frames, so the * stream stays decodable; the decoder just does less work. */ setPerformanceSkip(enabled: boolean): void; /** * Recreate the decoder after a fatal error */ /** * Re-arm the decoder for a random-access restart WITHOUT tearing the instance * down. reset() drops the queue, the pending callbacks and the configuration, * so the configure() that follows is a genuine fresh configuration — the same * state a brand-new decoder is in, which is what makes an open-GOP CRA * acceptable as `key` again. What it does NOT do is destroy and re-acquire the * platform decoder, which is the expensive, visibly glitchy half of a full * recreate (and, per the Firefox bug below, the crash-prone one). * * Returns false if the decoder can't be re-armed in place, in which case the * caller falls back to the full recreate. * * Refs: https://developer.mozilla.org/en-US/docs/Web/API/VideoDecoder/reset * https://bugzilla.mozilla.org/show_bug.cgi?id=1976929 */ private softRecreateDecoder; private recreateDecoder; private lastChunkInfo; /** * Decode an encoded video chunk */ private static MIN_DELTA_PACKET_BYTES; private static TINY_PACKET_DROP_WINDOW; private chunksSinceKeyframeWait; private playbackRate; setPlaybackRate(rate: number): void; decode(data: Uint8Array, timestamp: number, keyframe: boolean, dts?: number, isIdr?: boolean, isRasl?: boolean, disposable?: boolean): void; private recoverFromError; private _doRecover; /** * Map FFmpeg codec names to WebCodecs codec strings */ private mapCodecToWebCodecs; /** * Set frame output callback */ setOnFrame(callback: (frame: VideoFrame) => void): void; /** * Set error callback */ setOnError(callback: (error: Error) => void): void; /** * Flush the decoder */ flush(): Promise; /** * Reset the decoder */ reset(): void; /** * The WebCodecs codec string the current track was configured with, e.g. * "av01.0.13M.10". Empty until configure() has run. Callers use it to ask * isConfigSupported() about a DIFFERENT resolution of the same stream — * every rung of a ladder is the same codec, so this is what makes a * before-the-fact capability check possible. */ get configuredCodec(): string; /** * Close the decoder */ close(): void; /** * Check if decoder is configured */ get configured(): boolean; /** * Helper to check if we should try switching back to hardware */ private shouldRetryHardware; /** * Bitwise NAL unit inspection to detect true Sync/IDR frames */ private isLikelySyncFrame; /** * Get queue size */ get queueSize(): number; /** * Check if software decoder is being used */ get isSoftware(): boolean; /** * True when the pixels are coming off the CPU — the WASM decoder OR a * WebCodecs decoder configured with no hardware path available. The ABR's * resolution ceiling asks this rather than isSoftware: "WebCodecs succeeded" * is not the same as "hardware decoded", and treating them as the same left * a 1440p AV1 rung stuck with a full decode queue and no downshift. */ get isSoftwareBacked(): boolean; get isWaitingForKeyframe(): boolean; isRecentlyRecovering(graceMs?: number): boolean; /** * How long the decoder has been waiting for its keyframe, 0 when it isn't. * * A wait normally ends within a GOP. It ends never when the packets stop — * and since isRecentlyRecovering() is true for the whole of it, anything * gated on that is switched off for as long as the wait lasts. This is what * lets a caller put a ceiling on that. */ keyframeWaitMs(): number; /** * Get decoder stats for nerd stats overlay */ getStats(): { decoderType: string; queueSize: number; errorCount: number; }; /** * Split Annex B byte stream into individual NAL units. * Handles both 3-byte (00 00 01) and 4-byte (00 00 00 01) start codes. */ private static splitAnnexBNalUnits; /** * Remove Annex B emulation prevention bytes (00 00 03 → 00 00). * Required for parsing NAL unit content (profile_tier_level etc.) */ private static removeEpb; /** * Convert Annex B extradata to hvcC (HEVC Decoder Configuration Record). * Extracts VPS, SPS, PPS NAL units and packages them into ISO 14496-15 format. * Uses track metadata for reliable profile/tier/level (Annex B NALs have EPB that corrupt offsets). */ static annexBToHvcC(annexB: Uint8Array, track?: { profile?: number; level?: number; }): Uint8Array | null; /** * Convert Annex B extradata to avcC (AVC Decoder Configuration Record). * Extracts SPS and PPS NAL units. */ static annexBToAvcC(annexB: Uint8Array): Uint8Array | null; /** * Check if an HEVC NAL unit type should be stripped before feeding to WebCodecs. * Dolby Vision RPU (type 62), UNSPEC63 (type 63), and other non-standard * NAL types cause hardware decoder errors. */ private static isUnsupportedHevcNalType; /** * Convert Annex B packet data to 4-byte length-prefixed format. * Replaces start codes (00 00 01 or 00 00 00 01) with 4-byte NAL unit lengths. * Strips Dolby Vision RPU and other unsupported NAL unit types. */ static annexBToLengthPrefixed(data: Uint8Array): Uint8Array; static stripAudLengthPrefixed(data: Uint8Array): Uint8Array; } //# sourceMappingURL=VideoDecoder.d.ts.map