plugin / scripts.js
TDN-M's picture
Create scripts.js
658eafa verified
// Elements
const videoElement = document.getElementById("live-preview");
const canvas = document.getElementById("output-canvas");
const ctx = canvas.getContext("2d");
const videoSourceSelect = document.getElementById("video-source");
const videoStatus = document.getElementById("video-status");
const enableBgRemoval = document.getElementById("enable-bg-removal");
const showPreview = document.getElementById("show-preview");
const modelQuality = document.getElementById("model-quality");
const edgeSmoothness = document.getElementById("edge-smoothness");
const backgroundBlur = document.getElementById("background-blur");
const foregroundBrightness = document.getElementById("foreground-brightness");
const processingTimeDisplay = document.getElementById("processing-time");
const fpsDisplay = document.getElementById("fps");
const copyUrlButton = document.getElementById("copy-url");
const customImageInput = document.getElementById("custom-image-input");
const customVideoInput = document.getElementById("custom-video-input");
// Canvas setup
canvas.width = 1920;
canvas.height = 1080;
// Variables
let customImage = null;
let customVideo = null;
let lastFrameTime = performance.now();
let currentBackground = "transparent";
// Populate video sources
async function populateVideoSources() {
try {
const devices = await navigator.mediaDevices.enumerateDevices();
videoSourceSelect.innerHTML = '<option value="">Select a video source</option>';
devices
.filter((device) => device.kind === "videoinput")
.forEach((device) => {
const option = document.createElement("option");
option.value = device.deviceId;
option.text = device.label || `Camera ${videoSourceSelect.options.length}`;
videoSourceSelect.appendChild(option);
});
} catch (err) {
console.error("Lỗi khi liệt kê thiết bị video:", err);
videoStatus.textContent = "Không thể liệt kê thiết bị video.";
}
}
// Start video stream
async function startVideo(deviceId) {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { deviceId: deviceId ? { exact: deviceId } : undefined },
});
videoElement.srcObject = stream;
videoElement.play();
videoStatus.textContent = "";
processFrame();
} catch (err) {
console.error("Lỗi khi truy cập webcam:", err);
videoStatus.textContent = "Không thể truy cập webcam. Vui lòng kiểm tra quyền camera.";
}
}
// Simulated background removal (replace with real AI model in production)
function simulateBackgroundRemoval(imageData) {
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
// Simple green-screen-like removal (replace with AI model output)
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// Example: Remove pixels with high green value
if (g > 150 && r < 100 && b < 100) {
data[i + 3] = 0; // Set alpha to 0 (transparent)
}
}
return imageData;
}
// Process video frame
function processFrame() {
const startTime = performance.now();
// Draw video to canvas
ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
// Apply background removal if enabled
if (enableBgRemoval.checked) {
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
imageData = simulateBackgroundRemoval(imageData); // Replace with AI model
ctx.putImageData(imageData, 0, 0);
// Apply background
const tempCanvas = document.createElement("canvas");
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
const tempCtx = tempCanvas.getContext("2d");
// Draw background
if (currentBackground === "solid-black") {
tempCtx.fillStyle = "black";
tempCtx.fillRect(0, 0, canvas.width, canvas.height);
} else if (currentBackground === "solid-gray") {
tempCtx.fillStyle = "gray";
tempCtx.fillRect(0, 0, canvas.width, canvas.height);
} else if (currentBackground === "solid-green") {
tempCtx.fillStyle = "green";
tempCtx.fillRect(0, 0, canvas.width, canvas.height);
} else if (currentBackground === "custom-image" && customImage) {
tempCtx.drawImage(customImage, 0, 0, canvas.width, canvas.height);
} else if (currentBackground === "custom-video" && customVideo) {
tempCtx.drawImage(customVideo, 0, 0, canvas.width, canvas.height);
} else if (currentBackground === "blurred") {
tempCtx.filter = `blur(${backgroundBlur.value}px)`;
tempCtx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
}
// Draw foreground
tempCtx.globalCompositeOperation = "destination-over";
tempCtx.drawImage(canvas, 0, 0);
// Apply brightness
tempCtx.filter = `brightness(${foregroundBrightness.value})`;
tempCtx.drawImage(tempCanvas, 0, 0);
// Copy to main canvas
ctx.filter = `blur(${edgeSmoothness.value}px)`; // Edge smoothness
ctx.drawImage(tempCanvas, 0, 0);
}
// Update performance metrics
const endTime = performance.now();
const processingTime = endTime - startTime;
processingTimeDisplay.textContent = `${processingTime.toFixed(2)} ms`;
fpsDisplay.textContent = `${(1000 / processingTime).toFixed(2)}`;
lastFrameTime = endTime;
// Continue processing
requestAnimationFrame(processFrame);
}
// Event listeners
videoSourceSelect.addEventListener("change", () => {
startVideo(videoSourceSelect.value);
});
showPreview.addEventListener("change", () => {
videoElement.style.display = showPreview.checked ? "block" : "none";
});
document.querySelectorAll('input[name="background"]').forEach((input) => {
input.addEventListener("change", () => {
currentBackground = input.value;
});
});
customImageInput.addEventListener("change", (e) => {
const file = e.target.files[0];
if (file) {
customImage = new Image();
customImage.src = URL.createObjectURL(file);
currentBackground = "custom-image";
document.querySelector('input[value="custom-image"]').checked = true;
}
});
customVideoInput.addEventListener("change", (e) => {
const file = e.target.files[0];
if (file) {
customVideo = document.createElement("video");
customVideo.src = URL.createObjectURL(file);
customVideo.loop = true;
customVideo.play();
currentBackground = "custom-video";
document.querySelector('input[value="custom-video"]').checked = true;
}
});
copyUrlButton.addEventListener("click", () => {
const url = window.location.href;
navigator.clipboard.writeText(url).then(() => {
alert("Đã sao chép URL nguồn trình duyệt OBS!");
});
});
// Initialize
populateVideoSources();