如何使用 PyQt5 QtMultimedia 从 IP 摄像机流式传输视频?

问题描述 投票:0回答:1

任务是使用 PyQt5 框架中的 QtMultimedia 从 5 个 IP 摄像机传输图像。最初我尝试使用OpenCV,但是5个视频流的并行播放降低了fps。我们决定尝试 QtMultimedia 以尝试提高性能。

首先,我尝试连接 1-2 个摄像头并进一步扩展此解决方案。相机名称:D-Link DCS-931L。我通过 tp-link 将相机连接到网络。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QMainWindow, QMessageBox, QPushButton
from PyQt5.QtMultimedia import QCamera, QCameraInfo
from PyQt5.QtMultimediaWidgets import QCameraViewfinder
from PyQt5.QtCore import QUrl


class DualCameraApp(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Dual Camera App')
        self.setGeometry(100, 100, 800, 600)

        self.camera1 = QCamera(QCameraInfo.defaultCamera())
        #self.camera2 = QCamera(QCameraInfo.availableCameras()[1])

        self.viewfinder1 = QCameraViewfinder()
        #self.viewfinder2 = QCameraViewfinder()

        self.camera1.setViewfinder(self.viewfinder1)
        #self.camera2.setViewfinder(self.viewfinder2)

        self.camera1.start()
        #self.camera2.start()


        layout = QVBoxLayout()
        layout.addWidget(self.viewfinder1)
        #layout.addWidget(self.viewfinder2)
        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = DualCameraApp()
    window.show()
    sys.exit(app.exec_())

我使用 Camera 类来处理相机。我使用 QCameraInfo 类来连接相机。它具有 defaultCamera() 和可用的 Cameras() 方法。第一种方法给出默认的系统摄像头,第二种方法给出系统中的摄像头列表。

问题:这些方法不允许访问网络摄像机。总的来说,我只能连接到笔记本电脑中的相机。

然后我能够获得视频流的链接并尝试使用该链接进行连接。

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QCamera
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtCore import QUrl


class VideoPlayer(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("IP Camera Video Stream")
        self.setGeometry(100, 100, 800, 600)

        video_widget = QVideoWidget()
        layout = QVBoxLayout()
        layout.addWidget(video_widget)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.media_player = QMediaPlayer(self, QMediaPlayer.VideoSurface)
        self.media_player.setVideoOutput(video_widget)

        # http://IP/h264.flv - with sound?
        url = "http://admin:[email protected]/video.cgi"
        self.media_content = QMediaContent(QUrl(url))
        self.media_player.setMedia(self.media_content)
        self.media_player.play()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    player = VideoPlayer()
    player.show()
    sys.exit(app.exec_())

但也没有成功。在输出中,我得到一个没有视频流的空窗口。

请帮我解决一下。

更新:

我尝试在 PyQt6 中重写代码

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PyQt6.QtMultimedia import QMediaPlayer
from PyQt6.QtMultimediaWidgets import QVideoWidget
from PyQt6.QtCore import QUrl


class VideoPlayer(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("IP Camera Video Stream")
        self.setGeometry(100, 100, 800, 600)

        video_widget = QVideoWidget()
        layout = QVBoxLayout()
        layout.addWidget(video_widget)

        self.container = QWidget()
        self.container.setLayout(layout)
        self.setCentralWidget(self.container)

        url = "rtsp://admin:[email protected]/play1.sdp"
        self.media_player = QMediaPlayer(self)
        self.media_player.setSource(QUrl(url))
        self.video_widget = QVideoWidget()
        self.media_player.setVideoOutput(self.video_widget)
        # self.video_widget.show()
        self.media_player.play()



if __name__ == '__main__':
    app = QApplication(sys.argv)
    player = VideoPlayer()
    player.show()
    sys.exit(app.exec())
python pyqt pyqt5 webcam qtmultimedia
1个回答
0
投票

要使用 Python 和 OpenCV 在 YouTube 上流式传输视频(在本示例中,不显示如何处理音频),您只需使用 OpenCV 将帧捕获为 NumPy 数组,然后通过子进程将它们传递给 ffmpeg 以创建管道。具体方法如下:

Capture Video with OpenCV: Use OpenCV to capture frames from a video source.

Process Frames: Optionally, process or modify frames as needed.

Use ffmpeg via Subprocess: Use Python’s subprocess module to invoke ffmpeg, passing frames through a pipe.

以下是该过程的基本概要:

import cv2
import subprocess


class VideoStreamer:
    def __init__(self, resolution, fps, rtmp_url):
        self.resolution = resolution
        self.fps = fps
        self.rtmp_url = rtmp_url
        self.streaming = False
        self.command = [
            'ffmpeg',
            '-re',
            '-f', 'rawvideo',
            '-pix_fmt', 'bgr24',
            '-s', f'{resolution[0]}x{resolution[1]}',
            '-r', str(fps),
            '-i', '-',
            '-f', 'lavfi',
            '-i', 'anullsrc=channel_layout=stereo:sample_rate=44100',
            '-c:v', 'libx264',
            '-pix_fmt', 'yuv420p',
            '-x264-params', 'keyint=48:min-keyint=48:scenecut=-1',
            '-b:v', '4500k',
            '-b:a', '128k',
            '-ar', '44100',
            '-acodec', 'aac',
            '-vcodec', 'libx264',
            '-preset', 'medium',
            '-crf', '28',
            '-threads', '4',
            '-f', 'flv',
            self.rtmp_url
        ]

    def start(self):
        self.streaming = True
        self.pipe = subprocess.Popen(self.command, stdin=subprocess.PIPE)
        self.thread = threading.Thread(target=self.stream)
        self.thread.start()

    def stop(self):
        self.streaming = False
        self.thread.join()
        self.pipe.stdin.close()
        self.pipe.terminate()

    def stream(self):
        while self.streaming:
            if hasattr(self, 'frame'):
                self.pipe.stdin.write(self.frame.tobytes())

    def add_frame(self, frame):
        self.frame = frame


# Configura l'indirizzo RTMP di YouTube
rtmp_url = 'rtmp://a.rtmp.youtube.com/live2/YOUR_YOUTUBE_KEY'  # Sostituisci YOUR_STREAM_KEY con la tua chiave di streaming

# Configura i parametri di cattura della webcam
cap = cv2.VideoCapture(4)  # Usa 0 per la webcam predefinita

# Controlla se la webcam è aperta correttamente
if not cap.isOpened():
    print("Errore: impossibile aprire la webcam")
    exit()

# Ottieni le dimensioni del frame dalla webcam
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(cap.get(cv2.CAP_PROP_FPS))

# Inizializza il VideoStreamer
video_streamer = VideoStreamer((width, height), fps, rtmp_url)
video_streamer.start()

print("Iniziando lo streaming, premi 'q' per terminare")

try:
    while True:
        ret, frame = cap.read()
        if not ret:
            print("Errore: impossibile leggere un frame dalla webcam")
            break

        # Mostra il frame nella finestra (opzionale)
        cv2.imshow('Webcam', frame)

        # Aggiungi il frame al VideoStreamer
        video_streamer.add_frame(frame)

        # Esci se si preme 'q'
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
finally:
    # Rilascia le risorse
    cap.release()
    video_streamer.stop()
    cv2.destroyAllWindows()

我在 GitHub 上编写了一个小型视频混合器,网址为 https://github.com/AlessioMichelassi/openPyVision_013/。它仍在进行中,但您可以在那里找到很多代码。当然,我能写出来这要归功于musicamante和ellyanesc的学习! :)

© www.soinside.com 2019 - 2024. All rights reserved.