PyQt6 6.7.0 — Как исправить ошибку: бэкэнды QtMultimedia не найдены

Проблема в Windows 10 и Windows 11 с использованием Anaconda.

Вот полное сообщение об ошибке для PyQt6=6.7.0:

No QtMultimedia backends found. Only QMediaDevices, QAudioDevice, QSoundEffect, QAudioSink, and QAudioSource are available.
Failed to initialize QMediaPlayer "Not available"
Failed to create QVideoSink "Not available"

Установил PyQt6, используя файл требований:

PyQt6
PyQt6-WebEngine
requests
pyserial
pynput

Вот пара вещей, которые я попробовал:

  1. Переверните версию обратно на PyQt6=6.6.1. Это также приводит к ошибке: ImportError: Ошибка загрузки DLL при импорте QtGui: указанная процедура не найдена.
  2. Я подумал, что проблема может быть в отсутствии ffmpeg, поэтому установил его, но проблема не устранена.
  3. Попробовал настройку на Ubuntu (WSL2), проблема исчезла, но появился просто черный экран, и в виджете ничего не отображается. (Обновлено: все заработало, проблема заключалась в различиях в путях к файлам в Linux и Windows.)

Я новичок в PyQt, поэтому любые советы будут полезны!

Обновлено: Вот общий код (взятый из здесь), который выдает ту же ошибку:

from PyQt6.QtGui import QIcon, QFont
from PyQt6.QtCore import QDir, Qt, QUrl, QSize
from PyQt6.QtMultimedia import QMediaPlayer
from PyQt6.QtMultimediaWidgets import QVideoWidget
from PyQt6.QtWidgets import (QApplication, QFileDialog, QHBoxLayout, QLabel, QStyleFactory,
        QPushButton, QSizePolicy, QSlider, QStyle, QVBoxLayout, QWidget, QStatusBar)


class VideoPlayer(QWidget):

    def __init__(self, parent=None):
        super(VideoPlayer, self).__init__(parent)

        self.mediaPlayer = QMediaPlayer()

        btnSize = QSize(16, 16)
        videoWidget = QVideoWidget()

        openButton = QPushButton("Open Video")   
        openButton.setToolTip("Open Video File")
        openButton.setStatusTip("Open Video File")
        openButton.setFixedHeight(24)
        openButton.setIconSize(btnSize)
        openButton.setFont(QFont("Noto Sans", 8))
        openButton.setIcon(QIcon.fromTheme("document-open", QIcon("D:/_Qt/img/open.png")))
        openButton.clicked.connect(self.abrir)

        self.playButton = QPushButton()
        self.playButton.setEnabled(False)
        self.playButton.setFixedHeight(24)
        self.playButton.setIconSize(btnSize)
        self.playButton.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_MediaPlay))
        self.playButton.clicked.connect(self.play)

        self.positionSlider = QSlider(Qt.Orientation.Horizontal)
        self.positionSlider.setRange(0, 0)
        self.positionSlider.sliderMoved.connect(self.setPosition)

        self.statusBar = QStatusBar()
        self.statusBar.setFont(QFont("Noto Sans", 7))
        self.statusBar.setFixedHeight(14)

        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(openButton)
        controlLayout.addWidget(self.playButton)
        controlLayout.addWidget(self.positionSlider)

        layout = QVBoxLayout()
        layout.addWidget(videoWidget)
        layout.addLayout(controlLayout)
        layout.addWidget(self.statusBar)

        self.setLayout(layout)

        #help(self.mediaPlayer)
        self.mediaPlayer.setVideoOutput(videoWidget)
        self.mediaPlayer.playbackStateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)
        self.mediaPlayer.errorChanged.connect(self.handleError)
        self.statusBar.showMessage("Ready")

    def abrir(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Select Media",
                ".", "Video Files (*.mp4 *.flv *.ts *.mts *.avi)")

        if fileName != '':
            self.mediaPlayer.setSource(QUrl.fromLocalFile(fileName))
            self.playButton.setEnabled(True)
            self.statusBar.showMessage(fileName)
            self.play()

    def play(self):
        if self.mediaPlayer.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()

    def mediaStateChanged(self, state):
        if self.mediaPlayer.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self.playButton.setIcon(
                    self.style().standardIcon(QStyle.StandardPixmap.SP_MediaPause))
        else:
            self.playButton.setIcon(
                    self.style().standardIcon(QStyle.StandardPixmap.SP_MediaPlay))

    def positionChanged(self, position):
        self.positionSlider.setValue(position)

    def durationChanged(self, duration):
        self.positionSlider.setRange(0, duration)

    def setPosition(self, position):
        self.mediaPlayer.setPosition(position)

    def handleError(self):
        self.playButton.setEnabled(False)
        self.statusBar.showMessage("Error: " + self.mediaPlayer.errorString())

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    player = VideoPlayer()
    player.setWindowTitle("Player")
    player.resize(900, 600)
    player.show()
    sys.exit(app.exec())

