我不想说我需要多长时间才能到达这一点,但我完全理解PyQt5以及它与我看到的C++代码有何关系在Qt网站上,但我认为......我明白了,或者......至少我以为我做到了,直到完全失败。我将从输出结果开始,告诉我我有一个真正存在的文件。我已经尝试过mp3和ogg版本,以防某些原因AudioDecoder无法解码MP3,即使QtMultimedia的其他部分已经能够播放它(我试图让音量更低,因此我可以将声像应用于音频和转移左/右平衡,并且一旦我想出来可能还有其他有趣的事情)。QtMultimedia - QAudioDecoder - Python - 状态的变化,但缓冲区从来没有变得可用
调试输出:
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.
代码:
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()
修改后的代码,试图WAV,仍然没有虽然工作:从下面
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()
我的更新代码后的答案,它适用于mp3 :)
from PyQt5 import QtCore, QtMultimedia, QtWidgets
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
import signal
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(self.error)
self.decoder.stateChanged.connect(self.stateChanged)
self.decoder.positionChanged.connect(self.positionChanged)
self.decoder.bufferAvailableChanged.connect(self.bufferAvailableChanged)
self.decoder.setAudioFormat(self.desiredFormat)
self.decoder.setSourceFilename('D:\\python\\sounds\\30.mp3')
fs = QFileInfo()
print('File exists:' + str(fs.exists('D:\\python\\sounds\\30.mp3')))
#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())
def bufferAvailableChanged(self,available):
print('Available:' + str(available))
def positionChanged(self,position):
print('Position:' + str(position)+'/'+str(self.decoder.duration))
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))
def error(self,err):
print('Decoder error')
print(self.decoder.errorString())
def readBuffer(self):
print('Decoder ready for reading?')
buffer = self.decoder.read()
byteCount = buffer.byteCount()
print('Bytecount in buffer:' + str(byteCount))
if self.readamount == 0:
self.ba = QByteArray()
self.ba.fromRawData(buffer.constData().asstring(byteCount))
else:
self.ba.append(buffer.constData().asstring(byteCount))
self.readamount = self.readamount + 1
print('Bytearray size:' + str(self.ba.length()))
def play(self):
print('Decoding finished, ready to play')
app = QtWidgets.QApplication([''])
ad = AudioDecoder()
signal.signal(signal.SIGINT,signal.SIG_DFL)
app.exec_()
*我注意到一对夫妇失踪的事情在上面的代码中,没有什么东西会导致我得到的结果,但会导致意外行为的东西。例如,我忘了在阅读后忘记更新readamount,并且我注意到如果我在函数调用中放置状态,可以避免在连接的python插槽中调用decoder.state,但这并不会改变行为,即使它比以上。 –
在修复代码中的很多小错误之后,我能够让它工作正常。我只在linux上测试,但是(它使用gstreamer后端)。您可能想尝试使用'wav'文件,因为该格式可以得到支持。 – ekhumoro
以后我也尝试过用wav文件尝试一些调整(将它们放在下面)。你会介意在这里对你的代码做一些小的调整吗? –