This commit is contained in:
2026-05-30 00:08:59 +05:00
commit d3afd698b6
52 changed files with 8150 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>hevc.js Worker (OffscreenCanvas) — CoRE.Vision</title>
<style>
body { background:#0d0d0d; color:#ddd; font:13px system-ui,Arial; margin:0; padding:12px; }
#cv { background:#000; border:1px solid #333; display:block; margin:10px 0; width:100%; max-width:900px; height:auto; }
#log { white-space:pre-wrap; font:12px Consolas,monospace; color:#9f9; max-height:240px; overflow:auto; }
button { font:13px system-ui; padding:4px 10px; }
#stat { color:#ffd479; font-weight:bold; margin-left:12px; }
</style>
</head>
<body>
<div>
<button id="gomain">▶ main 3200×1800</button>
<button id="gosub">▶ sub 640×360</button>
<button id="stop">⏹ Stop</button>
<span id="stat"></span>
</div>
<canvas id="cv" width="1600" height="900"></canvas>
<div id="log"></div>
<script>
const logEl = document.getElementById("log"), statEl = document.getElementById("stat");
const log = (...a) => { logEl.textContent += a.map((x) => typeof x === "object" ? JSON.stringify(x) : String(x)).join(" ") + "\n"; logEl.scrollTop = 1e9; console.log("[hevcw]", ...a); };
window.onerror = (m, s, l) => log("‼ onerror", m, "@", l);
let worker = null, ws = null;
function stop() {
try { ws && ws.close(); } catch (e) {} ws = null;
if (worker) { try { worker.postMessage({ type: "stop" }); } catch (e) {} worker.terminate(); worker = null; }
statEl.textContent = "";
}
function start(stream) {
stop();
// canvas можно отдать в OffscreenCanvas только один раз → пересоздаём элемент при каждом старте
const old = document.getElementById("cv");
const cv = document.createElement("canvas");
cv.id = "cv";
cv.width = stream === "main" ? 1600 : 640;
cv.height = stream === "main" ? 900 : 360;
old.replaceWith(cv);
const off = cv.transferControlToOffscreen();
worker = new Worker("/static/vendor/hevcjs/hevc-player-worker.js", { type: "module" });
worker.onmessage = (e) => {
const m = e.data;
if (m.type === "ready") { log("worker ready → открываю WS"); openWS(stream); }
else if (m.type === "stat") { statEl.textContent = "декод/показ = " + m.fps + "/с"; if (m.fps) log("fps≈", m.fps); }
else if (m.type === "err") { log("‼ worker:", m.msg); }
};
worker.onerror = (e) => log("‼ worker.onerror:", e.message, "@", (e.filename || "") + ":" + (e.lineno || ""));
log("init worker (canvas " + cv.width + "x" + cv.height + ")");
worker.postMessage({
type: "init",
canvas: off,
wasmUrl: "/static/vendor/hevcjs/hevc-decode.esm.js",
wasmBinaryUrl: "/static/vendor/hevcjs/dist/wasm/hevc-decode.wasm",
}, [off]);
}
function openWS(stream) {
const proto = location.protocol === "https:" ? "wss" : "ws";
const url = `${proto}://${location.host}/api/cameras/cam32/flv?stream=${stream}`;
log("WS →", url);
ws = new WebSocket(url); ws.binaryType = "arraybuffer";
ws.onopen = () => log("WS open");
ws.onmessage = (e) => { if (worker) worker.postMessage({ type: "data", buf: e.data }, [e.data]); };
ws.onclose = (ev) => log("WS closed", ev.code);
ws.onerror = () => log("WS error");
}
document.getElementById("gomain").onclick = () => start("main");
document.getElementById("gosub").onclick = () => start("sub");
document.getElementById("stop").onclick = stop;
log("загружено. secure=", isSecureContext, "| COI=", crossOriginIsolated);
</script>
</body>
</html>