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
        self.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://live.hkstv.hk.lxdns.com/live/hks

  • 9
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 24
    评论
要使用 PyQt 结合 OpenCV 进行录制保存和播放视频,可以按照以下步骤进行: 1. 安装 PyQtOpenCV 库: ``` pip install PyQt5 pip install opencv-python ``` 2. 创建一个 PyQt 窗口,用于显示视频: ```python import sys from PyQt5.QtWidgets import QApplication, QWidget, QLabel from PyQt5.QtGui import QImage, QPixmap class VideoPlayer(QWidget): def __init__(self): super().__init__() self.label = QLabel(self) self.setGeometry(100, 100, 640, 480) self.show() ``` 3. 初始化 OpenCV 的摄像头,并将视频帧显示在 PyQt 窗口中: ```python import cv2 class VideoPlayer(QWidget): def __init__(self): super().__init__() self.label = QLabel(self) self.setGeometry(100, 100, 640, 480) self.show() self.cap = cv2.VideoCapture(0) self.timer = QTimer(self) self.timer.timeout.connect(self.update_frame) self.timer.start(50) def update_frame(self): ret, frame = self.cap.read() if ret: image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = image.shape bytes_per_line = ch * w convert_to_QtFormat = QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) p = convert_to_QtFormat.scaled(640, 480, Qt.KeepAspectRatio) self.label.setPixmap(QPixmap.fromImage(p)) ``` 4. 添加录制和保存视频的功能: ```python class VideoPlayer(QWidget): def __init__(self): super().__init__() self.label = QLabel(self) self.setGeometry(100, 100, 640, 480) self.show() self.cap = cv2.VideoCapture(0) self.timer = QTimer(self) self.timer.timeout.connect(self.update_frame) self.timer.start(50) self.recording = False self.video_writer = None def update_frame(self): ret, frame = self.cap.read() if ret: if self.recording: if self.video_writer is None: fourcc = cv2.VideoWriter_fourcc(*'MJPG') self.video_writer = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480)) self.video_writer.write(frame) image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = image.shape bytes_per_line = ch * w convert_to_QtFormat = QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) p = convert_to_QtFormat.scaled(640, 480, Qt.KeepAspectRatio) self.label.setPixmap(QPixmap.fromImage(p)) def keyPressEvent(self, event): if event.key() == Qt.Key_Space: self.recording = not self.recording if not self.recording and self.video_writer is not None: self.video_writer.release() self.video_writer = None ``` 5. 添加播放已保存视频的功能: ```python class VideoPlayer(QWidget): def __init__(self): super().__init__() self.label = QLabel(self) self.setGeometry(100, 100, 640, 480) self.show() self.cap = cv2.VideoCapture(0) self.timer = QTimer(self) self.timer.timeout.connect(self.update_frame) self.timer.start(50) self.recording = False self.video_writer = None self.playing = False self.video_capture = None def update_frame(self): ret, frame = self.cap.read() if ret: if self.recording: if self.video_writer is None: fourcc = cv2.VideoWriter_fourcc(*'MJPG') self.video_writer = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480)) self.video_writer.write(frame) image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = image.shape bytes_per_line = ch * w convert_to_QtFormat = QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) p = convert_to_QtFormat.scaled(640, 480, Qt.KeepAspectRatio) self.label.setPixmap(QPixmap.fromImage(p)) def keyPressEvent(self, event): if event.key() == Qt.Key_Space: self.recording = not self.recording if not self.recording and self.video_writer is not None: self.video_writer.release() self.video_writer = None elif event.key() == Qt.Key_P: self.playing = not self.playing if self.playing: self.video_capture = cv2.VideoCapture('output.avi') self.timer.stop() self.timer.timeout.connect(self.update_saved_frame) self.timer.start(1000//30) else: self.timer.stop() self.timer.timeout.connect(self.update_frame) self.timer.start(50) def update_saved_frame(self): ret, frame = self.video_capture.read() if ret: image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = image.shape bytes_per_line = ch * w convert_to_QtFormat = QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) p = convert_to_QtFormat.scaled(640, 480, Qt.KeepAspectRatio) self.label.setPixmap(QPixmap.fromImage(p)) ``` 完整的代码如下:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值