Pyqt 音视频播放器

时间:2022-02-08 05:29:20

在寻找如何使用Pyqt做一个播放器时首先找到的是openCV2

openCV2 貌似太强大了,各种关于图像处理的事情它都能完成,如 读取摄像头、图像识别、人脸识别、  图像灰度处理 、 播放视频等,强大的让你想不到!

openCV2 播放视频也很简单:

 #coding=utf-8

 import cv2.cv as cv
filename = "cn.avi"
win_name = "video player"
capture = cv.CaptureFromFile(filename)
cv.NamedWindow(win_name, cv.CV_WINDOW_AUTOSIZE) # 定义一个无限循环
while 1: # 每次从视频数据流框架中抓取一帧图片
image = cv.QueryFrame(capture) # 将图片显示在特定窗口上
cv.ShowImage(win_name, image) # 当安县Esc键时退出循环
c = cv.WaitKey(33)
if c == 27:
break # 退出循环后销毁显示窗口
cv.DestroyWindow(win_name)

效果:

Pyqt 音视频播放器

在这里也提供以些openCV的信息

下载地址:http://opencv.org/downloads.html      我使用的版本(V2.4.10) time:2015-02-10

下载完成后解压文件,找到opencv目录下的build-->python->cv2.pyd, 复制cv2.pyd到python的安装目录,此时运行脚本会报错,因为还要安装numpy,下载地址:https://pypi.python.org/pypi/numpy/1.9.1

再次运行不报错了但播放不了视频文件,为什么呢? 因为缺少解码器下载video codec解码器,http://www.xvidmovies.com/codec/

现在运行就OK了!

关于更多的openCV信息参考:

http://docs.opencv.org/trunk/doc/py_tutorials/py_gui/py_video_display/py_video_display.html#display-video

http://blog.sina.com.cn/s/blog_5562b0440102uw7g.html

-------------------------------------------------------------------------------

言归正传, 我们这里要讲的是如何用Pyqt 做一个音视频播放器。

使用openCV2播放视频,但openCV2只提供图像处理,没有音频处理,所以即使Pyqt集成openCV2也只能播放视频而没有声音。

现在我们使用Phonon 来完成这个功能。 话说 Phonon不属于QT, 是QT集成了Phonon

下面我们来讲讲用Phonon实现的过程。

在上一篇我转载过一篇关于Phonon的文章http://www.cnblogs.com/dcb3688/p/4283222.html

里面介绍了Phonon的结构、安装  、使用以及详细的例子,今天我们就在做一个例子

第一步:创建UI

老方法,先创建UI文件

video.ui  XML代码:

 <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>videofrom</class>
<widget class="QWidget" name="videofrom">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>880</width>
<height>572</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget_2">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>861</width>
<height>551</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_main" stretch="2">
<item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="8,1,1">
<item>
<layout class="QVBoxLayout" name="verticalLayout_player" stretch="">
<property name="spacing">
<number>6</number>
</property>
</layout>
</item>
<item>
<widget class="Phonon::SeekSlider" name="seekSlider"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,2,0,5,0,2">
<item>
<widget class="QPushButton" name="BtnOpen">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;选择文件,右键选择音频or 视频&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>选择文件</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_btn"/>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="Phonon::VolumeSlider" name="volumeSlider"/>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLCDNumber" name="lcdNumber"/>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>Phonon::SeekSlider</class>
<extends>QWidget</extends>
<header location="global">phonon/seekslider.h</header>
</customwidget>
<customwidget>
<class>Phonon::VolumeSlider</class>
<extends>QWidget</extends>
<header location="global">phonon/volumeslider.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

转换为py文件

video.py :

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

 # Form implementation generated from reading ui file 'video.ui'
