105 lines
2.9 KiB
JavaScript
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);
|