oaubert / python-vlc

Python vlc bindings
GNU Lesser General Public License v2.1
382 stars 108 forks source link

program crashes when switching between medias too quickly #209

Open FieryRMS opened 2 years ago

FieryRMS commented 2 years ago

When I press Left or Right, I get errors. So, I am certain it is caused by the nextFile() function from my code. More specifically, it is caused whenever I try to call stop(), set_media() or play() of the media_player. Some of the most common error are listed below.

[000001e7a8e0b2a0] cache_read stream error: cannot pre fill buffer
[000001e7ae098ee0] mjpeg demux error: cannot peek
[000001e7ae286d30] direct3d11 vout display error: SetThumbNailClip failed: 0x800706f4
[000001e7b6be89f0] avcodec decoder: Using D3D11VA (Intel(R) HD Graphics 5500, vendor 8086(Intel), device 1616, revision 9) for hardware decoding
[h264 @ 000001e7a90b1040] get_buffer() failed
[h264 @ 000001e7a90b1040] thread_get_buffer() failed
[h264 @ 000001e7a90b1040] decode_slice_header error
[000001dceaa2c890] mmdevice audio output error: cannot initialize COM (error 0x80010106)

If I switch media too quickly, it sometimes crashes. Sometimes when I play videos, the playback continually lags and the following error is logged every time it lags,

[h264 @ 000001e7a90b1040] get_buffer() failed
[h264 @ 000001e7a90b1040] thread_get_buffer() failed
[h264 @ 000001e7a90b1040] decode_slice_header error

Here is a simplified version of the code,

from time import sleep
import vlc
import tkinter as Tk
from tkinter import ttk
from tkinter.filedialog import askdirectory
import os

class Player(Tk.Frame):
    def __init__(self, parent, title=None):
        Tk.Frame.__init__(self, parent)

        self.base = ""
        self.files = ""
        self.currFile = -1
        self.parent = parent

        if title == None:
            title = "Project"
        self.parent.title(title)

        self.videopanel = ttk.Frame(self.parent)
        self.canvas = Tk.Canvas(self.videopanel).pack(fill=Tk.BOTH, expand=1)
        self.videopanel.pack(fill=Tk.BOTH, expand=1)

        self.sortOptions = ttk.Frame(self.parent)
        ttk.Button(self.sortOptions, text="Open...",
                   command=self.OnOpen).pack(side=Tk.LEFT)
        self.sortOptions.pack(side=Tk.BOTTOM)

        self.player = None

    def OnOpen(self):
        self.OnStop()
        currfolder = next(os.walk(askdirectory()))
        self.base = currfolder[0]
        self.files = []
        for file in currfolder[2]:
            if(file.endswith(('.png', '.jpg', '.jpeg', '.gif', '.mp4', '.mkv', '.mp3'))):
                self.files.append(file)

        for child in self.sortOptions.winfo_children():
            child.destroy()

        self.player = vlc.Instance().media_player_new()
        self.player.set_hwnd(self.videopanel.winfo_id())

        self.parent.bind("<Right>", lambda e: self.nextFile(e))
        self.parent.bind("<Left>", lambda e: self.nextFile(e, False))

        self.nextFile()

    def nextFile(self, event=None, next=True):
        self.OnStop()

        if(next):
            self.currFile += 1
            if(self.currFile == len(self.files)):
                self.currFile = 0
        else:
            self.currFile -= 1
            if(self.currFile == -1):
                self.currFile = len(self.files)-1

        filePath = os.path.join(self.base, self.files[self.currFile])

        self.player.set_media(vlc.Media(filePath))

        self.OnPlay()
        return

    def errorDialog(self, errormessage):
        Tk.tkMessageBox.showerror(self, 'Error', errormessage)

    def OnPlay(self):
        if not self.player.get_media():
            self.OnOpen()
        else:
            if self.player.play() == -1:
                self.errorDialog("Unable to play.")

    def OnStop(self):
        if(self.player):
            pass
            self.player.pause()

def Tk_get_root():
    if not hasattr(Tk_get_root, "root"):
        Tk_get_root.root = Tk.Tk()
    return Tk_get_root.root

def _quit():
    print("_quit: bye")
    root = Tk_get_root()
    root.quit()
    root.destroy()
    os._exit(1)

if __name__ == "__main__":
    root = Tk_get_root()
    root.protocol("WM_DELETE_WINDOW", _quit)

    player = Player(root, title="Project")
    root.mainloop()

the following is the output from py vlc.py -v

vlc.py: 3.0.12118 (Tue Apr 20 20:46:07 2021 3.0.12)
LibVLC version: 3.0.16 Vetinari (0x3001000)
LibVLC compiler: gcc version 6.4.0 (GCC)
Plugin path: C:\Program Files\VideoLAN\VLC
Python: 3.10.2 (64bit) Windows 10
mrJean1 commented 2 years ago

FWIW,

To run on macOS, the script above was modified with 2 snippets from example python-vlc/examples/tkvlc.py and to collect .mov files.

Then, using Python 3.10.2 (64-bit with tkinter.TkVersion 8.6), vlc.py 3.0.12 and libVLC 3.0.16, it runs the collected videos. Also, pressing the left and right arrow keys does not crash the script and only shows the following message at every click ...

[000000011df0f5e0] videotoolbox decoder: Using Video Toolbox to decode 'h264'
[000000011df0f5e0] videotoolbox decoder: vt cvpx chroma: 420v

issue209.py.zip