Search code examples
pythonpyqtpyqt5media-player

PYQT 5 - I need to make a new window with video output (QMediaPlayer)


I need to make a new window for video output. It should have some buttons (which I'll add later), and a video output. I have the main window with audio playback capability, and I can make a video output on the main window, not the second one. The video check using magic.python executes videopop, which opens a new window (VideoWindow).

Code:

file: main.py

import sys

import magic
# bude obsahovat menu (File, Edit, About,...), Queue, v menu bude historie
from PyQt5.QtCore import QUrl, Qt
from PyQt5.QtGui import QPalette, QColor, QIcon
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, QFileDialog, QWidget, QLabel, QVBoxLayout, QHBoxLayout, \
    QPushButton, QStyle, QSlider
from ui import UI

class QueueWin(QMainWindow, UI):
    def __init__(self, *args, **kwargs):
        super(QueueWin, self).__init__(*args, **kwargs)
        self.ui(self)

        self.setWindowTitle('MPx')  # nastavi title
        self.setWindowIcon(QIcon('media-player-5.ico'))  # nastavi ikonku

        p = self.palette()
        p.setColor(QPalette.Window, QColor(52, 51, 51))  # nastavi barvu okna
        self.setPalette(p)  # aplikuje barvu

        self.open_file_act.triggered.connect(self.open_file)
        #self.history_act.triggered.connect(self.open_history)
        self.history_act.triggered.connect(self.videopop)
        #self.open_act.triggered.connect(self.clr_history)

        self.mediaPlayer.stateChanged.connect(self.mediastate_changed) #mení ikonku na tlačítku play
        self.mediaPlayer.positionChanged.connect(self.update_position)
        self.mediaPlayer.durationChanged.connect(self.duration_changed)

        self.slider.valueChanged.connect(self.mediaPlayer.setPosition)
        self.audioSlider.valueChanged.connect(self.mediaPlayer.setVolume)

    def open_history (self):
        h = History(self)
        h.show()

    def videopop(self):
        v = VideoWindow(self)
        v.show()

    def credits(self):
        w = Credits(self)
        w.show()

    def open_file(self):
        filename, _ = QFileDialog.getOpenFileName(self, "Open Video")

        if filename != '':
            self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(filename)))
            self.playBtn.setEnabled(True)
            self.mediaPlayer.play()
            mime = magic.Magic(mime=True)  # check zda je soubor video
            videocheck = mime.from_file(filename)

            if videocheck.find('video') != -1:
                self.videopop()
                print('it is video')

    def position_changed(self, position):
        self.slider.setValue(position)

    def duration_changed(self,duration):
        self.slider.setRange(0, duration)

    def update_position(self, position):
        self.slider.blockSignals(True)
        self.slider.setValue(position)
        self.slider.blockSignals(False)

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

        else:
            self.mediaPlayer.play()

    def mediastate_changed(self, state):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))

        else:
            self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))

class VideoWindow(QMainWindow, UI):
    def __init__(self, *args, **kwargs):
        super(VideoWindow, self).__init__(*args, **kwargs)
        self.videoui(self)
        self.setWindowTitle('Video') #nastavi title
        self.setWindowIcon(QIcon('media-player-5.ico')) #nastavi ikonku
        # http://www.iconseeker.com/search-icon/isabi/media-player-5.html   <-- odkaz na ikonku
        self.setGeometry(710, 290, 500, 500) #xMistoOtevreni, yMistoOtevreni, xVelikost, yVelikost
        self.setMinimumSize(400, 400) # xMinimalniVelikost, yMinimalniVelikost
        p = self.palette()
        p.setColor(QPalette.Window, QColor(52, 51, 51)) #nastavi barvu okna
        self.setPalette(p) #aplikuje barvu

class History(QMainWindow):
    def __init__(self, parent=None):
        super(History, self).__init__(parent)
        self.setWindowTitle('Historie')  # nastavi title
        self.setWindowIcon(QIcon('media-player-5.ico'))  # nastavi ikonku
        # http://www.iconseeker.com/search-icon/isabi/media-player-5.html   <-- odkaz na ikonku
        self.setGeometry(710, 290, 500, 200)  # xMistoOtevreni, yMistoOtevreni, xVelikost, yVelikost
        self.setMinimumSize(200, 200)  # xMinimalniVelikost, yMinimalniVelikost

        p = self.palette()
        p.setColor(QPalette.Window, QColor(52, 51, 51))  # nastavi barvu okna
        self.setPalette(p)  # aplikuje barvu

class Credits(QMainWindow):
    def __init__(self, parent=None):
        super(Credits, self).__init__(parent)
        self.setWindowTitle('O programu')  # nastavi title
        self.setWindowIcon(QIcon('media-player-5.ico'))  # nastavi ikonku
        # http://www.iconseeker.com/search-icon/isabi/media-player-5.html   <-- odkaz na ikonku
        self.setGeometry(710, 290, 500, 200)  # xMistoOtevreni, yMistoOtevreni, xVelikost, yVelikost
        self.setMinimumSize(200, 200)  # xMinimalniVelikost, yMinimalniVelikost

        p = self.palette()
        p.setColor(QPalette.Window, QColor(52, 51, 51))  # nastavi barvu okna
        self.setPalette(p)  # aplikuje barvu

        self.label = QLabel('Autor: Tomáš Gabriel, 3.B OAUH<br>Napsáno pomocí Pythonu a PyQt5', self)
        self.label.setStyleSheet("color: yellow")
        self.label.adjustSize()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWin = QueueWin()
    mainWin.show()
    sys.exit(app.exec_())

file: UI.py

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtMultimedia import QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import QPushButton, QSlider, QStyle, QHBoxLayout, QVBoxLayout, QMenuBar


