VLC.py

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Antworten
Kleener
User
Beiträge: 3
Registriert: Dienstag 26. März 2013, 16:37

Hallo :)

ich habe ein problem mit dem VLC Python Bindings (http://wiki.videolan.org/Python_bindings)

Ich arbeite mit PyDev in Eclipse und nutze Python 2.7.

ich möchte die Mediafunktionen (was auch sonst :D ) des VLC-Players nutzen. insbesondere geht es um Audiodateien.

Dafür hab ich hier folgenden Code (ist aus einer Beispieldatei aus dem Netz):
[codebox=python file=x]import vlc

mlp = vlc.MediaListPlayer()
mp = vlc.MediaPlayer()

mlp.set_media_player(mp)

def cb(event):
print "cb:", event.type, event.u

mlp_em = mlp.event_manager()
mlp_em.event_attach(vlc.EventType.MediaListPlayerNextItemSet, cb)

mp_em = mp.event_manager()
mp_em.event_attach(vlc.EventType.MediaPlayerEndReached, cb)
mp_em.event_attach(vlc.EventType.MediaPlayerMediaChanged, cb)

ml = vlc.MediaList()

ml.add_media("D:\lied1.wav")
ml.add_media("D:\lied2.wav")
mlp.set_media_list(ml)

mlp.play()[/code]

Beim Ausführen des Programms kommt allerdings folgende Fehlermeldung:

----------------------------------------------------
cb: EventType.MediaPlayerMediaChanged <vlc.EventUnion object at 0x02320990>
cb: EventType.MediaListPlayerNextItemSet <vlc.EventUnion object at 0x02320990>
Warning: option --plugin-path no longer exists.
Warning: option --plugin-path no longer exists.
----------------------------------------------------

Wenn ich das richtig verstehe findet er den Plugin Pfad vom VLC-Player nicht. Hab schon Google bemüht, aber bisher keine brauchbare Hilfe gefunden.

Hat hier eventuell schon mal jemand damit gearbeitet und könnte mir den ein oder anderen Tipp geben woran das liegen könnte?

gruß
Zuletzt geändert von Anonymous am Samstag 24. Dezember 2016, 16:30, insgesamt 2-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Das sind ja offensichtlich nur Warnungen und das Programm funktioniert ja trotzdem.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Kleener
User
Beiträge: 3
Registriert: Dienstag 26. März 2013, 16:37

Bild

da oben steht etwas von "terminated" (start.py) und es wird auch nichts abgespielt... das spricht in meinen Augen eher gegen das Funktionieren des Programmes....
BlackJack

@Kleener: Ist die `play()`-Methode überhaupt synchron? Kann es sein dass Du das Programm danach nicht einfach beenden darfst, sondern auf das Ende des Abspielens warten musst‽
Kleener
User
Beiträge: 3
Registriert: Dienstag 26. März 2013, 16:37

BlackJack: Ich mag die Arbeit mit kompetenten Menschen :) hab jetz testweise einfach mal nach dem mlp.play() einen 60 sek sleep befehl reingesetzt.... und.... es spielts ab!

danke dir!
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo,

ich will mich hier anhängen, denn ich habe exakt das selbe Problem wie Kleener. Der Unterschied liegt nur darin, dass Kleener mit dem Hinweis von BlackJack etwas anfangen konnte und ich nicht.

Mein System ist Win 7/64, von Python verwende ich die Version 2.7.10. Bei meinem VLC-Player handelt es sich um die Version 2.2.1 / 32 Bit.

Der von mir verwendete Code gleicht dem von Kleener fast auf's Haar. Als Pfadtrenner habe ich allerdings nicht den einfachen Backlash '\' sondern den doppelten '\\' verwendet. Den Aufrufpfad (C:\Program Files (x86)\VideoLAN\VLC) für den VLC habe ich als Umgebungsvariable gesetzt.

Beim Ausführen des Programms kommen bei mir folgende Hinweise und Warnungen:
cb: EventType.MediaPlayerMediaChanged <vlc.EventUnion object at 0x02320990>
cb: EventType.MediaListPlayerNextItemSet <vlc.EventUnion object at 0x02320990>
Warning: option --plugin-path no longer exists.
Warning: option --plugin-path no longer exists.
Sie sind also mit denen, die Kleener bekommen hat, identisch.

