PyQt5:QMediaplayer,QVideowidget播放视频(3)

举报
何其不顾四月天 发表于 2020/12/28 23:37:01 2020/12/28
【摘要】 PyQt5:QMediaplayer,QVideowidget播放视频(3) 简介 在 PyQt5:QMediaplayer,QVideowidget播放视频(2)上一篇中完善了界面的布局,快进,慢进。在本篇更新中做了代码做了重构,架构的好坏就另说了,python 没有做过成熟的项目,一直自己写的玩。在本篇中主要更新了UI、播放列表、配置项、媒体文件管理、布局、子控...

PyQt5:QMediaplayer,QVideowidget播放视频(3)

简介

PyQt5:QMediaplayer,QVideowidget播放视频(2)上一篇中完善了界面的布局,快进,慢进。在本篇更新中做了代码做了重构,架构的好坏就另说了,python 没有做过成熟的项目,一直自己写的玩。在本篇中主要更新了UI播放列表配置项媒体文件管理布局子控件,还有快进、快退、音量等等一些基础功能。

代码结构

模块架构

文件结构

Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2020/9/21 20:52 __pycache__
-a---- 2020/5/18 22:28 761 audio.py
-a---- 2020/5/18 22:23 2008 audio.ui
-a---- 2020/9/22 22:13 379 config.json
-a---- 2020/5/6 23:31 2371 itemWidget.ui
-a---- 2020/9/22 22:15 7805 MediaPlayer.py
-a---- 2020/5/18 23:03 1776 MediaPlayer.pyproj
-a---- 2020/9/21 20:52 9788 MediaPlayer.ui
-a---- 2020/9/21 20:52 8664 ui.py
-a---- 2020/5/18 22:01 2281 ui_audio.py
-a---- 2020/5/14 21:10 5533 ui_url.py
-a---- 2020/5/18 23:03 991 urlWidget.py
-a---- 2020/5/14 21:10 7030 urlWidget.ui

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在上图中可以看到,主要分为三个模块,MediaPlayer、audio、urlWidget 三个模块。其中 MediaPlayer为主窗口,主体界面布局、逻辑功能、播放窗口、播放列表都在其中实现。audio模块主要负责音量条。urlWidget模块主要负责网络url弹窗输入。

源码介绍

Audio

在文件结构中可以看到,主要有三个文件。audio.ui,ui_audio.py,audio.py 分别是 UI设计文件,UIpy文件,code文件。

Audio.ui

UI设计文件:

在这里插入图片描述

Widget类型,布局全部用UI布局,不使用代码,原则是,尽量少用代码设置,方便后期修改维护。布局时,使用Frame嵌套,方便子控件修改。提高易用性,可读性。

Audio_ui.py

FileName = os.path.basename(sys.argv[0])
FilePath = sys.argv[0].replace(FileName,"")
UiName = FileName.replace(".py",".ui")
UiPath = FilePath +UiName
Ui_pyName = FilePath+"ui_audio.py"
FileFlag = os.path.isfile(Ui_pyName)

if FileFlag == 0:
	sys_cmd	 = os.popen("pyuic5"+" -o "+Ui_pyName+" "+UiPath)
	time.sleep(1)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

还是采用之前的方法,使用命令转换,在更新UI后,删除之前的 ui_xxx.py文件,下次会自动生成。记得将对应的audio.py 设置为启动文件。然后在切回去。

audio.py

from ui_audio import Ui_Audio
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

class audioWidget(QWidget):
	def __init__(self):
		super(audioWidget,self).__init__()
		global ui
		ui = Ui_Audio()
		ui.setupUi(self)
		self.audio = ui

	def getSlider(self):
		return self.audio.verticalSlider

	def getMuteBtn(self):
		return self.audio.pushButton

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

对外接口主要有两个 音量输出,静音输出。

urlWidget

与audio模块相同也是拥有三个对应文件. ui 和 ui.py 不做介绍

urlWidget.ui

urlWidget_ui.py

urlWidget.py

from ui_url import Ui_urlWidget
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

