After the video has finished playing, or the QMediaPlayer stop() method has been called, artifacts occur in place of the video widget when the window is resized. Below is a screen shot of the artifacts: A minimal example of a program:
import sys
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QFileDialog, QSlider
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QVideoWidget
class Player(QMainWindow):
def __init__(self, parent=None):
super(Player, self).__init__(parent)
self.media_player = QMediaPlayer(self)
self.video_widget = QVideoWidget(self)
self.slider = QSlider(Qt.Horizontal)
self.open_button = QPushButton("Open Media File")
self.open_button.clicked.connect(self.open_file)
layout = QVBoxLayout()
layout.addWidget(self.video_widget)
layout.addWidget(self.open_button)
layout.addWidget(self.slider)
widget = QWidget(self)
widget.setLayout(layout)
self.setCentralWidget(widget)
self.media_player.setVideoOutput(self.video_widget)
self.media_player.positionChanged.connect(self.update_slider)
self.slider.sliderMoved.connect(self.set_position)
def open_file(self):
file_dialog = QFileDialog.getOpenFileName(self, "Open Media File")
if file_dialog[0]:
self.set_and_play_file(file_dialog[0])
def set_and_play_file(self, selected_file):
self.media_player.setMedia(QMediaContent(QUrl.fromLocalFile(selected_file)))
self.media_player.play()
def update_slider(self, position):
self.slider.setMaximum(int(self.media_player.duration() / 1000))
self.slider.setValue(int(position / 1000))
def set_position(self, position):
self.media_player.setPosition(int(position * 1000))
if __name__ == "__main__":
app = QApplication(sys.argv)
player = Player()
player.show()
sys.exit(app.exec_())
I tried monitoring the QMediaPlayer.EndOfMedia state and replacing the stop() method with the pause() method, and changing the player position to 0. This improved things to some extent, but eventually I ran into artifacts again and decided that there must be a way to get rid of this problem. I also tried setting
self.video_widget.setAttribute(Qt.WA_OpaquePaintEvent, False)
self.video_widget.setAutoFillBackground()
self.video_widget.setAttribute(Qt.WA_NoSystemBackground, True)
but that didn't produce any results. Plus I tried to predefine paintEvent()
in the video widget and draw a red line on the widget, but in the end, probably due to my lack of experience with QPainter, I failed and the red line was not drawn on the widget.
For now, I don't want to believe that this is a flaw in QMediaPlayer, and eventually I'll just have to accept it and look for more and more workarounds.
I am using: Windows 10 x64 1809, PyQt5 5.15.10
A conditional and, in my opinion, incomplete solution was a call to
at the beginning of the code. This code changes the default
DirectShow
toWindows Media Foundation
. This only works on Windows and has its drawbacks, but at least it solves my artifact problem.