Qt和OpenCV视频播放器,包括暂停以及播放下一个视频以及滑动条功能

在树莓上想用PyQt5写一个视频播放器,PyQt5自带一个库PyQt5.QtMultimedia和PyQt5.QtMultimediaWidgets可以实现视频的播放,可是树莓上安装总是有问题,所以这里采取的是和OpenCV结合的方法。
视频功能的实现主要是调用cv2.VideoCapture(fn)和cap.read(),滑动条的实现是通过cap.set(cv2.CAP_PROP_POS_FRAMES, 视频的帧数)函数实现的。暂停就是一直cv2.waitKey。
文中用到的视频和图标要修改。
注意因为全屏了所以这里的退出方法是"Ctrl+q,或者在其他中退出"

#!/usr/bin/python3
#-*- coding:utf-8 -*-
import sys
import cv2
from time import sleep
from itertools import count
from threading import Thread
import pyaudio
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import QtGui

class PlayVideo(QWidget):
    bClose = False
    fn_list = ["/home/pi/Documents/垃圾分类图片和视频/movie/movie1.mp4","/home/pi/Documents/垃圾分类图片和视频/movie/movie2.mp4","/home/pi/Documents/垃圾分类图片和视频/movie/movie3.mp4"]
    play_index = 0

    def __init__(self, parent=None):
        super(PlayVideo, self).__init__(parent)
        self.setWindowTitle('视频播放')
        self.setWindowIcon(QIcon("/home/pi/Documents/垃圾分类图片和视频/pic/ico1.png"))
        self.screen = QDesktopWidget().screenGeometry()
        self.resize(self.screen.width(), self.screen.height())
        #设置菜单栏
        bar = QMenuBar(self)
        bar.setFixedSize(self.screen.width(),30)
        #设置选项二
        play_menu = bar.addMenu("播放选项")
        #设置按钮一
        play_video = QAction("打开视频文件",self)
        play_video.setShortcut("Ctrl+1")
        play_video.setIcon(QIcon('/home/pi/Documents/垃圾分类图片和视频/图标/播放视频'))
        play_video.triggered.connect(self.manual_choose)
        play_menu.addAction(play_video)
        #设置按钮二
        play_pictures = QAction("自动播放视频",self)
        play_pictures.setShortcut("Ctrl+2")
        play_pictures.setIcon(QIcon('/home/pi/Documents/垃圾分类图片和视频/图标/播放图片'))
        play_pictures.triggered.connect(self.auto_choose)
        play_menu.addAction(play_pictures)
        #设置停止按钮
        play_stop = QAction("停止",self)
        play_stop.setShortcut("Ctrl+3")
        play_stop.triggered.connect(self.video_stop)
        play_menu.addAction(play_stop)
        #设置退出按钮
        exit_menu = bar.addMenu("其他")
        exit_option = QAction("退出",self)
        exit_option.setShortcut("Ctrl+Q")
        exit_option.setIcon(QIcon('/home/pi/Documents/垃圾分类图片和视频/图标/退出'))
        exit_option.triggered.connect(self.exit_stop)
        exit_menu.addAction(exit_option)
        #设置菜单栏的位置
        bar.move(0,0)

        #用来显示视频画面的Label组建,自带双缓冲,不闪烁
        layout = QGridLayout()
        self.lbVideo = QLabel()
        self.lbVideo.setFixedSize(1000,620)
        self.lbVideo.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.lbVideo,0,0,3,3)
        #设置滑动条
        self.s1 = QSlider(Qt.Horizontal)
        self.s1.setToolTip("滑动条")
        self.s1.setMinimum(0)#设置最大值
        self.s1.setMaximum(50)#设置最小值
        self.s1.setSingleStep(1)#设置间隔
        self.s1.setValue(0)#设置当前值
        self.s1.sliderMoved.connect(self.start_drag)
        self.s1.sliderReleased.connect(self.drag_action)
        self.moving_flag = 0
        self.stop_flag = 0#如果当前为播放值为0,如果当前为暂停值为1
        layout.addWidget(self.s1,3,1,1,1)
        #设置两个标签分别是当前时间和结束时间
        self.label_start = QLabel("00:00")
        layout.addWidget(self.label_start,3,0,1,1)
        self.label_end = QLabel("00:00")
        layout.addWidget(self.label_end,3,2,1,1)
        #设置暂停播放和下一个按钮
        self.stop_button = QPushButton()
        self.stop_button.setIcon(QIcon('/home/pi/Documents/垃圾分类图片和视频/图标/暂停.png'))
        self.stop_button.setIconSize(QSize(40,40))
        self.stop_button.clicked.connect(self.stop_action)
        layout.addWidget(self.stop_button,4,0,1,1)
        self.next_button = QPushButton()
        self.next_button.setIcon(QIcon('/home/pi/Documents/垃圾分类图片和视频/图标/下一个.png'))
        self.next_button.setIconSize(QSize(40,40))
        self.next_button.clicked.connect(self.next_action)
        layout.addWidget(self.next_button,4,2,1,1)
        self.setLayout(layout)

    def cvImgtoQtImg(self,cvImg):#定义将opencv图像转PyQt图像的函数
        QtImgBuf = cv2.cvtColor(cvImg, cv2.COLOR_BGR2BGRA)
        QtImg = QtGui.QImage(QtImgBuf.data, QtImgBuf.shape[1], QtImgBuf.shape[0],QtGui.QImage.Format_RGB32)
        return QtImg

    def playVideoFile(self,fn):#播放影片
        self.cap = cv2.VideoCapture(fn)
        frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
        self.settingSlider(frames)
        fps = 24
        self.loop_flag = 0
        if not self.cap.isOpened():
            print("Cannot open Video File")
            exit()
        while not self.bClose:
            ret, frame = self.cap.read()#逐帧读取影片
            if not ret:
                if frame is None:
                    print("The video has end.")
                else:
                    print("Read video error!")
                break
            if self.moving_flag==0:
                self.label_start.setText(self.int2time(self.loop_flag))
                self.s1.setValue(int(self.loop_flag/24))#设置当前值
            self.loop_flag += 1
            QtImg = self.cvImgtoQtImg(frame)
            self.lbVideo.setPixmap(QtGui.QPixmap.fromImage(QtImg).scaled(self.lbVideo.size()))
            self.lbVideo.show()#刷新界面
            while self.stop_flag == 1:#暂停的动作
                cv2.waitKey(int(1000/fps))#休眠一会,因为每秒播放24张图片,相当于放完一张图片后等待41ms
            cv2.waitKey(int(1000/fps))#休眠一会,因为每秒播放24张图片,相当于放完一张图片后等待41ms
        #释放
        self.cap.release()

    def stop_action(self):
        if self.stop_flag == 0:
            self.stop_flag = 1
            self.stop_button.setIcon(QIcon('/home/pi/Documents/垃圾分类图片和视频/图标/播放.png'))
        else:
            self.stop_flag = 0
            self.stop_button.setIcon(QIcon('/home/pi/Documents/垃圾分类图片和视频/图标/暂停.png'))

    def next_action(self):
        self.bClose = True
        self.play_index = (self.play_index+1)%3
        self.bClose = False
        self.playVideoFile(self.fn_list[self.play_index])

    def start_drag(self):
        self.moving_flag = 1

    def drag_action(self):
        self.moving_flag = 0
        print('当前进度为%d,被拉动到的进度为%d'%(self.s1.value(), int(self.loop_flag/24)))
        if self.s1.value()!=int(self.loop_flag/24):
            print('当前进度为:'+str(self.s1.value()))
            self.loop_flag = self.s1.value()*24
            self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.loop_flag)

    def video_stop(self):
        self.bClose = True

    def manual_choose(self):#手动选择视频播放
        fn,_ = QFileDialog.getOpenFileName(self,'Open file','/home/pi/Documents/垃圾分类图片和视频/movie',"Video files (*.mp4 *.avi)")
        self.playVideoFile(fn)

    def auto_choose(self):#自动选择视频播放,如何自动视频播放?
        self.playVideoFile(self.fn_list[self.play_index])
    
    def settingSlider(self,maxvalue):
        self.s1.setMaximum(int(maxvalue/24))
        self.label_end.setText(self.int2time(maxvalue))

    def int2time(self,num):
        #每秒刷新24帧
        num = int(num/24)
        minute = int(num/60)
        second = num - 60*minute
        if minute < 10:
            str_minute = '0'+str(minute)
        else:
            str_minute = str(minute)
        if second < 10:
            str_second = '0'+str(second)
        else:
            str_second = str(second)
        return str_minute+":"+str_second

    def exit_stop(self):
        self.stop_flag = 0
        self.bClose = True
        self.close()

if __name__=="__main__":
    app = QApplication(sys.argv)
    form = PlayVideo()
    form.showFullScreen()
    sys.exit(app.exec_())

实现的效果:
Qt和OpenCV视频播放器,包括暂停以及播放下一个视频以及滑动条功能_第1张图片
缺陷:手动选择路径后按下一个可能不对应。

你可能感兴趣的:(UI界面,树莓派,qt,gui,opencv)