基于pyqt5的QMediaPlayer实现视频播放器(拨动进度条,音量,更换播放模式,加入多个播放文件)

Posted m0_46913647

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于pyqt5的QMediaPlayer实现视频播放器(拨动进度条,音量,更换播放模式,加入多个播放文件)相关的知识,希望对你有一定的参考价值。

前言

最近在学习pytq5的QMediaPlayer模块,其实刚开始是学习的pyside6的,因为pyside6的官方文档相对较详细一些,pyqt5的官方文档大片的文档解释都是TODO,我不太明白这种句式,但是做到添加播放列表QMediaPlaylist的时候,pyside6无法识别这个模块,我很疑惑,查了才发现现在Qt6的QtMultimedia相对与Qt5有较大重写,现在还有很多模块没有补齐,Qt6改动。后面有稍稍改了一下代码,改用pyqt5.
我遇到的一些pyqt6变化

  1. pyside6需要额外setAudioOutput()给视频连接音频的,否者视频播放出来没有声音。
  2. pyside6的设置音量大小的范围是0-1,是float型,而pyqt5的音量的大小范围是0-100,是int型,
  3. pyside6对中文路径不是很支持,文件名是中文都播放不了,此外pyside6的转换.ui文件出来的.py文件,其中的中文也会被改成字母字符,但是你运行出来窗口还是显示中文,比如你在designer中设置button的名字为“确定”,转化的.py文件中会变成一串字母,但是窗口是正常显示,pyqt5不会出现这种情况,
  4. pyside6读取媒体文件是self.player.setSource(QUrl),而pyqt5读取媒体文件时self.player.setMedal(QMediaContent),pyqt5获取url好像中间转了一下,不知道是不是这个原因,我用pyside6打开播放文件很顺畅,而pyqt5刚打开屏幕会闪一下,建议如果要做桌面动态壁纸的可以用pyside6,动态壁纸闪一下真的很影响感觉。

准备工作

  1. 安装pyqt5库
  2. 安装解码器,LAV Filters

没有实现重要功能

  1. 不能全屏
  2. 不能删除播放列表的文件

界面文件

图里面的需要的功能都完成,打开文件分两种的一种是添加单个或者多个文件,另一个是添加文件夹下面的所有文件(不过还没加检索,如果含有其他.txt .py文件也会一股脑添加到播放列表),此外没给控件设置样式,所以有点粗犷简陋。

如果要自己通过designer设计,需要记得添加一个Qwidget控件提升为QVideoWidget。
提升的类叫QVideoWidget,头文件:PyQt5.QtMultimediaWidgets