Auf der Seite Python bindings von VideoLAN fand ich für Win32, das ich ha nicht habe, folgenden Hinweis:
When initializing vlc.Instance() with no parameter, it tries to guess the location of the modules. However, if you pass any argument to vlc.Instance(), you will need to supply the appropriate "--plugin-path=/path/to/the/modules" yourself.
Das sollte also für Win 7/64 nicht gelten. Trotzdem frage ich mich, welche Module hier konkret gemeint sind, vlc.py, oder welche sonst.

Das mit dem Befehl 'time.sleep(60)' bringt bei mir nichts.

Was muss ich machen, damit der VLC über Python angesprochen werden kann?

Mit freundlichem Gruß,
kodela
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo,

sleep bewirkt doch etwas.

Ich habe den Beispiel-Code vereinfacht. Er sieht jetzt so aus:

Code: Alles auswählen

if __name__ == "__main__":
            
   import vlc
   import time
        
   p=vlc.MediaPlayer('file:///D:\\Musik\\TestAudio.mp3')
   p.play()
   time.sleep(60)
Und das TestAudio wird wiedergegeben - 60 Sekunden.

Führe ich dieses Miniprogramm direkt über die py-Datei aus, dann werden mir in der Konsole sofort die bekannten Warnungen
Warning: option --plugin-path no longer exists.
Warning: option --plugin-path no longer exists.
ausgegeben, TestAudio wird wiedergegeben und nach 60 Sekunden beendet sich das Programm.

Führe ich das Programm über die NetBeans-IDE aus, werden diese Warnungen erst im Zusammenhnag mit dem Programmabbruch nach 60 Sekunden ausgegeben.

Auch das erweiterte Programm

Code: Alles auswählen

if __name__ == "__main__":
            
   import vlc
   import time
        
   mlp = vlc.MediaListPlayer()
   mp = vlc.MediaPlayer()
   mlp.set_media_player(mp)
   def cb(event):
      print "cb:", event.type, event.u
   mlp_em = mlp.event_manager()
   mlp_em.event_attach(vlc.EventType.MediaListPlayerNextItemSet, cb)
   mp_em = mp.event_manager()
   mp_em.event_attach(vlc.EventType.MediaPlayerEndReached, cb)
   mp_em.event_attach(vlc.EventType.MediaPlayerMediaChanged, cb)
   ml = vlc.MediaList()
   ml.add_media("D:\\Musik\\AudioTest_1.mp3")
   ml.add_media("D:\\Musik\\AudioTest_2.mp3")
   mlp.set_media_list(ml)
   mlp.play()
   time.sleep(60)
verhält sich identisch zum "Miniprogramm". Nur werden hier bei der Ausführung über die IDE zusätzlich sofort nach dem Start die beiden Meldungen
cb: EventType.MediaPlayerMediaChanged <vlc.EventUnion object at 0x02418AD0>
cb: EventType.MediaListPlayerNextItemSet <vlc.EventUnion object at 0x02418AD0>
ausgegeben. Bei der Ausführung über die Konsole werden nach dem Start sofort die Meldungen und Warnungen ausgegeben.

Diese zeitlich begrenzte Wiedergabe kann aber doch wohl nicht das sein, was man sich von der Ansteuerung des VLC über Python erwarten darf. Kann jemand dazu etwas sagen, vor allem auch, was die Warnungen bedeuten.

Die zeitliche Begrenzung kann man ja auch über ein 'input()' umschiffen, aber das Wahre ist das doch auch nicht.

MfG, kodela
Zuletzt geändert von kodela am Sonntag 18. Oktober 2015, 12:38, insgesamt 2-mal geändert.
BlackJack

@kodela: Es wird halt asynchron abgespielt, also muss man dafür sorgen dass das Hauptprogramm lange genug läuft.
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

@BlackJack:

