wxWidgets / Phoenix

wxPython's Project Phoenix. A new implementation of wxPython, better, stronger, faster than he was before.
http://wxpython.org/
2.29k stars 516 forks source link

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

Open reticulatus opened 2 years ago

reticulatus commented 2 years ago

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. ```python 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() ```
RobinD42 commented 5 months ago

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

1marc1 commented 5 months ago

+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.