You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5 QMediaPlayer旋转视频缩放填充窗口实现方法

问题根因

fitInView() 调用后未生效是三个问题叠加导致的:

  • 初始化执行fitInView()时视频尚未加载完成,QGraphicsVideoItem还未获取到视频的实际分辨率,没有正确的尺寸基准做缩放计算
  • 窗口尺寸拖动变化时,没有重新触发适配逻辑,视频尺寸不会随窗口自动调整
  • QGraphicsView默认会显示滚动条,滚动条会占用视图的可用渲染空间,导致适配尺寸计算偏差
修复步骤
  • 第一步:隐藏QGraphicsView的水平、垂直滚动条,避免额外空间占用
  • 第二步:新增独立的视图适配方法,统一处理视频缩放逻辑
  • 第三步:监听QMediaPlayer的媒体状态变化信号,当视频元数据加载完成、拿到实际分辨率后,触发第一次适配
  • 第四步:重写组件的resizeEvent事件,每次窗口大小变化时重新执行适配,保证视频始终填充可用窗口空间
  • 额外说明:180度旋转不会改变视频的宽高占比,适配时可根据需求选择缩放模式:Qt.KeepAspectRatio为保持原比例留黑边,Qt.IgnoreAspectRatio为拉伸铺满整个窗口,和普通无旋转播放器的行为对齐即可
修改后完整代码
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView
from PyQt5.QtGui import QPalette
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QGraphicsVideoItem, QVideoWidget
import sys

class Player(QWidget):
    def __init__(self):
        super().__init__()
        
        self.setGeometry(350, 100, 700, 500)
        self.setWindowTitle('Non-Rotated Player')
 
        p = self.palette()
        p.setColor(QPalette.Window, Qt.black)
        self.setPalette(p)

        # 创建媒体播放器对象
        self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.player.setNotifyInterval(17)

        # 创建视频显示组件
        self.videowidget = QVideoWidget()

        # 创建垂直布局
        vboxLayout = QVBoxLayout()
        vboxLayout.addWidget(self.videowidget)
 
        self.setLayout(vboxLayout)
 
        self.player.setVideoOutput(self.videowidget)
        
        self.filename = 'my_video.MP4'
        self.player.setMedia(QMediaContent(QUrl.fromLocalFile(self.filename)))
        self.player.setMuted(True)
        self.player.play()

class RotatedPlayer(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('Rotated Player')
        self.setGeometry(350, 100, 700, 500)
 
        p = self.palette()
        p.setColor(QPalette.Window, Qt.black)
        self.setPalette(p)

        # 创建媒体播放器对象
        self.player = QMediaPlayer(self, QMediaPlayer.VideoSurface)
        
        # 创建场景和视图
        self.scene = QGraphicsScene(self)
        self.gv = QGraphicsView(self.scene)
        self.gv.setStyleSheet('background-color: black;')
        # 隐藏滚动条避免占用空间
        self.gv.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.gv.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        
        # 创建视频渲染项
        self.videoitem = QGraphicsVideoItem()
        self.scene.addItem(self.videoitem)
        self.videoitem.setRotation(180)
        
        self.player.setVideoOutput(self.videoitem)

        vboxLayout = QVBoxLayout()
        vboxLayout.addWidget(self.gv)
        # 去掉布局边距避免黑边
        vboxLayout.setContentsMargins(0,0,0,0)
 
        self.setLayout(vboxLayout)
        
        self.filename = 'my_video.MP4'
        self.player.setMedia(QMediaContent(QUrl.fromLocalFile(self.filename)))
        self.player.setMuted(True)
        # 媒体加载完成后触发首次适配
        self.player.mediaStatusChanged.connect(self._on_media_status_changed)
        self.player.play()

    def _fit_video_to_view(self):
        # 视频适配到视图大小,可按需替换为Qt.KeepAspectRatio保持比例
        self.gv.fitInView(self.videoitem, Qt.IgnoreAspectRatio)

    def _on_media_status_changed(self, status):
        # 媒体加载完成、拿到视频尺寸后做第一次适配
        if status == QMediaPlayer.LoadedMedia:
            self._fit_video_to_view()

    def resizeEvent(self, event):
        # 窗口大小变化时重新适配
        super().resizeEvent(event)
        self._fit_video_to_view()
                
if __name__ == '__main__':
    
    app = QApplication(sys.argv)
    p = Player() 
    p.show()
    r = RotatedPlayer()
    r.show()
    app.exec_()

上述代码额外去掉了布局的默认边距,避免窗口边缘出现不必要的黑边,和普通无旋转播放器的显示效果完全一致。

内容的提问来源于stack exchange,提问作者slalomchip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 20:21:19