High CPU usage in QGraphicsVideoItem
-
I am trying to simply play an MP4 video (1920x1080) using a QGraphicsVideoItem within a QGraphicsView, however, it consumes around 70% of CPU and after a while, it makes the application freeze! I tried the OpenGLWidget in the QGraphicsView to improve the performance but it did not make any noticeable difference!
While, if I substitute the QGraphicsView with a QVideoWidget, the CPU usage drastically drops to ~6%.
However, the problem is that I have to use the QGraphicsView to play the video because I need to draw some lines and texts over the video based on the user's mouse clicks.
My OS is macOS 10.15.7 and I am using PyQt5 version 5.15.2. I would appreciate it if someone please help me to know why there is such a difference between the performance of QVideoWidget and QGraphicsVideoItem.
Is there any particular setting in the QGraphicsVideoItem to improve its rendering performance?
It could help me to solve this problem. -
Am I correct in assuming that you override paint() in the class to add your drawing overlay? That would seem the most straightforward method to add drawing to the video frame.
Other option (I haven't tested) would be to use regular QVideoWidget and overlay a transparent background widget where you paint() the overlay primitives after display of each video frame.
And keep in mind that MP4 is a container format that could contain different codes, which may be hogs, especially with HD format video.
Just some thoughts.
-
Am I correct in assuming that you override paint() in the class to add your drawing overlay? That would seem the most straightforward method to add drawing to the video frame.
Other option (I haven't tested) would be to use regular QVideoWidget and overlay a transparent background widget where you paint() the overlay primitives after display of each video frame.
And keep in mind that MP4 is a container format that could contain different codes, which may be hogs, especially with HD format video.
Just some thoughts.
Hi @Kent-Dorfman , thanks for your reply.
In order to show the video, I am using a QGraphicsVideoItem added in a QGraphicsScene. So, the drawings are added in the same QGraphicsScene as QGraphicsItem. In this method, I do not override the paint(); everything including the rendering of drawings and video as well as the scaling of the drawings -when I resize the window- are managed by QGraphicsView.
Regarding using a regular QVideoWidget, I tried to override the paintEvent() of the QVideoWidget but it did not work! Because after playing the video, the graphics are obscured by the video. Also, I tried to put a transparent background QWidget over a QVideoWidget, but I did not manage to show the QWidget over the video! I think the point is that I did not override paint() in each video frame as you said. However, regarding that I am new in PyQt5 I would appreciate it if you please kindly help me to solve the problem.Besides, as for the MP4 format, is it required to take any particular action?
This is the sample code I used to show the video and overlaying a drawing. Reference: https://stackoverflow.com/questions/53899740/how-to-draw-qtgraphicsview-on-top-of-qvideowidget-with-transparency.
class Widget(QtWidgets.QWidget): def __init__(self, parent=None): super(Widget, self).__init__(parent) self._scene = QtWidgets.QGraphicsScene(self) self._gv = QtWidgets.QGraphicsView(self._scene) self._videoitem = QGraphicsVideoItem() self._scene.addItem(self._videoitem) self._line_item = QtWidgets.QGraphicsLineItem(0, 0, 320, 240, self._videoitem) self._line_item.setPen(QtGui.QPen(QtCore.Qt.red)) self._scene.addItem(self._line_item) self._player = QMediaPlayer(self, QMediaPlayer.VideoSurface) self._player.setVideoOutput(self._videoitem.videoSurface()) file = os.path.join(os.path.dirname(__file__), "GOPR0196.MP4") self._player.setMedia(QMediaContent(QtCore.QUrl.fromLocalFile(file))) button = QtWidgets.QPushButton("Play") button.clicked.connect(self.play) self.resize(640, 480) lay = QtWidgets.QVBoxLayout(self) lay.addWidget(self._gv) lay.addWidget(button) def play(self): oglWidget = QOpenGLWidget() self._gv.setViewport(oglWidget) if self._player.state() == QMediaPlayer.PlayingState: self._player.pause() else: self._player.play() if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) w = Widget() w.show() sys.exit(app.exec_())