2017-10-07 13 views
1

Ich hasse zu sagen, wie lange ich brauchte, um zu diesem Punkt zu kommen, aber ich hatte echte Schwierigkeiten, vollständig zu verstehen PyQt5 und wie es sich auf den C++ - Code bezieht auf der Qt-Website, aber ich denke .. ich verstehe, oder ... zumindest dachte ich, dass ich es getan habe, bis das völlig versagt hat. Ich beginne mit der Ausgabe, die ich bekomme, die mir sagt, dass ich eine Datei habe, die wirklich existiert. Ich habe mp3 und ogg Version aus irgendeinem Grund versucht, AudioDecoder kann die MP3 nicht dekodieren, obwohl andere Teile von QtMultimedia in der Lage waren, es zu spielen (Ich versuche, niedrigeres Niveau zu erreichen, damit ich Schwenken auf das Audio und anwenden kann) verschiebe das linke/rechte Gleichgewicht und vielleicht andere lustige Dinge, wenn ich das herausgefunden habe).QtMultimedia - QAudioDecoder - Python - Statusänderungen, aber Puffer nie verfügbar

Debug-Ausgabe:

MP3 exists:True 
Decoder stopped:True <- expected at this point, just confirming state works 
Decoder state changed? <- this means state change signal is being sent 
Decoder stopped?:False <- ok, state did actually change, that's expected 
Decoder decoding?:True <- expected, confirming there are only 2 states as documentation indicates 
Init finished, Decoder started? <- after this, i expect to see position changes, buffer availability changes, or errors ... but I get nothing and it just exits the script. 

Code:

from PyQt5 import QtCore, QtMultimedia 
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, QByteArray, QIODevice, QFileInfo 
from PyQt5.QtMultimedia import QAudioDecoder, QAudioFormat, QMediaObject, QAudioBuffer, QAudioOutput, QAudio 

class AudioDecoder(QObject): 
    def __init__(self): 
    super(AudioDecoder,self).__init__() 
    self.desiredFormat = QAudioFormat() 
    self.desiredFormat.setChannelCount(2) 
    self.desiredFormat.setCodec('audio/pcm') 
    self.desiredFormat.setSampleType(QAudioFormat.UnSignedInt) 
    self.desiredFormat.setSampleRate(48000) 
    self.desiredFormat.setSampleSize(16) 

    self.decoder = QAudioDecoder() 
    self.decoder.setAudioFormat(self.desiredFormat) 
    self.decoder.setSourceFilename('D:\\python\\sounds\\30.mp3') 
    fs = QFileInfo() 
    print('MP3 exists:' + str(fs.exists('D:\\python\\sounds\\30.mp3'))) 

    #self.connect(decoder,bufferReady(),None,readBuffer()) 
    self.decoder.bufferReady.connect(self.readBuffer) 
    self.decoder.finished.connect(self.play) 
    self.decoder.error.connect(self.error) 
    self.decoder.stateChanged.connect(self.stateChanged) 
    self.decoder.positionChanged.connect(self.positionChanged) 
    self.decoder.bufferAvailableChanged.connect(self.bufferAvailableChanged) 

    #using this to determine if we need to start byte array or append to it 
    self.readamount = 0 

    #Expect this to be true since we haven't started yet 
    print('Decoder stopped:' + str(self.decoder.state() == QAudioDecoder.StoppedState))  
    self.decoder.start() 
    print('Init finished, Decoder started?') 
    def bufferAvailableChanged(self): 
    print(str(decoder.available)) 
    def positionChanged(self): 
    print(str(decoder.position())+'/'+str(decoder.duration)) 
    def stateChanged(self): 
    #Confirm state is what we expect 
    print('Decoder state changed?') 
    print('Decoder stopped?:' + str(self.decoder.state() == QAudioDecoder.StoppedState)) 
    print('Decoder decoding?:' + str(self.decoder.state() == QAudioDecoder.DecodingState)) 
    def error(self): 
    print('Decoder error?') 
    print(self.decoder.errorString()) 
    def readBuffer(self): 
    print('Decoder ready for reading?') 
    buffer = self.decoder.read() 
    print('Bytecount in buffer:' + str(buffer.byteCount)) 
    if self.readamount == 0: 
     self.ba = QByteArray() 
     self.ba.fromRawData(buffer.data(),buffer.byteCount()) 
    else: 
     self.ba.append(buffer.data(),buffer.byteCount()) 
    print('Bytearray size:' + str(self.ba.length())) 
    def play(self): 
    print('Decoding finished, ready to play') 

ad = AudioDecoder() 

