Как QMediaPlayer.setPosition работает для mp3? - PullRequest
0 голосов
/ 03 августа 2020

У меня возникает проблема, когда я пытаюсь воспроизвести песню с определенной позиции: она не работает (песня воспроизводится с начала).

Эта проблема возникает, только если песня является 'mp3 'song, а не' m4a '(это единственный формат, который я тестировал).

Кажется, проблема исходит от qt (или PyQt?), но я не уверен, вот минимальный пример, я что-то пропустил?

from PyQt5.QtWidgets import QApplication
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtCore import QUrl

if __name__ == "__main__":
    app = QApplication([])

    player = QMediaPlayer()
    media_content = QMediaContent(QUrl.fromLocalFile("path_to_my_music_file.mp3"))
    player.setMedia(media_content)
    player.setPosition(10000)
    player.play()

    app.exec_()

1 Ответ

1 голос
/ 04 августа 2020

setMedia() асинхронно:

Примечание. Эта функция возвращается сразу после записи указанного источника носителя. Не дожидается завершения загрузки носителя sh и не проверяет наличие ошибок . Прослушивайте сигналы mediaStatusChanged () и error (), чтобы получать уведомления при загрузке носителя и при возникновении ошибки во время загрузки.

Возможно, что из-за природы файлов MP3 Qt принимает некоторое время прежде, чем смогу правильно искать. К сожалению, насколько я могу судить, это можно сделать только по прошествии некоторого времени после воспроизведения файла.

Возможное решение - подключиться к настраиваемой функции, которая задерживает setPosition, пока носитель не станет доступным для поиска.

Это подкласс, который должен позаботиться об этом (я тестировал только с файлами mp3, поэтому вы должны попробовать его с другими типами файлов, чтобы убедиться, что он работает правильно).

class Player(QMediaPlayer):
    _delayedPos = 0
    def setPosition(self, pos):
        super().setPosition(pos)
        if pos and not self.isSeekable():
            self._delayedPos = pos
            try:
                # ensure that the connection is done only once
                self.seekableChanged.connect(self.delaySetPosition, Qt.UniqueConnection)
            except:
                pass
        else:
            self._delayedPos = 0

    def delaySetPosition(self, seekable):
        if seekable:
            self.setPosition(self._delayedPos)
        try:
            # just to be safe, in case the media changes before the previous one
            # becomes seekable
            self.seekableChanged.disconnect(self.delaySetPosition)
        except:
            pass
...