我们正在使用基于 PyQt5 的工具进行一些视频处理。几天以来,一些用户抱怨该工具只显示黑屏而不是视频。声音仍然有效。我们能够使用一个小脚本重现此问题:
import os
from PyQt5 import QtCore, QtWidgets, QtMultimedia, QtMultimediaWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, path, parent=None):
super(MainWindow, self).__init__(parent)
video_widget = QtMultimediaWidgets.QVideoWidget()
self.setCentralWidget(video_widget)
self.player = QtMultimedia.QMediaPlayer(self, QtMultimedia.QMediaPlayer.VideoSurface)
self.player.setVideoOutput(video_widget)
self.player.setMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(path)))
self.player.play()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
file = "<file>.MP4"
w = MainWindow(file)
w.show()
sys.exit(app.exec_())
奇怪的是,所有用户都使用基于 Ubuntu 18.04 的相同桌面,但只有少数用户受到此问题的影响。我看不出他们的安装有任何可能与此问题相关的差异。我发现了许多相关问题,其中大多数都已过时。这似乎是某种 gstreamer 问题。但我不知道如何深入研究这个主题。
答案1
不同系统上某些用户的管道不同,而其他用户则不同,这表明 VAAPI 存在问题。按照以下说明禁用 VAAPI 后,一切正常:暂时跳过decodebin中的vaapi解码器。
有时,禁用 gstreamer 自动插入逻辑中的 vaapi 会很有用,例如当存在未决问题时,或者当需要强制在 decryptbin 中选择解码器以进行测试时。
标准可能性包括:
- 彻底删除 gstreamer-vaapi
- 覆盖插件排名系统以将 vaapi 插件降级到其他替代方案以下 - 这需要使用 gstreamer API,但 gst-launch 或 totem 无法使用。
我发现了一种更简单的方法:将 LIBVA_DRIVER_NAME 定义为一个假值,这将强制 vaapi 初始化失败,从而跳过其插件。
例如:
LIBVA_DRIVER_NAME=fakedriver gst-launch-1.0 playbin uri=file:///tmp/file.mp4
没有它:
$ gst-launch-1.0 playbin uri=file://`pwd`/bbb-1920-1080-30.mp4
Got context from element 'vaapisink0': gst.vaapi.Display=context, gst.vaapi.Display=(GstVaapiDisplay)"\(GstVaapiDisplayGLX\)\ vaapidisplayglx0";
通过环境变量,我们可以看到已经选择了 avdec_h264:
LIBVA_DRIVER_NAME=fakedriver gst-launch-1.0 playbin uri=file://`pwd`/bbb-1920-1080-30.mp4 -v
...
/GstPlayBin:playbin0/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/avdec_h264:avdec_h264-0.GstPad:sink: caps = video/x-h264, stream-format=(string)avc, alignment=(string)au, level=(string)4.1, profile=(string)high, codec_data=(buffer)01640029ffe1001b67640029acca501e0089f970110000030001000003003c8f18319601000568e93b2c8b, width=(int)1920, height=(int)1080, framerate=(fraction)30/1, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, chroma-format=(string)4:2:0, bit-depth-luma=(uint)8, bit-depth-chroma=(uint)8, parsed=(boolean)true