Mittlerweile kenne ich Python ja schon ein wenig besser und deshalb habe ich heute das "VLC-Problem" noch einmal in einem anderen Kontext ausprobiert und dabei festgestellt, dass die Wiedergabe einwandfrei funktioniert. Hier der Code, aus dem ich alle nicht relevanten Teile entfernt habe:

Code: Alles auswählen

from tkinter import *
import vlc

def play():
    p=vlc.MediaPlayer('C:/Music/Frank_Sinatra/My_Way.mp3')
    p.play()

root = Tk() 

frame = Frame(root, height=26, width=70)
frame.pack()

play_button = Button(frame, text="Play", command=play)
play_button.pack()

root.mainloop()
Ich bin mir sicher, dass Du mir einige Dinge sagen kannst, die in diesem Rumpf-Code nicht richtig sind oder besser gemacht werden können. Wichtig erscheint mir aber, dass für die durchgehende Wiedergabe bis zum Ende nichts weiter gemacht werden muss, also zum Beispiel kein "60 sek sleep Befehl".

@Kleener: (nachrichtlich)

MfG, kodela
BlackJack

@kodela: Als erstes fällt der Sternchenimport auf. Dann der Code auf Modulebene der keine Konstanten, Funktionen, oder Klassen definiert sondern das Hauptprogramm darstellt.

Einbuchstabige Namen sind in der Regel keine guten Namen. Das geht beispielsweise bei Schleifenvariablen die ganze Zahlen sind (`i`, `j`, `k`) oder `x` und `y` (und `z`) für Koordinaten weil man das aus der Mathematik kennt, oder wenn der Gültigkeitsbereich sehr klein ist, beispielsweise in anonymen Funktione, „list comprehensions“, oder Generatorausdrücken — aber allgemein sollte man aussagekräftige Namen verwenden. Oder gar keinen wenn es nicht sein muss und man etwas ohne das es zu kryptisch wird auch schreiben kann ohne ein Zwischenergebnis an einen eigenen Namen zu binden.

Statt dem `Frame` eine Grösse in Pixeln vorzugeben, wo man doch gar nicht weiss wie gross die Schaltfläche darin ist, würde ich beim `pack()` angeben wieviel zusätzlicher Rand um die Schaltfläche sein soll.

Ich komme dann auf so etwas:

Code: Alles auswählen

import tkinter as tk
import vlc


def play():
    vlc.MediaPlayer('C:/Music/Frank_Sinatra/My_Way.mp3').play()


def main():
    root = tk.Tk()
    tk.Button(root, text='Play', command=play).pack(padx=10, pady=5)
    root.mainloop()


if __name__ == '__main__':
    main()
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo,

wenn die Warnung: "Warning: option --plugin-path no longer exists." stört, kann sie durch einen kleinen Eingriff in die vlc.py beseitigt werden. Dazu muss nur in Zeile 1548 der Text "args = ['vlc', '--plugin-path=' + plugin_path]" zu "args = ['vlc', plugin_path]" geändert, also der String '--plugin-path=' einschließlich dem nachfolgenden Pluszeichen entfernt werden.

Der Parameter "plugin-path" wird nach meinen Feststellungen mindestens seit der VLC-Version 1.1.11 nicht mehr verwendet. Wenn das Modul "MediaPlayer" den VLC öffnet, wird offensichtlich die Konfigurationsdatei vlcrc eingelesen und der Parameter "plugin-path" darin nicht gefunden. Das Spiel wiederholt sich, wenn der VLC beendet wird, deshalb die zweimalige Ausgabe der Warnung.

kodela
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo @Kleener,

das ist zwar ein ziemlich altes Thema, trotzdem habe ich mich nach langer Abstinenz noch einmal damit beschäftigt. Es hat sich ja einiges geändert. Das Script sieht jetzt bei mir so aus:

Code: Alles auswählen

vlcInstance = vlc.Instance()
mp = vlcInstance.media_player_new()
ml = vlcInstance.media_list_new()
mlp = vlcInstance.media_list_player_new()


def cb(event):
    if event.type.value == vlc.EventType.MediaPlayerEndReached.value and nr() == ml.count():
        exit()