# -*- coding: utf-8 -*-

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(623, 446)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setHorizontalSpacing(6)
        self.gridLayout.setObjectName("gridLayout")
        self.nowtime = QtWidgets.QLabel(self.centralwidget)
        self.nowtime.setText("")
        self.nowtime.setObjectName("nowtime")
        self.gridLayout.addWidget(self.nowtime, 2, 4, 1, 1)
        self.playlistBox = QtWidgets.QComboBox(self.centralwidget)
        self.playlistBox.setObjectName("playlistBox")
        self.playlistBox.addItem("")
        self.playlistBox.addItem("")
        self.playlistBox.addItem("")
        self.gridLayout.addWidget(self.playlistBox, 1, 4, 1, 1)
        self.play_button = QtWidgets.QPushButton(self.centralwidget)
        self.play_button.setObjectName("play_button")
        self.gridLayout.addWidget(self.play_button, 3, 0, 1, 1)
        self.videoout = QVideoWidget(self.centralwidget)
        self.videoout.setEnabled(True)
        self.videoout.setObjectName("videoout")
        self.gridLayout.addWidget(self.videoout, 0, 0, 2, 4)
        self.mid_button = QtWidgets.QPushButton(self.centralwidget)
        self.mid_button.setObjectName("mid_button")
        self.gridLayout.addWidget(self.mid_button, 3, 2, 1, 1)
        self.timeSlider = QtWidgets.QSlider(self.centralwidget)
        self.timeSlider.setEnabled(True)
        self.timeSlider.setMaximum(99)
        self.timeSlider.setOrientation(QtCore.Qt.Horizontal)
        self.timeSlider.setObjectName("timeSlider")
        self.gridLayout.addWidget(self.timeSlider, 2, 0, 1, 4)
        self.volumeSlider = QtWidgets.QSlider(self.centralwidget)
        self.volumeSlider.setEnabled(True)
        self.volumeSlider.setOrientation(QtCore.Qt.Vertical)
        self.volumeSlider.setObjectName("volumeSlider")
        self.gridLayout.addWidget(self.volumeSlider, 1, 5, 2, 2)
        self.volume = QtWidgets.QLabel(self.centralwidget)
        self.volume.setObjectName("volume")
        self.gridLayout.addWidget(self.volume, 3, 5, 1, 2)
        self.listvidename = QtWidgets.QListWidget(self.centralwidget)
        self.listvidename.setObjectName("listvidename")
        self.gridLayout.addWidget(self.listvidename, 0, 4, 1, 3)
        self.left_button = QtWidgets.QPushButton(self.centralwidget)
        self.left_button.setEnabled(True)
        self.left_button.setObjectName("left_button")
        self.gridLayout.addWidget(self.left_button, 3, 1, 1, 1)
        self.right_button = QtWidgets.QPushButton(self.centralwidget)
        self.right_button.setObjectName("right_button")
        self.gridLayout.addWidget(self.right_button, 3, 3, 1, 1)
        self.gridLayout.setColumnStretch(0, 5)
        self.gridLayout.setColumnStretch(1, 5)
        self.gridLayout.setColumnStretch(2, 5)
        self.gridLayout.setColumnStretch(3, 5)
        self.gridLayout.setColumnStretch(4, 1)
        self.gridLayout.setColumnStretch(5, 1)
        self.gridLayout.setRowStretch(0, 10)
        self.gridLayout.setRowStretch(1, 5)
        self.gridLayout.setRowStretch(2, 1)
        self.gridLayout.setRowStretch(3, 1)
        self.verticalLayout.addLayout(self.gridLayout)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 623, 22))
        self.menubar.setObjectName("menubar")
        self.menu = QtWidgets.QMenu(self.menubar)
        self.menu.setObjectName("menu")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.toolBar = QtWidgets.QToolBar(MainWindow)
        self.toolBar.setObjectName("toolBar")
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
        self.actionfiles = QtWidgets.QAction(MainWindow)
        self.actionfiles.setObjectName("actionfiles")
        self.actiondirs = QtWidgets.QAction(MainWindow)
        self.actiondirs.setObjectName("actiondirs")
        self.actionnext = QtWidgets.QAction(MainWindow)
        self.actionnext.setEnabled(True)
        self.actionnext.setObjectName("actionnext")
        self.actionprevious = QtWidgets.QAction(MainWindow)
        self.actionprevious.setObjectName("actionprevious")
        self.actionpause = QtWidgets.QAction(MainWindow)
        self.actionpause.setObjectName("actionpause")
        self.actionstop = QtWidgets.QAction(MainWindow)
        self.actionstop.setObjectName("actionstop")
        self.menu.addAction(self.actionfiles)
        self.menu.addAction(self.actiondirs)
        self.menubar.addAction(self.menu.menuAction())
        self.toolBar.addAction(self.actionprevious)
        self.toolBar.addAction(self.actionpause)
        self.toolBar.addAction(self.actionnext)
        self.toolBar.addAction(self.actionstop)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.playlistBox.setItemText(0, _translate("MainWindow", "顺序播放"))
        self.playlistBox.setItemText(1, _translate("MainWindow", "随机播放"))
        self.playlistBox.setItemText(2, _translate("MainWindow", "洗脑循环"))
        self.play_button.setText(_translate("MainWindow", "播放"))
        self.mid_button.setText(_translate("MainWindow", "暂停"))
        self.volume.setText(_translate("MainWindow", "音量"))
        self.left_button.setText(_translate("MainWindow", "快退"))
        self.right_button.setText(_translate("MainWindow", "快进"))
        self.menu.setTitle(_translate("MainWindow", "打开文件"))
        self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))
        self.actionfiles.setText(_translate("MainWindow", "文件"))
        self.actiondirs.setText(_translate("MainWindow", "文件夹"))
        self.actionnext.setText(_translate("MainWindow", "下一部"))
        self.actionnext.setToolTip(_translate("MainWindow", "下首歌"))
        self.actionprevious.setText(_translate("MainWindow", "上一部"))
        self.actionprevious.setToolTip(_translate("MainWindow", "上"))
        self.actionpause.setText(_translate("MainWindow", "暂停"))
        self.actionpause.setToolyiTip(_translate("MainWindow", "暂停"))
        self.actionstop.setText(_translate("MainWindow", "停止"))
