PyQt 视频帧更新信号(每个视频帧后的触发函数)
Posted
技术标签:
【中文标题】PyQt 视频帧更新信号(每个视频帧后的触发函数)【英文标题】:PyQt video frame update signal (Trigger function after each video frame) 【发布时间】:2018-12-12 17:56:43 【问题描述】:我正在创建一个视频播放器,我需要在它上面绘制一些多边形。我正在使用 QGraphicsScene 来创建它,并且我需要在每一帧之后更新屏幕上的多边形。我目前正在使用与 QGraphicsVideoItem 配对的 QMediaPlayer 来创建它。我遇到的问题是 QMediaPlayer 没有在每一帧上激活的信号。它有 positionChanged(),但这似乎每秒触发一次。
我尝试使用 QMovie,因为它确实会在每一帧上发送更新,但它没有显示任何内容。这是我用来实现它的代码。
video_view = QGraphicsView()#view to hold video
video_item = QGraphicsVideoItem()#video item for scene
video_scene = QGraphicsScene()#scene for Qgraphics view
video_view.setScene(video_scene)
label = QLabel()
movie = QMovie(self.video_paths[index]) #contains file path
label.setMovie(movie)
video_scene.addWidget(label)
self.vlayout_main_video.addWidget(video_view)
我使用的视频文件是 .avi 文件,大小为 72Mb。
如果有人能指出我如何做到这一点的正确方向,我将不胜感激。我目前正在使用 PyQt5。
谢谢
【问题讨论】:
【参考方案1】:有两种选择:
positionChanged
每秒发出一次,因为 QMediaPlayer
的 notifyInterval
属性是在该期间设置的。因此,您可以更改该属性,例如更改为 60 毫秒。
from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia, QtMultimediaWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
self.video_view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(self.video_view)
self.player = QtMultimedia.QMediaPlayer(self, QtMultimedia.QMediaPlayer.VideoSurface)
self.video_item = QtMultimediaWidgets.QGraphicsVideoItem()
self.player.setVideoOutput(self.video_item)
scene.addItem(self.video_item)
file = "/path/of/video"
self.player.setMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(file)))
self.player.positionChanged.connect(self.on_positionChanged)
self.player.setNotifyInterval(60)
self.player.play()
@QtCore.pyqtSlot('qint64')
def on_positionChanged(self, p):
print(p, QtCore.QTime.currentTime().toString("hh:mm:ss.zzz"))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
使用来自QVideoProbe
的VideoFrameProbed
信号:
from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia, QtMultimediaWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
self.video_view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(self.video_view)
self.player = QtMultimedia.QMediaPlayer(self, QtMultimedia.QMediaPlayer.VideoSurface)
self.video_item = QtMultimediaWidgets.QGraphicsVideoItem()
self.player.setVideoOutput(self.video_item)
scene.addItem(self.video_item)
file = "/path/of/video"
self.player.setMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(file)))
self.player.play()
probe = QtMultimedia.QVideoProbe(self)
probe.videoFrameProbed.connect(self.on_videoFrameProbed)
probe.setSource(self.player)
@QtCore.pyqtSlot()
def on_videoFrameProbed(self):
print(QtCore.QTime.currentTime().toString("hh:mm:ss.zzz"))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
【讨论】:
感谢您的回答。它工作得很好。你知道是否有办法检查 on_videoFrameProbed 探测到的帧的索引吗?我一直在查看文档,但似乎找不到任何关于此的内容。 @MiguelKulisic 没有这样的属性,但可能的解决方案是创建一个索引并增加它。 这对我来说似乎很奇怪,但在我的情况下,它从来没有被称为 on_videoFrameProbed。这个例子仍然有效吗? @FranRaga 我现在已经对其进行了测试,它在 Linux 中可以正常工作。从终端或 CMD 执行您的应用程序,并告诉我是否收到任何消息,另一方面,您的操作系统是什么?第一个替代方案对您有用吗? @FranRaga 根据docs Directshow 有限制,您将无法使用 QVideoProbe。 目前不支持视频录制。此外,DirectShow 插件不支持任何低级视频功能,例如监控使用 QVideoProbe 或相关类播放或录制的视频帧。以上是关于PyQt 视频帧更新信号(每个视频帧后的触发函数)的主要内容,如果未能解决你的问题,请参考以下文章