Problem mit Subprocess und mplayer

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Kernelman
User
Beiträge: 6
Registriert: Montag 14. August 2006, 17:57

Hallo
ich habe irgendwie einen Denkfehler !

Code: Alles auswählen

import subprocess
import sys
import os

args = "/usr/bin/mplayer -slave -vo gl2 -ao alsa -really-quiet -nolirc /home/kernelman/Filme/test.mpg"

commands = {"?" : "list commands",
            "1" : "loadfile '/home/kernelman/Filme/test.mpg'",
            ">" : "seek 5",
            "<" : "seek -5",
            "q" : "quit", 
            "p" : "pause",
            "m" : "mute",
            "%" : "get_percent_pos",
            "l" : "get_time_length",
            "t" : "loadlist test.m3u"}

class Mplayer:
    def __init__(self):
        self.mplayer = None
        self.main()
        
    def _get_mplayer(self):
        if self.mplayer is None:
            self.mplayer = subprocess.Popen(args,  stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=True)                                                       
            
            print "Mplayer gestartet"
            return self.mplayer
    
    def get_command(self):
        line = sys.stdin.readline().strip()
        return line
    
    def main(self):
        mplayer = self._get_mplayer()
        line = None
        while mplayer:
            if line == "?":
                for key, command in commands.iteritems():
                    print "%3s: %s" % (key, command)    
            elif line == "q":
                print "sende %s" %("quit" + "\n")
                mplayer.stdin.write("quit" + "\n")
                mplayer.stdin.flush()
                break
            elif commands.has_key(line):
                print "sende %s" %(commands[line] + "\n")
                mplayer.stdin.write(commands[line] + "\n")
                mplayer.stdin.flush()
                line = None
            if mplayer.stdout:
                print "out ist da"
            print "activ"
            line = self.get_command()
            

player = Mplayer()
Nun kann ich zwar commandos senden, aber ich bekomme keine Daten über stdout zurück.

Sobald ich stdout abfrage ist keine eigabe mehr möglich.

Habe schon alles gegoogelt, nur ein vernünftiges Ergebnis habe ich leider nicht gefunden.
Ich steh voll auf dem Schlauch.(gagagagaga)
pSy
User
Beiträge: 44
Registriert: Montag 4. Oktober 2004, 17:58
Kontaktdaten:

Hallo Kernelman...

das Problem liegt darin, dass die STDOUT geschlossen wird. Der beste Weg, den MPlayer fernzusteuern ist per Socket. Schau mal in der MPlayer-ManPage danach. Du kannst ihn mit einem Socket aufrufen, über den er dann Befehle entgegennimmt. Diesen Socket dann mit einem Python-Programm schreiben, bzw auslesen.

Ich schau mal, ob ich das finde... hab nämlich kein Linux in der Nähe, sonst könnte ich dir ein fertiges Script schicken :-/
pSy
User
Beiträge: 44
Registriert: Montag 4. Oktober 2004, 17:58
Kontaktdaten:

Naja, war nicht ganz richtig... aber so siehts aus:
-input <Kommandos>

Diese Option kann benutzt werden, um bestimmte Teile von MPlayers Eingabesystem zu konfigurieren. Pfadangaben sind relativ zu ~/.mplayer/.
ANMERKUNG: Automatische Wiederholung (autorepeat) wird momentan nur von Joysticks unterstützt.

Die verfügbaren Kommandos lauten:

conf=<Dateiname>

Gib eine andere Konfigurationsdatei als die Standarddatei ~/.mplayer/input.conf an. Wenn kein Pfadname angegeben wird, dann wird ~/.mplayer/ <Dateiname> angenommen.

ar-delay

Zeit in Millisekunden, bevor ein Tastendruck automatisch wiederholt wird (0 deaktiviert dies).

ar-rate

Anzahl der Tastendrücke pro Sekunde bei automatisch wiederholten Tastendrücken (0 deaktiviert dies).

keylist

Zeigt alle Tastennamen an, die mit Kommandos belegt werden können.

cmdlist

Zeigt alle Kommandos an, die zugewiesen werden können.

js-dev

Gibt das zu benutzende Joystickgerät an (Standard: /dev/input/js0).

file=<Datei>

Liest Kommandos aus der angegeben Datei. Ist mit einem FIFO am sinnvollsten.
ANMERKUNG: Falls die angegebene Datei ein FIFO ist, öffnet MPlayer beide Enden, so daß mehrere ’echo "seek 10" > mp_pipe’ ausgeführt werden können und die Pipe in Ordnung bleibt.
Also startest du den MPlayer zB so:

Code: Alles auswählen

mplayer -input file=mp_pipe
und kannst dann mit Python die Befehle, die du mit Hilfe von

Code: Alles auswählen

mplayer -input cmdlist
erfragen kannst an das FIFO "mp_pipe" schicken.

