Pyqt 音視頻播放器

 

在尋找如何使用Pyqt作一個播放器時首先找到的是openCV2html

openCV2 貌似太強大了,各類關於圖像處理的事情它都能完成,如 讀取攝像頭、圖像識別、人臉識別、  圖像灰度處理 、 播放視頻等,強大的讓你想不到!python

openCV2 播放視頻也很簡單:chrome

 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)

效果:app

在這裏也提供以些openCV的信息框架

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

下載完成後解壓文件,找到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了!ui

關於更多的openCV信息參考:this

 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後很簡單: 沒有解碼器! 下載視頻解碼器嘍!

好!如今咱們運行看效果:

 

 

相關文章
相關標籤/搜索