feat: restructure overlay and video widget integration for improved rendering
This commit is contained in:
@@ -6,7 +6,7 @@ import logging
|
||||
|
||||
from PySide6.QtCore import Qt, QTimer
|
||||
from PySide6.QtMultimediaWidgets import QVideoWidget
|
||||
from PySide6.QtWidgets import QLabel, QMainWindow, QSizePolicy, QStatusBar
|
||||
from PySide6.QtWidgets import QLabel, QMainWindow, QSizePolicy, QStatusBar, QVBoxLayout, QWidget
|
||||
|
||||
from app.camera.camera_enumerator import CameraEnumerator, CameraInfo
|
||||
from app.camera.camera_service import CameraService
|
||||
@@ -41,21 +41,34 @@ class MainWindow(QMainWindow):
|
||||
self._dispatcher = FrameDispatcher(self)
|
||||
self._telemetry = TelemetryCollector(parent=self)
|
||||
|
||||
# --- Video widget (central widget) ---
|
||||
self._video_widget = QVideoWidget(self)
|
||||
# --- Central container ---
|
||||
# We need an extra QWidget layer between QMainWindow and QVideoWidget so
|
||||
# that OverlayWidget can be a sibling of QVideoWidget (not its child).
|
||||
# QVideoWidget renders via a native D3D/GL surface that occludes any
|
||||
# QWidget children painted on top of it.
|
||||
self._container = QWidget(self)
|
||||
self._container.setStyleSheet("background: black;")
|
||||
container_layout = QVBoxLayout(self._container)
|
||||
container_layout.setContentsMargins(0, 0, 0, 0)
|
||||
container_layout.setSpacing(0)
|
||||
|
||||
# --- Video widget ---
|
||||
self._video_widget = QVideoWidget(self._container)
|
||||
self._video_widget.setSizePolicy(
|
||||
QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
|
||||
)
|
||||
self._video_widget.setAspectRatioMode(Qt.AspectRatioMode.KeepAspectRatio)
|
||||
self.setCentralWidget(self._video_widget)
|
||||
container_layout.addWidget(self._video_widget)
|
||||
self.setCentralWidget(self._container)
|
||||
|
||||
# Connect camera session to video widget — this is the zero-copy render path
|
||||
self._camera_service.capture_session().setVideoOutput(self._video_widget)
|
||||
|
||||
# --- Overlay ---
|
||||
self._overlay = OverlayWidget(parent=self._video_widget)
|
||||
# Sibling of QVideoWidget inside _container; positioned manually so it
|
||||
# floats above the video without being occluded by the native GL surface.
|
||||
self._overlay = OverlayWidget(parent=self._container)
|
||||
self._overlay.raise_()
|
||||
self._overlay.resize(self._video_widget.size())
|
||||
|
||||
# --- Menu bar ---
|
||||
self._menu = AppMenuBar(self)
|
||||
@@ -72,6 +85,8 @@ class MainWindow(QMainWindow):
|
||||
|
||||
# --- Enumerate cameras and start ---
|
||||
QTimer.singleShot(0, self._initialise_cameras)
|
||||
# Reposition overlay after the event loop starts (layout is finalised)
|
||||
QTimer.singleShot(0, self._reposition_overlay)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Initialisation
|
||||
@@ -161,9 +176,16 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def resizeEvent(self, event) -> None: # noqa: N802
|
||||
super().resizeEvent(event)
|
||||
# Keep overlay covering the video widget
|
||||
if hasattr(self, "_overlay") and hasattr(self, "_video_widget"):
|
||||
self._overlay.resize(self._video_widget.size())
|
||||
self._reposition_overlay()
|
||||
|
||||
def _reposition_overlay(self) -> None:
|
||||
"""Keep the overlay covering the video widget exactly."""
|
||||
if not (hasattr(self, "_overlay") and hasattr(self, "_video_widget")):
|
||||
return
|
||||
# _overlay and _video_widget share the same parent (_container),
|
||||
# so video_widget.geometry() is already in the right coordinate space.
|
||||
self._overlay.setGeometry(self._video_widget.geometry())
|
||||
self._overlay.raise_()
|
||||
|
||||
def closeEvent(self, event) -> None: # noqa: N802
|
||||
self._camera_service.stop()
|
||||
|
||||
Reference in New Issue
Block a user