我正在尝试处理QMediaPlayer
中的每个QVideoFrame
并将其显示在QLabel
上。
下面是示例代码。
QMediaPlayer
发送QVideoFrame
到QVideoSink
- 视频接收器发送帧到
MyWorker
。 MyWorker
将QVideoFrame
转换为QPixmap
,做一些处理后发送像素图给QLabel
。
from PySide6.QtCore import QObject, QUrl, Signal, Slot
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import QLabel, QApplication
from PySide6.QtMultimedia import QMediaPlayer, QVideoSink, QVideoFrame
import sys
import time
class MyWorker(QObject):
pixmapChanged = Signal(QPixmap)
@Slot(QVideoFrame)
def setVideoFrame(self, frame: QVideoFrame):
qimg = frame.toImage()
pixmap = QPixmap.fromImage(qimg)
time.sleep(0.5) # represents time-consuming work
self.pixmapChanged.emit(pixmap)
app = QApplication(sys.argv)
player = QMediaPlayer()
sink = QVideoSink()
worker = MyWorker()
widget = QLabel()
player.setVideoSink(sink)
sink.videoFrameChanged.connect(worker.setVideoFrame)
worker.pixmapChanged.connect(widget.setPixmap)
player.setSource(QUrl.fromLocalFile("my-video.mp4"))
widget.show()
player.play()
app.exec()
app.quit()
处理需要一些时间,因此标签更新速度比原始视频FPS慢。这很好,但问题是,我目前的代码没有QThread
阻塞了GUI。
使用player.moveToThread(...)
不起作用。我如何在单独的线程中运行QMediaPlayer
?
多亏了@musicamente,我通过将worker移动到单独的线程来修复它。
注意,只有当worker准备好了,窗口才会发送帧给worker。如果没有,阻塞的信号与QVideoFrame
实例一起排队,并迅速消耗所有内存。