Pyqt 音视频播放器

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

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

openCV2 播放视频也很简单:

 1 #coding=utf-8
 2 
 3 import cv2.cv as cv
 4 filename = "cn.avi"
 5 win_name = "video player"
 6 capture = cv.CaptureFromFile(filename)
 7 cv.NamedWindow(win_name, cv.CV_WINDOW_AUTOSIZE)
 8 
 9 # 定义一个无限循环
10 while 1:
11 
12        # 每次从视频数据流框架中抓取一帧图片
13     image = cv.QueryFrame(capture)
14 
15     # 将图片显示在特定窗口上
16     cv.ShowImage(win_name, image)
17 
18     # 当安县Esc键时退出循环
19     c = cv.WaitKey(33)
20     if c == 27:
21         break
22 
23 # 退出循环后销毁显示窗口
24 cv.DestroyWindow(win_name)

效果:

在这里也提供以些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代码:

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <ui version="4.0">
  3  <class>videofrom</class>
  4  <widget class="QWidget" name="videofrom">
  5   <property name="geometry">
  6    <rect>
  7     <x>0</x>
  8     <y>0</y>
  9     <width>880</width>
 10     <height>572</height>
 11    </rect>
 12   </property>
 13   <property name="windowTitle">
 14    <string>Form</string>
 15   </property>
 16   <widget class="QWidget" name="verticalLayoutWidget_2">
 17    <property name="geometry">
 18     <rect>
 19      <x>10</x>
 20      <y>10</y>
 21      <width>861</width>
 22      <height>551</height>
 23     </rect>
 24    </property>
 25    <layout class="QVBoxLayout" name="verticalLayout_main" stretch="2">
 26     <item>
 27      <layout class="QVBoxLayout" name="verticalLayout" stretch="8,1,1">
 28       <item>
 29        <layout class="QVBoxLayout" name="verticalLayout_player" stretch="">
 30         <property name="spacing">
 31          <number>6</number>
 32         </property>
 33        </layout>
 34       </item>
 35       <item>
 36        <widget class="Phonon::SeekSlider" name="seekSlider"/>
 37       </item>
 38       <item>
 39        <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,2,0,5,0,2">
 40         <item>
 41          <widget class="QPushButton" name="BtnOpen">
 42           <property name="contextMenuPolicy">
 43            <enum>Qt::CustomContextMenu</enum>
 44           </property>
 45           <property name="toolTip">
 46            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;选择文件,右键选择音频or 视频&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
 47           </property>
 48           <property name="text">
 49            <string>选择文件</string>
 50           </property>
 51          </widget>
 52         </item>
 53         <item>
 54          <widget class="Line" name="line">
 55           <property name="orientation">
 56            <enum>Qt::Vertical</enum>
 57           </property>
 58          </widget>
 59         </item>
 60         <item>
 61          <layout class="QHBoxLayout" name="horizontalLayout_btn"/>
 62         </item>
 63         <item>
 64          <widget class="Line" name="line_2">
 65           <property name="orientation">
 66            <enum>Qt::Vertical</enum>
 67           </property>
 68          </widget>
 69         </item>
 70         <item>
 71          <widget class="Phonon::VolumeSlider" name="volumeSlider"/>
 72         </item>
 73         <item>
 74          <widget class="Line" name="line_3">
 75           <property name="orientation">
 76            <enum>Qt::Vertical</enum>
 77           </property>
 78          </widget>
 79         </item>
 80         <item>
 81          <widget class="QLCDNumber" name="lcdNumber"/>
 82         </item>
 83        </layout>
 84       </item>
 85      </layout>
 86     </item>
 87    </layout>
 88   </widget>
 89  </widget>
 90  <customwidgets>
 91   <customwidget>
 92    <class>Phonon::SeekSlider</class>
 93    <extends>QWidget</extends>
 94    <header location="global">phonon/seekslider.h</header>
 95   </customwidget>
 96   <customwidget>
 97    <class>Phonon::VolumeSlider</class>
 98    <extends>QWidget</extends>
 99    <header location="global">phonon/volumeslider.h</header>
100   </customwidget>
101  </customwidgets>
102  <resources/>
103  <connections/>
104 </ui>

转换为py文件