def nr(static={"n": 0}):
    static["n"] += 1
    return static["n"]


def setup_player():
    mlp.set_media_player(mp)
    mp_em = mp.event_manager()
    mp_em.event_attach(vlc.EventType.MediaPlayerEndReached, cb)
    ml.add_media("D:\lied1.wav")
    ml.add_media("D:\lied2.wav")
    mlp.set_media_list(ml)
    mlp.play()


setup_player()

while True:
    pass
Die while-Schleife durch "pass" verhindert eine vorzeitige Beendigung des Programms und durch die Auswertung von "vlc.EventType.MediaPlayerEndReached" wird das Programm nach Wiedergabe des letzten Objektes beendet.

Die Warnungen bezüglich dem plugin-path gibt es mit der aktuellen vlc.py nicht mehr. Dafür kommt beim Beenden des Programms ein KeyError. Der tut nicht weh. Die Ursache dafür habe ich noch nicht gefunden. Vielleicht kann ja jemand etwas dazu sagen.

MfG, kodela
BlackJack

@kodela: In die ``while``-Schleife gehört mindestens ein `time.sleep()`-Aufruf. So wie es jetzt ist, beschäftigt man wenn's blöd läuft einen kompletten Prozessorkern mit ”warten”. Besser wäre es etwas passendes aus dem `threading`-Modul zu verwenden um den Hauptthread aus der Rückruffunktion darüber zu informieren dass sich das Programm beenden soll, statt des `exit()`-Aufrufs dort aus einem anderen Thread.

Das `exit()` ohne es aus `sys` zu importieren, einfach so vorhanden ist, darf man nicht voraussetzen. Das ist ein Programmierfehler.
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Halli @BlackJack,

Du hast geschrieben:
In die ``while``-Schleife gehört mindestens ein `time.sleep()`-Aufruf. So wie es jetzt ist, beschäftigt man wenn's blöd läuft einen kompletten Prozessorkern mit ”warten”.
Fakt ist, das Programm muss so lange warten, bis das letzte Objekt der Wiedergabeliste abgespielt ist. Fakt ist auch, dass dies mit meinem Beispiel funktioniert. Andere Lösungen sind denkbar. So wurde in diesem Thema das Problem auf Deine Anregung hin:
Kann es sein dass Du das Programm danach nicht einfach beenden darfst, sondern auf das Ende des Abspielens warten musst‽
von @Kleener schon einmal über einen Aufruf von time.sleep() gelöst. Diese Lösung verlangt natürlich eine Zeitangabe, die mindestens der Summe aller Wiedergabezeiten für jedes Objekt in der Wiedergabeliste entsprechen muss. In diesem Beispiel könnte man diese Zeit feststellen und sleep() übergeben.

Wenn man dieses Script jedoch nur als ausbaufähiges Gerippe ansieht und vorhat, beim Programmaufruf eine Wiedergabeliste im m3u-oder im xspf-Format zu übergeben und wenn dann die Liste noch im Loop-Modus mit einem zeitlich unbestimmten Abbruch wiedergegeben werden soll, dann kann man eine Lösung über sleep() wohl vergessen.

In anderen Beispielen habe ich gesehen, dass man dieses Abwarten auf die Beendigung der Wiedergabe über ein input()-Kommando löst.

Ich frage mich allerdings, welchen Unterschied es für die Prozessorauslastung macht, ob das Programm in einer pass-, sleep()- oder input()-Schleife abwartet.

Damit komme ich zu Deinem Vorschlag:
Besser wäre es etwas passendes aus dem `threading`-Modul zu verwenden um den Hauptthread aus der Rückruffunktion darüber zu informieren dass sich das Programm beenden soll, statt des `exit()`-Aufrufs dort aus einem anderen Thread.
Ich habe vor etwa einem Jahr begonnen, mich für Python zu interessieren und musste dann bis dato eine "Zwangspause" einlegen. Ich habe also von dem, was Du empfiehlst, keine Ahnung. Daher meine Bitte, kennst Du hier in diesem Forum oder sonst wo eine Quelle, die mir helfen könnte, eine Lösung wie von Dir vorgeschlagen, zu realisieren?

