Files
BridgeSwarm/examples/shared/live-capture.js
T
Raven Scott a7b45f96d3
CI / Build & Test (push) Successful in 9m2s
Updates
2026-08-12 18:02:16 -04:00

105 lines
2.9 KiB
JavaScript

/**
* Shared capture helpers for live-encode / clip-studio demos.
*/
(function (global) {
'use strict';
function startCapture(kind) {
if (kind === 'camera') {
return navigator.mediaDevices.getUserMedia({
video: { width: { ideal: 1280 }, height: { ideal: 720 } },
audio: false,
});
}
return navigator.mediaDevices.getDisplayMedia({
video: { frameRate: { ideal: 30 } },
audio: false,
});
}
/**
* Pump video element frames onto a canvas at target FPS, calling onFrame(canvas).
* Returns { stop, canvas, setFps }.
*/
function startFramePump(videoEl, opts) {
opts = opts || {};
var fps = opts.fps || 10;
var maxW = opts.maxWidth || 640;
var maxH = opts.maxHeight || 360;
var canvas = opts.canvas || document.createElement('canvas');
var ctx = canvas.getContext('2d', { alpha: false });
var running = true;
var timer = null;
var lastPush = 0;
var inflight = false;
function sizeCanvas() {
var vw = videoEl.videoWidth || maxW;
var vh = videoEl.videoHeight || maxH;
var scale = Math.min(maxW / vw, maxH / vh, 1);
canvas.width = Math.max(2, Math.round(vw * scale / 2) * 2);
canvas.height = Math.max(2, Math.round(vh * scale / 2) * 2);
}
function tick() {
if (!running) return;
var interval = 1000 / fps;
var now = performance.now();
if (now - lastPush >= interval && !inflight && videoEl.readyState >= 2 && videoEl.videoWidth) {
lastPush = now;
if (!canvas.width || !canvas.height) sizeCanvas();
try {
ctx.drawImage(videoEl, 0, 0, canvas.width, canvas.height);
} catch (_) {}
if (typeof opts.onFrame === 'function') {
inflight = true;
Promise.resolve(opts.onFrame(canvas))
.catch(function () {})
.finally(function () { inflight = false; });
}
}
timer = requestAnimationFrame(tick);
}
function kickPlay() {
try {
videoEl.muted = true;
videoEl.playsInline = true;
videoEl.autoplay = true;
var p = videoEl.play();
if (p && typeof p.catch === 'function') p.catch(function () {});
} catch (_) {}
}
videoEl.addEventListener('loadedmetadata', function () {
sizeCanvas();
kickPlay();
});
if (videoEl.videoWidth) sizeCanvas();
kickPlay();
timer = requestAnimationFrame(tick);
return {
canvas: canvas,
stop: function () {
running = false;
if (timer) cancelAnimationFrame(timer);
timer = null;
},
setFps: function (n) {
fps = Math.max(1, Math.min(30, Number(n) || fps));
},
setMaxSize: function (w, h) {
maxW = w;
maxH = h;
sizeCanvas();
},
};
}
global.BridgeSwarmLiveCapture = {
startCapture: startCapture,
startFramePump: startFramePump,
};
})(typeof window !== 'undefined' ? window : globalThis);