Phoenix icon indicating copy to clipboard operation
Phoenix copied to clipboard

wx.MediaCtrl hangs for several seconds before it starts playing on Linux

Open reticulatus opened this issue 2 years ago • 2 comments

Operating system: Linux Mint 21 (based on Ubuntu 22.04) wxPython version & source: 4.2.0 from https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-22.04 Python version & source: 3.10.4 from Mint distribution

Description of the problem: When I run the MediaCtrl example from the wxPython demo there is a delay of several seconds from pressing the Play button until the video actually starts playing. On my 10 year old PC it takes about 6 seconds to start, on my more powerful 1 year old PC it takes 3 - 4 seconds.

If I wait several seconds after a video has loaded and then press Play, it sometimes plays a few frames from the video and then freezes for the usual delay period, before playing normally.

If I let the video run through to the end and press Play again, the delay happens again. However, if I stop or pause the video part way through and then press Play, the delay doesn't happen.

I have tested this with several different video files and a delay happens with all of them

Code Example (click to expand)

The following code was copied from wxPython demo and modified to run standalone. It also disables the Play button until an EVT_MEDIA_LOADED event has been triggered. However, this doesn't prevent the delay from occurring.


import wx
import wx.media
import os

#----------------------------------------------------------------------

class StaticText(wx.StaticText):
    """
    A StaticText that only updates the label if it has changed, to
    help reduce potential flicker since these controls would be
    updated very frequently otherwise.
    """
    def SetLabel(self, label):
        if label != self.GetLabel():
            wx.StaticText.SetLabel(self, label)

#----------------------------------------------------------------------

class TestPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1,
                          style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN)

        # Create some controls
        try:
            backend = "" # let MediaCtrl choose default backend
            #backend=wx.media.MEDIABACKEND_DIRECTSHOW
            #backend=wx.media.MEDIABACKEND_WMP10
            #backend = wx.media.MEDIABACKEND_GSTREAMER
            self.mc = wx.media.MediaCtrl()
            ok = self.mc.Create(self, style=wx.SIMPLE_BORDER,
                                szBackend=backend)
            if not ok:
                raise NotImplementedError
        except NotImplementedError:
            self.Destroy()
            raise

        # the following event is not sent with the Windows default backend
        # MEDIABACKEND_DIRECTSHOW
        # choose above e.g. MEDIABACKEND_WMP10 if this is a problem for you
        self.Bind(wx.media.EVT_MEDIA_LOADED, self.OnMediaLoaded)

        btn1 = wx.Button(self, -1, "Load File")
        self.Bind(wx.EVT_BUTTON, self.OnLoadFile, btn1)

        btn2 = wx.Button(self, -1, "Play")
        self.Bind(wx.EVT_BUTTON, self.OnPlay, btn2)
        self.playBtn = btn2

        btn3 = wx.Button(self, -1, "Pause")
        self.Bind(wx.EVT_BUTTON, self.OnPause, btn3)

        btn4 = wx.Button(self, -1, "Stop")
        self.Bind(wx.EVT_BUTTON, self.OnStop, btn4)

        slider = wx.Slider(self, -1, 0, 0, 10)
        self.slider = slider
        slider.SetMinSize((150, -1))
        self.Bind(wx.EVT_SLIDER, self.OnSeek, slider)

        self.st_size = StaticText(self, -1, size=(100,-1))
        self.st_len  = StaticText(self, -1, size=(100,-1))
        self.st_pos  = StaticText(self, -1, size=(100,-1))


        # setup the layout
        sizer = wx.GridBagSizer(5,5)
        sizer.Add(self.mc, (1,1), span=(5,1))#, flag=wx.EXPAND)
        sizer.Add(btn1, (1,3))
        sizer.Add(btn2, (2,3))
        sizer.Add(btn3, (3,3))
        sizer.Add(btn4, (4,3))
        sizer.Add(slider, (6,1), flag=wx.EXPAND)
        sizer.Add(self.st_size, (1, 5))
        sizer.Add(self.st_len,  (2, 5))
        sizer.Add(self.st_pos,  (3, 5))
        self.SetSizer(sizer)

        self.playBtn.Disable()

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer)
        self.timer.Start(100)



    def OnLoadFile(self, evt):
        dlg = wx.FileDialog(self, message="Choose a media file",
                            defaultDir=os.getcwd(), defaultFile="",
                            style=wx.FD_OPEN | wx.FD_CHANGE_DIR )
        if dlg.ShowModal() == wx.ID_OK:
            self.playBtn.Disable()
            path = dlg.GetPath()
            self.DoLoadFile(path)
        dlg.Destroy()


    def DoLoadFile(self, path):

        if not self.mc.Load(path):
            wx.MessageBox("Unable to load %s: Unsupported format?" % path,
                          "ERROR",
                          wx.ICON_ERROR | wx.OK)
        else:
            self.mc.SetInitialSize()
            self.GetSizer().Layout()
            self.slider.SetRange(0, self.mc.Length())
            self.playBtn.Enable()

    def OnMediaLoaded(self, evt):
        print("OnMediaLoaded")
        self.playBtn.Enable()

    def OnPlay(self, evt):
        if not self.mc.Play():
            wx.MessageBox("Unable to Play media : Unsupported format?",
                          "ERROR",
                          wx.ICON_ERROR | wx.OK)
        else:
            self.mc.SetInitialSize()
            self.GetSizer().Layout()
            self.slider.SetRange(0, self.mc.Length())

    def OnPause(self, evt):
        self.mc.Pause()

    def OnStop(self, evt):
        self.mc.Stop()


    def OnSeek(self, evt):
        offset = self.slider.GetValue()
        self.mc.Seek(offset)

    def OnTimer(self, evt):
        offset = self.mc.Tell()
        self.slider.SetValue(offset)
        self.st_size.SetLabel('size: %s' % self.mc.GetBestSize())
        self.st_len.SetLabel('length: %d seconds' % (self.mc.Length()/1000))
        self.st_pos.SetLabel('position: %d' % offset)

    def ShutdownDemo(self):
        self.timer.Stop()
        del self.timer

#----------------------------------------------------------------------

class TestFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, -1)

        p = TestPanel(self)
        self.SetMinSize((1100, 650))



def runTest():

    app = wx.App()
    frame = TestFrame(None)
    frame.Show()
    app.MainLoop()


#----------------------------------------------------------------------

if __name__ == '__main__':
    runTest()

reticulatus avatar Sep 12 '22 21:09 reticulatus

This issue has been mentioned on Discuss wxPython. There might be relevant details there:

https://discuss.wxpython.org/t/video-playback-influenced-by-amount-of-time-webpage-is-open/36902/2

RobinD42 avatar Apr 23 '24 14:04 RobinD42

+1 Just commenting here as the issue described by reticulatus could be related to my problem that I posted on Discuss wxPython, that RobinD42 linked to. Hopefully someone has the time and inclination to look into this.

1marc1 avatar Apr 25 '24 12:04 1marc1