Auto-size video widget to match video aspect ratio

Detects video dimensions from first frame via QVideoSink,
sets max height on the video widget to eliminate black bars.
Resets on each new video. Uses KeepAspectRatio mode.
This commit is contained in:
pax 2026-04-05 20:18:36 -05:00
parent 30de2fa6ed
commit 843d49e4a3

View File

@ -399,9 +399,9 @@ class VideoPlayer(QWidget):
layout.setContentsMargins(0, 0, 0, 0) layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0) layout.setSpacing(0)
# Video surface — inherit theme background instead of black # Video surface
self._video_widget = QVideoWidget() self._video_widget = QVideoWidget()
self._video_widget.setStyleSheet("background: transparent;") self._video_widget.setAspectRatioMode(Qt.AspectRatioMode.KeepAspectRatio)
layout.addWidget(self._video_widget, stretch=1) layout.addWidget(self._video_widget, stretch=1)
# Player # Player
@ -471,6 +471,11 @@ class VideoPlayer(QWidget):
self._player.playbackStateChanged.connect(self._on_state) self._player.playbackStateChanged.connect(self._on_state)
self._player.mediaStatusChanged.connect(self._on_media_status) self._player.mediaStatusChanged.connect(self._on_media_status)
self._player.errorOccurred.connect(self._on_error) self._player.errorOccurred.connect(self._on_error)
# Resize video widget to match video aspect ratio
self._video_sized = False
sink = self._player.videoSink()
if sink:
sink.videoFrameChanged.connect(self._on_video_size)
self._current_file: str | None = None self._current_file: str | None = None
self._error_fired = False self._error_fired = False
@ -478,6 +483,8 @@ class VideoPlayer(QWidget):
self._current_file = path self._current_file = path
self._error_fired = False self._error_fired = False
self._ended = False self._ended = False
self._video_sized = False
self._video_widget.setMaximumHeight(16777215) # reset max height
self._last_pos = 0 self._last_pos = 0
self._player.setLoops(QMediaPlayer.Loops.Infinite) self._player.setLoops(QMediaPlayer.Loops.Infinite)
self._player.setSource(QUrl.fromLocalFile(path)) self._player.setSource(QUrl.fromLocalFile(path))
@ -554,6 +561,18 @@ class VideoPlayer(QWidget):
else: else:
self._play_btn.setText("Play") self._play_btn.setText("Play")
def _on_video_size(self, frame) -> None:
"""Resize video widget to match video aspect ratio on first frame."""
if self._video_sized or not frame.isValid():
return
self._video_sized = True
vw = frame.size().width()
vh = frame.size().height()
if vw > 0 and vh > 0:
available_w = self._video_widget.width()
scaled_h = int(available_w * vh / vw)
self._video_widget.setMaximumHeight(scaled_h)
def _on_media_status(self, status) -> None: def _on_media_status(self, status) -> None:
pass pass