任务是使用 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 和 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的学习! :)