Search code examples
pythonpython-vlc

Python window doesn't close after video ended


I'm currently making a code that will do various things such as controlling motors etc but at one point I need to code to popup a video on vlc and exit the window when the video ended, the problem is that the window currently stays after the video ended and the whole code just freezes and I can't do anything past the video

I tried various things such as calculating the video length and call a self.close() when the timer hit but still the same thing

I also tried adding "--play-and-exit" to the vlc parameters but it still won't budge...

Here's the code if someone knows how to do it properly !

import PySimpleGUI as sg

import os
import sys
import platform
import time
from time import sleep
from PyQt5.QtCore import (QCoreApplication, QObject, QRunnable, QThread,
                          QThreadPool, pyqtSignal)
from PyQt5 import QtCore, QtGui, QtWidgets
import vlc

class Player(QtWidgets.QMainWindow):

    def __init__(self, master=None):
        QtWidgets.QMainWindow.__init__(self, master)

        self.media_files = [
            "Toxic.mp4",
        ]
        self.current_index = 0
        self.showFullScreen()
        self.init_ui()
        vlc_options = [
            "--embedded-video",
            "--play-and-exit",
            "--autoscale",
            "--fullscreen",
            "--video-on-top",
            "--verbose -1",
            "--canvas-aspect 3:4",
            "--no-canvas-padd"
        ]

        self.instance = vlc.Instance(" ".join(vlc_options))
        self.media = None
        self.player = self.instance.media_player_new()
        
        if platform.system() == "Linux":
            self.player.set_xwindow(int(self.videoframe.winId()))
        elif platform.system() == "Windows":  # for Windows
            self.player.set_hwnd(int(self.videoframe.winId()))

        self.open_file(self.media_files[self.current_index])
        
    def init_ui(self):
        
      
        self.videoframe = QtWidgets.QFrame()
       
        self.palette = self.videoframe.palette()
        self.palette.setColor(QtGui.QPalette.Window, QtGui.QColor(0, 0, 0))
        self.videoframe.setPalette(self.palette)
        self.videoframe.setAutoFillBackground(True)
        self.setCentralWidget(self.videoframe)
        
    def with_opencv(filename):
        
        import cv2
        video = cv2.VideoCapture(filename)
    
        duration = video.get(cv2.CAP_PROP_POS_MSEC)
        frame_count = video.get(cv2.CAP_PROP_FRAME_COUNT)
    
        return duration, frame_count

    def open_file(self, filename):
       
        if not filename:
            return
        
        self.media = self.instance.media_new(filename)
      
        self.player.set_media(self.media)
       
        self.media.parse()
     
        self.player.play()
        
        
    
def main():
    
    layout = [[sg.Text('Test', font=("Helvetica", 30))],
              [sg.Text('Clique sur le boutton <<Lancer>>', font=("Calibri", 20))],
              [sg.Button('Lancer'), sg.Button('Sortie')]
              ]
    
    window = sg.Window('02.05.2022', layout, size = (800, 480), element_justification="Center", finalize=True)
    
    
   
        
    while True:
        event, values = window.Read()
        print(event, values)
        if event in (sg.WINDOW_CLOSED, 'Sortie'):
            break
        if event in (sg.WINDOW_CLOSED, 'Lancer'):
            
            app = QtWidgets.QApplication(sys.argv)
        
            player = Player()
            player.show()
            
            sys.exit(app.exec_())           
            break
    
    window.close()

if __name__ == '__main__':
   main()

Thank you !


Solution

  • I have found the solution. This is the new main loop:

    while True:
        event, values = window.Read()
        print(event, values)
        if event in (sg.WINDOW_CLOSED, 'Sortie'):
            break
        if event in (sg.WINDOW_CLOSED, 'Lancer'):
            
            app = QtWidgets.QApplication(sys.argv)
        
            player = Player()
            player.show()
            # Wait for is_playing to register the fact that it is playing 
            time.sleep(0.1)
            while True:
                app.processEvents()
    
                if not player.player.is_playing():
                    break        
            break
    

    Instead of app.exec_(), it calls app.processEvents() in a loop and also checks if player stopped playing in that loop.