PyQt5 Video Player with QMediaPlayer

This article explains how to make a Video Player in PyQt5.

One of PyQt5’s most unique widgets (in my opinion anyway) is the QMediaPlayer with it’s ability to display videos in a PyQt5 GUI. Since it’s a pretty complex task, you’ll need other classes and widgets from the QMultimedia class (we’ll explain all these).

In any case, it’s cool to know how to so that’s something. It looks pretty good and modern looking too so that’s another bonus. By the end of this article we’ll show you an implementation that looks almost as good as fully fledged Video players like VLC.

In the event that the Video does not load and play correctly, there must be an Issue with your Graphic drivers or something similar. I experienced issues on my Laptop (an APU) with an AMD Vega graphic card, so I switch over to my PC which had an NVIDIA card and it worked just fine.


Playing Videos in PyQt5

In this section we’ll discuss how to get a simple video player up and running. It’s a very bare bone video player with only the ability to play/pause videos and select a file.

Clicking the play button once will start the Video and clicking it again will pause the Video.

from PyQt5.QtCore import QDir, Qt, QUrl
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import (QMainWindow, QWidget, QPushButton, QApplication,
                             QLabel, QFileDialog, QStyle, QVBoxLayout)
import sys

class VideoPlayer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PyQt5 Video Player") 

        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        videoWidget = QVideoWidget()

        self.playButton = QPushButton()
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.playButton.clicked.connect(self.play)

        self.openButton = QPushButton("Open Video")   
        self.openButton.clicked.connect(self.openFile)

        widget = QWidget(self)
        self.setCentralWidget(widget)

        layout = QVBoxLayout()
        layout.addWidget(videoWidget)
        layout.addWidget(self.openButton)
        layout.addWidget(self.playButton)

        widget.setLayout(layout)
        self.mediaPlayer.setVideoOutput(videoWidget)

    def openFile(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie",
                QDir.homePath())

        if fileName != '':
            self.mediaPlayer.setMedia(
                    QMediaContent(QUrl.fromLocalFile(fileName)))

    def play(self):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()


app = QApplication(sys.argv)
videoplayer = VideoPlayer()
videoplayer.resize(640, 480)
videoplayer.show()
sys.exit(app.exec_())

It’s alot of code, so we’ll try explaining it line by line. For explanations regarding the non-Video Player code, please refer to our PyQt5 tutorial series where all other widgets are explained.

        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        videoWidget = QVideoWidget()

In the first line we create our MediaPlayer object by passing the required parameters in QMediaPlayer. In the second we create a video widget using QVideoWidget.

self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.playButton.clicked.connect(self.play)

The first line is actually an optional one simply for the “look” of the “play button we’ll be creating. This line gives it that special triangular icon that all play buttons have. The second line connects the button to the play function. More on the play function later.

        self.openButton = QPushButton("Open Video")   
        self.openButton.clicked.connect(self.openFile)

This the “open button” which will allow the user to select a video of his choice from his computer. We connect this button to the function called openFile where the File dialog code is stored.

    self.mediaPlayer.setVideoOutput(videoWidget)

Remember that video widget we created earlier? We need to pass that into our MediaPlayer Video output function. Imagine a QMediaPlayer as the actual supporting software around the video, and the QVideoWidget is the actual PyQt5 video output.

    def openFile(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie",
                QDir.homePath())

        if fileName != '':
            self.mediaPlayer.setMedia(
                    QMediaContent(QUrl.fromLocalFile(fileName)))

This function is responsible for creating a File Dialog which allows the user to pick a local video file from his computer. The filepath of the video file is returned which we will be using to set the QMediaContent. The setMedia() function is used to insert the MediaContent into the MediaPlayer object you created.

    def play(self):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()

The play function is pretty simple. If the Video is not playing, the Video will begin once the play function is called. If the Video is playing, the play function will pause the video.

You could make this even simpler if you wanted by removing the play button and the file dialog. However, this would come at the cost of two things. The loss of the ability to play and pause at will and the ability to select the file to be played.

There’s no (significant) limit to the size of the video that you load up, as I tested a full length (2 hours 20 min) movie with QMediaPlayer and it worked perfectly.


Full Video Player in PyQt5

Below is the full implementation of a proper Video Player in PyQt5. There is only really one big change, which is the addition of a slider bar. Changing the position of this Slider will change the current scene playing on the Screen, just like a regular video player.

Another change is the addition of an error handling system. In the event the Video File you loaded was unable to run or some error occurred, an error message will display.

from PyQt5.QtCore import QDir, Qt, QUrl
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import (QApplication, QFileDialog, QHBoxLayout, QLabel,
        QPushButton, QSizePolicy, QSlider, QStyle, QVBoxLayout, QWidget)
from PyQt5.QtWidgets import QMainWindow,QWidget, QPushButton, QAction
from PyQt5.QtGui import QIcon
import sys

class VideoPlayer(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PyQt5 Video Player") 

        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)

        videoWidget = QVideoWidget()

        self.playButton = QPushButton()
        self.playButton.setEnabled(False)
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.playButton.clicked.connect(self.play)

        self.positionSlider = QSlider(Qt.Horizontal)
        self.positionSlider.setRange(0, 0)
        self.positionSlider.sliderMoved.connect(self.setPosition)

        self.error = QLabel()
        self.error.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)

        openButton = QPushButton("Open Video")   
        openButton.setToolTip("Open Video File")
        openButton.setStatusTip("Open Video File")
        openButton.setFixedHeight(24)
        openButton.clicked.connect(self.openFile)


        # Create a widget for window contents
        wid = QWidget(self)
        self.setCentralWidget(wid)

        # Create layouts to place inside widget
        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(self.playButton)
        controlLayout.addWidget(self.positionSlider)

        layout = QVBoxLayout()
        layout.addWidget(videoWidget)
        layout.addLayout(controlLayout)
        layout.addWidget(self.error)
        layout.addWidget(openButton)

        # Set widget to contain window contents
        wid.setLayout(layout)

        self.mediaPlayer.setVideoOutput(videoWidget)
        self.mediaPlayer.stateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)
        self.mediaPlayer.error.connect(self.handleError)

    def openFile(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Open Movie",
                QDir.homePath())

        if fileName != '':
            self.mediaPlayer.setMedia(
                    QMediaContent(QUrl.fromLocalFile(fileName)))
            self.playButton.setEnabled(True)

    def exitCall(self):
        sys.exit(app.exec_())

    def play(self):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()

    def mediaStateChanged(self, state):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.playButton.setIcon(
                    self.style().standardIcon(QStyle.SP_MediaPause))
        else:
            self.playButton.setIcon(
                    self.style().standardIcon(QStyle.SP_MediaPlay))

    def positionChanged(self, position):
        self.positionSlider.setValue(position)

    def durationChanged(self, duration):
        self.positionSlider.setRange(0, duration)

    def setPosition(self, position):
        self.mediaPlayer.setPosition(position)

    def handleError(self):
        self.playButton.setEnabled(False)
        self.error.setText("Error: " + self.mediaPlayer.errorString())


app = QApplication(sys.argv)
videoplayer = VideoPlayer()
videoplayer.resize(640, 480)
videoplayer.show()
sys.exit(app.exec_())

An screen shot from a movie that I tested in QMediaPlayer.

PyQt5 Video Player

This marks the end of the PyQt5 Video Player with QMediaPlayer article. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the article content can be asked in the comments section below.

Subscribe
Notify of
guest
3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments