wx.MediaCtrl(): haengende LoadURI-Streams sauber beenden

Plattformunabhängige GUIs mit wxWidgets.
Antworten
snakeseven
User
Beiträge: 405
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Sonntag 22. März 2009, 11:14

Moin,
ein verregneter Sonntag Morgen ist die beste Gelegenheit, sich mit einem nervigen wx.MediaCtrl-Problem rumzuschlagen :)

Streamt man mit LoadURI() MP3s über HTTP, hängt sich MediaCtrl bei korrupten Files gnadenlos auf und legt die gesamte Applikation lahm.
Da ein try-except Konstrukt nicht greifen würde und MediaCtrl auch keine Fehlermeldungen an seine Aussenwelt absondert, muss man den haengenden Prozess gewaltsam beenden und MediaCtrl neu starten.

Wichtig ist dabei, dass man auch die Childprozesse killt, da sonst im Hintergrund MediaCtrl.Play() weiterhin versuchen würde, das korrupte File abzuspielen. Kann man selbst überprüfen, indem man die Zeilen

Code: Alles auswählen

wx.CallAfter(self.mp.DestroyChildren)
auskommentiert. Es wäre dann nicht möglich, die Anwendung mit cancel sauber zu beenden.

Gruss, Seven

Code: Alles auswählen

# Demonstartion eines haengenden Play-Aufrufes mit wx.MediaCtrl
# Das erste mit LoadURI() gesladene Mp3 ist korrupt und kann nicht abgespielt werden
# Normalerweise haengt sich wx.MediaCtrl bei soetwas auf.
# Durch Killen des Childprozesses Play() und anschliessendem Killen der wx.MediaCtrl-Instanz mp
# kann das verhindert werden.
# Anschliessend wird eine neue Instanz von wx.MediaCtrl erzeugt und es kann wieder 
# abgespielt werden

import wx 
import wx.media 


class MediaControl(wx.Frame): 

    def __init__(self,parent,id): 
        wx.Frame.__init__(self,parent,id) 
        self.Bind(wx.EVT_CLOSE, self.cancel)
        self.initmediacontrol()
        # Laden eines korrupten MP3-Streams
        self.loadmedia("http://www.sonidorock.org/lala/01.Secret%20Valentine.mp3")
                    
                    
    def initmediacontrol(self):
        self.mp = wx.media.MediaCtrl(self, size=wx.Size(512,384)) 
        self.mp.Bind(wx.media.EVT_MEDIA_LOADED,self.OnPlay) 
        
        
    def loadmedia(self, med):
        self.isplaying = False
        self.mp.LoadURI(med)
            
        while not self.isplaying:
            wx.YieldIfNeeded()
            dp = self.mp.GetDownloadProgress()
            print dp
            if dp > 0:
                # nach 10Sekunden checken, ob abgespielt wird
                wx.FutureCall(10000,self.checkifplaying)
                break



    def OnPlay(self,event): 
        self.isplaying = True
        self.mp.Play() 
        print "playing" 
        
            
            
    def checkifplaying(self):
        if not self.isplaying:
            # Killen der Childprozesse von mp (z.B. Play())
            wx.CallAfter(self.mp.DestroyChildren)
            
            # Killen der Instanz mp
            wx.CallAfter(self.mp.Destroy)
            
            print "mp.destroyed"
            self.initmediacontrol()
            # Laden eines intakten MP3-Streams
            self.loadmedia("http://www.fileden.com/files/2008/11/29/2205665/fall_out_boy-americas_suitehearts.mp3")
            
            
            
    def cancel(self, event=None):
        wx.CallAfter(self.mp.DestroyChildren)
        wx.CallAfter(self.mp.Destroy)
        self.Destroy()
            
            

app = wx.PySimpleApp() 
frame=MediaControl(parent=None,id=-1) 

frame.Show() 
app.MainLoop()
Update 26.03:
Leider ist es doch nicht ganz so einfach, schade, schade. Mit Childdren sind in der Doku wohl offensichhtlich Objekte vom Typ wx.Windows gemeint und keine Kindprozesse von wx.MediaCtrl. Warum diese Methode trotzdem in den meisten von mir getesteten Fällen den hängenden Mediastream beenden konnte, verstehe ich nun doch nicht mehr. Werde wohl noch weiter forschen müssen. Schade, dass wx.MediaCtrl so eine undurchsichtige Blackbox ist, die sich noch nicht einmal mit "try - except" bändigen lässt.
snakeseven
User
Beiträge: 405
Registriert: Freitag 7. Oktober 2005, 14:37
Wohnort: Berlin
Kontaktdaten:

Donnerstag 26. März 2009, 18:11

Aha, es hängt unter Windows vom gewählten Backend ab, ob wx.MediaCtrl mit der Aussenwelt kommuniziert, oder nicht.

Ich hatte bislang immer "wx.media.MEDIABACKEND_DIRECTSHOW" gewählt, weil sich damit flüssiger Seeken lässt. Jedoch kann man damit keine variablen Bitraten abspielen, denn dabei hängt sich MediaCtrl grundsätzlich auf.

Mit "wx.media.MEDIABACKEND_WMP10" kann man VBRs zumindest über LoadURI() abspielen. Will man sie aber von der Festplatte laden, bekommt man mitgeteilt, dass dieses Format nicht unterstützt wird.

Gruss, Seven
Antworten