Dass für den Aufruf von exit() ein Imprt von sys zwingend ist, überrascht mich. Das habe ich bisher nie beachtet und es hat trotzdem funktioniert. Aber Du hast sicher recht.

MfG, kodela
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@kodela: da Du das Programm sowieso per »exit« hart beendest, ist es egal wie man wartet, ob per »sleep« für die nächsten dreieinhalb Jahre oder per »input« bis jemand mal Enter drückt. »while True: pass« dagegen verbrät unnötig Rechenzeit, es sei denn, Du willst Deinen Rechner als Elektroheizung benutzen. Ansonsten ist Deine Zählfunktion etwas seltsam, dafür gibt es »itertools.count«. Variablennamen sollte man nicht abkürzen, wer weiß schon auf anhieb was mlp heißen soll?

Statt der vielen globalen Variablen sollte man eigentlich eine Klasse verwenden.

Hier mit »Event« um das Ende der Playlist zu signalisieren:

Code: Alles auswählen

from itertools import count
from threading import Event

class Player(object):
    def __init__(self):
        self.played = count()
        self.finished = Event()
        vlcInstance = vlc.Instance()
        self.media_player = vlcInstance.media_player_new()
        self.media_list = vlcInstance.media_list_new()
        self.media_list_player = vlcInstance.media_list_player_new()
        self.media_list_player.set_media_player(self.media_player)
        event_manager = self.media_player.event_manager()
        event_manager.event_attach(vlc.EventType.MediaPlayerEndReached, self.end_reached)

    def add_media(filename):
        self.media_list.add_media(filename)
     
    def play(self):
        self.media_list_player.set_media_list(self.media_list)
        self.media_list_player.play()
        
    def wait(self):
        self.finished.wait()

    def end_reached(self, event):
        if event.type.value == vlc.EventType.MediaPlayerEndReached.value:
            if next(self.played) == self.media_list.count():
                self.finished.set()

player = Player()
player.add_media("D:/lied1.wav")
player.add_media("D:/lied2.wav")
player.play()
player.wait()
kodela
User
Beiträge: 185
Registriert: Montag 12. Oktober 2015, 21:24
Wohnort: Landsberg am Lech
Kontaktdaten:

Hallo Sirius3:

danke für die Mühe, die Du Dir mit meinem Problem gemacht hast. Im Prinzip funktioniert die Wiedergabe mit Deinem Code. Du hattest nur den Import von vlc und in Zeile 16 die Referenzierung auf "self" übersehen. Und ich habe großen Bockmist gebaut, wofür ich um Entschuldigung bitte. Als Mediaobjekte habe ich wie der Themenersteller zwei Audioobjekte verwendet. Tatsächlich arbeite ich aber mit Videoobjekten und die werden im Gegensatz zu Audioobjekten bekanntlich in einem Fenster dargestellt. Und genau um dieses Fenster geht es, denn es wird mit Deinem Code nicht geschlossen und damit bleibt auch das Python-Fenster offen. Die Funktion end_reached() in Deinem Code wird überhaupt nicht angesprungen.

In meinem Beitrag vom Samstag, 24.12.16 habe ich ja gezielt den Themenersteller @Kleener angesprochen und dem ging es nicht um irgend welche Fenster, die offen bleiben, dem ging es darum, dass es überhaupt zu keiner Wiedergabe kam. Und da habe ich die zwei Mediaobjekte so übernommen, wie er sie in seinem Code hatte.

Ich hatte allerdings mit meiner Ereignisbehandlung erreicht, dass nach der Wiedergabe des letzten Mediaobjektes der Wiedergabeliste das Video- und das Pythonfenster geschlossen werden.

Damit ich aber nicht noch einmal "nachtarocken" muss, komme ich zu einer Frage, die ich eigentlich separat stellen wollte, den sie hat mit dem Problem von Kleener nichts zu tun. Gibt es eine Möglichkeit, Python so zu starten, dass sich kein Fenster öffnet oder zumindest nur minimiert öffnet?

MfG, kodela
Antworten