Spaces:
Runtime error
Runtime error
File size: 3,315 Bytes
1123781 ff9325e 12ffaf3 ff9325e 3207814 3dd0aef ff9325e 3dd0aef 46bd9ac ff9325e 12ffaf3 ff9325e 46bd9ac 12ffaf3 3dd0aef 12ffaf3 46bd9ac 12ffaf3 3dd0aef ff9325e 3207814 ff9325e 12ffaf3 ff9325e 12ffaf3 46bd9ac 12ffaf3 1d3190d ff9325e 3207814 ff9325e 12ffaf3 ff9325e 12ffaf3 ff9325e 1123781 0e5136c d1f4c77 3dd0aef 12ffaf3 3dd0aef d1f4c77 3dd0aef d1f4c77 12ffaf3 d1f4c77 d6fedfa |
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 |
<script lang="ts">
import 'rvfc-polyfill';
import { onDestroy, onMount } from 'svelte';
import {
mediaStreamStatus,
MediaStreamStatusEnum,
onFrameChangeStore,
mediaStream,
mediaDevices
} from '$lib/mediaStream';
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;
// ajust the throttle time to your needs
const THROTTLE_TIME = 1000 / 15;
let selectedDevice: string = '';
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_TIME) {
videoFrameCallbackId = videoEl.requestVideoFrameCallback(onFrameChange);
return;
}
const videoWidth = videoEl.videoWidth;
const videoHeight = videoEl.videoHeight;
const blob = await grapCropBlobImg(
videoEl,
videoWidth / 2 - size.width / 2,
videoHeight / 2 - size.height / 2,
size.width,
size.height
);
onFrameChangeStore.set({ blob });
videoFrameCallbackId = videoEl.requestVideoFrameCallback(onFrameChange);
}
$: if ($mediaStreamStatus == MediaStreamStatusEnum.CONNECTED) {
videoFrameCallbackId = videoEl.requestVideoFrameCallback(onFrameChange);
}
async function grapCropBlobImg(
video: HTMLVideoElement,
x: number,
y: number,
width: number,
height: number
) {
const canvas = new OffscreenCanvas(width, height);
const ctx = canvas.getContext('2d') as OffscreenCanvasRenderingContext2D;
ctx.drawImage(video, x, y, width, height, 0, 0, width, height);
const blob = await canvas.convertToBlob({ type: 'image/jpeg', quality: 1 });
return blob;
}
</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}
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>
|