#
# Created: Thu Feb 12 17:25:10 2015
# by: PyQt4 UI code generator 4.10.3
#
# WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig) class Ui_videofrom(object):
def setupUi(self, videofrom):
videofrom.setObjectName(_fromUtf8("videofrom"))
videofrom.resize(880, 572)
self.verticalLayoutWidget_2 = QtGui.QWidget(videofrom)
self.verticalLayoutWidget_2.setGeometry(QtCore.QRect(10, 10, 861, 551))
self.verticalLayoutWidget_2.setObjectName(_fromUtf8("verticalLayoutWidget_2"))
self.verticalLayout_main = QtGui.QVBoxLayout(self.verticalLayoutWidget_2)
self.verticalLayout_main.setMargin(0)
self.verticalLayout_main.setObjectName(_fromUtf8("verticalLayout_main"))
self.verticalLayout = QtGui.QVBoxLayout()
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.verticalLayout_player = QtGui.QVBoxLayout()
self.verticalLayout_player.setObjectName(_fromUtf8("verticalLayout_player"))
self.verticalLayout.addLayout(self.verticalLayout_player)
self.seekSlider = phonon.Phonon.SeekSlider(self.verticalLayoutWidget_2)
self.seekSlider.setObjectName(_fromUtf8("seekSlider"))
self.verticalLayout.addWidget(self.seekSlider)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.BtnOpen = QtGui.QPushButton(self.verticalLayoutWidget_2)
self.BtnOpen.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.BtnOpen.setObjectName(_fromUtf8("BtnOpen"))
self.horizontalLayout.addWidget(self.BtnOpen)
self.line = QtGui.QFrame(self.verticalLayoutWidget_2)
self.line.setFrameShape(QtGui.QFrame.VLine)
self.line.setFrameShadow(QtGui.QFrame.Sunken)
self.line.setObjectName(_fromUtf8("line"))
self.horizontalLayout.addWidget(self.line)
self.horizontalLayout_btn = QtGui.QHBoxLayout()
self.horizontalLayout_btn.setObjectName(_fromUtf8("horizontalLayout_btn"))
self.horizontalLayout.addLayout(self.horizontalLayout_btn)
self.line_2 = QtGui.QFrame(self.verticalLayoutWidget_2)
self.line_2.setFrameShape(QtGui.QFrame.VLine)
self.line_2.setFrameShadow(QtGui.QFrame.Sunken)
self.line_2.setObjectName(_fromUtf8("line_2"))
self.horizontalLayout.addWidget(self.line_2)
self.volumeSlider = phonon.Phonon.VolumeSlider(self.verticalLayoutWidget_2)
self.volumeSlider.setObjectName(_fromUtf8("volumeSlider"))
self.horizontalLayout.addWidget(self.volumeSlider)
self.line_3 = QtGui.QFrame(self.verticalLayoutWidget_2)
self.line_3.setFrameShape(QtGui.QFrame.VLine)
self.line_3.setFrameShadow(QtGui.QFrame.Sunken)
self.line_3.setObjectName(_fromUtf8("line_3"))
self.horizontalLayout.addWidget(self.line_3)
self.lcdNumber = QtGui.QLCDNumber(self.verticalLayoutWidget_2)
self.lcdNumber.setObjectName(_fromUtf8("lcdNumber"))
self.horizontalLayout.addWidget(self.lcdNumber)
self.horizontalLayout.setStretch(0, 1)
self.horizontalLayout.setStretch(2, 2)
self.horizontalLayout.setStretch(4, 5)
self.horizontalLayout.setStretch(6, 2)
self.verticalLayout.addLayout(self.horizontalLayout)
self.verticalLayout.setStretch(0, 8)
self.verticalLayout.setStretch(1, 1)
self.verticalLayout.setStretch(2, 1)
self.verticalLayout_main.addLayout(self.verticalLayout)
self.verticalLayout_main.setStretch(0, 2) self.retranslateUi(videofrom)
QtCore.QMetaObject.connectSlotsByName(videofrom) def retranslateUi(self, videofrom):
videofrom.setWindowTitle(_translate("videofrom", "Form", None))
self.BtnOpen.setToolTip(_translate("videofrom", "<html><head/><body><p>选择文件,右键选择音频or 视频</p></body></html>", None))
self.BtnOpen.setText(_translate("videofrom", "选择文件", None)) from PyQt4 import phonon if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
videofrom = QtGui.QWidget()
ui = Ui_videofrom()
ui.setupUi(videofrom)
videofrom.show()
sys.exit(app.exec_())