Revised Code, WAV versuchen, immer noch nicht funktioniert aber:

from PyQt5 import QtCore, QtMultimedia 
from PyQt5.QtTest import QSignalSpy 
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, QByteArray, QIODevice, QFileInfo 
from PyQt5.QtMultimedia import QAudioDecoder, QAudioFormat, QMediaObject, QAudioBuffer, QAudioOutput, QAudio 

class AudioDecoder(QObject): 
    def __init__(self): 
    super(AudioDecoder,self).__init__() 
    self.desiredFormat = QAudioFormat() 
    self.desiredFormat.setChannelCount(2) 
    self.desiredFormat.setCodec('audio/pcm') 
    self.desiredFormat.setSampleType(QAudioFormat.UnSignedInt) 
    self.desiredFormat.setSampleRate(48000) 
    self.desiredFormat.setSampleSize(16) 

    self.decoder = QAudioDecoder() 

    self.decoder.bufferReady.connect(self.readBuffer) 
    self.decoder.finished.connect(self.play) 
    self.decoder.error.connect(lambda: self.error(self.decoder.error())) 
    self.decoder.stateChanged.connect(lambda: self.stateChanged(self.decoder.state())) 
    self.decoder.positionChanged.connect(lambda: self.positionChanged(self.decoder.position(),self.decoder.duration())) 
    self.decoder.bufferAvailableChanged.connect(lambda: self.bufferAvailableChanged(self.decoder.available())) 

    self.decoder.setAudioFormat(self.desiredFormat) 
    self.decoder.setSourceFilename('D:\\python\\sounds\\piano2.wav') 
    fs = QFileInfo() 
    print('File exists:' + str(fs.exists('D:\\python\\sounds\\piano2.wav'))) 

    #using this to determine if we need to start byte array or append to it 
    self.readamount = 0 

    #Expect this to be true since we haven't started yet 
    print('Decoder stopped?:' + str(self.decoder.state() == QAudioDecoder.StoppedState))  
    self.decoder.start()  
    print('Init finished, Decoder started on file:' + self.decoder.sourceFilename())  
    @pyqtSlot() 
    def bufferAvailableChanged(self,available): 
    print('Available:' + str(available)) 
    @pyqtSlot() 
    def positionChanged(self,position,duration): 
    print('Position:' + str(position())+'/'+str(duration())) 
    @pyqtSlot() 
    def stateChanged(self,state): 
    #Confirm state is what we expect 
    print('Decoder state changed') 
    if state == QAudioDecoder.StoppedState: 
     print('Decoder stopped?:' + str(state == QAudioDecoder.StoppedState)) 
    else: 
     print('Decoder decoding?:' + str(state == QAudioDecoder.DecodingState))  
    @pyqtSlot() 
    def error(self,err): 
    print('Decoder error') 
    print(self.decoder.errorString()) 
    def readBuffer(self): 
    print('Decoder ready for reading?') 
    buffer = self.decoder.read() 
    print('Bytecount in buffer:' + str(buffer.byteCount)) 
    if self.readamount == 0: 
     self.ba = QByteArray() 
     self.ba.fromRawData(buffer.data(),buffer.byteCount()) 
    else: 
     self.ba.append(buffer.data(),buffer.byteCount()) 
    self.readamount = self.readamount + 1 
    print('Bytearray size:' + str(self.ba.length()))  
    def play(self): 
    print('Decoding finished, ready to play') 

ad = AudioDecoder() 

von unten Meine Update-Code Post Antwort, und es funktioniert mit mp3 :)

01 Hier
+0

* Ich habe ein paar Dinge fehlen bemerkt im obigen Code nichts, was das Ergebnis, das ich bekomme, verursachen sollte, aber Dinge, die zu unerwartetem Verhalten führen würden. Ich habe vergessen, readamount nach dem Lesen zu aktualisieren, und ich habe festgestellt, dass ich vermeiden kann, decoder.state im angeschlossenen Python-Slot aufzurufen, wenn ich den Funktionsaufruf state, aber das hat das Verhalten nicht verändert, auch wenn es sauberer ist über. –

+0

Nachdem ich viele kleine Fehler im Code behoben hatte, konnte ich es in Ordnung bringen. Ich habe jedoch nur auf Linux getestet (welches das gstreamer Backend verwendet). Vielleicht möchten Sie es mit einer 'wav'-Datei versuchen, da dieses Format garantiert unterstützt wird. – ekhumoro

+0