PS: Deutsche MPlayer ManPage
Kernelman
User
Beiträge: 6
Registriert: Montag 14. August 2006, 17:57

@pSi Vielen Dank für Deine Antwort.

Ich kann zwar in den Fifo schreiben, aber wie kann ich den auslesen ?

Die Kommandos ohne Rückmeldung sind kein Problem,
aber eine Antwort kommt nie an.

Heul. Ist also genau wie ohne Fifo (vorher).

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import subprocess
import sys
import os

args = "/usr/bin/mplayer -vo gl2 -ao alsa -really-quiet -nolirc -slave -input file='./mplayer_fifo' /home/kernelman/Filme/test.mpg"
fifo_name = "./mplayer_fifo"
commands = {"?" : "list commands",
            "1" : "loadfile '/home/kernelman/Filme/test.mpg'",
            ">" : "seek 5",
            "<" : "seek -5",
            "q" : "quit", 
            "p" : "pause",
            "m" : "mute",
            "%" : "get_percent_pos",
            "l" : "get_time_length"}

class Mplayer:
    def __init__(self):
        self.mplayer = None
        self.fifo = self.get_fifo()
        self.main()
        
    def _get_mplayer(self):
        if self.mplayer is None:
            print "Creating player process"
            subprocess.STARTF_USESHOWWINDOW = 1
            self.mplayer = subprocess.Popen(args, stdin = None, stdout = None, stderr = subprocess.PIPE,shell=True)
            print "Mplayer gestartet"
            return self.mplayer
    
    def get_fifo(self):
        if os.path.exists(fifo_name):
            os.unlink(fifo_name)
        fifo = os.mkfifo(fifo_name)
        return fifo
    
    def write_fifo(self, data):
        w = open(fifo_name, "w")
        w.write(data)
        w.flush()
        w.close()
        print "gesendet"
        
    def read_fifo(self):
        w = open(fifo_name, "r")
        data = w.read()
        w.flush()
        w.close()
        return data
    
    def get_command(self):
        line = sys.stdin.readline().strip()
        return line
    
    def main(self):
        mplayer = self._get_mplayer()
        line = None
        while mplayer:
            if line == "?":
                for key, command in commands.iteritems():
                    print "%3s: %s" % (key, command)    
            elif line == "q":
                print "sende %s" %("quit" + "\n")
                self.write_fifo("quit" + "\n")
                sys.exit()
            elif line == "%":
                data = "get_percent_pos" + "\n"
                self.write_fifo(data)
                data = self.read_fifo()
                print data
            elif commands.has_key(line):
                self.write_fifo(commands[line] + "\n")
                print commands[line]
            print "activ"
            line = self.get_command()

player = Mplayer()
Liegt das am Mplayer ? Öffnet Mplayer nur eine Seite der Pipe (nur schreiben)?
Hab ich was übersehen ? So viele fragen...
Zuletzt geändert von Kernelman am Dienstag 15. August 2006, 20:51, insgesamt 1-mal geändert.
pSy
User
Beiträge: 44
Registriert: Montag 4. Oktober 2004, 17:58
Kontaktdaten:

Also der MPlayer öffnet beide Seiten:
ANMERKUNG: Falls die angegebene Datei ein FIFO ist, öffnet MPlayer beide Enden, [...]
Leider kann ich dir im Moment keine so hundertprozentig sichere Antwort geben, da ich nie ausprobieren kann, ob es auch klappt.
Ich bin allerdings der Meinung, dass es nicht so klug ist, dass FIFO direkt nach dem schreiben und lesen wieder zu schließen.
Sollte es nicht auch ein fifoF.seek(0) bzw fifoF.seek(fifoLen-1) tun?

Ich kann hier leider nur spekulieren, krame aber im Netz, ob ich nochwas finde ;)
BlackJack

Auf FIFOs kann man kein `seek()` machen. Und nein, schliessen sollte man sie nicht. Das bekommt nämlich die Gegenseite mit und denkt sich "Okay, der Kommunikationspartner ist weg".
pSy
User
Beiträge: 44
Registriert: Montag 4. Oktober 2004, 17:58
Kontaktdaten:

ach ja, stimmt. aber es sollte doch problemlos funktionieren in den fifo zu schreiben und ihn wieder auszulesen, seek und vorallem close. flush... weis ich nicht, das müsste ich erst probieren und das klappt hier gerade nicht.

Aber ich habe auch was anderes gefunden. Bin noch am durchschauen, denn es ist größer als ich gedacht habe. Falls dir freevo[url] was sagt: Dort wird der MPlayer auch v ... unterladen oder den CVS durchsuchen.

Es müsste unter src/video/plugin/mplayer.py zu finden sein.
Kernelman
User
Beiträge: 6
Registriert: Montag 14. August 2006, 17:57

