feat(core): lighter preview copies of heavy videos below full quality (#6365)

* feat(core): tell which video files deserve a lighter preview copy, and at which size

* feat(studio-server): serve lighter copies of heavy playable files, a keyframe every second

* feat(core): the preview plays lighter copies of heavy videos below full quality

* style: shorten two comments

* style: shorten a comment

* style: shorten a comment

* fix(core): format the preview quality files and split the copy sizing for the complexity gate

* style: format the studio-server preview files

* fix(core): type the copy job's level as a preview quality

* chore(producer): raise the package size budget for the preview runtime growth
This commit is contained in:
Miguel Ángel
2026-10-26 03:53:21 +00:00
committed by GitHub
parent c0ddd3228d
commit 38d9aeb5ea
19 changed files with 721 additions and 118 deletions
+9
View File
@@ -268,11 +268,20 @@ export {
type ToneMapSourceColour,
} from "./hdrToneMap";
export {
HEAVY_BITRATE,
HEAVY_PIXEL_SHARE,
PREVIEW_PROXY_BOX_PARAM,
PREVIEW_PROXY_LIGHT_PARAM,
PREVIEW_QUALITY_LEVELS,
formatPreviewProxyBox,
isHeavyForPreview,
isPreviewQuality,
parsePreviewProxyBox,
quantizePreviewProxyBox,
scalePreviewProxyBox,
type PreviewProxyBox,
type PreviewQuality,
type PreviewSourceFacts,
} from "./previewProxyBox";
// Inline scripts
+39 -1
View File
@@ -1,5 +1,12 @@
import { describe, expect, it } from "vitest";
import { parsePreviewProxyBox, quantizePreviewProxyBox } from "./previewProxyBox";
import {
isHeavyForPreview,
isPreviewQuality,
parsePreviewProxyBox,
quantizePreviewProxyBox,
scalePreviewProxyBox,
type PreviewSourceFacts,
} from "./previewProxyBox";
describe("preview proxy box", () => {
it("rounds each side up to the next rung", () => {
@@ -28,3 +35,34 @@ describe("preview proxy box", () => {
expect(parsePreviewProxyBox("")).toBeNull();
});
});
describe("lighter copies of files Chrome can play", () => {
const full: PreviewSourceFacts = { width: 1920, height: 1080, bitDepth: 8, bitrate: 10_000_000 };
const box = { width: 1218, height: 724 };
const shown = { width: 1448, height: 862 };
it("multiplies the shown box by the level, on the ladder", () => {
expect(scalePreviewProxyBox(box, 1)).toEqual(box);
expect(scalePreviewProxyBox(box, 0.5)).toEqual({ width: 724, height: 362 });
expect(scalePreviewProxyBox(box, 0.125)).toEqual({ width: 256, height: 256 });
});
it("calls a file heavy for a much larger source, 10-bit or deeper, or 40 Mbit/s and up", () => {
expect(isHeavyForPreview(full, shown)).toBe(false);
expect(isHeavyForPreview({ ...full, width: 3840, height: 2160 }, shown)).toBe(true);
expect(isHeavyForPreview({ ...full, bitDepth: 10 }, shown)).toBe(true);
expect(isHeavyForPreview({ ...full, bitrate: 39_999_999 }, shown)).toBe(false);
expect(isHeavyForPreview({ ...full, bitrate: 40_000_000 }, shown)).toBe(true);
});
it("calls a source heavy when the copy box has half its pixels or fewer", () => {
const half = { width: 1448, height: 724 };
expect(isHeavyForPreview({ ...full, width: 2896, height: 1448 }, half)).toBe(true);
expect(isHeavyForPreview({ ...full, width: 1448, height: 1000 }, half)).toBe(false);
});
it("knows the four levels and nothing else", () => {
expect([1, 0.5, 0.25, 0.125].every(isPreviewQuality)).toBe(true);
expect([0, 0.75, 2, "1", null].some(isPreviewQuality)).toBe(false);
});
});
+31
View File
@@ -1,6 +1,8 @@
/** Query parameter carrying the largest box, in device pixels, a preview shows a proxied video at. */
export const PREVIEW_PROXY_BOX_PARAM = "hf-proxy-box";
export const PREVIEW_PROXY_LIGHT_PARAM = "hf-proxy-light";
export type PreviewProxyBox = { width: number; height: number };
// 256 * 2^(k/4), even: nearby boxes share one cached copy, and a rung overshoots by at most ~19%.
@@ -33,3 +35,32 @@ export function parsePreviewProxyBox(raw: string): PreviewProxyBox | null {
const height = Number(match[2]);
return RUNGS.includes(width) && RUNGS.includes(height) ? { width, height } : null;
}
export const PREVIEW_QUALITY_LEVELS = [1, 0.5, 0.25, 0.125] as const;
export type PreviewQuality = (typeof PREVIEW_QUALITY_LEVELS)[number];
export function isPreviewQuality(value: unknown): value is PreviewQuality {
return PREVIEW_QUALITY_LEVELS.some((level) => level === value);
}
export type PreviewSourceFacts = {
width: number;
height: number;
bitDepth: number;
bitrate: number;
};
export const HEAVY_PIXEL_SHARE = 0.5;
export const HEAVY_BITRATE = 40_000_000;
export function scalePreviewProxyBox(box: PreviewProxyBox, level: PreviewQuality): PreviewProxyBox {
return quantizePreviewProxyBox(box.width * level, box.height * level) ?? box;
}
export function isHeavyForPreview(facts: PreviewSourceFacts, copyBox: PreviewProxyBox): boolean {
return (
copyBox.width * copyBox.height <= HEAVY_PIXEL_SHARE * facts.width * facts.height ||
facts.bitDepth > 8 ||
facts.bitrate >= HEAVY_BITRATE
);
}
+2
View File
@@ -33,6 +33,7 @@ type BridgeDeps = {
onSetRuntimeData?: (channel: string, payload: unknown, requestId?: number) => void;
onClearRuntimeData?: (channel: string, requestId?: number) => void;
onSetDisplayScale?: (scale: number) => void;
onSetPreviewQuality?: (level: number) => void;
getCanonicalFps: () => number;
};
@@ -76,6 +77,7 @@ const CONTROL_HANDLERS = new Map<string, ControlHandler>(
"set-playback-rate": (data, deps) => deps.onSetPlaybackRate(Number(data.playbackRate ?? 1)),
"set-idle-heartbeat": (data, deps) => deps.onSetIdleHeartbeat(Boolean(data.slow)),
"set-display-scale": (data, deps) => deps.onSetDisplayScale?.(Number(data.scale)),
"set-preview-quality": (data, deps) => deps.onSetPreviewQuality?.(Number(data.level)),
"set-root-duration": (data, deps) => deps.onSetRootDuration(Number(data.durationSeconds ?? 0)),
"set-play-range": (data, deps) =>
deps.onSetPlayRange(
+2
View File
@@ -95,6 +95,7 @@ import {
handleMetadataForProxy,
isRenderMode,
maybeProxyProactively,
setPreviewQuality,
setProxyDisplayScale,
} from "./mediaProxy";
import {
@@ -5973,6 +5974,7 @@ export function initSandboxRuntimeModular(): void {
setProxyDisplayScale(scale);
setPreviewRasterScale(scale);
},
onSetPreviewQuality: setPreviewQuality,
onSetIdleHeartbeat: (slow) => {
slowIdleHeartbeat = slow;
wakeTransport();
@@ -869,3 +869,133 @@ describe("a copy sized to how large the video shows", () => {
expect(boxOf(el)).toBe("2436x4096");
});
});
describe("preview quality: lighter copies of heavy files", () => {
const HEAVY = { width: 3840, height: 2160, bitDepth: 8, bitrate: 10_000_000 };
const LIGHT = { width: 1280, height: 720, bitDepth: 8, bitrate: 10_000_000 };
// A framed page showing a 1920x1080 stage at full size on a 1x screen: a 2048x1218 box.
async function stage(facts: Record<string, typeof HEAVY>, codecMap?: Record<string, unknown>) {
vi.resetModules();
vi.spyOn(window, "parent", "get").mockReturnValue({} as Window);
const mod = await import("./mediaProxy");
window.__HF_MEDIA_SOURCE_FACTS__ = facts;
if (codecMap) window.__HF_MEDIA_CODEC_MAP__ = codecMap as never;
Object.defineProperty(document.documentElement, "clientWidth", {
configurable: true,
value: 1920,
});
Object.defineProperty(document.documentElement, "clientHeight", {
configurable: true,
value: 1080,
});
vi.spyOn(window, "devicePixelRatio", "get").mockReturnValue(1);
const video = (src = "/video.mp4") => {
const el = createVideo(src);
stubCanPlayType(el, "probably");
el.getBoundingClientRect = () => ({ width: 1920, height: 1080 }) as DOMRect;
return el;
};
mod.setProxyDisplayScale(1);
return { ...mod, video };
}
const params = (el: HTMLMediaElement) => new URL(el.src, document.baseURI).searchParams;
afterEach(() => {
delete (window as { __HF_MEDIA_SOURCE_FACTS__?: unknown }).__HF_MEDIA_SOURCE_FACTS__;
});
it("changes nothing at full quality", async () => {
const { video, setPreviewQuality, maybeProxyProactively } = await stage({
"/video.mp4": HEAVY,
});
const el = video();
maybeProxyProactively(el);
setPreviewQuality(1);
await settle();
expect(isProxied(el)).toBe(false);
expect(fetch).not.toHaveBeenCalled();
});
it("swaps a heavy file Chrome can play to a copy at the shown box times the level", async () => {
const { video, setPreviewQuality } = await stage({ "/video.mp4": HEAVY });
const el = video();
setPreviewQuality(0.5);
await settle();
expect(params(el).get("hf-proxy")).toBe("auto");
expect(params(el).get("hf-proxy-box")).toBe("1024x724");
expect(params(el).get("hf-proxy-light")).toBe("1");
});
it("leaves a file alone that is not heavy at that box", async () => {
const { video, setPreviewQuality } = await stage({ "/video.mp4": LIGHT });
const el = video();
setPreviewQuality(0.5);
await settle();
expect(isProxied(el)).toBe(false);
});
it("puts the original back at full quality", async () => {
const { video, setPreviewQuality } = await stage({ "/video.mp4": HEAVY });
const el = video();
setPreviewQuality(0.5);
await settle();
expect(isProxied(el)).toBe(true);
setPreviewQuality(1);
expect(el.getAttribute("src")).toBe("/video.mp4");
expect(el.load).toHaveBeenCalledTimes(2);
});
it("lightens a video that appears after the level was lowered", async () => {
const { video, setPreviewQuality, maybeProxyProactively } = await stage({
"/video.mp4": HEAVY,
});
setPreviewQuality(0.25);
const el = video();
maybeProxyProactively(el);
await settle();
expect(params(el).get("hf-proxy-box")).toBe("512x362");
});
it("sizes the copy a file cannot play without by the level too, and resizes it as the level moves", async () => {
const { video, setPreviewQuality, maybeProxyProactively } = await stage(
{ "/video.mp4": HEAVY },
{ "/video.mp4": HEVC_ENTRY },
);
const el = video();
stubCanPlayType(el, "");
maybeProxyProactively(el);
await settle();
expect(params(el).get("hf-proxy-box")).toBe("2048x1218");
expect(params(el).has("hf-proxy-light")).toBe(false);
setPreviewQuality(0.5);
await settle();
expect(params(el).get("hf-proxy-box")).toBe("1024x724");
expect(params(el).has("hf-proxy-light")).toBe(false);
setPreviewQuality(1);
await settle();
expect(params(el).get("hf-proxy-box")).toBe("2048x1218");
});
it("ignores a level that is not one of the four", async () => {
const { video, setPreviewQuality } = await stage({ "/video.mp4": HEAVY });
const el = video();
setPreviewQuality(0.7);
await settle();
expect(isProxied(el)).toBe(false);
});
});
+166 -57
View File
@@ -9,9 +9,15 @@ import { waitForServedProxy } from "./proxyWait";
import { registerSeekCompletion } from "./adapters/seek-dispatch";
import {
formatPreviewProxyBox,
isHeavyForPreview,
isPreviewQuality,
PREVIEW_PROXY_BOX_PARAM,
PREVIEW_PROXY_LIGHT_PARAM,
quantizePreviewProxyBox,
scalePreviewProxyBox,
type PreviewProxyBox,
type PreviewQuality,
type PreviewSourceFacts,
} from "../previewProxyBox";
/**
@@ -34,6 +40,7 @@ export type MediaCodecMapEntry = {
declare global {
interface Window {
__HF_MEDIA_CODEC_MAP__?: Record<string, MediaCodecMapEntry>;
__HF_MEDIA_SOURCE_FACTS__?: Record<string, PreviewSourceFacts>;
}
}
@@ -45,7 +52,7 @@ const DIAGNOSTIC_FALLBACK_CODE = "runtime_media_proxy_fallback";
* did) proxy it — a remote asset, or the proxy URL itself failing. */
const DIAGNOSTIC_UNAVAILABLE_CODE = "runtime_media_proxy_unavailable";
type ProxyTrigger = "proactive" | "reactive" | "tertiary";
type ProxyTrigger = "proactive" | "reactive" | "tertiary" | "light";
// `swappedElements` gates every trigger, so a second undecodable-video signal never re-swaps.
@@ -63,6 +70,10 @@ function currentSrcValue(el: HTMLMediaElement): string {
return el.currentSrc || el.src;
}
// Below 1, heavy files get lighter copies at the shown box times this level; 1 is the preview as it always was.
let previewQuality: PreviewQuality = 1;
const lightElements = new WeakSet<HTMLMediaElement>();
// How large the host shows this document, in its CSS pixels per ours (player fit x page zoom).
// A top-level page shows itself at 1; a framed one waits for its host to say.
let displayScale: number | null = window.parent === window ? 1 : null;
@@ -72,7 +83,13 @@ const displayScaleKnown = new Promise<void>((arrived) => (displayScaleArrived =
const DISPLAY_SCALE_WAIT_MS = 1000;
// Elements on a size-bounded copy: the source, the copy's URL and the box it was made for.
type BoxedCopy = { originalSrc: string; variant: string; href: string; box: PreviewProxyBox };
type BoxedCopy = {
originalSrc: string;
variant: string;
href: string;
box: PreviewProxyBox;
light: boolean;
};
const boxedElements = new Map<HTMLMediaElement, BoxedCopy>();
// The larger copy each element waits for; a newer ask replaces it and the older wait stops.
const pendingUpgrades = new WeakMap<HTMLMediaElement, string>();
@@ -106,6 +123,19 @@ export function setProxyDisplayScale(scale: number): void {
for (const el of boxedElements.keys()) keepSized(el, scale);
}
function codecEntryOf(el: HTMLMediaElement): MediaCodecMapEntry | null {
const map = window.__HF_MEDIA_CODEC_MAP__;
const key = deriveCodecMapKey(el);
return map && key !== null ? lookupCodecMapEntry(key, map) : null;
}
function sourceFactsOf(el: HTMLMediaElement): PreviewSourceFacts | null {
const facts = window.__HF_MEDIA_SOURCE_FACTS__;
const key = deriveCodecMapKey(el);
return facts && key !== null ? lookupCodecMapEntry(key, facts) : null;
}
// fallow-ignore-next-line complexity
function keepSized(el: HTMLMediaElement, scale: number): void {
const copy = boxedElements.get(el);
if (!copy) return;
@@ -113,32 +143,68 @@ function keepSized(el: HTMLMediaElement, scale: number): void {
boxedElements.delete(el);
return;
}
const needed = shownBox(el, scale);
if (needed && needed.width <= copy.box.width && needed.height <= copy.box.height) return;
// Never smaller on either side than the copy it replaces.
const box = needed && {
width: Math.max(needed.width, copy.box.width),
height: Math.max(needed.height, copy.box.height),
const shown = shownBox(el, scale);
const lowered = previewQuality < 1;
const needed = shown && lowered ? scalePreviewProxyBox(shown, previewQuality) : shown;
if (lowered && !needed) return;
if (needed && lowered && copy.light && lightCopyNoLongerNeeded(el, needed)) {
return restoreOriginal(el);
}
if (boxCovers(copy.box, needed, lowered)) return;
requestBox(el, copy, lowered || !needed ? needed : growOnly(needed, copy.box));
}
function lightCopyNoLongerNeeded(el: HTMLMediaElement, needed: PreviewProxyBox): boolean {
const facts = sourceFactsOf(el);
return facts !== null && !isHeavyForPreview(facts, needed);
}
function boxCovers(current: PreviewProxyBox, needed: PreviewProxyBox | null, exact: boolean) {
if (exact) return needed?.width === current.width && needed.height === current.height;
return needed !== null && needed.width <= current.width && needed.height <= current.height;
}
function growOnly(needed: PreviewProxyBox, current: PreviewProxyBox): PreviewProxyBox {
return {
width: Math.max(needed.width, current.width),
height: Math.max(needed.height, current.height),
};
const href = appendProxyParam(copy.originalSrc, copy.variant, box);
}
function requestBox(el: HTMLMediaElement, copy: BoxedCopy, box: PreviewProxyBox | null): void {
const href = appendProxyParam(copy.originalSrc, copy.variant, box, copy.light);
if (pendingUpgrades.get(el) === href) return;
pendingUpgrades.set(el, href);
const wanted = () =>
pendingUpgrades.get(el) === href && el.isConnected && el.getAttribute("src") === copy.href;
void waitForServedProxy(href, wanted).then((served) => {
if (served && wanted()) loadProxy(el, href, copy.originalSrc, copy.variant, box);
if (served && wanted()) loadProxy(el, href, copy.originalSrc, copy.variant, box, copy.light);
if (pendingUpgrades.get(el) === href) pendingUpgrades.delete(el);
});
}
/** Puts a video that only got a lighter copy back on its original. */
function restoreOriginal(el: HTMLMediaElement): void {
const original = swappedElements.get(el) ?? null;
for (const state of [boxedElements, pendingUpgrades, proxyRequested, swappedElements]) {
state.delete(el);
}
lightElements.delete(el);
evictMediaSyncState(el);
if (original === null) el.removeAttribute("src");
else el.setAttribute("src", original);
el.load();
}
function loadProxy(
el: HTMLMediaElement,
href: string,
originalSrc: string,
variant: string,
box: PreviewProxyBox | null,
light = false,
): void {
if (box) boxedElements.set(el, { originalSrc, variant, href, box });
if (box) boxedElements.set(el, { originalSrc, variant, href, box, light });
else boxedElements.delete(el);
// Sync state measured on the previous file would read the new file's buffering as drift.
evictMediaSyncState(el);
@@ -202,10 +268,7 @@ export function deriveCodecMapKey(el: HTMLMediaElement): string | null {
* ending in `"/notfoo.mp4"`, since that would require the literal substring
* `"/foo.mp4"` to appear where the last `/` already fell a segment later).
*/
function lookupLongestExactSuffix(
pathname: string,
map: Record<string, MediaCodecMapEntry>,
): MediaCodecMapEntry | null {
function lookupLongestExactSuffix<T>(pathname: string, map: Record<string, T>): T | null {
let bestKey: string | null = null;
for (const key of Object.keys(map)) {
if (!pathname.endsWith(key)) continue;
@@ -214,10 +277,7 @@ function lookupLongestExactSuffix(
return bestKey ? (map[bestKey] ?? null) : null;
}
function lookupNormalizedSuffix(
pathname: string,
map: Record<string, MediaCodecMapEntry>,
): MediaCodecMapEntry | null {
function lookupNormalizedSuffix<T>(pathname: string, map: Record<string, T>): T | null {
// Case-insensitive filesystems and Unicode-normalizing filesystems can
// serve an authored URL whose spelling differs from the canonical path
// ffprobe returned (Clip.mp4 vs clip.mp4, NFC vs NFD). Exact matching stays
@@ -226,7 +286,7 @@ function lookupNormalizedSuffix(
// spellings never select the wrong asset.
const normalizedPathname = pathname.normalize("NFC").toLowerCase();
let normalizedBestLength = -1;
let normalizedBest: MediaCodecMapEntry | null = null;
let normalizedBest: T | null = null;
let ambiguous = false;
for (const [key, entry] of Object.entries(map)) {
const normalizedKey = key.normalize("NFC").toLowerCase();
@@ -242,10 +302,7 @@ function lookupNormalizedSuffix(
return ambiguous ? null : normalizedBest;
}
function lookupCodecMapEntry(
pathname: string,
map: Record<string, MediaCodecMapEntry>,
): MediaCodecMapEntry | null {
function lookupCodecMapEntry<T>(pathname: string, map: Record<string, T>): T | null {
return (
map[pathname] ??
lookupLongestExactSuffix(pathname, map) ??
@@ -253,10 +310,16 @@ function lookupCodecMapEntry(
);
}
function appendProxyParam(src: string, variant: string, box: PreviewProxyBox | null): string {
function appendProxyParam(
src: string,
variant: string,
box: PreviewProxyBox | null,
light = false,
): string {
const url = new URL(src, document.baseURI);
url.searchParams.set(PROXY_QUERY_PARAM, variant);
if (box) url.searchParams.set(PREVIEW_PROXY_BOX_PARAM, formatPreviewProxyBox(box));
if (light && box) url.searchParams.set(PREVIEW_PROXY_LIGHT_PARAM, "1");
return url.href;
}
@@ -300,6 +363,49 @@ function emitUnavailableDiagnostic(
console.info(`[hyperframes] ${DIAGNOSTIC_UNAVAILABLE_CODE}: "${asset}" (${reason}): ${note}`);
}
type CopyJob = {
originalSrc: string;
originalAttr: string | null;
variant: string;
lightFacts?: PreviewSourceFacts;
level: PreviewQuality;
live: () => boolean;
};
// fallow-ignore-next-line complexity
async function makeCopy(el: HTMLMediaElement, job: CopyJob, scale: number | null) {
const { originalSrc, originalAttr, variant, lightFacts, level, live } = job;
// Asked once the shown size is known, so the copy is made at that size and only once.
const shown = scale === null ? null : shownBox(el, scale);
const box = shown && level < 1 ? scalePreviewProxyBox(shown, level) : shown;
if (lightFacts && !(box && isHeavyForPreview(lightFacts, box))) {
if (proxyRequested.get(el) === originalAttr) proxyRequested.delete(el);
return;
}
const proxiedSrc = appendProxyParam(originalSrc, variant, box, lightFacts !== undefined);
const served = await waitForServedProxy(proxiedSrc, live);
if (!live()) {
if (proxyRequested.get(el) === originalAttr) proxyRequested.delete(el);
if (lightFacts && el.isConnected && el.getAttribute("src") === originalAttr) {
applyPreviewQuality(el);
}
return;
}
if (!served) {
emitUnavailableDiagnostic(el, "proxy_playback_failed", originalSrc);
return;
}
swappedElements.set(el, originalAttr);
if (lightFacts) lightElements.add(el);
loadProxy(el, proxiedSrc, originalSrc, variant, box, lightFacts !== undefined);
// The shown size may have grown while this copy was being made.
if (displayScale !== null) keepSized(el, displayScale);
return new Promise((landed) => {
el.addEventListener("loadeddata", landed, { once: true });
el.addEventListener("error", landed, { once: true });
});
}
/**
* Swap `el` to its alpha-aware proxy URL, evict stale per-source sync state, and
* emit the one-time diagnostic + console line. Safe to call from any of the
@@ -309,6 +415,7 @@ export function swapToProxy(
el: HTMLMediaElement,
entry: MediaCodecMapEntry | null = null,
trigger: ProxyTrigger = "reactive",
lightFacts?: PreviewSourceFacts,
): void {
if (swappedElements.has(el)) return;
if (proxyRequested.has(el) && proxyRequested.get(el) === el.getAttribute("src")) return;
@@ -323,29 +430,15 @@ export function swapToProxy(
}
const originalAttr = el.getAttribute("src");
proxyRequested.set(el, originalAttr);
const live = () => el.isConnected && el.getAttribute("src") === originalAttr;
const swap = shownScale().then(async (scale) => {
// Asked once the shown size is known, so the copy is made at that size and only once.
const box = scale === null ? null : shownBox(el, scale);
const proxiedSrc = appendProxyParam(originalSrc, variant, box);
const served = await waitForServedProxy(proxiedSrc, live);
if (!live()) {
if (proxyRequested.get(el) === originalAttr) proxyRequested.delete(el);
return;
}
if (!served) {
emitUnavailableDiagnostic(el, "proxy_playback_failed", originalSrc);
return;
}
swappedElements.set(el, originalAttr);
loadProxy(el, proxiedSrc, originalSrc, variant, box);
// The shown size may have grown while this copy was being made.
if (displayScale !== null) keepSized(el, displayScale);
return new Promise((landed) => {
el.addEventListener("loadeddata", landed, { once: true });
el.addEventListener("error", landed, { once: true });
});
});
const level = previewQuality;
// A lighter copy waits for no level but its own; a copy the file cannot play without finishes at any level.
const live = () =>
el.isConnected &&
el.getAttribute("src") === originalAttr &&
(!lightFacts || previewQuality === level);
const job: CopyJob = { originalSrc, originalAttr, variant, lightFacts, level, live };
const swap = shownScale().then((scale) => makeCopy(el, job, scale));
if (lightFacts) return;
// A frame capture holds for the copy as it held for a loading video before, up to the same cap.
registerSeekCompletion(
Promise.race([swap, new Promise((cap) => setTimeout(cap, HOLD_CAP_MS))]),
@@ -383,15 +476,31 @@ export function maybeProxyProactively(el: HTMLMediaElement): void {
if (isRenderMode(el)) return;
if (!isVideoElement(el)) return;
if (swappedElements.has(el)) return;
const map = window.__HF_MEDIA_CODEC_MAP__;
if (!map) return;
const key = deriveCodecMapKey(el);
if (key === null) return;
const entry = lookupCodecMapEntry(key, map);
if (!entry || !entry.browserHostile) return;
const canPlay = entry.representativeMime ? el.canPlayType(entry.representativeMime) : "";
if (canPlay === "probably" || canPlay === "maybe") return;
swapToProxy(el, entry, "proactive");
const entry = codecEntryOf(el);
const canPlay = entry?.representativeMime ? el.canPlayType(entry.representativeMime) : "";
const playable = canPlay === "probably" || canPlay === "maybe";
if (entry?.browserHostile && !playable) swapToProxy(el, entry, "proactive");
else if (previewQuality < 1) lightenIfHeavy(el, entry);
}
function lightenIfHeavy(el: HTMLMediaElement, entry: MediaCodecMapEntry | null): void {
if (swappedElements.has(el) || proxyRequested.has(el)) return;
const facts = sourceFactsOf(el);
if (facts) swapToProxy(el, entry, "light", facts);
}
function applyPreviewQuality(el: HTMLMediaElement): void {
if (isRenderMode(el) || !isVideoElement(el)) return;
if (previewQuality === 1 && lightElements.has(el)) return restoreOriginal(el);
if (boxedElements.has(el) && displayScale !== null) return keepSized(el, displayScale);
if (previewQuality < 1) lightenIfHeavy(el, codecEntryOf(el));
}
/** The host's preview quality: below 1, heavy videos play lighter copies sized to the shown box times the level. */
export function setPreviewQuality(level: number): void {
if (!isPreviewQuality(level) || level === previewQuality) return;
previewQuality = level;
for (const el of document.querySelectorAll("video")) applyPreviewQuality(el);
}
/**
+2
View File
@@ -22,6 +22,7 @@ type RuntimeBridgeControlActionBase =
| "set-web-audio-media-disabled"
| "set-idle-heartbeat"
| "set-display-scale"
| "set-preview-quality"
| "set-root-duration"
| "set-play-range"
| "stop-media"
@@ -41,6 +42,7 @@ type RuntimeBridgeControlMessageBase = {
disabled?: boolean;
slow?: boolean;
scale?: number;
level?: number;
playbackRate?: number;
target?: HfColorGradingTarget | string | null;
grading?: RuntimeJson;
@@ -10,6 +10,7 @@ import {
probeAssetCodec,
proxyVariantFor,
resolveProxyVariantRequest,
scanProjectMedia,
scanProjectMediaCodecMap,
shouldPrewarmProxy,
type AssetCodecFacts,
@@ -24,7 +25,14 @@ const FAKE_FFPROBE_PATH = process.execPath;
function makeRunner(
codecByPath: Record<
string,
string | { codecName: string; pixFmt?: string; tags?: Record<string, string> }
| string
| {
codecName: string;
pixFmt?: string;
tags?: Record<string, string>;
size?: [number, number];
bitRate?: string;
}
>,
): FfprobeRunner {
return (_command, args) => {
@@ -38,6 +46,9 @@ function makeRunner(
codec_name: normalized.codecName,
pix_fmt: normalized.pixFmt,
tags: normalized.tags,
width: normalized.size?.[0],
height: normalized.size?.[1],
bit_rate: normalized.bitRate,
},
]
: [];
@@ -328,6 +339,68 @@ describe("decideMediaProxyEligibility", () => {
});
});
describe("a lighter copy of a file Chrome can play", () => {
const playable = {
codecName: "h264",
browserHostile: false,
representativeMime: null,
hasAlpha: false,
source: { width: 3840, height: 2160, bitDepth: 8, bitrate: 10_000_000 },
};
it("is allowed only for the box it is asked at, and only when the file is heavy there", () => {
expect(decideMediaProxyEligibility(playable)).toEqual({
eligible: false,
reason: "browser_safe_codec",
});
expect(decideMediaProxyEligibility(playable, { width: 724, height: 362 })).toEqual({
eligible: true,
});
expect(
decideMediaProxyEligibility(
{ ...playable, source: { ...playable.source, width: 1920, height: 1080 } },
{ width: 2048, height: 1218 },
),
).toEqual({ eligible: false, reason: "browser_safe_codec" });
});
it("reads the size, bit depth and bitrate off the probe, and keeps them with the codec facts", async () => {
const project = tmpProject();
const videoPath = join(project, "cam.mov");
writeFileSync(videoPath, "fake video bytes");
const facts = await probeAssetCodec(
videoPath,
makeRunner({
[videoPath]: {
codecName: "hevc",
pixFmt: "yuv420p10le",
size: [3840, 2160],
bitRate: "60000000",
},
}),
);
expect(facts?.source).toEqual({ width: 3840, height: 2160, bitDepth: 10, bitrate: 60_000_000 });
});
it("scans the sizes of the playable videos too, while the codec map keeps only the hostile ones", async () => {
const project = tmpProject();
writeFileSync(join(project, "cam.mp4"), "fake video bytes");
writeFileSync(join(project, "broll.mov"), "fake video bytes");
const scan = await scanProjectMedia(project, [{ html: videoHtml("cam.mp4", "broll.mov") }], {
runner: makeRunner({
[join(project, "cam.mp4")]: { codecName: "h264", size: [1920, 1080] },
[join(project, "broll.mov")]: { codecName: "hevc", size: [3840, 2160] },
}),
});
expect(Object.keys(scan.codecMap)).toEqual(["/broll.mov"]);
expect(Object.keys(scan.sourceFacts).sort()).toEqual(["/broll.mov", "/cam.mp4"]);
});
});
describe("proxyVariantFor", () => {
it("uses VP8 for alpha and H.264 otherwise", () => {
const facts = {
@@ -9,6 +9,11 @@ import {
isUnresolvedAssetPlaceholder,
resolveExistingLocalAsset as resolveAsset,
} from "@hyperframes/parsers/asset-resolution";
import {
isHeavyForPreview,
type PreviewProxyBox,
type PreviewSourceFacts,
} from "@hyperframes/core";
import { probeMediaMetadata, type FfprobeRunner } from "./mediaMetadata.js";
/**
@@ -27,6 +32,8 @@ export interface AssetCodecFacts {
/** Source carries an alpha channel (`MediaMetadata.hasAlpha`). Alpha sources use a
* VP8/WebM proxy so their transparency is preserved across Chromium builds. */
hasAlpha: boolean;
/** Size, bit depth and bitrate, for deciding whether a playable file deserves a lighter copy. */
source?: PreviewSourceFacts;
}
/** Server-root-relative URL pathname -> that asset's codec facts. */
@@ -176,20 +183,34 @@ export type MediaProxyEligibility =
| { eligible: true }
| { eligible: false; reason: MediaProxyIneligibilityReason };
/** Single policy gate shared by proactive scans and on-demand proxy routes. */
export function decideMediaProxyEligibility(facts: AssetCodecFacts | null): MediaProxyEligibility {
/**
* Single policy gate shared by proactive scans and on-demand proxy routes. A file Chrome can play is
* eligible only for a lighter copy (`lightBox`, the box that request asks for) and only when it is heavy there.
*/
export function decideMediaProxyEligibility(
facts: AssetCodecFacts | null,
lightBox?: PreviewProxyBox,
): MediaProxyEligibility {
if (!facts) return { eligible: false, reason: "unknown_codec" };
if (!facts.browserHostile) return { eligible: false, reason: "browser_safe_codec" };
return { eligible: true };
if (facts.browserHostile) return { eligible: true };
if (lightBox && facts.source && isHeavyForPreview(facts.source, lightBox)) {
return { eligible: true };
}
return { eligible: false, reason: "browser_safe_codec" };
}
function codecFactsFor(codecName: string, hasAlpha: boolean): AssetCodecFacts {
function codecFactsFor(
codecName: string,
hasAlpha: boolean,
source?: PreviewSourceFacts,
): AssetCodecFacts {
const hostile = hostileCodecEntry(codecName);
return {
codecName,
browserHostile: hostile !== undefined,
representativeMime: hostile?.representativeMime ?? null,
hasAlpha,
...(source && { source }),
};
}
@@ -205,7 +226,7 @@ async function probeCodecFacts(
if (metadata.kind !== "video") return null;
const codecName = metadata.color.codecName;
if (!codecName) return null;
return codecFactsFor(codecName, metadata.hasAlpha === true);
return codecFactsFor(codecName, metadata.hasAlpha === true, metadata.source);
}
interface CachedAssetProbe {
@@ -347,20 +368,12 @@ export interface ScanProjectMediaCodecMapOptions {
runner?: FfprobeRunner;
}
/**
* Scans a project's composition HTML for local `<video src>` references and
* returns the injection map: root-relative URL pathname -> codec facts.
* Best-effort throughout — a video whose codec can't be determined (missing
* ffprobe, probe error, no video stream) is simply omitted, never thrown.
*/
export async function scanProjectMediaCodecMap(
async function probeProjectAssets(
projectDir: string,
htmlSources: HtmlSourceLike[],
options: ScanProjectMediaCodecMapOptions = {},
): Promise<MediaCodecMap> {
options: ScanProjectMediaCodecMapOptions,
): Promise<Array<[string, AssetCodecFacts | null]>> {
const candidates = collectLocalVideoAssets(projectDir, htmlSources);
if (candidates.size === 0) return {};
const cache = options.cache ?? defaultProbeCache;
const entries = [...candidates.entries()]; // [resolvedPath, rootRelativePathname]
const facts = new Array<AssetCodecFacts | null>(entries.length).fill(null);
@@ -376,11 +389,35 @@ export async function scanProjectMediaCodecMap(
}
}),
);
return entries.map(([, pathname], index) => [pathname, facts[index] ?? null]);
}
const map: MediaCodecMap = {};
entries.forEach(([, pathname], index) => {
const entryFacts = facts[index];
if (entryFacts?.browserHostile) map[pathname] = entryFacts;
});
return map;
/** What a scan of a project's local videos finds: the hostile ones for the proxy map, and every readable one's size. */
export interface ProjectMediaScan {
codecMap: MediaCodecMap;
/** Root-relative URL pathname -> size, bit depth and bitrate. */
sourceFacts: Record<string, PreviewSourceFacts>;
}
/** Scans composition HTML for local `<video src>` references; a video that can't be probed is omitted. */
export async function scanProjectMedia(
projectDir: string,
htmlSources: HtmlSourceLike[],
options: ScanProjectMediaCodecMapOptions = {},
): Promise<ProjectMediaScan> {
const scan: ProjectMediaScan = { codecMap: {}, sourceFacts: {} };
for (const [pathname, facts] of await probeProjectAssets(projectDir, htmlSources, options)) {
if (facts?.browserHostile) scan.codecMap[pathname] = facts;
if (facts?.source) scan.sourceFacts[pathname] = facts.source;
}
return scan;
}
/** The injection map alone: root-relative URL pathname -> codec facts of the hostile videos. */
export async function scanProjectMediaCodecMap(
projectDir: string,
htmlSources: HtmlSourceLike[],
options: ScanProjectMediaCodecMapOptions = {},
): Promise<MediaCodecMap> {
return (await scanProjectMedia(projectDir, htmlSources, options)).codecMap;
}
@@ -120,6 +120,33 @@ describe("probeMediaMetadata", () => {
expect(flac.kind).toBe("audio");
});
it("reads the size, bit depth and bitrate a lighter copy is judged by", async () => {
const probe = (stream: object, format: object = {}) =>
probeMediaMetadata("/tmp/clip.mp4", () => ({
status: 0,
stdout: JSON.stringify({ streams: [{ codec_type: "video", ...stream }], format }),
stderr: "",
}));
expect(
(await probe({ width: 3840, height: 2160, pix_fmt: "yuv420p10le", bit_rate: "9" })).source,
).toEqual({
width: 3840,
height: 2160,
bitDepth: 10,
bitrate: 9,
});
expect(
(await probe({ width: 1920, height: 1080, pix_fmt: "yuv420p" }, { bit_rate: "55000000" }))
.source,
).toEqual({ width: 1920, height: 1080, bitDepth: 8, bitrate: 55_000_000 });
expect(
(await probe({ width: 1920, height: 1080, pix_fmt: "yuv420p", bits_per_raw_sample: "12" }))
.source?.bitDepth,
).toBe(12);
expect((await probe({ pix_fmt: "yuv420p" })).source).toBeUndefined();
});
it("ignores attached cover art and reads the real video stream", async () => {
const metadata = await probeMediaMetadata("/tmp/clip.mp4", () => ({
status: 0,
@@ -3,6 +3,7 @@ import { extname } from "node:path";
import {
firstFrameColourArgs,
parseFirstFrameColour,
type PreviewSourceFacts,
type ToneMapSourceColour,
} from "@hyperframes/core";
import { findFfBinary } from "@hyperframes/parsers/ff-binaries";
@@ -77,6 +78,7 @@ export interface MediaMetadata {
/** Video stream carries alpha (pix_fmt or the VP8/VP9 alpha_mode tag). */
hasAlpha?: boolean;
durationSeconds?: number;
source?: PreviewSourceFacts;
probeError?: string;
}
@@ -89,6 +91,9 @@ interface FfprobeStream {
color_transfer?: string;
color_primaries?: string;
bits_per_raw_sample?: string;
width?: number;
height?: number;
bit_rate?: string;
disposition?: { attached_pic?: number };
tags?: Record<string, string | undefined>;
}
@@ -192,6 +197,27 @@ export async function probeFirstFrameColour(
return result.status === 0 ? parseFirstFrameColour(String(result.stderr)) : {};
}
function bitDepthOf(stream: FfprobeStream): number {
const raw = Number(stream.bits_per_raw_sample);
if (Number.isFinite(raw) && raw > 0) return raw;
const suffixed = /(\d{1,3})(?:le|be)$/.exec(stream.pix_fmt ?? "");
return suffixed ? Number(suffixed[1]) : 8;
}
function sourceFactsOf(
stream: FfprobeStream | undefined,
formatBitrate: string | undefined,
): PreviewSourceFacts | undefined {
if (!stream?.width || !stream.height) return undefined;
const bitrate = Number(stream.bit_rate ?? formatBitrate);
return {
width: stream.width,
height: stream.height,
bitDepth: bitDepthOf(stream),
bitrate: Number.isFinite(bitrate) ? bitrate : 0,
};
}
export async function probeMediaMetadata(
filePath: string,
runner: FfprobeRunner = execFileRunner,
@@ -216,7 +242,7 @@ export async function probeMediaMetadata(
"-v",
"error",
"-show_entries",
"stream=codec_type,codec_name,profile,pix_fmt,color_space,color_transfer,color_primaries,bits_per_raw_sample:stream_disposition=attached_pic:stream_tags=alpha_mode:format=duration",
"stream=codec_type,codec_name,profile,pix_fmt,color_space,color_transfer,color_primaries,bits_per_raw_sample,width,height,bit_rate:stream_disposition=attached_pic:stream_tags=alpha_mode:format=duration,bit_rate",
"-of",
"json",
"--",
@@ -235,7 +261,7 @@ export async function probeMediaMetadata(
try {
const parsed = JSON.parse(String(result.stdout || "{}")) as {
streams?: FfprobeStream[];
format?: { duration?: string };
format?: { duration?: string; bit_rate?: string };
};
const stream = parsed.streams?.find((item) => {
if (kind === "image") return item.codec_type === "video";
@@ -247,6 +273,7 @@ export async function probeMediaMetadata(
metadata.hasAlpha = stream !== undefined && videoStreamHasAlpha(stream);
const duration = Number(parsed.format?.duration);
if (Number.isFinite(duration) && duration > 0) metadata.durationSeconds = duration;
metadata.source = sourceFactsOf(stream, parsed.format?.bit_rate);
}
return metadata;
} catch {
@@ -23,7 +23,10 @@ function hostile(codecName: string, representativeMime: string | null): AssetCod
return { codecName, browserHostile: true, representativeMime, hasAlpha: false };
}
async function loadHelper(map: MediaCodecMap): Promise<{
async function loadHelper(
map: MediaCodecMap,
sourceFacts: Record<string, unknown> = {},
): Promise<{
injectMediaCodecMapIntoHtml: typeof import("./mediaProxyPreview.js").injectMediaCodecMapIntoHtml;
mediaProxyDemand: typeof import("./mediaCodecMap.js").mediaProxyDemand;
resolveProxy: ReturnType<typeof vi.fn>;
@@ -35,7 +38,7 @@ async function loadHelper(map: MediaCodecMap): Promise<{
// replaced, so this asserts the shipped policy rather than a copy of it.
vi.doMock("./mediaCodecMap.js", async () => ({
...(await vi.importActual<typeof import("./mediaCodecMap.js")>("./mediaCodecMap.js")),
scanProjectMediaCodecMap: async () => map,
scanProjectMedia: async () => ({ codecMap: map, sourceFacts }),
}));
const { injectMediaCodecMapIntoHtml } = await import("./mediaProxyPreview.js");
const { mediaProxyDemand } = await import("./mediaCodecMap.js");
@@ -55,6 +58,33 @@ afterEach(() => {
for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true });
});
describe("injectMediaCodecMapIntoHtml source facts", () => {
const facts = { "/videos/cam.mp4": { width: 3840, height: 2160, bitDepth: 10, bitrate: 0 } };
it("hands the page the sizes of its videos, and no codec map when none is hostile", async () => {
const { injectMediaCodecMapIntoHtml } = await loadHelper({}, facts);
const html = await injectMediaCodecMapIntoHtml(
"<html><head></head><body></body></html>",
tmpProject(),
[{ html: "<html></html>" }],
);
expect(html).toContain("window.__HF_MEDIA_SOURCE_FACTS__=");
expect(html).toContain('"/videos/cam.mp4"');
expect(html).not.toContain("__HF_MEDIA_CODEC_MAP__");
});
it("leaves the page untouched when there is nothing to say about its videos", async () => {
const { injectMediaCodecMapIntoHtml } = await loadHelper({}, {});
const page = "<html><head></head><body></body></html>";
expect(await injectMediaCodecMapIntoHtml(page, tmpProject(), [{ html: "<html></html>" }])).toBe(
page,
);
});
});
describe("injectMediaCodecMapIntoHtml pre-warm", () => {
it("pre-warms the codec with no cross-platform decode and leaves the widely-decoded one lazy", async () => {
const projectDir = tmpProject();
@@ -6,10 +6,10 @@ import {
createMediaCodecProbeCache,
proxyVariantFor,
recordProxyPrewarm,
scanProjectMediaCodecMap,
scanProjectMedia,
shouldPrewarmProxy,
type HtmlSourceLike,
type MediaCodecMap,
type ProjectMediaScan,
type MediaCodecProbeCache,
} from "./mediaCodecMap.js";
import { resolveProxy, PROXY_PARAMS_VERSION } from "./proxyTranscoder.js";
@@ -97,18 +97,16 @@ export async function injectMediaCodecMapIntoHtml(
signal?: AbortSignal,
box?: PreviewProxyBox,
): Promise<string> {
let map: MediaCodecMap;
let scan: ProjectMediaScan;
try {
map = await scanProjectMediaCodecMap(
projectDir,
htmlSources,
probeCache ? { cache: probeCache } : {},
);
scan = await scanProjectMedia(projectDir, htmlSources, probeCache ? { cache: probeCache } : {});
} catch {
// Best-effort: a scan failure must never block serving the page.
return html;
}
if (Object.keys(map).length === 0) return html;
const { codecMap: map, sourceFacts } = scan;
const hasMap = Object.keys(map).length > 0;
if (!hasMap && Object.keys(sourceFacts).length === 0) return html;
for (const [rootRelativePathname, facts] of Object.entries(map)) {
if (!prewarm || !shouldPrewarmProxy(facts)) continue;
recordProxyPrewarm();
@@ -125,11 +123,17 @@ export async function injectMediaCodecMapIntoHtml(
}
// <-escape prevents a src path containing "</script>" from breaking out of
// the injected tag, mirroring injectPreviewVariables in helpers/previewVariables.ts.
const json = JSON.stringify(map)
.replace(/</g, "\\u003c")
.replace(/\u2028/g, "\\u2028")
.replace(/\u2029/g, "\\u2029");
const tag = `<script data-hf-media-codec-map>window.__HF_MEDIA_CODEC_MAP__=${json};</script>`;
const safeJson = (value: unknown): string =>
JSON.stringify(value)
.replace(/</g, "\\u003c")
.replace(/\u2028/g, "\\u2028")
.replace(/\u2029/g, "\\u2029");
// An empty map stays out: the runtime reads a present map as leave to rescue unlisted files.
const assignments = [
...(hasMap ? [`window.__HF_MEDIA_CODEC_MAP__=${safeJson(map)};`] : []),
`window.__HF_MEDIA_SOURCE_FACTS__=${safeJson(sourceFacts)};`,
];
const tag = `<script data-hf-media-codec-map>${assignments.join("")}</script>`;
return insertBeforeCloseTag(html, "head", `${tag}\n`) ?? `${tag}\n${html}`;
}
@@ -451,6 +451,22 @@ describe("resolveProxy", () => {
await expect(resultPromise).resolves.toBe(vp8Path);
});
it("puts a keyframe every second into a copy, so scrubbing lands close", async () => {
const { spawn, calls } = createSpawnSpy();
const { resolveProxy } = await loadModule(spawn, FFMPEG_PATH);
const projectDir = tmpProject();
const sourcePath = join(projectDir, "clip.mov");
writeFileSync(sourcePath, "source-bytes");
const result = resolveProxy(projectDir, sourcePath);
await flush();
const args = calls[0]!.args;
expect(args[args.indexOf("-force_key_frames") + 1]).toBe("expr:gte(t,n_forced*1)");
succeed(calls[0]!);
await result;
});
it("decodes a VP9 alpha source with libvpx-vp9 so the VP8 proxy keeps its alpha", async () => {
const { spawn, calls } = createSpawnSpy();
const { resolveProxy } = await loadModule(spawn, FFMPEG_PATH, false, null, "vp9");
@@ -35,7 +35,7 @@ import { mkdirWithinProject, realpath, realProjectRoot } from "./safePath.js";
* dropped from the queue or its ffmpeg is killed.
*/
export const PROXY_PARAMS_VERSION = "v6";
export const PROXY_PARAMS_VERSION = "v7";
export const CACHE_DIR_NAME = ".transcode-cache";
@@ -595,6 +595,7 @@ async function encodeInChunks(
for (const piece of pieces) if (existsSync(piece)) unlinkSync(piece);
}
const KEYFRAME_EVERY_SECOND_ARGS = ["-force_key_frames", "expr:gte(t,n_forced*1)"];
// Fixed recipe; changing either array means bumping PROXY_PARAMS_VERSION.
const H264_ARGS = [
"-c:v",
@@ -717,6 +718,7 @@ async function runFfmpeg(
...(range ? ["-t", String(range.lengthSeconds)] : []),
"-vf",
videoFilter,
...KEYFRAME_EVERY_SECOND_ARGS,
...(keepsAlpha ? [...VP8_ARGS, ...vp8Threads(range ? gate.size : 1)] : H264_ARGS),
target,
],
@@ -1390,6 +1390,7 @@ describe("hf-proxy negotiation and media codec map injection (U3)", () => {
browserHostile: boolean;
representativeMime: string | null;
hasAlpha: boolean;
source?: { width: number; height: number; bitDepth: number; bitrate: number };
} | null>;
}): Promise<typeof import("./preview.js")> {
vi.resetModules();
@@ -1424,7 +1425,10 @@ describe("hf-proxy negotiation and media codec map injection (U3)", () => {
...(await vi.importActual<typeof import("../helpers/mediaCodecMap.js")>(
"../helpers/mediaCodecMap.js",
)),
scanProjectMediaCodecMap: opts.scanMapImpl ?? (async () => ({})),
scanProjectMedia: async (...args: Parameters<ScanMapImpl>) => ({
codecMap: await (opts.scanMapImpl ?? (async () => ({})))(...args),
sourceFacts: {},
}),
createMediaCodecProbeCache: () => new Map(),
probeAssetCodec:
opts.probeAssetCodecImpl ??
@@ -1434,18 +1438,6 @@ describe("hf-proxy negotiation and media codec map injection (U3)", () => {
representativeMime: null,
hasAlpha: false,
})),
decideMediaProxyEligibility: (
facts: {
browserHostile: boolean;
hasAlpha: boolean;
} | null,
) => {
if (!facts) return { eligible: false, reason: "unknown_codec" };
if (!facts.browserHostile) {
return { eligible: false, reason: "browser_safe_codec" };
}
return { eligible: true };
},
isProxyVariant: (value: string) => value === "h264" || value === "vp8",
isProxyVariantRequest: (value: string) =>
value === "auto" || value === "h264" || value === "vp8",
@@ -1578,9 +1570,72 @@ describe("hf-proxy negotiation and media codec map injection (U3)", () => {
expect(sized.headers.get("ETag")).not.toBe(full.headers.get("ETag"));
});
describe("a lighter copy of a file Chrome can play", () => {
const playable = (width: number, height: number) => async () => ({
codecName: "h264",
browserHostile: false,
representativeMime: null,
hasAlpha: false,
source: { width, height, bitDepth: 8, bitrate: 10_000_000 },
});
it("is made at the asked box when the file is heavy there", async () => {
const projectDir = createProjectDir();
writeFileSync(join(projectDir, "clip.mp4"), "original-bytes");
const resolveProxyMock = vi.fn(async () => {
const proxyPath = join(projectDir, "light.mp4");
writeFileSync(proxyPath, "light-bytes");
return proxyPath;
});
const { registerPreviewRoutes: register } = await loadPreviewModule({
resolveProxyImpl: resolveProxyMock,
probeAssetCodecImpl: playable(3840, 2160),
});
const app = new Hono();
register(app, createAdapter(projectDir));
const res = await app.request(
"http://localhost/projects/demo/preview/clip.mp4?hf-proxy=h264&hf-proxy-light=1&hf-proxy-box=724x362",
);
expect(res.status).toBe(200);
expect(await res.text()).toBe("light-bytes");
expect(resolveProxyMock).toHaveBeenCalledWith(
projectDir,
join(projectDir, "clip.mp4"),
"h264",
{ width: 724, height: 362 },
);
});
it("is refused when the file is not heavy at that box, and without the ask", async () => {
const projectDir = createProjectDir();
writeFileSync(join(projectDir, "clip.mp4"), "original-bytes");
const resolveProxyMock = vi.fn(async () => "should-not-be-called");
const { registerPreviewRoutes: register } = await loadPreviewModule({
resolveProxyImpl: resolveProxyMock,
probeAssetCodecImpl: playable(1920, 1080),
});
const app = new Hono();
register(app, createAdapter(projectDir));
const small = await app.request(
"http://localhost/projects/demo/preview/clip.mp4?hf-proxy=h264&hf-proxy-light=1&hf-proxy-box=2048x1218",
);
const unasked = await app.request(
"http://localhost/projects/demo/preview/clip.mp4?hf-proxy=h264&hf-proxy-box=724x362",
);
expect(small.status).toBe(422);
expect(unasked.status).toBe(422);
expect(resolveProxyMock).not.toHaveBeenCalled();
});
});
it.each([
["a size off the ladder", "?hf-proxy=h264&hf-proxy-box=1000x2000"],
["a size without a copy", "?hf-proxy-box=1448x2048"],
["a lighter copy without a size", "?hf-proxy=h264&hf-proxy-light=1"],
])("refuses %s before making anything", async (_name, query) => {
const projectDir = createProjectDir();
writeFileSync(join(projectDir, "clip.mp4"), "original-hevc-bytes");
+12 -3
View File
@@ -18,7 +18,11 @@ import {
STUDIO_PREVIEW_MARK_META,
STUDIO_PREVIEW_ERRORS,
} from "@hyperframes/core/studio-preview-mark";
import { PREVIEW_PROXY_BOX_PARAM, parsePreviewProxyBox } from "@hyperframes/core";
import {
PREVIEW_PROXY_BOX_PARAM,
PREVIEW_PROXY_LIGHT_PARAM,
parsePreviewProxyBox,
} from "@hyperframes/core";
import {
GSAP_BASE_URL_META,
gsapCdnDist,
@@ -697,7 +701,12 @@ export function registerPreviewRoutes(api: Hono, adapter: PreviewApiAdapter): vo
const proxyParam = c.req.query("hf-proxy");
const boxParam = c.req.query(PREVIEW_PROXY_BOX_PARAM);
const proxyBox = boxParam === undefined ? undefined : parsePreviewProxyBox(boxParam);
if (proxyBox === null || (proxyBox && proxyParam === undefined)) {
const lightRequested = c.req.query(PREVIEW_PROXY_LIGHT_PARAM) !== undefined;
if (
proxyBox === null ||
(proxyBox && proxyParam === undefined) ||
(lightRequested && !proxyBox)
) {
return c.text("not found", 404);
}
let proxyVariant: ProxyVariant | undefined;
@@ -710,7 +719,7 @@ export function registerPreviewRoutes(api: Hono, adapter: PreviewApiAdapter): vo
return c.text("not found", 404);
}
const facts = await probeAssetCodec(file, undefined, mediaCodecProbeCache);
const eligibility = decideMediaProxyEligibility(facts);
const eligibility = decideMediaProxyEligibility(facts, lightRequested ? proxyBox : undefined);
if (!eligibility.eligible) {
return c.text(`media proxy unavailable: ${eligibility.reason}`, 422);
}
+1 -1
View File
@@ -36,7 +36,7 @@
"unpacked": 541601
},
"@hyperframes/producer": {
"packed": 781312,
"packed": 828932,
"unpacked": 2840135
},
"@hyperframes/sdk": {