【问题标题】:PyQt5 : QMediaPlayer can't replay audio from QBufferPyQt5:QMediaPlayer 无法从 QBuffer 重放音频
【发布时间】:2017-10-19 19:29:42
【问题描述】:

我在 RAM 中有一个带有临时 wav 文件的 QBuffer,我想让用户在任何时候都可以随意收听它。但是,它只允许播放一次,并且不允许重播。如果我从文件 (QUrl.fromLocalFile) 播放音频,它可以重播它。有什么不同?如何解决?

1) 要从 RAM 播放 wav 文件,我使用以下代码:

    data = b""
    with open(fname, "rb") as file:
        data = file.read()
    buf = QBuffer()
    buf.setData(data) #For debugging. Real buffer is filled differently.
    buf.open(QIODevice.ReadOnly);

    self.mediaPlayer=QMediaPlayer(self)
    self.mediaPlayer.setMedia(QMediaContent(),buf)

然后,如果我调用self.mediaplayer.play(),它将播放文件到最后。但是,对self.mediaplayer.play() 的所有后续调用均无效。这不是我想要的。

2) 如果我从文件中启动媒体播放器,则:

self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile("/home/me/myTestApp/test.wav")))

它工作正常 - 如果我在上一次播放结束后调用play(),QMediaPlayer 只会重复播放。

【问题讨论】:

    标签: python pyqt pyqt5 qmediaplayer qbuffer


    【解决方案1】:

    QBuffer 是一个 io 设备 - 一旦你读过它,你需要重置它的位置才能再次读取它。所以在你的代码中你需要做这样的事情:

        ...
        self._buffer = buf
        self.mediaPlayer=QMediaPlayer(self)
        self.mediaPlayer.setMedia(QMediaContent(), self._buffer)
    
    def play(self):
        self._buffer.seek(0)
        self.mediaPlayer.play()
    

    编辑

    经过一些实际测试,我发现只需要保留对缓冲区的引用即可重播音频。下面的脚本是一个适合我的完整示例(在 Linux 上,使用 GStreamer 后端):

    import sys
    from PyQt5 import QtCore, QtWidgets, QtMultimedia
    
    class Window(QtWidgets.QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.buttonOpen = QtWidgets.QPushButton('Open', self)
            self.buttonOpen.clicked.connect(self.handleOpen)
            self.buttonPlay = QtWidgets.QPushButton('Play', self)
            self.buttonPlay.clicked.connect(self.handlePlay)
            layout = QtWidgets.QHBoxLayout(self)
            layout.addWidget(self.buttonOpen)
            layout.addWidget(self.buttonPlay)
            self.mediaPlayer = QtMultimedia.QMediaPlayer(self)
            self._buffer = QtCore.QBuffer()
    
        def handlePlay(self):
            if self.buttonPlay.text() == 'Play':
                self.buttonPlay.setText('Stop')
                # self._buffer.seek(0)
                self.mediaPlayer.play()
            else:
                self.buttonPlay.setText('Play')
                self.mediaPlayer.stop()
    
        def handleOpen(self):
            path, ok = QtWidgets.QFileDialog.getOpenFileName(
                self, filter='WAV Files (*.wav)')
            if ok:
                self._buffer.close()
                with open(path, 'rb') as stream:
                    self._buffer.setData(stream.read())
                if self._buffer.open(QtCore.QIODevice.ReadOnly):
                    self.mediaPlayer.setMedia(
                        QtMultimedia.QMediaContent(), self._buffer)
    
    if __name__ == '__main__':
    
        app = QtWidgets.QApplication(sys.argv)
        window = Window()
        window.setGeometry(600, 100, 200, 50)
        window.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 不,它不起作用。而且,实际上,我认为您的解释是错误的,因为如果您重播文件,QMediaPlayer 的实现也必须寻求文件的开头。
    • @al.zatv。是的,我承认我没有测试任何东西,这主要只是一种预感。无论如何,我在我的答案中添加了一个完整的示例。你能测试一下吗?
    • 是的,它正在工作。我稍微改变一下你的解决方案:我在构造函数中读取它,并将其重新设置为对 QMediaPlayer.stateChanged 信号的响应,如果状态设置为 0(停止状态)。它允许我在音频中间暂停后和句号后使用“播放”按钮继续。 def onStateChanged(self): if self.mediaPlayer.state()==0: self.mediaPlayer.setMedia(QMediaContent(), self.wavBuf) 这个解决方案有一些问题: b)移动到停止状态后,位置设置为文件的开头,这在我的应用程序中不方便。
    猜你喜欢
    • 1970-01-01
    • 2020-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多