Ich habe es später mit einer WAV-Datei versucht, auch nachdem ich einige Anpassungen vorgenommen habe (werde sie unten setzen). Würde es Ihnen etwas ausmachen, hier eine Antwort zu geben, mit den kleinen Anpassungen, die Sie am Code vorgenommen haben? –

Antwort

1

ist mein (Linux) Arbeitsversion des Original-Skript:

from PyQt5 import QtWidgets 
from PyQt5 import QtCore, QtMultimedia 
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, QByteArray, QIODevice, QFileInfo 
from PyQt5.QtMultimedia import QAudioDecoder, QAudioFormat, QMediaObject, QAudioBuffer, QAudioOutput, QAudio 

class AudioDecoder(QObject): 
    def __init__(self): 
    super(AudioDecoder,self).__init__() 
    self.desiredFormat = QAudioFormat() 
    self.desiredFormat.setChannelCount(2) 
    self.desiredFormat.setCodec('audio/pcm') 
    self.desiredFormat.setSampleType(QAudioFormat.UnSignedInt) 
    self.desiredFormat.setSampleRate(48000) 
    self.desiredFormat.setSampleSize(16) 

    self.decoder = QAudioDecoder() 
    self.decoder.setAudioFormat(self.desiredFormat) 
    fs = QFileInfo('test.wav') 
    self.decoder.setSourceFilename(fs.absoluteFilePath()) 
    print('File exists:' + str(fs.exists())) 

    #self.connect(decoder,bufferReady(),None,readBuffer()) 
    self.decoder.bufferReady.connect(self.readBuffer) 
    self.decoder.finished.connect(self.play) 
    self.decoder.error.connect(self.error) 
    self.decoder.stateChanged.connect(self.stateChanged) 
    self.decoder.positionChanged.connect(self.positionChanged) 
    self.decoder.bufferAvailableChanged.connect(self.bufferAvailableChanged) 

    #using this to determine if we need to start byte array or append to it 
    self.readamount = 0 

    #Expect this to be true since we haven't started yet 
    print('Decoder stopped:' + str(self.decoder.state() == QAudioDecoder.StoppedState)) 
    self.decoder.start() 
    print('Init finished, Decoder started?') 
    def bufferAvailableChanged(self): 
    print(str(self.decoder.bufferAvailable())) 
    def positionChanged(self): 
    print(str(self.decoder.position())+'/'+str(self.decoder.duration())) 
    def stateChanged(self): 
    #Confirm state is what we expect 
    print('Decoder state changed?') 
    print('Decoder stopped?:' + str(self.decoder.state() == QAudioDecoder.StoppedState)) 
    print('Decoder decoding?:' + str(self.decoder.state() == QAudioDecoder.DecodingState)) 
    def error(self): 
    print('Decoder error?') 
    print(self.decoder.errorString()) 
    def readBuffer(self): 
    print('Decoder ready for reading?') 
    buffer = self.decoder.read() 
    count = buffer.byteCount() 
    print('Bytecount in buffer:' + str(count)) 
    if self.readamount == 0: 
     self.ba = QByteArray() 
     self.ba.fromRawData(buffer.constData().asstring(count)) 
     self.readamount = count 
    else: 
     self.ba.append(buffer.constData().asstring(count)) 
    print('Bytearray size:' + str(self.ba.length())) 
    def play(self): 
    print('Decoding finished, ready to play') 

app = QtWidgets.QApplication(['']) 
ad = AudioDecoder() 

import signal 
signal.signal(signal.SIGINT, signal.SIG_DFL) 
# press Ctrl+C to exit 

app.exec_() 

Diff:

--- yours 
+++ mine 
@@ -1,3 +1,4 @@ 
+from PyQt5 import QtWidgets 
from PyQt5 import QtCore, QtMultimedia 
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, QByteArray, QIODevice, QFileInfo 
from PyQt5.QtMultimedia import QAudioDecoder, QAudioFormat, QMediaObject, QAudioBuffer, QAudioOutput, QAudio 
@@ -14,9 +15,9 @@ 

    self.decoder = QAudioDecoder() 
    self.decoder.setAudioFormat(self.desiredFormat) 
- self.decoder.setSourceFilename('D:\\python\\sounds\\30.mp3') 
- fs = QFileInfo() 
- print('MP3 exists:' + str(fs.exists('D:\\python\\sounds\\30.mp3'))) 
+ fs = QFileInfo('test.wav') 
+ self.decoder.setSourceFilename(fs.absoluteFilePath()) 
+ print('File exists:' + str(fs.exists())) 

    #self.connect(decoder,bufferReady(),None,readBuffer()) 
    self.decoder.bufferReady.connect(self.readBuffer) 
