Advance Blender 5.2 web parity through M12-03D
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-08-17 17:30:27 -04:00
parent 0fe8d2bb56
commit 5a11045ca5
148 changed files with 11683 additions and 66 deletions

View File

@@ -42,7 +42,13 @@ async function sha256(data: ArrayBuffer): Promise<string> {
return Array.from(new Uint8Array(result), (value) => value.toString(16).padStart(2, "0")).join("");
}
function waitForLoadedFrame(video: HTMLVideoElement, timeoutMs: number): Promise<void> {
function cancelled(signal: AbortSignal | undefined): void {
if (signal?.aborted) {
throw new SequencerMediaCacheValidationError("SEQUENCER_CANCELLED", "Movie proxy generation was cancelled");
}
}
function waitForLoadedFrame(video: HTMLVideoElement, timeoutMs: number, signal?: AbortSignal): Promise<void> {
if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) return Promise.resolve();
return new Promise((resolve, reject) => {
const timeout = window.setTimeout(() => finish(new Error("timeout")), timeoutMs);
@@ -50,12 +56,16 @@ function waitForLoadedFrame(video: HTMLVideoElement, timeoutMs: number): Promise
window.clearTimeout(timeout);
video.removeEventListener("loadeddata", ready);
video.removeEventListener("error", failed);
signal?.removeEventListener("abort", aborted);
if (error) reject(error); else resolve();
};
const ready = (): void => finish();
const failed = (): void => finish(new Error("decode"));
const aborted = (): void => finish(new SequencerMediaCacheValidationError("SEQUENCER_CANCELLED", "Movie proxy generation was cancelled"));
video.addEventListener("loadeddata", ready, { once: true });
video.addEventListener("error", failed, { once: true });
signal?.addEventListener("abort", aborted, { once: true });
if (signal?.aborted) aborted();
});
}
@@ -64,7 +74,9 @@ export async function generateInitialSequencerMovieProxyFrame(
capabilityValue: unknown,
profileValue: unknown,
sourceData: ArrayBuffer,
signal?: AbortSignal,
): Promise<SequencerGeneratedProxyFrameIR> {
cancelled(signal);
const source = parseSequencerCodecProbeRequest(sourceValue);
const capability = parseSequencerCodecProbeResult(capabilityValue);
const profile = parseSequencerMediaProxyProfile(profileValue);
@@ -75,6 +87,7 @@ export async function generateInitialSequencerMovieProxyFrame(
if (!(sourceData instanceof ArrayBuffer) || sourceData.byteLength !== source.byteLength || await sha256(sourceData) !== source.sourceSha256) {
throw new SequencerMediaCacheValidationError("SEQUENCER_CACHE_SOURCE_MISMATCH", "Movie proxy source bytes failed identity verification");
}
cancelled(signal);
if (typeof document === "undefined" || typeof HTMLMediaElement === "undefined") {
throw new SequencerMediaCacheValidationError("SEQUENCER_CODEC_UNSUPPORTED", "HTML media proxy generation is unavailable");
}
@@ -87,7 +100,8 @@ export async function generateInitialSequencerMovieProxyFrame(
try {
video.src = url;
video.load();
await waitForLoadedFrame(video, 10_000);
await waitForLoadedFrame(video, 10_000, signal);
cancelled(signal);
const canvas = document.createElement("canvas");
canvas.width = profile.width;
canvas.height = profile.height;
@@ -97,6 +111,7 @@ export async function generateInitialSequencerMovieProxyFrame(
}
context.clearRect(0, 0, profile.width, profile.height);
context.drawImage(video, 0, 0, profile.width, profile.height);
cancelled(signal);
const pixels = context.getImageData(0, 0, profile.width, profile.height).data;
const data = pixels.buffer.slice(pixels.byteOffset, pixels.byteOffset + pixels.byteLength);
return {