diff options
Diffstat (limited to 'js/pico-cam')
-rw-r--r-- | js/pico-cam/index.html | 5 | ||||
-rw-r--r-- | js/pico-cam/pico-cam.js | 79 | ||||
-rw-r--r-- | js/pico-cam/service-worker.js | 4 |
3 files changed, 84 insertions, 4 deletions
diff --git a/js/pico-cam/index.html b/js/pico-cam/index.html index 0948b04..05b8335 100644 --- a/js/pico-cam/index.html +++ b/js/pico-cam/index.html @@ -46,6 +46,10 @@ color: #FFFFFF; } + .capture-frame#captureVideo.active { + background-color: #FF0000; + } + .media-container { display: flex; justify-content: center; @@ -76,6 +80,7 @@ <div class="footer"> <button id="toggleCamera">Turn Camera On</button> <button id="captureFrame" class="capture-frame" disabled>Capture Frame</button> + <button id="captureVideo" class="capture-frame" disabled>Capture Video</button> </div> <div class="media-container"> <video id="webcam" autoplay playsinline style="display:none;"></video> diff --git a/js/pico-cam/pico-cam.js b/js/pico-cam/pico-cam.js index f51179e..3dc7646 100644 --- a/js/pico-cam/pico-cam.js +++ b/js/pico-cam/pico-cam.js @@ -1,5 +1,6 @@ const toggleCameraButton = document.getElementById('toggleCamera'); const captureFrameButton = document.getElementById('captureFrame'); +const captureVideoButton = document.getElementById('captureVideo'); const video = document.getElementById('webcam'); const canvas = document.getElementById('ditheredOutput'); const context = canvas.getContext('2d'); @@ -8,6 +9,7 @@ let stream = null; let isCameraOn = false; const lowResWidth = 160; // Gameboy camera resolution: 160×144 const lowResHeight = 144; +const videoLength = 3000; // 3 seconds video.style.width = lowResWidth + 'px'; video.style.height = lowResHeight + 'px'; @@ -24,7 +26,9 @@ toggleCameraButton.addEventListener('click', async () => { isCameraOn = true; toggleCameraButton.textContent = 'Turn Camera Off'; captureFrameButton.disabled = false; + captureVideoButton.disabled = false; captureFrameButton.classList.add('active'); + captureVideoButton.classList.add('active'); video.addEventListener('loadeddata', () => { canvas.width = lowResWidth; canvas.height = lowResHeight; @@ -39,19 +43,90 @@ toggleCameraButton.addEventListener('click', async () => { isCameraOn = false; toggleCameraButton.textContent = 'Turn Camera On'; captureFrameButton.disabled = true; + captureVideoButton.disabled = true; captureFrameButton.classList.remove('active'); + captureVideoButton.classList.remove('active'); } }); captureFrameButton.addEventListener('click', () => { const link = document.createElement('a'); link.href = canvas.toDataURL('image/png'); - link.download = 'frame.png'; + link.download = 'dithered-frame.png'; link.click(); }); +captureVideoButton.addEventListener('click', () => { + const startRecording = (canvas, duration) => { + return new Promise((resolve, reject) => { + const stream = canvas.captureStream(); + if (!stream) { + const errtxt = 'Stream capture from canvas failed.'; + console.error(errtxt); + return reject(errtxt); + } + + const mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm' }); + let chunks = []; + + mediaRecorder.ondataavailable = (event) => { + if (event.data.size > 0) { + chunks.push(event.data); + } + }; + + mediaRecorder.onstop = () => { + const blob = new Blob(chunks, { type: 'video/webm' }); + resolve(blob); + }; + + mediaRecorder.onerror = (event) => { + console.error('MediaRecorder error:', event.error); + reject(event.error); + }; + + // console.log('Starting recording...'); + mediaRecorder.start(); + setTimeout(() => { + // console.log('Stopping recording...'); + mediaRecorder.stop(); + }, duration); + }); + }; + + const handleCaptureVideo = async () => { + if (!isCameraOn) { + console.error('Camera is not active.'); + return; + } + + try { + captureVideoButton.disabled = true; + const videoBlob = await startRecording(ditheredOutput, videoLength); + const videoURL = URL.createObjectURL(videoBlob); + + const videoLink = document.createElement('a'); + videoLink.href = videoURL; + videoLink.download = 'dithered-video.webm'; + videoLink.click(); + + // Enable the button again after recording + captureVideoButton.disabled = false; + } catch (error) { + console.error('Error recording video:', error); + captureVideoButton.disabled = false; + } + }; + + handleCaptureVideo(); +}); + + function processFrame() { - if (!isCameraOn) return; + if (!isCameraOn) { + console.error('Camera is not active.'); + return; + } // Crop and draw the middle part of the video frame const videoAspect = video.videoWidth / video.videoHeight; diff --git a/js/pico-cam/service-worker.js b/js/pico-cam/service-worker.js index a64353c..ce5271b 100644 --- a/js/pico-cam/service-worker.js +++ b/js/pico-cam/service-worker.js @@ -1,4 +1,4 @@ -var CACHE_NAME = 'pico-cam-v1'; +var CACHE_NAME = 'pico-cam-v2'; var urlsToCache = [ './', './index.html', @@ -30,7 +30,7 @@ self.addEventListener('fetch', function(event) { }); self.addEventListener('activate', function(event) { - var cacheWhitelist = ['pico-cam-v1']; + var cacheWhitelist = ['pico-cam-v2']; event.waitUntil( caches.keys().then(function(cacheNames) { return Promise.all( |