from PyQt5.QtMultimediaWidgets import QVideoWidget

逻辑部分

我挑一些我做时候比较困难的,最后发完整代码

文件读取

  1. 打开文件
    选取文件这个方法目的保证选择多个文件添加后播放的是第一个文件,并且保证播放文件的名称在播放列表里面是高亮的,可以多次添加。
    把文件名添加到播放列表,这里把文件路径通过split切割了一下
  2. 打开文件夹
    这里需要把文件名和文件夹路径拼接起来传给QMediaContent
  3. 如果必要的话,添加格式检索,筛选.mp4 .avi格式,这里我没有筛选,视频格式太多了,有点麻烦。
        # 打开文件
        self.actionfiles.triggered.connect(self.open_file)
        # 打开文件夹
        self.actiondirs.triggered.connect(self.open_dir)
            # 选取文件
    def open_file(self):
        urls = QFileDialog.getOpenFileUrls()[0]
        for url in urls:
            yu = url.toString()
            drv, left = os.path.split(yu)
            self.listvidename.addItem(left)
            content = QMediaContent(url)
            self.playlist.addMedia(content)
        num = self.playlist.mediaCount() - len(urls)
        self.playlist.setCurrentIndex(num)
        self.listvidename.setCurrentRow(num)
        self.player.play()

    # 选取文件夹
    def open_dir(self):
        dir = QFileDialog.getExistingDirectory()
        files = os.listdir(dir)
        for file in files:
            self.listvidename.addItem(file)
            url = os.path.join(dir, file)
            Qurl = QUrl.fromLocalFile(url)
            content = QMediaContent(Qurl)
            self.playlist.addMedia(content)
        self.playlist.setCurrentIndex(0)
        self.listvidename.setCurrentRow(0)
        self.player.play()

音量修改

        # 当前播放音量
        self.volumeSlider.setValue(50) #默认音量是50
        self.volumeSlider.setTickInterval(10)
        self.volumeSlider.setTickPosition(QSlider.TicksBelow)  # 刻度位置
        self.volumeSlider.valueChanged.connect(self.change_volume)  # 修改音量
     # 调节音量
    def change_volume(self, num):
        self.volume.setText(str(num))
        self.player.setVolume(num)

显示进度条

这里需要注意一点,self.timeSlider的最大值放在槽函数里面,原因
这段代码只显示分和秒,不显示小时,all是总时间,单位是毫秒,换算成小时,分,秒即可,num是已经播放的时间,修改和前面一样

        # 当前播放的进度,显示调整视频进度条
        self.timeSlider.setValue(0)
        self.timeSlider.setMinimum(0)
        self.player.positionChanged.connect(self.get_time)
            # 获取获得进度条进度
    def get_time(self, num):
        self.timeSlider.setMaximum(self.player.duration())
        self.timeSlider.setValue(num)
        d = QDateTime.fromMSecsSinceEpoch(num).toString("mm:ss")
        all = self.player.duration()
        all_d = QDateTime.fromMSecsSinceEpoch(all).toString("mm:ss")
        self.nowtime.setText(d + '/ ' + all_d)

调整进度条改变视频进度

        self.timeSlider.sliderPressed.connect(self.player.pause)
        self.timeSlider.sliderMoved.connect(self.change_time)
        self.timeSlider.sliderReleased.connect(self.player.play)
    # 调节播放进度
    def change_time(self, num):
        self.player.setPosition(num)

切换播放模式

这里是结合combobox控件来选择模式,它列表元素的被选中后会反射index,根据box里面的每行对应的内容匹配对应模式

        # 默认设置顺序循环播放
        self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
        # 改变播放顺序
        self.playlistBox.activated.connect(self.change_PlayBackMode)
            # 切换播放模式
    def change_PlayBackMode(self, num):
        self.actionnext.setEnabled(True)
        if num == 0:
            self.playlist.setPlaybackMode(QMediaPlaylist.Loop)  # 顺序循环播放
        if num == 1:
            self.playlist.setPlaybackMode(QMediaPlaylist.Random)  # 随机播放
        if num == 2:
            self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)  # 当前视频循环播放
            self.actionnext.setDisabled(True)