video.py :

  1 # -*- coding: utf-8 -*-
  2 
  3 # Form implementation generated from reading ui file 'video.ui'
  4 #
  5 # Created: Thu Feb 12 17:25:10 2015
  6 #      by: PyQt4 UI code generator 4.10.3
  7 #
  8 # WARNING! All changes made in this file will be lost!
  9 
 10 from PyQt4 import QtCore, QtGui
 11 
 12 try:
 13     _fromUtf8 = QtCore.QString.fromUtf8
 14 except AttributeError:
 15     def _fromUtf8(s):
 16         return s
 17 
 18 try:
 19     _encoding = QtGui.QApplication.UnicodeUTF8
 20     def _translate(context, text, disambig):
 21         return QtGui.QApplication.translate(context, text, disambig, _encoding)
 22 except AttributeError:
 23     def _translate(context, text, disambig):
 24         return QtGui.QApplication.translate(context, text, disambig)
 25 
 26 class Ui_videofrom(object):
 27     def setupUi(self, videofrom):
 28         videofrom.setObjectName(_fromUtf8("videofrom"))
 29         videofrom.resize(880, 572)
 30         self.verticalLayoutWidget_2 = QtGui.QWidget(videofrom)
 31         self.verticalLayoutWidget_2.setGeometry(QtCore.QRect(10, 10, 861, 551))
 32         self.verticalLayoutWidget_2.setObjectName(_fromUtf8("verticalLayoutWidget_2"))
 33         self.verticalLayout_main = QtGui.QVBoxLayout(self.verticalLayoutWidget_2)
 34         self.verticalLayout_main.setMargin(0)
 35         self.verticalLayout_main.setObjectName(_fromUtf8("verticalLayout_main"))
 36         self.verticalLayout = QtGui.QVBoxLayout()
 37         self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
 38         self.verticalLayout_player = QtGui.QVBoxLayout()
 39         self.verticalLayout_player.setObjectName(_fromUtf8("verticalLayout_player"))
 40         self.verticalLayout.addLayout(self.verticalLayout_player)
 41         self.seekSlider = phonon.Phonon.SeekSlider(self.verticalLayoutWidget_2)
 42         self.seekSlider.setObjectName(_fromUtf8("seekSlider"))
 43         self.verticalLayout.addWidget(self.seekSlider)
 44         self.horizontalLayout = QtGui.QHBoxLayout()
 45         self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
 46         self.BtnOpen = QtGui.QPushButton(self.verticalLayoutWidget_2)
 47         self.BtnOpen.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
 48         self.BtnOpen.setObjectName(_fromUtf8("BtnOpen"))
 49         self.horizontalLayout.addWidget(self.BtnOpen)
 50         self.line = QtGui.QFrame(self.verticalLayoutWidget_2)
 51         self.line.setFrameShape(QtGui.QFrame.VLine)
 52         self.line.setFrameShadow(QtGui.QFrame.Sunken)
 53         self.line.setObjectName(_fromUtf8("line"))
 54         self.horizontalLayout.addWidget(self.line)
 55         self.horizontalLayout_btn = QtGui.QHBoxLayout()
 56         self.horizontalLayout_btn.setObjectName(_fromUtf8("horizontalLayout_btn"))
 57         self.horizontalLayout.addLayout(self.horizontalLayout_btn)
 58         self.line_2 = QtGui.QFrame(self.verticalLayoutWidget_2)
 59         self.line_2.setFrameShape(QtGui.QFrame.VLine)
 60         self.line_2.setFrameShadow(QtGui.QFrame.Sunken)
 61         self.line_2.setObjectName(_fromUtf8("line_2"))
 62         self.horizontalLayout.addWidget(self.line_2)
 63         self.volumeSlider = phonon.Phonon.VolumeSlider(self.verticalLayoutWidget_2)
 64         self.volumeSlider.setObjectName(_fromUtf8("volumeSlider"))
 65         self.horizontalLayout.addWidget(self.volumeSlider)
 66         self.line_3 = QtGui.QFrame(self.verticalLayoutWidget_2)
 67         self.line_3.setFrameShape(QtGui.QFrame.VLine)
 68         self.line_3.setFrameShadow(QtGui.QFrame.Sunken)
 69         self.line_3.setObjectName(_fromUtf8("line_3"))
 70         self.horizontalLayout.addWidget(self.line_3)
 71         self.lcdNumber = QtGui.QLCDNumber(self.verticalLayoutWidget_2)
 72         self.lcdNumber.setObjectName(_fromUtf8("lcdNumber"))
 73         self.horizontalLayout.addWidget(self.lcdNumber)
 74         self.horizontalLayout.setStretch(0, 1)
 75         self.horizontalLayout.setStretch(2, 2)
 76         self.horizontalLayout.setStretch(4, 5)
 77         self.horizontalLayout.setStretch(6, 2)
 78         self.verticalLayout.addLayout(self.horizontalLayout)
 79         self.verticalLayout.setStretch(0, 8)
 80         self.verticalLayout.setStretch(1, 1)
 81         self.verticalLayout.setStretch(2, 1)
 82         self.verticalLayout_main.addLayout(self.verticalLayout)
 83         self.verticalLayout_main.setStretch(0, 2)
 84 
 85         self.retranslateUi(videofrom)
 86         QtCore.QMetaObject.connectSlotsByName(videofrom)
 87 
 88     def retranslateUi(self, videofrom):
 89         videofrom.setWindowTitle(_translate("videofrom", "Form", None))
 90         self.BtnOpen.setToolTip(_translate("videofrom", "<html><head/><body><p>选择文件,右键选择音频or 视频</p></body></html>", None))
 91         self.BtnOpen.setText(_translate("videofrom", "选择文件", None))
 92 
 93 from PyQt4 import phonon
 94 
 95 if __name__ == "__main__":
 96     import sys
 97     app = QtGui.QApplication(sys.argv)
 98     videofrom = QtGui.QWidget()
 99     ui = Ui_videofrom()
