Evocam Webcam Html - //top\\
For integrating an EvoCam webcam feed into an HTML page, you typically use a basic image tag combined with a meta refresh tag to keep the live feed updating. Standard HTML Implementation
To display a live image that refreshes automatically (e.g., every 60 seconds), use the following structure:
Powered by EvoCam
Use code with caution. Copied to clipboard Advanced Integration Options
Video Element: Modern setups may use a tag for smoother streaming if your EvoCam version supports a direct stream URL:
Use code with caution. Copied to clipboard
Java Applet: Older versions of EvoCam support a Java-based applet stream for real-time video without page refreshes.
Internal Web Server: To view video directly, ensure the EvoCam internal web server is active (commonly on port 8080). Key Troubleshooting Tips
File Path: Ensure the webcam.jpg image is in the same folder as your HTML file. If it's elsewhere, update the src attribute with the correct path. evocam webcam html
Google Dorking: For security research or locating open feeds, the common search string used is intitle:"EvoCam" inurl:"webcam.html".
Mastering the Evocam Webcam HTML Code: The Ultimate Guide to Live Streaming
Introduction
In the modern era of smart homes, remote monitoring, and DIY security, the ability to view a live webcam feed from anywhere in the world is no longer a luxury—it’s a necessity. If you own an Evocam setup (whether it’s a standard USB webcam, an IP camera, or even an iPhone/android acting as a camera), you hold a powerful tool for surveillance, wildlife observation, or keeping an eye on your pets.
However, the hardware is only half the battle. The real magic lies in Evocam Webcam HTML—the code that allows you to embed that live feed directly into a website. Whether you want a private dashboard or a public live stream, understanding how to generate and customize the HTML is crucial.
This 2,500+ word guide will walk you through everything: from setting up Evocam, generating the correct HTML embed code, customizing the player, troubleshooting common errors, and advanced optimization techniques.
Part 4: Advanced HTML Customizations for Evocam
To truly master Evocam webcam HTML, you need to go beyond basic embedding. Add controls, overlays, and responsive designs.
Part 10: Conclusion – The Power of Evocam Webcam HTML
Learning to generate and customize Evocam webcam HTML transforms a simple USB camera into a professional broadcasting tool. Whether you’re monitoring a construction site, streaming bird feeders on YouTube, or checking on elderly relatives, the HTML embed is your bridge between hardware and the world wide web.
Key Takeaways:
- Use MJPEG for simplicity or HLS for modern adaptive streaming.
- Always secure your feed with authentication and HTTPS.
- Customize the HTML with responsive layouts, toggles, and overlays.
- Troubleshoot systematically – check IP, port, and firewall first.
Now that you have the complete toolkit, open Evocam, copy your stream URL, and paste it into the HTML templates above. Your live camera feed is just five minutes away from being online.
Further Resources:
- Official Evocam User Manual (HTML streaming section)
- MDN Web Docs:
<video>and<img>tags - Let’s Encrypt for free SSL certificates
Last updated: October 2025 – Compatible with Evocam 4.5+ and all modern browsers.
This article is part of the "DIY Streaming" series. For questions or custom code snippets, leave a comment below.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>EvoCam Live · Webcam Studio</title>
<style>
*
box-sizing: border-box;
user-select: none; /* avoid accidental text selection on buttons */
body
background: linear-gradient(145deg, #0a0f1e 0%, #0c1222 100%);
font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
padding: 24px 16px;
/* main glassmorphic card */
.evo-container
max-width: 880px;
width: 100%;
background: rgba(18, 25, 45, 0.65);
backdrop-filter: blur(10px);
border-radius: 2.5rem;
padding: 1.5rem;
box-shadow: 0 25px 45px rgba(0, 0, 0, 0.4), inset 0 1px 1px rgba(255, 255, 255, 0.08);
border: 1px solid rgba(72, 187, 255, 0.2);
transition: all 0.2s ease;
h1
font-size: 1.85rem;
font-weight: 600;
letter-spacing: -0.3px;
margin: 0 0 0.25rem 0;
background: linear-gradient(135deg, #e0f0ff, #9acdff);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
display: inline-flex;
align-items: center;
gap: 10px;
.sub
color: #8a9bcd;
font-size: 0.85rem;
margin-bottom: 1.5rem;
border-left: 3px solid #3b82f6;
padding-left: 12px;
font-weight: 450;
/* webcam stage */
.cam-stage
background: #01040f;
border-radius: 1.8rem;
overflow: hidden;
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
margin-bottom: 1.8rem;
transition: all 0.2s;
video
width: 100%;
height: auto;
display: block;
transform: scaleX(1); /* natural mirror effect? we keep normal, but user expects realistic preview — no mirror by default */
background: #000;
object-fit: cover;
aspect-ratio: 16 / 9;
/* canvas snapshot (hidden) */
#snapshotCanvas
display: none;
/* button panel */
.button-panel
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 1rem;
margin-top: 0.5rem;
margin-bottom: 1.5rem;
.cam-btn
background: rgba(20, 30, 55, 0.8);
backdrop-filter: blur(4px);
border: 1px solid rgba(59, 130, 246, 0.5);
padding: 0.7rem 1.6rem;
border-radius: 3rem;
font-weight: 600;
font-size: 0.9rem;
font-family: inherit;
color: #eef5ff;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 10px;
transition: 0.2s;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
.cam-btn i
font-style: normal;
font-weight: 600;
font-size: 1.1rem;
.cam-btn:active
transform: scale(0.96);
.cam-btn.primary
background: #1e3a8a;
border-color: #3b82f6;
color: white;
text-shadow: 0 0 2px rgba(0,0,0,0.2);
.cam-btn.primary:hover
background: #2563eb;
box-shadow: 0 0 12px rgba(59,130,246,0.4);
.cam-btn.warning
background: #991b1b80;
border-color: #ef4444;
.cam-btn.warning:hover
background: #dc2626cc;
border-color: #ff7777;
.cam-btn:hover:not(:disabled)
background: #2d3a6e;
border-color: #60a5fa;
transform: translateY(-2px);
.cam-btn:disabled
opacity: 0.5;
cursor: not-allowed;
transform: none;
/* snapshot gallery area */
.snapshot-section
background: rgba(0, 0, 0, 0.35);
border-radius: 1.5rem;
padding: 1rem;
margin-top: 0.5rem;
.section-title
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 0.8rem;
flex-wrap: wrap;
gap: 8px;
.section-title h3
margin: 0;
font-weight: 500;
font-size: 1.1rem;
color: #b9d0ff;
letter-spacing: -0.2px;
.clear-btn
background: none;
border: none;
color: #f97316;
font-size: 0.75rem;
font-weight: 500;
cursor: pointer;
padding: 4px 12px;
border-radius: 30px;
transition: 0.2s;
background: rgba(249, 115, 22, 0.15);
.clear-btn:hover
background: rgba(249, 115, 22, 0.4);
color: #ffc296;
.snapshot-strip
display: flex;
flex-wrap: wrap;
gap: 14px;
justify-content: flex-start;
align-items: center;
max-height: 180px;
overflow-x: auto;
overflow-y: hidden;
padding-bottom: 8px;
padding-top: 4px;
.snap-card
background: #0f172ad9;
border-radius: 18px;
padding: 8px 8px 10px 8px;
backdrop-filter: blur(4px);
border: 1px solid #3b82f680;
transition: 0.1s;
flex-shrink: 0;
width: 130px;
text-align: center;
.snap-card img
width: 114px;
height: 80px;
object-fit: cover;
border-radius: 12px;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
display: block;
margin: 0 auto;
.snap-actions
display: flex;
justify-content: center;
gap: 12px;
margin-top: 8px;
.snap-actions button
background: none;
border: none;
font-size: 0.7rem;
font-weight: 600;
cursor: pointer;
background: #1f2a48;
padding: 4px 10px;
border-radius: 24px;
color: #cfdfff;
transition: 0.1s;
.snap-actions button:hover
background: #3b4a7a;
color: white;
.info-text
font-size: 0.75rem;
text-align: center;
margin-top: 16px;
color: #6e85b5;
.status-badge
display: inline-block;
background: #1e293bb3;
border-radius: 40px;
padding: 0.2rem 0.7rem;
font-size: 0.7rem;
font-weight: 500;
margin-left: 12px;
color: #b9d0ff;
footer
font-size: 0.7rem;
text-align: center;
color: #4a5b89;
margin-top: 1.2rem;
@media (max-width: 550px)
.evo-container
padding: 1rem;
.cam-btn
padding: 0.5rem 1.2rem;
font-size: 0.8rem;
.snap-card
width: 110px;
.snap-card img
width: 94px;
height: 66px;
</style>
</head>
<body>
<div class="evo-container">
<div style="display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap;">
<div>
<h1>📸 EvoCam Webcam <span class="status-badge" id="camStatusLabel">⚫ idle</span></h1>
<div class="sub">high‑fidelity preview · instant snapshots · download shots</div>
</div>
</div>
<!-- video preview area -->
<div class="cam-stage">
<video id="webcamVideo" autoplay playsinline muted></video>
</div>
<!-- hidden canvas for capture -->
<canvas id="snapshotCanvas" width="1280" height="720"></canvas>
<!-- control panel -->
<div class="button-panel">
<button class="cam-btn primary" id="startCamBtn">🎥 Start Webcam</button>
<button class="cam-btn" id="snapBtn" disabled>📸 Take Snapshot</button>
<button class="cam-btn warning" id="stopCamBtn" disabled>⏹️ Stop Camera</button>
</div>
<!-- snapshot gallery -->
<div class="snapshot-section">
<div class="section-title">
<h3>📷 captured moments <span style="font-size:0.7rem;" id="snapshotCount">(0)</span></h3>
<button class="clear-btn" id="clearAllSnapsBtn">🗑️ clear all</button>
</div>
<div id="snapshotStrip" class="snapshot-strip">
<!-- dynamic snapshot cards will appear here -->
<div style="color:#5e6f9e; width:100%; text-align:center; padding:12px;">✨ snapshots will appear here ✨</div>
</div>
<div class="info-text">
💡 Click snapshot to download single image · every capture saves as PNG
</div>
</div>
<footer>
EvoCam live • requires camera permission • works on modern browsers
</footer>
</div>
<script>
(function()
// DOM elements
const video = document.getElementById('webcamVideo');
const canvas = document.getElementById('snapshotCanvas');
const startBtn = document.getElementById('startCamBtn');
const snapBtn = document.getElementById('snapBtn');
const stopBtn = document.getElementById('stopCamBtn');
const camStatusSpan = document.getElementById('camStatusLabel');
const snapshotStrip = document.getElementById('snapshotStrip');
const snapshotCountSpan = document.getElementById('snapshotCount');
const clearAllBtn = document.getElementById('clearAllSnapsBtn');
// state
let mediaStream = null; // current camera stream
let isCameraActive = false;
let snapshotsArray = []; // store objects id, dataURL, timestamp
// Helper: update UI status text + button states
function updateUIForCameraState()
if (isCameraActive && mediaStream && mediaStream.active)
camStatusSpan.innerHTML = '🟢 LIVE';
camStatusSpan.style.color = '#9effb4';
startBtn.disabled = true;
snapBtn.disabled = false;
stopBtn.disabled = false;
else
camStatusSpan.innerHTML = '⚫ inactive';
camStatusSpan.style.color = '#b9d0ff';
startBtn.disabled = false;
snapBtn.disabled = true;
stopBtn.disabled = true;
// stop tracks and clean stream
async function stopCamera()
if (mediaStream)
mediaStream.getTracks().forEach(track =>
if (track.readyState === 'live')
track.stop();
);
mediaStream = null;
video.srcObject = null;
isCameraActive = false;
updateUIForCameraState();
// start camera with default device (user-facing / rear / any)
async function startCamera()
// if already active, do nothing but ensure preview is good
if (isCameraActive && mediaStream && mediaStream.active)
// already live, just update UI in case
updateUIForCameraState();
return;
// stop any previous dangling stream
if (mediaStream)
await stopCamera();
try
const constraints =
video:
width: ideal: 1280 ,
height: ideal: 720 ,
facingMode: "user" // user-facing camera (front on most devices)
,
audio: false
;
const stream = await navigator.mediaDevices.getUserMedia(constraints);
mediaStream = stream;
video.srcObject = stream;
// ensure video plays
await video.play();
isCameraActive = true;
updateUIForCameraState();
catch (err)
console.error('Camera error:', err);
let errorMsg = 'Unable to access webcam. ';
if (err.name === 'NotAllowedError') errorMsg += 'Permission denied.';
else if (err.name === 'NotFoundError') errorMsg += 'No camera found.';
else errorMsg += 'Check device & permissions.';
alert(`⚠️ EvoCam error: $errorMsg`);
isCameraActive = false;
updateUIForCameraState();
// reset stream variable
if (mediaStream)
mediaStream.getTracks().forEach(t => t.stop());
mediaStream = null;
video.srcObject = null;
// capture snapshot from current video frame
function captureSnapshot() !video.videoHeight)
alert('Camera is not ready. Please start the webcam and wait for preview.');
return;
// set canvas dimensions to match video actual display size (preserve ratio)
const vw = video.videoWidth;
const vh = video.videoHeight;
canvas.width = vw;
canvas.height = vh;
const ctx = canvas.getContext('2d');
// draw current video frame
ctx.drawImage(video, 0, 0, vw, vh);
// convert to PNG dataURL
const dataURL = canvas.toDataURL('image/png');
const timestamp = new Date();
const formattedTime = `$timestamp.getHours().toString().padStart(2,'0'):$timestamp.getMinutes().toString().padStart(2,'0'):$timestamp.getSeconds().toString().padStart(2,'0')`;
const snapshotObj =
id: Date.now() + Math.random().toString(36).substring(2, 6),
dataURL: dataURL,
timestamp: timestamp,
timeLabel: formattedTime
;
snapshotsArray.push(snapshotObj);
renderSnapshotGallery();
// download single snapshot by id or dataURL directly
function downloadSnapshotById(snapshotId)
const snap = snapshotsArray.find(s => s.id === snapshotId);
if (!snap) return;
const link = document.createElement('a');
const dateStr = new Date(snap.timestamp).toISOString().slice(0,19).replace(/:/g, '-');
link.download = `evocam_$dateStr.png`;
link.href = snap.dataURL;
link.click();
// delete snapshot from array and re-render
function deleteSnapshotById(snapshotId)
snapshotsArray = snapshotsArray.filter(s => s.id !== snapshotId);
renderSnapshotGallery();
// clear all snapshots
function clearAllSnapshots()
if (snapshotsArray.length > 0 && confirm('Remove all captured snapshots?'))
snapshotsArray = [];
renderSnapshotGallery();
else if (snapshotsArray.length === 0)
// optional silent nothing
// render snapshot strip
function renderSnapshotGallery()
// update counter
snapshotCountSpan.innerText = `($snapshotsArray.length)`;
if (snapshotsArray.length === 0)
snapshotStrip.innerHTML = `<div style="color:#5e6f9e; width:100%; text-align:center; padding:12px;">📭 no snapshots yet — press 📸 button</div>`;
return;
// build cards
let html = '';
for (let snap of snapshotsArray)
const timeStr = `$snap.timestamp.toLocaleTimeString([], hour:'2-digit', minute:'2-digit', second:'2-digit')`;
html += `
<div class="snap-card" data-id="$snap.id">
<img src="$snap.dataURL" alt="snapshot" loading="lazy">
<div style="font-size:0.65rem; margin-top: 6px; color:#adc6ff;">$timeStr</div>
<div class="snap-actions">
<button class="download-snap" data-id="$snap.id">⬇️ save</button>
<button class="delete-snap" data-id="$snap.id">🗑️</button>
</div>
</div>
`;
snapshotStrip.innerHTML = html;
// attach event listeners dynamically for each snapshot button
document.querySelectorAll('.download-snap').forEach(btn =>
btn.addEventListener('click', (e) =>
e.stopPropagation();
const id = Number(btn.getAttribute('data-id'));
downloadSnapshotById(id);
);
);
document.querySelectorAll('.delete-snap').forEach(btn =>
btn.addEventListener('click', (e) =>
e.stopPropagation();
const id = Number(btn.getAttribute('data-id'));
deleteSnapshotById(id);
);
);
// optional: if you click on image also download? we could add, but we keep dedicated buttons.
// Event listeners for main controls
startBtn.addEventListener('click', () =>
startCamera().catch(e =>
console.warn(e);
alert('Could not initialize camera. Check permissions.');
);
);
snapBtn.addEventListener('click', () =>
captureSnapshot();
);
stopBtn.addEventListener('click', () =>
stopCamera();
);
clearAllBtn.addEventListener('click', () =>
clearAllSnapshots();
);
// on page load: we do NOT auto-start camera to respect user privacy
// but we can show a friendly placeholder state.
// also, if the user already granted permissions previously, we don't start automatically (better UX)
// but we set status text
updateUIForCameraState();
// safety: if the video element loses track due to device change, we update state.
video.addEventListener('play', () =>
if (mediaStream && mediaStream.active)
isCameraActive = true;
updateUIForCameraState();
);
video.addEventListener('pause', () =>
// Only consider inactive if stream exists but not active OR paused externally
if (mediaStream && !mediaStream.active)
isCameraActive = false;
updateUIForCameraState();
);
// when track ends unexpectedly
if (navigator.mediaDevices)
// optional: listen for devicechange to re-evaluate? not needed
// Additional: if the page is closed or user leaves, we could stop tracks but it's fine
window.addEventListener('beforeunload', () =>
if (mediaStream)
mediaStream.getTracks().forEach(track =>
if (track.readyState === 'live') track.stop();
);
);
// Provide a small console hint
console.log('EvoCam Webcam Studio ready — click "Start Webcam" to begin');
)();
</script>
</body>
</html>
The phrase "intitle:EvoCam inurl:webcam.html" is a well-known Google Dork used to find live, public webcam feeds powered by the EvoCam software. What is EvoCam?
EvoCam was a popular webcam software for macOS (formerly Mac OS X) that allowed users to host live camera feeds on the web. While it was a legitimate tool for creating personal or professional webcasts, its default settings often created publicly accessible pages that could be indexed by search engines. Common HTML Implementation
Users typically integrated the feed into their websites using two methods:
Built-in Tags: Some versions allowed adding a tag to an HTML page, which the software would then populate with the stream.
Static Image Refresh: A common technique involved uploading a recurring image named webcam.jpg via FTP and using a standard HTML image tag:The page would then use a meta-refresh tag or JavaScript to update the image at specific intervals (e.g., every 60 seconds). Privacy and Security Note
Because these cameras were often left unsecured, they became a target for "cam-hunting." If you are looking for this code to host your own camera, ensure you use password protection or secure authentication to prevent unauthorized users from viewing your private feed. If you'd like, I can help you: Find modern alternatives to EvoCam for macOS or Windows.
Write a JavaScript snippet to create a self-refreshing image feed for a modern website. Understand the security risks of public-facing IoT devices. How would you like to proceed? EvoCam integrated into iWeb page...comments welcomed! For integrating an EvoCam webcam feed into an
To integrate an EvoCam feed into an HTML webpage, you typically use the software's built-in capability to generate a streaming link or a complete HTML5-ready file. EvoCam is a macOS-based application designed for high-quality video streaming and surveillance, often used by weather enthusiasts and for security. Methods for Embedding EvoCam into HTML
Depending on your technical comfort, you can use one of these three primary methods to get your camera live on a site: 1. The Direct HTML5 Video Tag
EvoCam 4 can automatically create the .m3u8 playlist and necessary .html files for HTTP Live Streaming (HLS). If you have a custom page, you can manually add the video feed using the standard HTML5 tag:
Use code with caution. 2. Using JavaScript for Native Browser Access
If you are using EvoCam as a local webcam source (USB) rather than a remote IP stream, you can use the MediaDevices API to pull the feed directly into your site. Step 1: Create an HTML video element with an id.
Step 2: Use the getUserMedia method in JavaScript to request camera permission and assign the stream to the video element's srcObject. 3. Remote IP Camera Embedding
If your EvoCam is configured as a network-accessible IP camera, you may need to use Port Forwarding on your router (typically port 80 or 554) to make the feed accessible from outside your local network. Once accessible, you can embed the feed using an or a direct URL provided by the EvoCam software. Optimization and Security intitle:"EvoCam" inurl:"webcam.html" - Exploit-DB
Integrating EvoCam Webcam Feeds into HTML: A Comprehensive Guide
For web developers and site owners, adding a live webcam feed can transform a static page into an interactive, real-time experience. EvoCam is a longstanding webcam software designed for Mac users that simplifies this process by providing built-in tools for video streaming and image capturing.
Whether you are looking to build a professional surveillance portal or a simple live-view page for a hobbyist site, here is how you can use EvoCam with HTML. What is EvoCam?
EvoCam is a versatile application for Mac OS X used for live streaming and security. Its key strengths for web integration include:
Built-in Web Server: It can host its own streaming pages, making it accessible via a browser without external hosting in some cases.
Action Triggers: Users can set "Actions" to perform tasks like publishing an image to a web server via FTP or creating timelapse movies.
Standards Support: The software supports industry-standard H.264 video and AAC audio.
HTML5 & HLS: It can automatically create the .m3u8 playlists and necessary HTML files required for HTTP Live Streaming (HLS), ensuring compatibility with modern browsers like Safari and mobile devices like iPhones. Embedding EvoCam Streams in HTML
Depending on your technical needs, there are three primary ways to integrate EvoCam feeds into your website. 1. Using EvoCam’s Automated HTML Export
The most straightforward method for most users is EvoCam's built-in Media Encoder. This tool can re-encode video and automatically generate the segmented media files and a pre-configured .html file. You can then copy these files directly to your web server for streaming over HTTP. 2. Manual HTML5 Implementation
If you want to customize the player or integrate the feed into an existing page, you can use the standard HTML5 tag.
Use code with caution.
To make this functional, you must link the video source to the live stream URL generated by EvoCam (often an RTSP or HLS link). For modern mobile support, the HLS (.m3u8) link is generally preferred. 3. JavaScript and MediaDevices API
For developers who want to capture a local webcam directly within the browser rather than a remote stream, the MediaDevices API is the standard approach. While EvoCam often acts as a source, you can access your computer’s webcam using the following JavaScript structure: javascript
const video = document.querySelector('#evocam-video'); // Request permission to access the webcam window.navigator.mediaDevices.getUserMedia( video: true ) .then(stream => // Assign the stream to your video element video.srcObject = stream; video.onloadedmetadata = () => video.play(); ; ) .catch(error => console.error("Camera access denied:", error); ); Use code with caution.
Source: Based on Live Stream your Webcam to HTML Page - DEV Community. Security and Privacy Considerations When embedding live feeds, privacy is paramount.
HTTPS Requirement: Modern browsers typically require your website to be hosted on an HTTPS connection for the camera or stream to work correctly.
Credential Exposure: Be careful when using direct URLs that include usernames and passwords (e.g., http://ip:port/stream?user=admin&pwd=password). These credentials can be visible to anyone who inspects your page's HTML code.
Authentication: For private feeds, consider using .htaccess password protection on the folder where your webcam.html is located to restrict access. Alternatives and Further Tools
If you find EvoCam lacks specific features, other popular options include: EvoCam for Mac Download
Useful tools and libraries
- hls.js (HLS playback in browsers)
- FFmpeg (transcode/transmux)
- Media servers: Janus, Ant Media, Kurento, Jitsi, mediasoup
- ONVIF libs (node-onvif, onvif npm, libonvif)
- VLC (testing RTSP/MJPEG)
Part 8: Going Live – Hosting Your Evocam Webcam HTML Page
You have the code; now you need a host.
Performance and scalability tips
- Avoid direct browser connections to many cameras from many clients; use a media server or CDN for HLS segments.
- For many simultaneous viewers, HLS via CDN scales best.
- Keep HLS segment length short (1–3s) for better perceived latency; tradeoff with overhead.
- Use hardware encoding (on the capture device) where possible to reduce CPU usage and improve quality.