Сигнал обновления видеокадра PyQt (функция триггера после каждого видеокадра)

Я создаю видеоплеер, и мне нужно нарисовать поверх него несколько полигонов. Я использую QGraphicsScene для его создания, и мне нужно обновлять многоугольники на экране после каждого кадра. В настоящее время я использую QMediaPlayer в паре с QGraphicsVideoItem для его создания. Проблема, с которой я столкнулся, заключается в том, что 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 размером 72 МБ.

Я был бы очень признателен, если бы кто-нибудь указал мне в правильном направлении, как я могу это сделать. В настоящее время я использую PyQt5.

Спасибо


person Miguel Kulisic    schedule 12.12.2018    source источник


Ответы (1)


Есть 2 варианта:

  • positionChanged излучается каждую секунду, потому что свойство notifyInterval для QMediaPlayer установлено в этот период. Таким образом, вы можете изменить это свойство, например, на 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_())
  • Используйте сигнал VideoFrameProbed от QVideoProbe:

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_())
person eyllanesc    schedule 12.12.2018
comment
Спасибо за ответ. Работает отлично. Вы знаете, есть ли способ проверить индекс кадра, проверенного on_videoFrameProbed? Я просматривал документацию и, похоже, ничего не нашел по этому поводу. - person Miguel Kulisic; 13.12.2018
comment
@MiguelKulisic Такого свойства нет, но возможное решение - создать индекс и увеличить его. - person eyllanesc; 13.12.2018
comment
Мне это кажется странным, но в моем случае он никогда не вызывается on_videoFrameProbed. Этот пример все еще работает? - person Fran Raga; 14.05.2019
comment
@FranRaga Я его сейчас протестировал, и он корректно работает в Linux. Запустите свое приложение из терминала или CMD и скажите мне, если вы получите какое-либо сообщение, с другой стороны, какая у вас ОС? Вам подействовала первая альтернатива? - person eyllanesc; 15.05.2019
comment
из терминала покажи qt.multimedia.plugins.directshow: Unable to connect the video probe!, интересно. Я использую Windows 10 и QT версии 5.11.2. Не работает ни один пример, использующий QVideoProbe. Я хотел сделать тест по порядку звонков, но не могу заставить этот класс работать. Видео, если играет - person Fran Raga; 15.05.2019
comment
@FranRaga Согласно документам Directshow имеет ограничения, и вы будете не сможет использовать QVideoProbe. Запись видео в настоящее время не поддерживается. Кроме того, подключаемый модуль DirectShow не поддерживает какие-либо низкоуровневые функции видео, такие как мониторинг воспроизводимых или записываемых видеокадров с использованием QVideoProbe или связанных классов. - person eyllanesc; 15.05.2019
comment
Спасибо. Вижу, это вроде известная проблема! forum.qt. io / topic / 95260 / - person Fran Raga; 15.05.2019