Spaces:
Build error
Build error
File size: 6,522 Bytes
6cbbb50 | 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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | import logging
import flet as ft
from js_execution import set_camera_frame_callback
from flet_extensions import eval_js
import asyncio
from typing import List, Dict
logger = logging.getLogger(__name__)
class Frame:
def __init__(self, data: str, timestamp: float):
self.data = data
self.timestamp = timestamp
class CameraImage(ft.Container):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.stream_active = False
self.video_image1 = ft.Image(
src="",
width=self.width,
height=self.height,
fit=ft.ImageFit.CONTAIN,
visible=False,
)
self.video_image2 = ft.Image(
src="",
width=self.width,
height=self.height,
fit=ft.ImageFit.CONTAIN,
visible=False,
)
self.current_video_image = self.video_image1
self.video_stack = ft.Stack([self.video_image1, self.video_image2])
self.content = self.video_stack
set_camera_frame_callback(self.handle_camera_frame)
self.captured_frames: Dict[int, Frame] = {}
self.stream_start_time = None
async def start_camera_stream_async(self) -> str:
try:
result = await eval_js(self.page, """
window.cameraStreamActive = false;
window.cameraWebSocket = null;
async function setupCameraStream() {
console.log("setupCameraStream called");
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
console.log("Camera access granted");
const video = document.createElement('video');
video.srcObject = stream;
await video.play();
const canvas = document.createElement('canvas');
canvas.width = video.videoWidth / 2;
canvas.height = video.videoHeight / 2;
const ctx = canvas.getContext('2d');
window.cameraWebSocket = new WebSocket(`ws://${window.location.host}/ws/camera`);
function sendFrame() {
if (window.cameraWebSocket && window.cameraWebSocket.readyState === WebSocket.OPEN) {
ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, canvas.width, canvas.height);
window.cameraWebSocket.send(canvas.toDataURL('image/jpeg', 0.2)); // Added quality parameter
window.cameraStreamActive && setTimeout(sendFrame, 1000 / 60);
}
}
window.cameraWebSocket.onopen = () => {
console.log("WebSocket connection opened");
window.cameraStreamActive = true;
sendFrame();
};
window.cameraWebSocket.onclose = () => {
console.log("WebSocket connection closed");
window.cameraStreamActive = false;
stream.getTracks().forEach(track => track.stop());
};
return "Camera stream setup complete";
} catch (error) {
console.error("Error accessing camera:", error);
throw error;
}
}
return await setupCameraStream();
""")
logger.info(f"start_camera_stream_async result: {result}")
self.stream_active = True
self.stream_start_time = asyncio.get_event_loop().time()
self.captured_frames.clear()
return result
except Exception as e:
logger.error(f"Error in start_camera_stream_async: {str(e)}")
return f"Error: {str(e)}"
async def stop_camera_stream_async(self) -> str:
try:
result = await eval_js(self.page, """
if (window.cameraWebSocket) {
window.cameraStreamActive = false;
window.cameraWebSocket.close();
window.cameraWebSocket = null;
}
return 'Camera stream stopped';
""")
logger.info(f"stop_camera_stream_async result: {result}")
self.stream_active = False
self.stream_start_time = None
return result
except Exception as e:
logger.error(f"Error in stop_camera_stream_async: {str(e)}")
return f"Error: {str(e)}"
async def handle_camera_frame(self, frame_data: str):
if self.stream_active:
await self.update_webcam_image(frame_data)
self.capture_timed_frames(frame_data)
def capture_timed_frames(self, frame_data: str):
current_time = asyncio.get_event_loop().time()
if self.stream_start_time is None:
self.stream_start_time = current_time
elapsed_time = current_time - self.stream_start_time
for seconds in [1, 2, 3]:
if elapsed_time >= seconds and seconds not in self.captured_frames:
self.captured_frames[seconds] = Frame(frame_data, current_time)
def get_captured_frames(self) -> List[Frame]:
return list(self.captured_frames.values())
async def update_webcam_image(self, frame_data: str) -> None:
if not frame_data:
print("Empty data!")
return
# Frame data is already in Data URI format
new_src = frame_data
self.video_image1.visible = True
self.video_image2.visible = True
# Determine which image to update
if self.current_video_image == self.video_image1:
image_to_update = self.video_image2
image_to_hide = self.video_image1
else:
image_to_update = self.video_image1
image_to_hide = self.video_image2
# Update the hidden image
image_to_update.src = new_src
image_to_update.update()
# Wait for the browser to load the new image
await asyncio.sleep(0.02) # Adjust this delay if needed
# Update opacity
image_to_update.opacity = 1
image_to_hide.opacity = 0
self.current_video_image = image_to_update
# Final update to apply opacity changes
self.video_stack.update()
|