So,nach ein paar Experimenten habe ich festgestellt : :?

1. Der Fifo wird "nur" vom mplayer gelsesen.(bis jetzt)

2. Wenn ich den Fifo mit Python wieder auslese, kommt kein Kommando beim Mplayer an. Mplayer schreibt also das Ergebnis in stdout.

3. die Freevo-Quelle Mplayer.py verstehe ich nur soweit:
Player wird mit enem eigenen Thread gestartet und dann über stdin gesteuert.
Nur wie freevo die Antworten abfängt ist mir bis jetzt ein Rätsel.

Ich weiss nur es ist möglich.

Nun werde ich den Mplayer mit einem Fifo ansteuern und die Ergebnisse (wenn vorhanden) aus dem stdout filtern.

Sobald ich soweit bin werde ich das Ergebnis hier wieder einstellen.
Kernelman
User
Beiträge: 6
Registriert: Montag 14. August 2006, 17:57

So hier eine Lösung: :)

mplayer.py

Code: Alles auswählen

import subprocess
import sys
import os

file = "/home/kernelman/Filme/test.mpg"
args = " -vo gl2 -ao alsa -quiet -nolirc -slave -input file=./mplayer_fifo "+ file # Auf keinen Fall -realy-quiet
command = "/usr/bin/mplayer" + args 

class Mplayer:
    def __init__(self, status):
        self.mplayer = None
        self.status = status
            
    def __get_mplayer(self):
        if self.mplayer is None:
            mplayer = subprocess.Popen([command], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=True)
            return mplayer
    
    def run(self):
        self.mplayer = self.__get_mplayer()
        
    def get_status(self):
        line = self.mplayer.stdout.readline()
        if not 'ANS_' in line:
            self.get_status()
        elif 'ANS_LENGTH' in line:
            self.status['length_total'] = line[0:-1].replace('ANS_LENGTH=', "")
        elif 'ANS_TIME_POSITION' in line:
            self.status['played_time'] = line[0:-1].replace('ANS_TIME_POSITION=', "")
        elif 'ANS_PERCENT_POSITION' in line:
            self.status['per_pos'] = line[0:-1].replace('ANS_PERCENT_POSITION=', "")
        return self.status


Funktioniert nur unter Linux und nur mit import mplayer.

Falls jemand weiss warum das nur mit einem import funzt hätte ich gerne eine Antwort. :)
Kernelman
User
Beiträge: 6
Registriert: Montag 14. August 2006, 17:57

Nun die Steuerung mit FIFO :

steuerung.py

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import sys
import os
import mplayer

fifo_name = "./mplayer_fifo"

commands = {"?" : "list commands",
            "1" : "loadfile '/home/kernelman/Filme/test.mpg'",
            ">" : "seek 5",
            "<" : "seek -5",
            "q" : "quit", 
            "p" : "pause",
            "m" : "mute",
            "%" : "get_percent_pos",
            "l" : "get_time_length",
            "b" : "vo_border",
            "f" : "get_time_pos"
            }

class MplayerControl:
    """Muss vor mplayer.py gestartet werden."""
    def __init__(self):
        self.get_fifo()
        self.status = {
            'length_total' : 0,
            'per_pos' : 0,
            'played_time' : 0
            }
        self.player = mplayer.Mplayer(self.status)
        self.player.run()
        self.main()
        
    def get_fifo(self):
        if os.path.exists(fifo_name):
            os.unlink(fifo_name)
        fifo = os.mkfifo(fifo_name, 0666)   # Erstelle fifo
        output = open(fifo_name, "r+")    
        
    def write_fifo(self, data):               
        print "Sende %s" %(data)
        self.output= open(fifo_name, "w")    
        self.output.write(data)
        self.output.flush()
        self.output.close()
        
    def get_command(self):
        line = sys.stdin.readline().strip()
        return line

    def main(self):
        line = None
        print "Kommando :"
        while 1:
            if line == "?":
                for key, command in commands.iteritems():
                    print "%3s: %s" % (key, command)    
            elif line == "q":
                print "sende %s" %("quit" + "\n")
                self.write_fifo("quit \n")
                break
            elif line == "l":
                print "sende %s" %("get_time_length" + "\n")
                self.write_fifo("get_time_length" + "\n")
                self.status = self.player.get_status()
                print self.status
            elif line == "%":
                self.write_fifo(commands[line] + "\n")
                self.status = self.player.get_status()
                print self.status
            elif line == "f":
                self.write_fifo(commands[line] + "\n")
                self.status = self.player.get_status()
                print self.status
            elif commands.has_key(line):
                self.write_fifo(commands[line] + "\n")
            line = self.get_command()

if __name__ == "__main__":
    control = MplayerControl()
Viel Spass. :)

Und vielen Dank an pSy und BlackJack
Antworten