import logging from PIL import Image import io logger = logging.getLogger(__name__) class CaptureEngine: def __init__(self): self.camera = None self.running = False self.running = False def start(self): if self.running: return self.running = True # Init dxcam try: import dxcam self.camera = dxcam.create(output_color="RGB") self.camera.start(target_fps=5) # 5 FPS is optimal for AI coaching to save processing logger.info("JARVIS 10X: DXCAM Desktop Duplication Started") except Exception as e: logger.error(f"Failed to start DXCAM: {e}") def stop(self): self.running = False if self.camera: self.camera.stop() # explicit release to prevent GPU memory leak across long sessions del self.camera self.camera = None def get_latest_frame_bytes(self): if not self.camera: return None frame = self.camera.get_latest_frame() if frame is None: return None try: img = Image.fromarray(frame) buf = io.BytesIO() # Compress significantly to save tokens for Gemini img.thumbnail((1280, 720)) img.save(buf, format="JPEG", quality=60) return buf.getvalue() except Exception as e: logger.error(f"Error processing frame: {e}") return None def is_exclusive_fullscreen(self): """ Fullscreen detection & Failsafe: Checks if the foreground window is likely an exclusive fullscreen DX12/Vulkan game. """ try: import win32gui, win32api, win32con hwnd = win32gui.GetForegroundWindow() if not hwnd: return False rect = win32gui.GetWindowRect(hwnd) w = rect[2] - rect[0] h = rect[3] - rect[1] screen_w = win32api.GetSystemMetrics(win32con.SM_CXSCREEN) screen_h = win32api.GetSystemMetrics(win32con.SM_CYSCREEN) style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE) # If it takes up the whole screen and has no caption (borderless or exclusive) if w == screen_w and h == screen_h and not (style & win32con.WS_CAPTION): return True return False except Exception: return False capture_engine = CaptureEngine()