在Qt中显示解码视频帧的最有效方法是什么?

Jas*_*n B 36 c++ qt image-processing

将图像显示到Qt小部件的最快方法是什么?我使用libavformat和libavcodec解码了视频,所以我已经有了原始RGB或YCbCr 4:2:0帧.我目前正在使用QGraphicsView和一个包含QGraphicsPixmapItem的QGraphicsScene对象.我目前通过使用内存缓冲区中的QImage构造函数将帧数据转换为QPixmap,并使用QPixmap :: fromImage()将其转换为QPixmap.

我喜欢这个结果,看起来相对较快,但我不禁想到必须有一个更有效的方法.我也听说QImage到QPixmap的转换很昂贵.我已经实现了一个在小部件上使用SDL覆盖的解决方案,但我想继续使用Qt,因为我能够使用QGraphicsView轻松捕获点击和其他用户与视频显示的交互.

我正在使用libswscale进行任何所需的视频缩放或颜色空间转换,所以我只想知道是否有人在执行所有处理后有更有效的方式显示图像数据.

谢谢.

Jas*_*n B 33

感谢您的回答,但我终于重新审视了这个问题,并提出了一个相当简单的解决方案,可以提供良好的性能.它涉及从函数派生QGLWidget和重写paintEvent().在paintEvent()函数内部,您可以调用QPainter::drawImage(...)它,如果可用,它将使用硬件为您执行缩放到指定的矩形.所以它看起来像这样:

class QGLCanvas : public QGLWidget
{
public:
    QGLCanvas(QWidget* parent = NULL);
    void setImage(const QImage& image);
protected:
    void paintEvent(QPaintEvent*);
private:
    QImage img;
};

QGLCanvas::QGLCanvas(QWidget* parent)
    : QGLWidget(parent)
{
}

void QGLCanvas::setImage(const QImage& image)
{
    img = image;
}

void QGLCanvas::paintEvent(QPaintEvent*)
{
    QPainter p(this);

    //Set the painter to use a smooth scaling algorithm.
    p.setRenderHint(QPainter::SmoothPixmapTransform, 1);

    p.drawImage(this->rect(), img);
}
Run Code Online (Sandbox Code Playgroud)

有了这个,我仍然需要将YUV 420P转换为RGB32,但ffmpeg在libswscale中实现了非常快速的转换.主要收益来自两件事:

  • 无需软件扩展.缩放在视频卡上完成(如果可用)
  • 从转换QImageQPixmap,这是在发生QPainter::drawImage()函数在原始图像的分辨率进行,而不是对放大全屏分辨率.

我用我之前的方法将处理器挂在显示器上(解码是在另一个线程中完成).现在我的显示线程仅使用大约8-9%的核心来进行全屏1920x1200 30fps播放.我敢肯定,如果我可以将YUV数据直接发送到视频卡,它可能会变得更好,但现在这已经足够好了.