Spaces:
Sleeping
Sleeping
File size: 4,007 Bytes
d16b52d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
<script lang="ts">
import 'rvfc-polyfill';
import { onDestroy, onMount } from 'svelte';
import {
mediaStreamStatus,
MediaStreamStatusEnum,
onFrameChangeStore,
mediaStream,
mediaDevices,
mediaStreamActions
} from '$lib/mediaStream';
import Button from './Button.svelte';
import MediaListSwitcher from './MediaListSwitcher.svelte';
export let width = 512;
export let height = 512;
const size = { width, height };
let videoEl: HTMLVideoElement;
let canvasEl: HTMLCanvasElement;
let ctx: CanvasRenderingContext2D;
let videoFrameCallbackId: number;
let isWebCamActive: boolean = false;
// adjust the throttle time to your needs
const THROTTLE = 1000 / 120;
let selectedDevice: string = '';
let videoIsReady = false;
onMount(() => {
ctx = canvasEl.getContext('2d') as CanvasRenderingContext2D;
canvasEl.width = size.width;
canvasEl.height = size.height;
});
$: {
console.log(selectedDevice);
}
onDestroy(() => {
if (videoFrameCallbackId) videoEl.cancelVideoFrameCallback(videoFrameCallbackId);
});
$: if (videoEl) {
videoEl.srcObject = $mediaStream;
}
let lastMillis = 0;
async function onFrameChange(now: DOMHighResTimeStamp, metadata: VideoFrameCallbackMetadata) {
if (now - lastMillis < THROTTLE) {
videoFrameCallbackId = videoEl.requestVideoFrameCallback(onFrameChange);
return;
}
const videoWidth = videoEl.videoWidth;
const videoHeight = videoEl.videoHeight;
let height0 = videoHeight;
let width0 = videoWidth;
let x0 = 0;
let y0 = 0;
if (videoWidth > videoHeight) {
width0 = videoHeight;
x0 = (videoWidth - videoHeight) / 2;
} else {
height0 = videoWidth;
y0 = (videoHeight - videoWidth) / 2;
}
ctx.drawImage(videoEl, x0, y0, width0, height0, 0, 0, size.width, size.height);
const blob = await new Promise<Blob>((resolve) => {
canvasEl.toBlob(
(blob) => {
resolve(blob as Blob);
},
'image/jpeg',
1
);
});
onFrameChangeStore.set({ blob });
videoFrameCallbackId = videoEl.requestVideoFrameCallback(onFrameChange);
}
$: if ($mediaStreamStatus == MediaStreamStatusEnum.CONNECTED && videoIsReady) {
videoFrameCallbackId = videoEl.requestVideoFrameCallback(onFrameChange);
}
$: isWebCamActive = $mediaStreamStatus === MediaStreamStatusEnum.CONNECTED;
async function startWebCam() {
await mediaStreamActions.enumerateDevices();
await mediaStreamActions.start();
}
function stopWebCam() {
mediaStreamActions.stop();
}
async function toggleWebCam() {
if (isWebCamActive) {
stopWebCam();
} else {
await startWebCam();
}
}
</script>
<div class="relative mx-auto max-w-lg overflow-hidden rounded-lg border border-slate-300">
<div class="relative z-10 aspect-square w-full object-cover">
{#if $mediaDevices.length > 0}
<div class="absolute bottom-0 right-0 z-10">
<MediaListSwitcher />
</div>
{/if}
<video
class="pointer-events-none aspect-square w-full object-cover"
bind:this={videoEl}
on:loadeddata={() => {
videoIsReady = true;
}}
playsinline
autoplay
muted
loop
></video>
<canvas bind:this={canvasEl} class="absolute left-0 top-0 aspect-square w-full object-cover"
></canvas>
</div>
<div class="absolute left-0 top-0 flex aspect-square w-full items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 448" class="w-40 p-5 opacity-20">
<path
fill="currentColor"
d="M224 256a128 128 0 1 0 0-256 128 128 0 1 0 0 256zm-45.7 48A178.3 178.3 0 0 0 0 482.3 29.7 29.7 0 0 0 29.7 512h388.6a29.7 29.7 0 0 0 29.7-29.7c0-98.5-79.8-178.3-178.3-178.3h-91.4z"
/>
</svg>
</div>
</div>
<Button on:click={toggleWebCam}>
{#if isWebCamActive}
<span>Stop WebCam</span>
{:else}
<span>Start WebCam</span>
{/if}
</Button>
|