Files
Piped/src/utils/firefoxMediaCapabilitiesFix.js
2026-05-31 21:25:00 +03:00

57 lines
2.5 KiB
JavaScript

/**
* HACK: Firefox-only fast path for navigator.mediaCapabilities.decodingInfo().
*
* Rough comparison: Chromium ~0.1 ms/call vs Firefox ~20 ms/call.
* Shaka calls decodingInfo once per Variant while filtering the manifest, so on
* a YouTube-shape manifest with many Variants Firefox stalls several seconds at
* player init before any SourceBuffer is added.
*
* This module delegates "supported" to MediaSource.isTypeSupported (sub-ms on
* Firefox) and synthesizes smooth = powerEfficient = supported.
*
* KNOWN DOWNSIDE: by forcing smooth and powerEfficient to true we discard the
* native signals Shaka would otherwise see. If anything in the player chain
* reads those fields (e.g. preferredDecodingAttributes is set, a downstream
* consumer ranks variants on power efficiency, or a Shaka upgrade changes
* filtering), this shim will cause Shaka to pick streams the device cannot
* decode in real time — frame drops, software-decode CPU spikes, battery
* drain. Today (Shaka 5.1, Piped default config) those fields are not read
* and the shim is harmless; revisit on every Shaka upgrade.
*
* Active only on Gecko engines, so Chromium / Safari / Edge / iOS Firefox
* (WebKit) are unaffected. DRM probes (keySystemConfiguration) and non-
* media-source query types fall through to the native API unchanged.
*
* Refs:
* https://bugzilla.mozilla.org/show_bug.cgi?id=2043895
* https://github.com/TeamPiped/Piped/issues/4238
*/
if (
typeof navigator !== "undefined" &&
/Gecko\/[0-9]/.test(navigator.userAgent) &&
navigator.mediaCapabilities &&
typeof navigator.mediaCapabilities.decodingInfo === "function"
) {
const orig = navigator.mediaCapabilities.decodingInfo.bind(navigator.mediaCapabilities);
const cache = new Map();
const mimeOk = mime => {
if (!cache.has(mime)) cache.set(mime, MediaSource.isTypeSupported(mime));
return cache.get(mime);
};
navigator.mediaCapabilities.decodingInfo = function (config) {
if (config && config.type === "media-source" && !config.keySystemConfiguration) {
const v = config.video;
const a = config.audio;
const supported = (!v || mimeOk(v.contentType)) && (!a || mimeOk(a.contentType));
return Promise.resolve({
supported,
smooth: supported,
powerEfficient: supported,
keySystemAccess: null,
configuration: config,
});
}
return orig(config);
};
}