Unsolved QGraphicsScene and QGraphicsVideoItem extreme high CPU use on Mac
-
Hi all,
Trying to do a pixmap overlay on video.
It works fine on Windows, but is extremely CPU hungry on Mac.
Then, depending on the video codec, I get black flashes.
Here is my stripped down code:from PyQt5 import QtWidgets, QtGui, QtCore, QtMultimediaWidgets, QtMultimedia from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtMultimedia import * from PyQt5.QtMultimediaWidgets import * import sys VIDEO_WIDTH = 1280 VIDEO_HEIGHT = 720 ######################################## # ######################################## class MyVideoView(QGraphicsView): def __init__(self, parent=None): super(QGraphicsView, self).__init__(parent) # self._main = parent self.setBackgroundBrush(Qt.black) self._scene = QGraphicsScene(self) self.setScene(self._scene) self._videoItem = QGraphicsVideoItem() self._videoItem.setPos(0, 0) self._videoItem.setSize(QSizeF(VIDEO_WIDTH, VIDEO_HEIGHT)) self._scene.addItem(self._videoItem) self._overlay = QPixmap(VIDEO_WIDTH, VIDEO_HEIGHT) self._overlay.fill(QColor(0, 150, 0, 150)) self._graphicsPixmapItem = self._scene.addPixmap(self._overlay) self._player = QMediaPlayer(self) self._player.setVideoOutput(self._videoItem) def loadVideo(self, fn): self._player.setMedia(QMediaContent(QUrl.fromLocalFile(fn))) self._player.play() class Video(QMainWindow): def __init__(self, parent=None): super(QMainWindow, self).__init__(parent) self.setWindowTitle("Video window") # self.setContentsMargins(-2, -2, -2, -2) # get rid of black lines around the vid self._splitter = QSplitter(Qt.Vertical) self.setCentralWidget(self._splitter) self._videoView = MyVideoView(self) self._splitter.addWidget(self._videoView) self._videoView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._videoView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.show() self._videoView.loadVideo('/Volumes/Data/videofiles/demo_BITC 2.mov') if __name__ == '__main__': app = QApplication(sys.argv) app.setQuitOnLastWindowClosed(True) w = Video() sys.exit(app.exec_())
What am I missing here?
Thx,
Bouke -
Hi and welcome to devnet,
What version of PyQt5 are you using ?
How did you install it ?
What version of macOS are you running ?
Can you tell what model is you machine ? -
Hi:
PyQt5 5.9.2, installed with Pip in a Python 3.6.8 venv
But just updated to 5.14.2, does not seem to make a difference.Running OS 10.15.4 on an Imac (Retina, quad core i5, Radeon Pro 555 2 GB)
Does that help?
-
I forgot, what video codec has issues ?
-
You did not forget, I did not told you :-)
H264 (x264) does play, although suffering from the high CPU consumption.
ProRes flickers (black frames alternating video frames).The CPU use increases when the window gets bigger.
I suspect there are too many updates or something like that, Qmediaplayer in a 'bare' surrounding does not have these issues.
-
Try using a QOpenGLWidget as viewport of your QGraphicsView.
-
@SGaist
Well, I would if I could, but I'm new to Python (and not a real coder, I'm coming from Adobe Director...)
Do you have any pointers?
thx, -
Something like:
my_scene.setViewport(new QGLWidget())
-
@SGaist
Ok, I've added to my QGraphicsView:self.widget = glWidget(self)
self.setViewport(self.widget)class glWidget(QGLWidget):
def init(self, parent=None):
QGLWidget.init(self, parent) -
that was send out too fast... (Can't I edit my own posts?)
CPU use is now reduced to a quarter of what it was before, so that's the good news.
The bad news is that the video is displayed twice too big. (Due to my Retina screen I think...) -
Dirty hack that sorta kinda fixes stuff:
from PyQt5 import QtWidgets, QtGui, QtCore, QtMultimediaWidgets, QtMultimedia from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtMultimedia import * from PyQt5.QtMultimediaWidgets import * import sys from PyQt5.QtOpenGL import * VIDEO_WIDTH = 1200 VIDEO_HEIGHT = int(VIDEO_WIDTH / 16 * 9)å ######################################## # ######################################## class MyVideoView(QGraphicsView): def __init__(self, parent=None): super(QGraphicsView, self).__init__(parent) # self._main = parent # 9% CPU use, rem out this to get high CPU use (depends on window size, up to 100%) self.widget = glWidget() self.setViewport(self.widget) self.setBackgroundBrush(Qt.black) self._scene = QGraphicsScene(self) self.setScene(self._scene) self._videoItem = QGraphicsVideoItem() # self._videoItem.setPos(0, 0) self._scene.addItem(self._videoItem) self._overlay = QPixmap(VIDEO_WIDTH, VIDEO_HEIGHT) self._overlay.fill(QColor(0, 150, 0, 150)) self._graphicsPixmapItem = self._scene.addPixmap(self._overlay) self._player = QMediaPlayer(self) self._player.setVideoOutput(self._videoItem) def loadVideo(self, fn): self._player.setMedia(QMediaContent(QUrl.fromLocalFile(fn))) self._player.play() # self._player.setPlaybackRate(0.5) class glWidget(QGLWidget): def __init__(self, parent=None): QGLWidget.__init__(self, parent) class Video(QMainWindow): def __init__(self, parent=None): super(QMainWindow, self).__init__(parent) self.setWindowTitle("Video window") self._splitter = QSplitter(Qt.Vertical) self.setCentralWidget(self._splitter) self._videoView = MyVideoView(self) self._splitter.addWidget(self._videoView) self._videoView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._videoView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.show() self._videoView.loadVideo('/Volumes/Data/videofiles/demo_BITC 2.mov') self.resizeEvent(False) def resizeEvent(self, e): # print(dir(QResizeEvent)) if not e: _w = self.geometry().width() _h = self.geometry().height() else: _w = e.size().width() _h = e.size().height() self._videoView._videoItem.setSize(QSizeF(_w / 2, _h / 2)) # do not get a feedback loop try: if self.ignorscaling: self.ignorscaling = False return except: pass self.ignorscaling = True # order of stuff is important here! self._videoView._videoItem.setSize(QSizeF(_w, _h)) _w = self._videoView._videoItem.sceneBoundingRect().right() _h = self._videoView._videoItem.sceneBoundingRect().bottom() - self._videoView._videoItem.sceneBoundingRect().top() self.resize(_w, _h) if __name__ == '__main__': app = QApplication(sys.argv) app.setQuitOnLastWindowClosed(True) w = Video() sys.exit(app.exec_())