运行效果:

Pyqt 音视频播放器

看起来很乱的布局是吧,在这理因为的是layout里面的setStretch 方法,该方法可以按照百分比的比例来显示控件的坐标,空的地方我们预留了一个 QToolBar 和  VideoWidget。

为什么是VideoWidget 而不是VideoPlayer 呢? 因为VideoPlayer 提供的方法太少。只有播放 暂停 停止等,而VideoWidget 提供了更多的方法和功能。

在Qt designer中我一直在找Phonon的VideoWidget 控件一直找不到,只有一个VideoPlayer, 所以只能在逻辑页面 addWidget了。

第二步: 编写逻辑页面

细节不讲了,直接贴出代码:

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

 from PyQt4 import QtCore, QtGui
from PyQt4 import phonon
from video import Ui_videofrom
import sys
import icoqrc class mainvideo(QtGui.QWidget):
def __init__(self):
super(mainvideo, self).__init__()
self.UI=Ui_videofrom()
self.UI.setupUi(self)
self.setWindowTitle(u'Pyqt 音视频播放器')
self.setWindowIcon(QtGui.QIcon(':flash.ico'))
self.mediaObject = phonon.Phonon.MediaObject(self)
self.mediaObject.stateChanged.connect(self.stateChanged) # 对象改变时
self.mediaObject.tick.connect(self.tick) # 链接到时间
self.setupUi()
self.connect(self.UI.BtnOpen, QtCore.SIGNAL('customContextMenuRequested (const QPoint&)'), self.openright)
self.connect(self.UI.BtnOpen, QtCore.SIGNAL('clicked()'), self.alert) self.UI.videoPlayer =phonon.Phonon.VideoWidget(self)
self.UI.verticalLayout_player.addWidget(self.UI.videoPlayer) def setupUi(self):
self.playAction = QtGui.QAction(self.style().standardIcon(QtGui.QStyle.SP_MediaPlay), "Play",self, shortcut="Ctrl+P", enabled=False, triggered=self.mediaObject.play)
self.pauseAction = QtGui.QAction(self.style().standardIcon(QtGui.QStyle.SP_MediaPause), "Pause", self, shortcut="Ctrl+A", enabled=False, triggered=self.mediaObject.pause)
self.stopAction = QtGui.QAction(self.style().standardIcon(QtGui.QStyle.SP_MediaStop), "Stop", self, shortcut="Ctrl+S", enabled=False,triggered=self.mediaObject.stop)
# 添加工具条 包含 播放, 暂停, 重新开始
bar = QtGui.QToolBar()
bar.addAction(self.playAction)
bar.addAction(self.pauseAction)
bar.addAction(self.stopAction)
self.UI.horizontalLayout_btn.addWidget(bar)
# 显示LED时间
palette = QtGui.QPalette()
palette.setBrush(QtGui.QPalette.Light, QtCore.Qt.darkGray)
self.timeLcd = self.UI.lcdNumber
self.timeLcd.setPalette(palette)
self.timeLcd.display('00:00')
self.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint) # PyQT禁止窗口最大化按钮:
self.setFixedSize(self.width(), self.height()) # PyQT禁止调整窗口大小: # button 右键菜单
def openright(self):
popMenu = QtGui.QMenu()
popMenu.addAction(QtGui.QAction(QtGui.QIcon(':chrome.ico'), u'音频文件', self, enabled=True, triggered=self.openaudio))
popMenu.addAction(QtGui.QAction(QtGui.QIcon(':myfavicon.ico'), u'视频文件', self, enabled=True, triggered=self.openvideo))
popMenu.exec_(QtGui.QCursor.pos()) # 选择打开音频
def openaudio(self):
file = self.addFiles('audio')
self.mediaObject.setCurrentSource(phonon.Phonon.MediaSource(file))
# 初始化音频的输出按钮
self.audioOutput = phonon.Phonon.AudioOutput(phonon.Phonon.VideoCategory, self)
phonon.Phonon.createPath(self.mediaObject, self.audioOutput)
# 连接到音量
self.UI.volumeSlider.setAudioOutput(self.audioOutput)
self.UI.seekSlider.setMediaObject(self.mediaObject)
self.mediaObject.play() # 选择打开视频文件
def openvideo(self):
file = self.addFiles('video')
self.mediaObject.setCurrentSource(phonon.Phonon.MediaSource(file)) # 加载当前的源文件
phonon.Phonon.createPath(self.mediaObject, self.UI.videoPlayer)
# 初始化视频输出
self.UI.videoPlayer.setAspectRatio(phonon.Phonon.VideoWidget.AspectRatioAuto)
# 初始化音频的输出按钮
self.audioOutput =phonon.Phonon.AudioOutput(phonon.Phonon.VideoCategory, self)
phonon.Phonon.createPath(self.mediaObject, self.audioOutput)
# 连接到音量按钮
self.UI.volumeSlider.setAudioOutput(self.audioOutput)
self.UI.seekSlider.setMediaObject(self.mediaObject)
self.mediaObject.play() def alert(self):
QtGui.QMessageBox.question(self, (u'提示'),(u'请右键选择打开文件!'),QtGui.QMessageBox.Ok) # 选择文件
def addFiles(self,filetype='all'):
if filetype=='audio':
tips=u'选择音频文件'
expand = 'Image Files(*.mp3 *.wav)'
elif filetype=='video':
tips = u'选择视频文件'
expand = 'Image Files(*.mp4 *.avi)'
else:
tips =u'请选择播放文件'
expand = 'Image Files(*.mp3 *.wav *.mp4 *.avi)'
# getOpenFileName 只能选择一个 getOpenFileNames 可多个选择
files = QtGui.QFileDialog.getOpenFileName(self, tips,QtGui.QDesktopServices.storageLocation(QtGui.QDesktopServices.MusicLocation), expand) # QStringList getOpenFileNames (QWidget parent = None, QString caption = QString(), QString directory = QString(), QString filter = QString(), Options options = 0) if not files:
return '' return files
# 改变状态
def stateChanged(self, newState): if newState == phonon.Phonon.ErrorState:
if self.mediaObject.errorType() == phonon.Phonon.FatalError:
QtGui.QMessageBox.warning(self, "Fatal Error",
self.mediaObject.errorString())
else:
QtGui.QMessageBox.warning(self, "Error",
self.mediaObject.errorString()) elif newState == phonon.Phonon.PlayingState:
self.playAction.setEnabled(False)
self.pauseAction.setEnabled(True)
self.stopAction.setEnabled(True) elif newState == phonon.Phonon.StoppedState:
self.stopAction.setEnabled(False)
self.playAction.setEnabled(True)
self.pauseAction.setEnabled(False)
self.timeLcd.display("00:00") elif newState == phonon.Phonon.PausedState:
self.pauseAction.setEnabled(False)
self.stopAction.setEnabled(True)
self.playAction.setEnabled(True)
# 时间显示
def tick(self, time):
displayTime = QtCore.QTime(0, (time / 60000) % 60, (time / 1000) % 60)
self.timeLcd.display(displayTime.toString('mm:ss')) def keyPressEvent(self, event):
if event.key() ==QtCore.Qt.Key_Escape:
self.close() if __name__ == '__main__':
app=QtGui.QApplication(sys.argv)
mainapp = mainvideo()
app.setQuitOnLastWindowClosed(True)
mainapp.show()
sys.exit(app.exec_())

第三步: 运行和排除问题

按理来说,应该是先排除问题再运行。

在完成这个Pyqt的播放器中过程中遇到了N多问题

一个大问题是:没有声音和视频画面, 问题google后很简单: 没有解码器! 下载视频解码器喽!

好!现在我们运行看效果:

Pyqt 音视频播放器

Pyqt 音视频播放器

Pyqt 音视频播放器