小言_互联网的博客

PyQt5 实现视频播放器(二) ,详细版本 ,适合新手入门

1588人阅读  评论(0)

      去年写了一个PyQt5实现播放器的简单demo,没想到居然是我博客里面关注最多的(然而我的本职并不是做这个,手动苦笑)因为要贴代码的时候,资料百度网盘下载需要太久了,所以就重新写了一个。记录一下全部过程,方便新手入门。

一、环境准备:

pycharm+python3.5+pyqt5.6+qtdesigner+ 解码器

1、pycharm 官网下载就可以,community版本,免费使用。

2、python3.5 安装anaconda,官网下载

3、pyqt5.6 , 试用pip或conda命令安装一下,例如 conda install pyqt

4、qtdesigner 详细见https://blog.csdn.net/doublezsx/article/details/79739715 ,按着步骤走   (附送python安装whl的方法            https://blog.csdn.net/weixin_41592575/article/details/78984585,两个external 工具最好设置一下,很方便)

5、解码器的话下载安装就好 LAV 解码器的 地址:http://forum.doom9.org/showthread.php?t=156191

      Version 0.73.1: Installer (both x86/x64)   (我是直接下载的这个安装一下就解决问题了)

  (PS: DirectShowPlayerService::doPlay: Unresolved error code 8007000e 这个错误      在cmd中运行python可以看到,如果直接是pycharm中运行的话打开视频文件后就一直无      反应。)

       

    此外如果安装之后.mp4的文件仍然无法打开报同样错误(被我碰到了,win7系统,推荐安装K-Lite Codec Pack               http://www.codecguide.com/download_k-lite_codec_pack_basic.htm

二、详细代码

1、简单的第一个demo代码如下(py_player_demo1.py):


  
  1. from PyQt5.QtWidgets import *
  2. from PyQt5.QtMultimedia import *
  3. from PyQt5.QtMultimediaWidgets import QVideoWidget
  4. import sys
  5. if __name__ == '__main__':
  6. app = QApplication(sys.argv)
  7. player = QMediaPlayer()
  8. vw=QVideoWidget() # 定义视频显示的widget
  9. vw.show()
  10. player.setVideoOutput(vw) # 视频播放输出的widget,就是上面定义的
  11. player.setMedia(QMediaContent(QFileDialog.getOpenFileUrl()[ 0])) # 选取视频文件
  12. player.play() # 播放视频
  13. sys.exit(app.exec_())

创建一个QMediaPlayer,然后直接用文件对话框打开视频播放,选择完之后直接进行播放。效果如下:

 (打开文件)     (播放效果)

2、带有播放控制的版本

(1)界面设计:

首先我们在目录下创建一个GUI.ui的文件,然后右键用external tools 的qtdesigner打开来构建所需要的界面:

 (方便打开qtdesigner)   (创建mainwindow)

在QT Desinger 中可以根据需要直接拖控件,这里只实现了最简单的视屏播放功能,所以放了三个pushbutton,一个slide,一个label一个widget。因为后面要进行双击事件的响应,所以要重写QVideoWidget 这个类,我把新继承的类名定为myVideoWidget。 在刚才拖放好的界面中右键提升widget,提升为myVideoWidget控件就完成界面GUI 设计了。(promot 提升的时候promoted class name 填写的就是自己的写的类,比如myVideoWidget,header file 填写的就是类所在的文件名

 (界面)  (提升widget)

然后保存设计好的ui文件,可以覆盖掉刚才新建的。然后用pyuic 将ui文件转成py文件:

 (这样目一录下就会多出一个GUI.py 文件,这个py才是实际运行的时候的界面UI文件)

(2)代码设计:

  新建一个文件myVideoWidget.py 然后继承原来的QVideoWidget, 重写鼠标双击事件,当有双击时发送信号:

注意这里的文件名和类名要和对应上面widget提升时候的名字。)


  
  1. from PyQt5.QtMultimediaWidgets import QVideoWidget
  2. from PyQt5.QtCore import *
  3. class myVideoWidget(QVideoWidget):
  4. doubleClickedItem = pyqtSignal(str) # 创建双击信号
  5. def __init__(self,parent=None):
  6. super(QVideoWidget,self).__init__(parent)
  7. def mouseDoubleClickEvent(self,QMouseEvent): #双击事件
  8. self.doubleClickedItem.emit( "double clicked")

主函数设计: py_player_demo2.py

这里实现全屏的思路就是使用两个myVideoWidget,然后根据双击,进行切换,实现效果基本上看不出有两个widget(如果你切换任务管理器就能明显看到是两个窗口)


  
  1. from PyQt5.QtWidgets import *
  2. from PyQt5.QtMultimedia import *
  3. from PyQt5.QtGui import *
  4. from PyQt5.QtCore import *
  5. from PyQt5.QtMultimediaWidgets import QVideoWidget
  6. from GUI import Ui_MainWindow
  7. from myVideoWidget import myVideoWidget
  8. import sys
  9. class myMainWindow(Ui_MainWindow,QMainWindow):
  10. def __init__(self):
  11. super(Ui_MainWindow, self).__init__()
  12. self.setupUi(self)
  13. self.sld_video_pressed= False #判断当前进度条识别否被鼠标点击
  14. self.videoFullScreen = False # 判断当前widget是否全屏
  15. self.videoFullScreenWidget = myVideoWidget() # 创建一个全屏的widget
  16. self.videoFullScreenWidget.setFullScreen( 1)
  17. self.videoFullScreenWidget.hide() # 不用的时候隐藏起来
  18. self.player = QMediaPlayer()
  19. self.player.setVideoOutput(self.wgt_video) # 视频播放输出的widget,就是上面定义的
  20. self.btn_open.clicked.connect(self.openVideoFile) # 打开视频文件按钮
  21. self.btn_play.clicked.connect(self.playVideo) # play
  22. self.btn_stop.clicked.connect(self.pauseVideo) # pause
  23. self.player.positionChanged.connect(self.changeSlide) # change Slide
  24. self.videoFullScreenWidget.doubleClickedItem.connect(self.videoDoubleClicked) #双击响应
  25. self.wgt_video.doubleClickedItem.connect(self.videoDoubleClicked) #双击响应
  26. self.sld_video.setTracking( False)
  27. self.sld_video.sliderReleased.connect(self.releaseSlider)
  28. self.sld_video.sliderPressed.connect(self.pressSlider)
  29. self.sld_video.sliderMoved.connect(self.moveSlider)
  30. def moveSlider(self, position):
  31. if self.player.duration() > 0: # 开始播放后才允许进行跳转
  32. video_position = int((position / 100) * self.player.duration())
  33. self.player.setPosition(video_position)
  34. self.lab_video.setText(str(round(position, 2)) + '%')
  35. def pressSlider(self):
  36. self.sld_video_pressed = True
  37. print( "pressed")
  38. def releaseSlider(self):
  39. self.sld_video_pressed = False
  40. def changeSlide(self, position):
  41. if not self.sld_video_pressed: # 进度条被鼠标点击时不更新
  42. self.vidoeLength = self.player.duration()+ 0.1
  43. self.sld_video.setValue(round((position/self.vidoeLength)* 100))
  44. self.lab_video.setText(str(round((position/self.vidoeLength)* 100, 2))+ '%')
  45. def openVideoFile(self):
  46. self.player.setMedia(QMediaContent(QFileDialog.getOpenFileUrl()[ 0])) # 选取视频文件
  47. self.player.play() # 播放视频
  48. def playVideo(self):
  49. self.player.play()
  50. def pauseVideo(self):
  51. self.player.pause()
  52. def videoDoubleClicked(self, text):
  53. if self.player.duration() > 0: # 开始播放后才允许进行全屏操作
  54. if self.videoFullScreen:
  55. self.player.pause()
  56. self.videoFullScreenWidget.hide()
  57. self.player.setVideoOutput(self.wgt_video)
  58. self.player.play()
  59. self.videoFullScreen = False
  60. else:
  61. self.player.pause()
  62. self.videoFullScreenWidget.show()
  63. self.player.setVideoOutput(self.videoFullScreenWidget)
  64. self.player.play()
  65. self.videoFullScreen = True
  66. if __name__ == '__main__':
  67. app = QApplication(sys.argv)
  68. vieo_gui = myMainWindow()
  69. vieo_gui.show()
  70. sys.exit(app.exec_())

 

效果如下:

 (播放界面)                (全屏界面)

视频进度条更新

   通过changeSlide 函数我们已经实现了视频播放的进度更新,那么如何实现进度条的拖拽、点击实现视频的跳转呢?

首先需要了解slider(进度条)的一些UI响应操作,比如通常我们所说的进度条“拖拽”,在qt的slider里面其实是分为三个部分:

 (1)鼠标点击进度条   发送sliderPressed 信号 (2)进度条拖动 发送sliderMoved 信号 (3)松开鼠标 发送 sliderReleased信号

因此实现拖拽控制视频进度跳转的逻辑就为:sliderPressed 的时候,原先的进度条就不需要根据视频播放的进度不断更新,因此设置了

sld_video_pressed 为TRUE转态变量,让进度条不要跟着视频播放自动更新,然后moved的时候就不断根据当前的位置去设置视频的播放位置

self.player.setPosition(video_position)来完成,最后sliderReleased 的时候再把sld_video_pressed 设置为False,让进度条跟着视频播放自动更新

实现进度条点击跳转的逻辑为: 由于slider的位置信息是由视频进度来控制(视频播放进度是由slider的value来展示的),因此我们无法直接通过slider的valueChanged信号函数来实现视频进度的点击跳转(否则会造成死循环:视频播放到A位置,slider跳转到A位置进行进度显示(发出valuChanged信号),A位置出发valueChanged信号告诉视频要播放到A位置)

因此我们单独写了一个myslider这个类,重写了里面的mousePressEvent 事件,通过鼠标点击的位置,间接算出应该跳转的进度位置,发出ClickedValue 信号来告诉视频应该跳转的位置来实现。


  
  1. from PyQt5.QtCore import *
  2. from PyQt5.QtWidgets import QSlider
  3. class myVideoSlider(QSlider):
  4. ClickedValue = pyqtSignal(int)
  5. def __init__(self, father):
  6. super().__init__(Qt.Horizontal, father)
  7. def mousePressEvent(self, QMouseEvent): #单击事件
  8. super().mousePressEvent(QMouseEvent)
  9. value = QMouseEvent.localPos().x()
  10. # self.setValue(int(value)/9)
  11. value = round(value/self.width()*self.maximum()) # 根据鼠标点击的位置和slider的长度算出百分比
  12. self.ClickedValue.emit(value)

 最后重新排版了一下界面(视频的widget可以随着界面的拖动自动缩放),哦,对了还把声音控制的进度条加上了(掌握了视频的进度条,这个就不在话下):

视频播放界面

 

    总结:

1、涉及的知识点主要包括,qtdesigner 的使用,采用控件的使用、如何重写原来的控件,增添新的功能。

     pytqt5 中信号和槽 的使用,这些都是qt掌握的基本。

2、主要是实现视频播放的demo,这个例子理解了,后面其它功能的添加就好比搭积木一样了

3、后面可以扩展的功能有很多,比如不同倍速播放、快捷键等,都可以自己根据需求添加如声音控制,视频进度控制(这里进度条只是显示而已,视频进度条这里也有个坑,

今天不填,主要是显示和调整两个有冲突)

    视频截图功能涉及到的东西比较多就单独写了一篇:https://blog.csdn.net/u012552296/article/details/115281883?spm=1001.2014.3001.5501

4、写代码简单,要整理成博客就难,费了一下,截了很多图(要卒),完整代码放在GitHub上面。https://github.com/taroshi/PyQt_Video_Demo

CSDN 上面的下载链接:https://download.csdn.net/download/u012552296/16045621?spm=1001.2014.3001.5503  (附带了一个视频播放解码器)

5、如果使用中遇到一些问题,可以先翻一翻评论,有些问题大家互相交流可能就解决了,也可以私信我,看到了就会回复


转载:https://blog.csdn.net/u012552296/article/details/89295273
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场