全部逻辑部分代码

# 基于pyqt5
import os
import sys

from PyQt5.QtCore import QDateTime, QUrl
from PyQt5.QtMultimedia import QAudioOutput, QMediaPlayer, QMediaContent, QMediaPlaylist
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import QMainWindow, QFileDialog, QApplication, QSlider

from mediawin_qt5 import Ui_MainWindow


class Video_win(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(Video_win, self).__init__()
        self.setupUi(self)
        # self.audio = QAudioOutput()  #pyside6中要单独实例音频
        self.player = QMediaPlayer()
        # self.player.setAudioOutput(self.audio)  # 读取输出音频设备
        self.player.setVideoOutput(self.videoout)
        # 播放列表
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)
        # 当前播放的进度,显示调整视频进度条
        self.timeSlider.setValue(0)
        self.timeSlider.setMinimum(0)
        self.player.positionChanged.connect(self.get_time)
        self.timeSlider.sliderPressed.connect(self.player.pause)
        self.

PyQt5 - 在新窗口中打开 QMediaplayer 并播放视频

【中文标题】PyQt5 - 在新窗口中打开 QMediaplayer 并播放视频【英文标题】:PyQt5 - open QMediaplayer in new window and play video 【发布时间】:2018-11-15 14:27:18 【问题描述】:

这可能归结为对 python 的基本理解,但我正在努力使用 PyQt5 和 Python3 在新窗口中打开视频。

当我运行这段代码时:

from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import  QApplication
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
import sys

app = QApplication(sys.argv)
w = QVideoWidget()
w.resize(300, 300)
w.move(0, 0)
w.show()
player = QMediaPlayer()
player.setMedia(QMediaContent(QUrl.fromLocalFile(inputVideo)))
player.setVideoOutput(w)
player.play()
sys.exit(app.exec_())

窗口打开并播放视频文件。

我尝试将此代码添加到我的主程序中的一个类中,并尝试调用它,但总是失败。

我想要实现的是在主 GUI 中按下 QPushbutton 以打开一个新窗口并在该新窗口中播放视频。

正如我所说,这可能是基本的 python 编码,但我想我还没有。

非常感谢您的帮助!! 谢谢!

【问题讨论】:

【参考方案1】:

您必须构造一个QPushButtonconnectclicked 插槽来显示和播放您的视频。

(你必须先setVideoOutputsetMedia

from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication, QPushButton
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
import sys

class VideoPlayer:

    def __init__(self):
        self.video = QVideoWidget()
        self.video.resize(300, 300)
        self.video.move(0, 0)
        self.player = QMediaPlayer()
        self.player.setVideoOutput(self.video)
        self.player.setMedia(QMediaContent(QUrl.fromLocalFile("./some_video_file.avi")))

    def callback(self):
        self.player.setPosition(0) # to start at the beginning of the video every time
        self.video.show()
        self.player.play()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    v = VideoPlayer()
    b = QPushButton('start')
    b.clicked.connect(v.callback)
    b.show()
    sys.exit(app.exec_())

【讨论】:

乔纳斯,非常感谢您的回复。在调整您的示例以适合我的代码后,它可以工作了! 足以从网络链接self.player.setMedia(QMediaContent(QUrl("http://<url>:<port>/stream.mjpg"))) 流式传输视频只是为了完成答案:)

以上是关于基于pyqt5的QMediaPlayer实现视频播放器(拨动进度条,音量,更换播放模式,加入多个播放文件)的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5 QMediaPlayer播放不了视频

QMediaPlayer setPlaybackRate > 1 导致高音音频

PyQt5 QMediaplayer找不到服务错误

Qt系列文章之二十六(基于QMediaPlayer 在 QVideoWidget或QGraphicsVideoItem 组件上播放视频)

Qt系列文章之二十六(基于QMediaPlayer 在 QVideoWidget或QGraphicsVideoItem 组件上播放视频)

PyQt5:QMediaPlayer 无法从 QBuffer 重放音频