class urlWidget(QWidget):
	fileInfo_Signle = pyqtSignal(list)
	def __init__(self):
		super(urlWidget,self).__init__()
		global ui
		ui = Ui_urlWidget()
		ui.setupUi(self)
		self.url = ui
		ui.pushButton_2.clicked.connect(self.sltConfirm)

	def getFileInfo(self):
		return [self.url.lineEdit_url.text(),self.url.lineEdit.text()]

	def sltConfirm(self):
		self.fileInfo_Signle.emit([self.url.lineEdit_url.text(),self.url.lineEdit.text()])
		self.hide()

	def sltCancel(self):
		self.hide()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

其功能主要是添加网络媒体资源时,提供单独的窗口,有两个输入的LineEidt ,一个是 url 路径,一个 媒体资源名称。

提供了两种方式对外输出urlhe 媒体文件名称。调用接口与信号槽

	def getFileInfo(self):
		return [self.url.lineEdit_url.text(),self.url.lineEdit.text()]

  
 
  • 1
  • 2
	fileInfo_Signle = pyqtSignal(list)
	def sltConfirm(self):
		self.fileInfo_Signle.emit([self.url.lineEdit_url.text(),self.url.lineEdit.text()])
		self.hide()

  
 
  • 1
  • 2
  • 3
  • 4

MediaPlayer

该模块主窗口模块,主要负责逻辑部分即业务部分。还有一些 listwdiget,videowidget 主要功能实现,其实按照设计模式应该也做单独的 模块,主窗口负责调用。

下面介绍MediaPlayer

初始化

init

	def __init__(self):
		super(m_window,self).__init__()
		self.setupUi(self)
		self.videoframe = QVideoWidget(self) # videoWidget 初始化
		self.layout_videoframe.addWidget(self.videoframe) # 布局添加videoWidget
		self.player = QMediaPlayer(self) #播放器初始化 -- 只负责播放功能
		self.player.setVideoOutput(self.videoframe)  #设置播放窗体
		self.playListInit() #播放列表初始化
		self.connectBind() # 初始化槽函数绑定,适用于全局,以及全流程
		self.bindPlaylistAnddListWidget() # 绑定播放列表与ListWidget
		self.initAudioAndFile() #音频设置初始化
		self.fileBtnMenuInit() # 文件菜单初始化
		self.readConfig() #载入配置文件

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

音频设置初始化,文件添加初始化

	#音频设置初始化,文件添加初始化
	def initAudioAndFile(self):
		self.urlWidget = urlWidget()
		self.urlWidget.fileInfo_Signle.connect(self.sltUrlWidget)
		self.audio = audioWidget()
		self.audio.getSlider().valueChanged.connect(self.sltSetAudioValue)
		self.audio.getMuteBtn().clicked.connect(self.sltSetAudioMute)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

播放列表初始化

	#播放列表初始化 - 声明/定义/播放模式设置
	def playListInit(self):
		self.playList = QMediaPlaylist()
		self.player.setPlaylist(self.playList)
		self.playList.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
		self.player.positionChanged.connect(self.sltShowPlayTime)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

文件菜单初始化

	#文件按钮绑定菜单/本地文件/网络资源
	def fileBtnMenuInit(self):
		btnMenu=QMenu(self)
		btnMenu.addAction("本地文件")
		btnMenu.addAction("网络资源")
		self.pushButton_file.setMenu(btnMenu)
		btnMenu.triggered.connect(self.sltFile)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
全局信号槽
	#信号槽绑定函数 -- 主要功能按键 播放/上一个/下一个/音频/文件/设置
	def connectBind(self):
		self.pushButton_play.clicked.connect(self.sltPlayState)
		self.pushButton_befor.clicked.connect(self.sltPlayBefore)
		self.pushButton_next.clicked.connect(self.sltPlayNext)
		self.pushButton_audio.clicked.connect(self.sltAudio)
		self.pushButton_setup.clicked.connect(self.sltSetup) # 设置ListWidget 右键菜单模式
		self.listWidget_playlist.setContextMenuPolicy(Qt.CustomContextMenu)
		self.listWidget_playlist.customContextMenuRequested.connect(self.listWidgetRightMenu)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
文件添加

