基于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.timeSlider.sliderMoved.connect(self.change_time)
        self.timeSlider.sliderReleased.connect(self.player.play)
        # 当前播放音量
        self.volumeSlider.setValue(50)
        self.volumeSlider.setTickInterval(10)
        self.volumeSlider.setTickPosition(QSlider.TicksBelow)  # 刻度位置
        self.volumeSlider.valueChanged.connect(self.change_volume)  # 修改音量
        # 打开文件
        self.actionfiles.triggered.connect(self.open_file)
        # 打开文件夹
        self.actiondirs.triggered.connect(self.open_dir)
        # 通过列表切换视频
        self.listvidename.itemClicked.connect(self.change_by_list)
        # 快进
        self.right_button.clicked.connect(self.up_time)
        # play
        self.play_button.clicked.connect(self.player.play)
        # pause
        self.mid_button.clicked.connect(self.player.pause)
        # 快退
        self.left_button.clicked.connect(self.down_time)
        # 下一部
        self.actionnext.triggered.connect(self.next_video)
        # 上一部
        self.actionprevious.triggered.connect(self.previous_video)
        # 默认设置顺序循环播放
        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)

    # 下一部
    def next_video(self):
        self.playlist.next()
        num = self.playlist.currentIndex()
        self.listvidename.setCurrentRow(num)
        # self.player.play()

    # 上一部
    def previous_video(self):
        self.playlist.previous()
        num = self.playlist.currentIndex()
        self.listvidename.setCurrentRow(num)
        self.player.play()

    # 选取文件
    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()

    # 调节音量
    def change_volume(self, num):
        self.volume.setText(str(num))
        self.player.setVolume(num)

    # 调节播放进度
    def change_time(self, num):
        self.player.setPosition(num)

    # 快进
    def up_time(self):
        num = self.player.position() + int(self.player.duration() / 20)
        self.player.setPosition(num)

    def down_time(self):
        num = self.player.position() - int(self.player.duration() / 20)
        self.player.setPosition(num)

    # 获取获得进度条进度
    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)

    # 通过点击播放列表切换视频
    def change_by_list(self, current):
        index = self.listvidename.currentRow()
        self.playlist.setCurrentIndex(index)
        self.player.play()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Video_win()
    win.show()
    sys.exit(app.exec())

总结

学习这个QMediaPlayer模块的过程中走了好多弯路,网上关于Qt的资料倒是挺多,但写的很详细的大部分都是C++,我本身C++可能入门都谈不上,看官方文档也很吃力,遇到问题一般都是结合这两者,虽然磕磕盼盼,到最后勉强还是能解决问题。当然这个模块还有很多地方没用到,也不够熟练。
最后,这篇代码写得不够精细,存在错误的地方请指点一下,谢谢

猜你喜欢

转载自blog.csdn.net/m0_46913647/article/details/122078826