@@ -34,9 +35,9 @@ 
    self.decoder.start() 
    print('Init finished, Decoder started?') 
    def bufferAvailableChanged(self): 
- print(str(decoder.available)) 
+ print(str(self.decoder.bufferAvailable())) 
    def positionChanged(self): 
- print(str(decoder.position())+'/'+str(decoder.duration)) 
+ print(str(self.decoder.position())+'/'+str(self.decoder.duration())) 
    def stateChanged(self): 
    #Confirm state is what we expect 
    print('Decoder state changed?') 
@@ -48,14 +49,23 @@ 
    def readBuffer(self): 
    print('Decoder ready for reading?') 
    buffer = self.decoder.read() 
- print('Bytecount in buffer:' + str(buffer.byteCount)) 
+ count = buffer.byteCount() 
+ print('Bytecount in buffer:' + str(count)) 
    if self.readamount == 0: 
     self.ba = QByteArray() 
-  self.ba.fromRawData(buffer.data(),buffer.byteCount()) 
+  self.ba.fromRawData(buffer.constData().asstring(count)) 
+  self.readamount = count 
    else: 
-  self.ba.append(buffer.data(),buffer.byteCount()) 
+  self.ba.append(buffer.constData().asstring(count)) 
    print('Bytearray size:' + str(self.ba.length())) 
    def play(self): 
    print('Decoding finished, ready to play') 

+app = QtWidgets.QApplication(['']) 
ad = AudioDecoder() 
+ 
+import signal 
+signal.signal(signal.SIGINT, signal.SIG_DFL) 
+# press Ctrl+C to exit 
+ 
+app.exec_() 

Ausgang:

File exists:True 
Decoder stopped:True 
Init finished, Decoder started? 
Decoder state changed? 
Decoder stopped?:False 
Decoder decoding?:True 
True 
Decoder ready for reading? 
0/196238 
Bytecount in buffer:7680 
Bytearray size:0 
Decoder ready for reading? 
40/196238 
Bytecount in buffer:7680 
Bytearray size:7680 
Decoder ready for reading? 
80/196238 
Bytecount in buffer:7680 
Bytearray size:15360 
Decoder ready for reading? 
120/196238 
Bytecount in buffer:7680 
Bytearray size:23040 
Decoder ready for reading? 
False 
160/196238 
Bytecount in buffer:7680 
Bytearray size:30720 
... 

Bytecount in buffer:7680 
Bytearray size:37662720 
Decoder ready for reading? 
False 
196200/196238 
Bytecount in buffer:7364 
Bytearray size:37670084 
Decoding finished, ready to play 
Decoder state changed? 
Decoder stopped?:True 
Decoder decoding?:False 
+0

Ok, ich werde etwas nachlesen müssen, um einige der Unterschiede in dem, was Sie getan haben, zu verstehen, aber ich verstehe, was das Problem war. Der Grund, warum alles nicht voranschreitet, scheint mit der Tatsache zu tun zu haben, dass ich Ihr QtWidgets.QApplication-Objekt nicht hatte, und führe aus, was ich die "Anwendungsschleife" nennen könnte. Ich hatte einige Python-Bibliotheken gesehen, die das erforderten und andere nicht und ich wusste nicht, warum sie das taten, aber ich glaube, ich verstehe das jetzt. All diese Signal-/Slot-Sachen müssen nicht unbedingt passieren, solange das Haupt-App-Loop-Objekt nicht läuft. –

+0

Danke für deine Antwort, das war enorm hilfreich. Ich weiß, dass ich der gesamten Anwendungsschleife mit all diesen verschiedenen Bibliotheken viel mehr Aufmerksamkeit schenken muss. Sobald ich hinzugefügt habe, dass ich begann, Fehler zu bekommen, und der Rest Ihrer Änderungen fiel perfekt ein, um diese zu beheben. Wenn ich mich erinnere, an anderer Stelle zu lesen, ist der Zweck der Signal.Signal-Linie, mir zu erlauben, noch Anwendung Schleife mit Strg + C zu beenden? –

+0

@MatthewSwaringen.Ah - ich habe mich über das Fehlen eines App-Objekts gewundert, aber ich nahm an, dass dein Beispiel Teil eines vollständigeren Skripts war. Das Signal-Slot-Framework ist vom Event-Framework getrennt, sodass häufig keine laufende Event-Schleife erforderlich ist. Einige wichtige Ausnahmen sind jedoch Timer und Threads, da sie asynchron sein müssen. Ich nehme an, dass die Multimedia-Klassen Timer und Threads ziemlich häufig verwenden. – ekhumoro