按钮初始化

	#文件按钮绑定菜单/本地文件/网络资源
	def fileBtnMenuInit(self):
		btnMenu=QMenu(self)
		btnMenu.addAction("本地文件")
		btnMenu.addAction("网络资源")
		self.pushButton_file.setMenu(btnMenu)
		btnMenu.triggered.connect(self.sltFile)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

本地资源添加

	#添加本地文件
	def addLoadFile(self):
		str = QFileDialog.getOpenFileName(self,"选择媒体文件","D:/","video files(*.avi *.mp4 *.wmv)")
		filePath = str[0]
		fileName = (filePath.split('/')[-1]).split('.')[0]
		return [filePath,fileName]

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

网络资源

	#添加网络文件
	def addNetFile(self):
		self.urlWidget.show()

	def sltUrlWidget(self,list):
		config['playlist'].append({'filepath':list[0],'filename':list[1]})
		self.addFile(list[0],list[1])

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

槽函数 -按钮添加文件

	#槽函数-添加文件
	def sltFile(self,action):
		if action.text() == "本地文件": fileInfo = self.addLoadFile() config['playlist'].append({'filepath':fileInfo[0],'filename':fileInfo[1]}) self.addFile(fileInfo[0],fileInfo[1])
		elif action.text() == "网络资源": self.addNetFile()

	def addFile(self,filePath,fileName):
		self.playList.addMedia(QMediaContent(QUrl.fromLocalFile(filePath)))
		self.createItem(fileName)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
音频设置
	#音频设置
	def sltAudio(self):
		pos = self.pushButton_audio.mapTo(self,QPoint(0,0)) #获取相对主窗口坐标 #计算 X ,Y
		x = pos.x() + self.pushButton_audio.width()/2 - self.audio.width() / 2
		y = pos.y() - self.audio.height() - 6
		self.audio.move(x,y)
		if self.audio.isHidden() == True: self.audio.show()
		else: self.audio.hide()

	def sltSetAudioValue(self,value): #设置音量值
		self.player.setVolume(value)

	def sltSetAudioMute(self): #设置静音
		self.player.setMuted(bool(1 - self.player.isMuted()))

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
播放列表

QMediaPlayList

	#播放列表初始化 - 声明/定义/播放模式设置
	def playListInit(self):
		self.playList = QMediaPlaylist()
		self.player.setPlaylist(self.playList) #播放器绑定播放列表
		self.playList.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) #设置播放模式
		self.player.positionChanged.connect(self.sltShowPlayTime) #显示播放位置即进度

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

添加列表文件

	#创建QListWidgetItem
	def createItem(self,str):
		self.item = QListWidgetItem(str)
		self.listWidget_playlist.addItem(self.item)

	#绑定QPlayList与QListWidget -- 利用playlist与widgetlist 的 index 索引 一一对应即实现绑定
	def bindPlaylistAnddListWidget(self):
		self.listWidget_playlist.itemDoubleClicked.connect(self.doublePressPlayMedia)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

ListWidget-双击播放

	def doublePressPlayMedia(self,item):
		self.player.stop()
		self.playList.setCurrentIndex(self.listWidget_playlist.row(item))
		self.player.play()
		self.pushButton_play.setText("暂停")

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

ListWidget-右键菜单

	def listWidgetRightMenu(self,point):
		self.menu = QMenu(self.listWidget_playlist)
		self.currentItem = self.listWidget_playlist.itemAt(point)
		play_action = QAction('播放')
		del_action = QAction('删除')
		self.menu.addAction(play_action)
		self.menu.addAction(del_action)
		play_action.triggered.connect(self.actionPlay)
		del_action.triggered.connect(self.actionDel)
		self.menu.exec(QCursor.pos())

	#右键播放槽函数
	def actionPlay(self):
		self.player.stop()
		self.playList.setCurrentIndex(self.listWidget_playlist.row(self.currentItem))
		self.player.play()
		self.pushButton_play.setText("暂停") #右键删除槽函数
	def actionDel(self):
		index = self.listWidget_playlist.row(self.currentItem)
		if index == self.playList.currentIndex(): self.player.stop()
		self.delCurrentIndex(index)

	def delCurrentIndex(self,index):
		current = self.playList.currentIndex()
		if current == index: self.playList.setCurrentIndex(0) self.player.stop()
		self.playList.removeMedia(index)
		self.listWidget_playlist.takeItem(index)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