100     ui.setupUi(videofrom)
101     videofrom.show()
102     sys.exit(app.exec_())

运行效果:

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

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

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

第二步: 编写逻辑页面

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

  1 # -*- coding: utf-8 -*-
  2 
  3 
  4 
  5 from PyQt4 import QtCore, QtGui
  6 from PyQt4 import phonon
  7 from video import Ui_videofrom
  8 import sys
  9 import icoqrc
 10 
 11 class mainvideo(QtGui.QWidget):
 12     def __init__(self):
 13         super(mainvideo, self).__init__()
 14         self.UI=Ui_videofrom()
 15         self.UI.setupUi(self)
 16         self.setWindowTitle(u'Pyqt 音视频播放器')
 17         self.setWindowIcon(QtGui.QIcon(':flash.ico'))
 18         self.mediaObject = phonon.Phonon.MediaObject(self)
 19         self.mediaObject.stateChanged.connect(self.stateChanged)  # 对象改变时
 20         self.mediaObject.tick.connect(self.tick)  # 链接到时间
 21         self.setupUi()
 22         self.connect(self.UI.BtnOpen, QtCore.SIGNAL('customContextMenuRequested (const QPoint&)'), self.openright)
 23         self.connect(self.UI.BtnOpen, QtCore.SIGNAL('clicked()'), self.alert)
 24 
 25         self.UI.videoPlayer =phonon.Phonon.VideoWidget(self)
 26         self.UI.verticalLayout_player.addWidget(self.UI.videoPlayer)
 27 
 28 
 29     def setupUi(self):
 30         self.playAction = QtGui.QAction(self.style().standardIcon(QtGui.QStyle.SP_MediaPlay), "Play",self, shortcut="Ctrl+P", enabled=False, triggered=self.mediaObject.play)
 31         self.pauseAction = QtGui.QAction(self.style().standardIcon(QtGui.QStyle.SP_MediaPause), "Pause", self, shortcut="Ctrl+A", enabled=False, triggered=self.mediaObject.pause)
 32         self.stopAction = QtGui.QAction(self.style().standardIcon(QtGui.QStyle.SP_MediaStop), "Stop",  self, shortcut="Ctrl+S", enabled=False,triggered=self.mediaObject.stop)
 33         # 添加工具条  包含 播放, 暂停, 重新开始
 34         bar = QtGui.QToolBar()
 35         bar.addAction(self.playAction)
 36         bar.addAction(self.pauseAction)
 37         bar.addAction(self.stopAction)
 38         self.UI.horizontalLayout_btn.addWidget(bar)
 39         #  显示LED时间
 40         palette = QtGui.QPalette()
 41         palette.setBrush(QtGui.QPalette.Light, QtCore.Qt.darkGray)
 42         self.timeLcd = self.UI.lcdNumber
 43         self.timeLcd.setPalette(palette)
 44         self.timeLcd.display('00:00')
 45         self.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint)  # PyQT禁止窗口最大化按钮:
 46         self.setFixedSize(self.width(), self.height())   # PyQT禁止调整窗口大小:
 47 
 48 
 49 
 50 
 51 
 52     # button 右键菜单
 53     def openright(self):
 54         popMenu = QtGui.QMenu()
 55         popMenu.addAction(QtGui.QAction(QtGui.QIcon(':chrome.ico'), u'音频文件', self,  enabled=True, triggered=self.openaudio))
 56         popMenu.addAction(QtGui.QAction(QtGui.QIcon(':myfavicon.ico'), u'视频文件', self,  enabled=True, triggered=self.openvideo))
 57         popMenu.exec_(QtGui.QCursor.pos())
 58 
 59 
 60     # 选择打开音频
 61     def openaudio(self):
 62         file = self.addFiles('audio')
 63         self.mediaObject.setCurrentSource(phonon.Phonon.MediaSource(file))
 64         # 初始化音频的输出按钮
 65         self.audioOutput = phonon.Phonon.AudioOutput(phonon.Phonon.VideoCategory, self)
 66         phonon.Phonon.createPath(self.mediaObject, self.audioOutput)
 67         # 连接到音量
 68         self.UI.volumeSlider.setAudioOutput(self.audioOutput)
 69         self.UI.seekSlider.setMediaObject(self.mediaObject)
 70         self.mediaObject.play()
 71         
 72 
 73     # 选择打开视频文件
 74     def openvideo(self):
 75         file = self.addFiles('video')
 76         self.mediaObject.setCurrentSource(phonon.Phonon.MediaSource(file))   # 加载当前的源文件
 77         phonon.Phonon.createPath(self.mediaObject, self.UI.videoPlayer)
 78         # 初始化视频输出
 79         self.UI.videoPlayer.setAspectRatio(phonon.Phonon.VideoWidget.AspectRatioAuto)
 80         # 初始化音频的输出按钮
 81         self.audioOutput  =phonon.Phonon.AudioOutput(phonon.Phonon.VideoCategory, self)
 82         phonon.Phonon.createPath(self.mediaObject, self.audioOutput)
 83         # 连接到音量按钮
 84         self.UI.volumeSlider.setAudioOutput(self.audioOutput)
 85         self.UI.seekSlider.setMediaObject(self.mediaObject)
 86         self.mediaObject.play()
 87 
 88 
 89 
 90     def alert(self):
 91         QtGui.QMessageBox.question(self, (u'提示'),(u'请右键选择打开文件!'),QtGui.QMessageBox.Ok)
 92         
 93     # 选择文件
 94     def addFiles(self,filetype='all'):
 95         if filetype=='audio':
 96             tips=u'选择音频文件'
 97             expand = 'Image Files(*.mp3 *.wav)'
 98         elif filetype=='video':
 99             tips = u'选择视频文件'