Видео, которые я хочу воспроизвести, находятся в той же папке, что и этот файл .py. Окружающая среда conda (python 3.9.2), над которой я работаю, имеет следующие пакеты:

certifi                     2024.6.2
charset-normalizer          3.3.2
idna                        3.7
pip                         24.0
pynput                      1.7.6
PyQt6                       6.7.0
PyQt6-Qt6                   6.7.1
PyQt6-sip                   13.6.0
PyQt6-WebEngine             6.7.0
PyQt6-WebEngine-Qt6         6.7.1
PyQt6-WebEngineSubwheel-Qt6 6.7.1
pyserial                    3.5
requests                    2.31.0
setuptools                  69.5.1
six                         1.16.0
urllib3                     2.2.1
wheel                       0.43.0

PS: Похоже, у MacOS та же проблема.

1. Вам не нужно «раскрывать код», вы должны предоставить правильный минимально воспроизводимый пример, который воспроизводит ту же проблему; 2. Как вы установили PyQt? 3. Какая ОС? Обратите внимание: при использовании стандартного дистрибутива Qt QtMultimedia использует внутреннюю сборку ffmpeg, но если вы устанавливаете ее с помощью управления пакетами вашей ОС, она может отличаться.

musicamante 04.06.2024 20:08

Я пытаюсь запустить видео (.mp4) в виджете, но получаю эту ошибку и черный экран.

Belleroph0N 04.06.2024 20:27

Я обновил вопрос, включив в него минимальный воспроизводимый пример (по крайней мере, в моей системе) @musicamante.

Belleroph0N 04.06.2024 20:43

Похоже, это связано с отчетом о выпуске 6.7.0-1 . Следующие сообщения (в теме и в ML) не упоминают официальные исправления, за исключением возможного обходного пути, требующего локальной перестройки. Недавно была обнаружена похожая, возможно, связанная с PYSIDE-2656 проблема. Помните, что также важно всегда сообщать фактическую версию Qt, которая не всегда соответствует версии привязок: для PyQt используйте QtCore.QT_VERSION_STR.

musicamante 05.06.2024 06:19

Я нашел обходной путь. Проблема определенно связана с самыми последними выпусками PyQt6. Ответ опубликую сегодня где-нибудь. Спасибо! @musicamante

Belleroph0N 05.06.2024 15:46
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
5
418
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема с серверной частью вызвана новой версией PyQt6=6.7.0. Простого обновления версии PyQt6 и PyQt6-WebEngine до предыдущей версии было недостаточно, поскольку подпакеты, которые были установлены как часть этой версии, не были обновлены автоматически. Это вызвало проблему из-за несоответствия пакетов:

PyQt6: DLL load failed while importing QtGui: The specified procedure could not be found.

Чтобы это исправить, переустановите все соответствующие пакеты вручную. Вот файл requirements.txt, который я сгенерировал после того, как все заработало:

pynput==1.7.7
PyQt6==6.6.0
PyQt6-Qt6==6.6.0
PyQt6-sip==13.6.0
PyQt6-WebEngine==6.6.0
PyQt6-WebEngine-Qt6==6.6.0
PyQt6-WebEngineSubwheel-Qt6==6.7.1
pyserial==3.5
requests==2.32.3

ПРИМЕЧАНИЕ. Я считаю, что разработчики знают об этой проблеме и решили ее. Он будет выпущен в следующей версии (см. также комментарий @musicamante).

Примечание: отчет об ошибке касается PySide (помните, что PySide и PyQt — это не одно и то же), и хотя между этими двумя ошибками может быть связь, их исправление может и не быть. Согласно сегодняшнему сообщению от сопровождающего PyQt, это будет исправлено, как только выйдет следующая версия Qt (6.7.2), которая ожидается в конце следующей недели; если я правильно понимаю, он соответствующим образом обновит колеса PyQt.

musicamante 06.06.2024 00:11

Другие вопросы по теме