播放设置

播放状态设置

	def sltPlayState(self):
		if self.player.state() == QMediaPlayer.StoppedState or self.player.state() == QMediaPlayer.PausedState: self.player.play() self.pushButton_play.setText("暂停")
		else: self.player.pause() self.pushButton_play.setText("播放")

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上一首、下一首

	def sltPlayBefore(self):
		self.player.stop()
		self.playList.setCurrentIndex((self.playList.currentIndex()-1 < 0) and 0 or self.playList.currentIndex()-1 )
		self.player.play()

	def sltPlayNext(self):
		self.player.stop()
		self.playList.setCurrentIndex((self.playList.currentIndex() + 1 == self.playList.mediaCount()) and 0 or (self.playList.currentIndex() + 1))
		self.player.play()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

播放进度

	#显示播放时长
	def sltShowPlayTime(self,postion):
		self.lcdNumber_progress.display(round(postion/1000))

  
 
  • 1
  • 2
  • 3
配置文件

配置文件格式

config = {'playlist':[],'playCurrent':{'index':0,'audio':30,'postion':0}}	

  
 
  • 1
{
	"playlist": [{
		"filepath": "D:/13-\u5c0f\u53ef\u7231/df839b27228fa56f81925bd3a619dc96.mp4",
		"filename": "df839b27228fa56f81925bd3a619dc96"
	}, {
		"filepath": "D:/13-\u5c0f\u53ef\u7231/1569254169777.mp4",
		"filename": "1569254169777"
	}, {
		"filepath": "D:/13-\u5c0f\u53ef\u7231/1569254169777.mp4",
		"filename": "1569254169777"
	}],
	"playCurrent": {
		"index": 0,
		"audio": 30,
		"postion": 2.035
	}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

读取配置文件

	#配置文件初始化
	def readConfig(self):
		file = open("./config.json","r+",encoding='UTF-8')
		json_str_str = json.load(file)
		for fileInfo in json_str_str['playlist']: self.addFile(fileInfo["filepath"],fileInfo["filename"]) config['playlist'].append({'filepath':fileInfo["filepath"],'filename':fileInfo["filename"]})
		self.playList.setCurrentIndex(json_str_str["playCurrent"]["index"])
		self.audio.getSlider().setValue(json_str_str["playCurrent"]["audio"])
		self.player.setVolume(json_str_str["playCurrent"]["audio"])
		self.player.setPosition(json_str_str["playCurrent"]["postion"] * 1000)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

写入配置文件

	#写入配置文件
	def writeConfig(self):
		print("Write ConfigFile!")
		for i in range(0,self.playList.mediaCount()): path = "" if self.playList.media(i).canonicalUrl().isLocalFile(): path = self.playList.media(i).canonicalUrl().toLocalFile() else: path = self.playList.media(i).canonicalUrl().toString() config['playlist'][i]["filepath"] = path config['playlist'][i]["filename"] = self.listWidget_playlist.item(i).text()
		config['playCurrent']['index'] = self.playList.currentIndex()
		config['playCurrent']['audio'] = self.player.volume()
		config['playCurrent']['postion'] = self.player.position() / 1000
		with open("./config.json",'w') as f: json.dump(config,f)

	#关闭事件,再退出前重写config配置文件
	def closeEvent(self,event):
		self.writeConfig()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

运行结果

UI布局

在这里插入图片描述

音频设置

在这里插入图片描述

本地文件导入

在这里插入图片描述

网络

在这里插入图片描述

下载

Git:https://github.com/WQuit/pyqt-qmediaplayer/tree/qmediaplayer-v0.1

CSDN:https://download.csdn.net/download/u011218356/12885123

后续

下期更新,不围着PyQt5 打转了,最近搭好了OpenCv 框架,将搭配OpenCv 进行 图像处理。

文章来源: blog.csdn.net,作者:何其不顾四月天,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/u011218356/article/details/108785986

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。