100             expand = 'Image Files(*.mp4 *.avi)'
101         else:
102             tips =u'请选择播放文件'
103             expand = 'Image Files(*.mp3 *.wav *.mp4 *.avi)'
104         # getOpenFileName  只能选择一个    getOpenFileNames  可多个选择
105         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)
106         
107         if not files:
108             return ''
109         
110         return files
111     # 改变状态
112     def stateChanged(self, newState):
113 
114         if newState == phonon.Phonon.ErrorState:
115             if self.mediaObject.errorType() == phonon.Phonon.FatalError:
116                 QtGui.QMessageBox.warning(self, "Fatal Error",
117                         self.mediaObject.errorString())
118             else:
119                 QtGui.QMessageBox.warning(self, "Error",
120                         self.mediaObject.errorString())
121 
122         elif newState == phonon.Phonon.PlayingState:
123             self.playAction.setEnabled(False)
124             self.pauseAction.setEnabled(True)
125             self.stopAction.setEnabled(True)
126 
127         elif newState == phonon.Phonon.StoppedState:
128             self.stopAction.setEnabled(False)
129             self.playAction.setEnabled(True)
130             self.pauseAction.setEnabled(False)
131             self.timeLcd.display("00:00")
132 
133 
134         elif newState == phonon.Phonon.PausedState:
135             self.pauseAction.setEnabled(False)
136             self.stopAction.setEnabled(True)
137             self.playAction.setEnabled(True)
138     # 时间显示
139     def tick(self, time):
140         displayTime = QtCore.QTime(0, (time / 60000) % 60, (time / 1000) % 60)
141         self.timeLcd.display(displayTime.toString('mm:ss'))
142 
143 
144 
145     def keyPressEvent(self, event):
146          if event.key() ==QtCore.Qt.Key_Escape:
147              self.close()
148 
149 
150 if __name__ == '__main__':
151     app=QtGui.QApplication(sys.argv)
152     mainapp = mainvideo()
153     app.setQuitOnLastWindowClosed(True)
154     mainapp.show()
155     sys.exit(app.exec_())

第三步: 运行和排除问题

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

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

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

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

 

原文地址:https://www.cnblogs.com/dcb3688/p/4290315.html