class UI(object):
    def ui(self, QueueWin):
        QueueWin.setObjectName("QueueWin")
        QueueWin.resize(600, 500)
        _translate = QtCore.QCoreApplication.translate
        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.centralWidget = QtWidgets.QWidget(QueueWin)
        #sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
        #sizePolicy.setHorizontalStretch(0)
        #sizePolicy.setVerticalStretch(0)
        #sizePolicy.setHeightForWidth(self.centralWidget.sizePolicy().hasHeightForWidth())
        #self.centralWidget.setSizePolicy(sizePolicy)



        self.openFileBtn = QPushButton("Otevrit soubor...", self.centralWidget)
        self.openFileBtn.clicked.connect(self.open_file)

        self.playBtn = QPushButton(self.centralWidget)  # vytvori tlacitko "play"
        self.playBtn.setEnabled(False)
        self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.playBtn.clicked.connect(self.play_video)

        self.slider = QSlider(Qt.Horizontal, self.centralWidget)  # vytvori slider
        self.slider.setRange(0, 0)

        self.audioSlider = QSlider(Qt.Horizontal, self.centralWidget)
        self.audioSlider.setMaximum(100)
        self.audioSlider.setProperty("value", 100)

        QueueWin.setCentralWidget(self.centralWidget)

        # self.queue = QListView(self)
        # self.queue.setAcceptDrops(True)
        # self.queue.setAlternatingRowColors(True)

        self.hbox = QHBoxLayout(self.centralWidget)  # umisti tlacitka, slidery,... do UI
        self.hbox.setContentsMargins(11, 11, 11, 11)
        self.hbox.addWidget(self.openFileBtn)
        self.hbox.addWidget(self.playBtn)
        self.hbox.addWidget(self.slider)
        self.hbox.addWidget(self.audioSlider)

        self.vbox = QVBoxLayout(self.centralWidget)
        #self.vbox.addWidget(videowidget)
        # vbox.addWidget(self.queue)
        self.vbox.addLayout(self.hbox)
        #self.mediaPlayer.setVideoOutput(videowidget)

        #self.mediaPlayer.positionChanged.connect(self.update_position)
        #self.mediaPlayer.durationChanged.connect(self.duration_changed)


        self.menuBar = QMenuBar(QueueWin)
        QueueWin.setMenuBar(self.menuBar)

        self.open = QtWidgets.QMenu(self.menuBar)
        self.open_file_act = QtWidgets.QAction(QueueWin)
        self.open.addAction(self.open_file_act)
        self.open_file_act.setText(_translate("QueueWin", "Otevřít..."))
        self.menuBar.addAction(self.open.menuAction())
        self.open.setTitle(_translate("QueueWin", "Soubor"))

        self.history = QtWidgets.QMenu(self.menuBar)
        self.history_act = QtWidgets.QAction(QueueWin)
        self.history.addAction(self.history_act)
        self.history_act.setText(_translate("QueueWin", "Otevřít historii"))
        self.menuBar.addAction(self.history.menuAction())
        self.history.setTitle(_translate("QueueWin", "Historie"))

        self.historyClr_act = QtWidgets.QAction(QueueWin)
        self.history.addAction(self.historyClr_act)
        self.historyClr_act.setText(_translate("QueueWin", "Vymazat historii"))
        self.historyClr_act.setShortcut('ALT+H')

        #about = self.menuBar.addMenu('Autor')
        #about_act = QAction('O autorovi...', self)
        #about_act.setShortcut('CTRL+A')
        #about_act.triggered.connect(lambda: self.credits())
        #about.addAction(about_act)

        QtCore.QMetaObject.connectSlotsByName(QueueWin)

    def videoui(self, VideoWindow):
        VideoWindow.setObjectName("QueueWin")
        VideoWindow.resize(600, 500)
        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.centralWidget = QtWidgets.QWidget(VideoWindow)
        self.videowidget = QVideoWidget(self.centralWidget)
        VideoWindow.setCentralWidget(self.centralWidget)
        self.hbox = QHBoxLayout(self.centralWidget)  # umisti tlacitka, slidery,... do UI
        self.hbox.setContentsMargins(11, 11, 11, 11)
        self.hbox.addWidget(self.videowidget)
        self.vbox = QVBoxLayout(self.centralWidget)
        self.vbox.addLayout(self.hbox)

        QtCore.QMetaObject.connectSlotsByName(VideoWindow)

Solution

  • You're not setting the video output, and the QMediaPlayer in VideoWindow is completely useless (so you can remove that), while you should use the one created for QueueWin and set the video output with the QVideoWidget of the other window.

    The "basic" solution would be the following:

               if videocheck.find('video') != -1:
                    videoWindow = VideoWindow(self)
                    self.mediaPlayer.setVideoOutput(videoWindow.videowidget)
                    videoWindow.show()
    

    Be aware, though, that your code has some important issues that would require fixing.

    First of all, files generated by the pyuic utility should never, ever be manually modified (read how to properly use those files in the official guidelines about using Designer).

    Then, while technically working, creating a new QMainWindow with another one as parent is not suggested; you also continuously create a new window everytime the function is called, while you should reuse any existing window. A more proper approach would be to create the child windows when creating the main one, and show them when required, in this way you can already set up the video output for the separate video widget.
    Also note that you don't need to use an external module to check if the media actually has video: just use the videoAvailableChanged signal and show the video window if the argument is True (you cannot just check isVideoAvailable() right after setMedia(), as that function is asynchronous).

    Finally, if you're not using any of the QMainWindow features (menu, toolbars, dock widgets, status bar), just use a basic QWidget instead.