【转】pyqt5+opencv实现视频播放组件,支持实时流

pyqt5+opencv实现视频播放

详细源码链接为:https://github.com/2500284064/pyqt5-opencv-video 
基本原理是通过 VideoCapture 类读取视频源的每一帧数据,将数据转化为图片展示在QWidget中

(pyqt5网上资料太少,一开始查到用 vlc 做视频控件,走了很多弯路,后面发现 opencv 用来做视频控件更方便,而且opencv 的功能更加全面)

直接贴代码

import time 
import sys 
 
from PyQt5.QtCore import * 
from PyQt5.QtGui import * 
from PyQt5.QtWidgets import * 
from cv2 import * 
 
 
class VideoBox(QWidget): 
 
    VIDEO_TYPE_OFFLINE = 0 
    VIDEO_TYPE_REAL_TIME = 1 
 
    STATUS_INIT = 0 
    STATUS_PLAYING = 1 
    STATUS_PAUSE = 2 
 
    video_url = "" 
 
    def __init__(self, video_url="", video_type=VIDEO_TYPE_OFFLINE, auto_play=False): 
        QWidget.__init__(self) 
        self.video_url = video_url 
        self.video_type = video_type  # 0: offline  1: realTime 
        self.auto_play = auto_play 
        selfself.status = self.STATUS_INIT  # 0: init 1:playing 2: pause 
 
        # 组件展示 
        self.pictureLabel = QLabel() 
        init_image = QPixmap("../assets/images/no_video.jpeg").scaled(self.width(), self.height()) 
        self.pictureLabel.setPixmap(init_image) 
 
        self.playButton = QPushButton() 
        self.playButton.setEnabled(True) 
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) 
        self.playButton.clicked.connect(self.switch_video) 
 
        control_box = QHBoxLayout() 
        control_box.setContentsMargins(0, 0, 0, 0) 
        control_box.addWidget(self.playButton) 
 
        layout = QVBoxLayout() 
        layout.addWidget(self.pictureLabel) 
        layout.addLayout(control_box) 
 
        self.setLayout(layout) 
 
        # timer 设置 
        self.timer = VideoTimer() 
        self.timer.timeSignal.signal[str].connect(self.show_video_images) 
 
        # video 初始设置 
        self.playCapture = VideoCapture() 
        if self.video_url != "": 
            self.playCapture.open(self.video_url) 
            fps = self.playCapture.get(CAP_PROP_FPS) 
            self.timer.set_fps(fps) 
            self.playCapture.release() 
            if self.auto_play: 
                self.switch_video() 
            # self.videoWriter = VideoWriter('*.mp4', VideoWriter_fourcc('M', 'J', 'P', 'G'), self.fps, size) 
 
    def reset(self): 
        self.timer.stop() 
        self.playCapture.release() 
        self.status = VideoBox.STATUS_INIT 
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) 
 
    def show_video_images(self): 
        if self.playCapture.isOpened(): 
            success, frame = self.playCapture.read() 
            if success: 
                height, width = frame.shape[:2] 
                if frame.ndim == 3: 
                    rgb = cvtColor(frame, COLOR_BGR2RGB) 
                elif frame.ndim == 2: 
                    rgb = cvtColor(frame, COLOR_GRAY2BGR) 
 
                temp_image = QImage(rgb.flatten(), width, height, QImage.Format_RGB888) 
                temp_pixmap = QPixmap.fromImage(temp_image) 
                self.pictureLabel.setPixmap(temp_pixmap) 
            else: 
                print("read failed, no frame data") 
                success, frame = self.playCapture.read() 
                if not success and self.video_type is VideoBox.VIDEO_TYPE_OFFLINE: 
                    print("play finished")  # 判断本地文件播放完毕 
                    self.reset() 
                    self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) 
                return 
        else: 
            print("open file or capturing device error, init again") 
            self.reset() 
 
    def switch_video(self): 
        if self.video_url == "" or self.video_url is None: 
            return 
        if self.status is VideoBox.STATUS_INIT: 
            self.playCapture.open(self.video_url) 
            self.timer.start() 
            self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) 
        elif self.status is VideoBox.STATUS_PLAYING: 
            self.timer.stop() 
            if self.video_type is VideoBox.VIDEO_TYPE_REAL_TIME: 
                self.playCapture.release() 
            self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) 
        elif self.status is VideoBox.STATUS_PAUSE: 
            if self.video_type is VideoBox.VIDEO_TYPE_REAL_TIME: 
                self.playCapture.open(self.video_url) 
            self.timer.start() 
            self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) 
 
        self.status = (VideoBox.STATUS_PLAYING, 
                       VideoBox.STATUS_PAUSE, 
                       VideoBox.STATUS_PLAYING)[self.status] 
 
 
class Communicate(QObject): 
 
    signal = pyqtSignal(str) 
 
 
class VideoTimer(QThread): 
 
    def __init__(self, frequent=20): 
        QThread.__init__(self) 
        self.stopped = False 
        self.frequent = frequent 
        self.timeSignal = Communicate() 
        self.mutex = QMutex() 
 
    def run(self): 
        with QMutexLocker(self.mutex): 
            self.stopped = False 
        while True: 
            if self.stopped: 
                return 
            self.timeSignal.signal.emit("1") 
            time.sleep(1 / self.frequent) 
 
    def stop(self): 
        with QMutexLocker(self.mutex): 
            self.stopped = True 
 
    def is_stopped(self): 
        with QMutexLocker(self.mutex): 
            return self.stopped 
 
    def set_fps(self, fps): 
        self.frequent = fps 
 
 
if __name__ == "__main__": 
   app = QApplication(sys.argv) 
   box = VideoBox("home.mp4") 
   box.show() 
   sys.exit(app.exec_()) 

通过timer根据帧率不停的触发 show_video_images 方法, 读取到每一帧数据,将其展示在QLabel中。

本代码支持实时流,本地视频 和 远程视频文件,如需要测试实时流的播放,将视频 video_url 替换为:rtmp://58.200.131.2:1935/livetv/cctv1

 

 

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liuyuinsdu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值