PyQt5播放實時視頻流或本地視頻文件


編輯UI

編輯UI如下圖所示:

新建視頻播放類Display

定義如下初始化函數

def __init__(self, ui, mainWnd):
    self.ui = ui
    self.mainWnd = mainWnd

    # 默認視頻源為相機
    self.ui.radioButtonCam.setChecked(True)
    self.isCamera = True

    # 信號槽設置
    ui.Open.clicked.connect(self.Open)
    ui.Close.clicked.connect(self.Close)
    ui.radioButtonCam.clicked.connect(self.radioButtonCam)
    ui.radioButtonFile.clicked.connect(self.radioButtonFile)

    # 創建一個關閉事件並設為未觸發
    self.stopEvent = threading.Event()
    self.stopEvent.clear()

打開相機

防止UI卡死,需要單獨用一個線程去顯示視頻,可以選中打開相機還是打開本機mp4文件。

    def Open(self):
        if not self.isCamera:
            self.fileName, self.fileType = QFileDialog.getOpenFileName(self.mainWnd, 'Choose file', '', '*.mp4')
            self.cap = cv2.VideoCapture(self.fileName)
            self.frameRate = self.cap.get(cv2.CAP_PROP_FPS)
        else:
            # 下面兩種rtsp格式都是支持的
            # cap = cv2.VideoCapture("rtsp://admin:Supcon1304@172.20.1.126/main/Channels/1")
            self.cap = cv2.VideoCapture("rtsp://admin:Supcon1304@172.20.1.126:554/h264/ch1/main/av_stream")

        # 創建視頻顯示線程
        th = threading.Thread(target=self.Display)
        th.start()

關閉相機

啟動線程可以直接調用start(),但是結束線程並沒有現成的接口可以調用。

添加一個事件用來判斷是否需要關閉相機

def Close():
    # 關閉事件設為觸發,關閉視頻播放
    stopEvent.set()

顯示視頻畫面

注意:

  1. OpenCV獲得的圖像幀數據是RGB格式,QImage是BGR格式,所以需要進行格式轉換;
  2. 每次顯示完成后都去判斷是否點擊了關閉按鈕。
    def Display(self):
        self.ui.Open.setEnabled(False)
        self.ui.Close.setEnabled(True)

        while self.cap.isOpened():
            success, frame = self.cap.read()
            # RGB轉BGR
            frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
            img = QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
            self.ui.DispalyLabel.setPixmap(QPixmap.fromImage(img))

            if self.isCamera:
                cv2.waitKey(1)
            else:
                cv2.waitKey(int(1000 / self.frameRate))

            # 判斷關閉事件是否已觸發
            if True == self.stopEvent.is_set():
                # 關閉事件置為未觸發,清空顯示label
                self.stopEvent.clear()
                self.ui.DispalyLabel.clear()
                self.ui.Close.setEnabled(False)
                self.ui.Open.setEnabled(True)
                break

完整源代碼

文件VideoDisplay.py


import cv2
import threading
from PyQt5.QtCore import QFile
from PyQt5.QtWidgets import QFileDialog, QMessageBox
from PyQt5.QtGui import QImage, QPixmap

class Display:
    def __init__(self, ui, mainWnd):
        self.ui = ui
        self.mainWnd = mainWnd

        # 默認視頻源為相機
        self.ui.radioButtonCam.setChecked(True)
        self.isCamera = True

        # 信號槽設置
        ui.Open.clicked.connect(self.Open)
        ui.Close.clicked.connect(self.Close)
        ui.radioButtonCam.clicked.connect(self.radioButtonCam)
        ui.radioButtonFile.clicked.connect(self.radioButtonFile)

        # 創建一個關閉事件並設為未觸發
        self.stopEvent = threading.Event()
        self.stopEvent.clear()

    def radioButtonCam(self):
        self.isCamera = True

    def radioButtonFile(self):
        self.isCamera = False

    def Open(self):
        if not self.isCamera:
            self.fileName, self.fileType = QFileDialog.getOpenFileName(self.mainWnd, 'Choose file', '', '*.mp4')
            self.cap = cv2.VideoCapture(self.fileName)
            self.frameRate = self.cap.get(cv2.CAP_PROP_FPS)
        else:
            # 下面兩種rtsp格式都是支持的
            # cap = cv2.VideoCapture("rtsp://admin:Supcon1304@172.20.1.126/main/Channels/1")
            self.cap = cv2.VideoCapture("rtsp://admin:Supcon1304@172.20.1.126:554/h264/ch1/main/av_stream")

        # 創建視頻顯示線程
        th = threading.Thread(target=self.Display)
        th.start()

    def Close(self):
        # 關閉事件設為觸發,關閉視頻播放
        self.stopEvent.set()

    def Display(self):
        self.ui.Open.setEnabled(False)
        self.ui.Close.setEnabled(True)

        while self.cap.isOpened():
            success, frame = self.cap.read()
            # RGB轉BGR
            frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
            img = QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
            self.ui.DispalyLabel.setPixmap(QPixmap.fromImage(img))

            if self.isCamera:
                cv2.waitKey(1)
            else:
                cv2.waitKey(int(1000 / self.frameRate))

            # 判斷關閉事件是否已觸發
            if True == self.stopEvent.is_set():
                # 關閉事件置為未觸發,清空顯示label
                self.stopEvent.clear()
                self.ui.DispalyLabel.clear()
                self.ui.Close.setEnabled(False)
                self.ui.Open.setEnabled(True)
                break

文件main.py


import sys
import DisplayUI
from PyQt5.QtWidgets import QApplication, QMainWindow
from VideoDisplay import Display

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWnd = QMainWindow()
    ui = DisplayUI.Ui_MainWindow()

    # 可以理解成將創建的 ui 綁定到新建的 mainWnd 上
    ui.setupUi(mainWnd)

    display = Display(ui, mainWnd)

    mainWnd.show()

    sys.exit(app.exec_())

效果圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM