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

C++ 在Qt中显示解码视频帧最有效的方法是什么?,c++,qt,image-processing,C++,Qt,Image Processing,向Qt小部件显示图像的最快方式是什么?我已经用libavformat和libavcodec解码了视频,所以我已经有了原始RGB或YCbCr 4:2:0帧。我目前正在使用QGraphicsView和包含QGraphicsPixmapItem的QGraphicscene对象。我目前正在使用QImage构造函数从内存缓冲区获取帧数据到QPixmap,并使用QPixmap::fromImage()将其转换为QPixmap 我喜欢这样做的结果,而且速度似乎相对较快,但我忍不住认为必须有一种更有效的方法。我

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

我喜欢这样做的结果,而且速度似乎相对较快,但我忍不住认为必须有一种更有效的方法。我还听说QImage到QPixmap的转换非常昂贵。我已经实现了一个在小部件上使用SDL覆盖的解决方案,但我只想使用Qt,因为我能够使用QGraphicsView轻松捕获点击和其他用户与视频显示的交互

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


谢谢。

< P>我和GTKMM(GTK+C++包裹)有同样的问题。除了使用SDL覆盖外,最好的解决方案是直接更新小部件的图像缓冲区,然后要求重新绘制。但我不知道Qt是否可行


我的2美分

根据您的OpenGL/着色技能,您可以尝试将视频帧复制到纹理,将纹理映射到矩形(或任何其他..有趣!)并在OpenGL场景中显示它。这不是最直接的方法,但速度很快,因为您直接将数据写入图形内存(如SDL)。我还建议只使用YCbCR,因为这种格式是压缩的(颜色,Y=完全Cb,Cr是帧的1/4),所以显示帧需要更少的内存+更少的复制。我不是直接使用Qts GL,而是在Qt(vis OSG)中间接使用GL,可以实时显示大约7-11个全高清(1440 x 1080)视频。

感谢您的回答,但我最终重新讨论了这个问题,并提出了一个相当简单的解决方案,提供了良好的性能。它涉及从
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);
}
有了这个,我仍然需要将YUV420P转换为RGB32,但是ffmpeg在libswscale中有一个非常快速的转换实现。主要的收益来自两方面:

  • 不需要软件扩展。在视频卡上进行缩放(如果可用)
  • QImage
    QPixmap
    的转换发生在
    QPainter::drawImage()
    函数中,该转换以原始图像分辨率执行,而不是以放大的全屏分辨率执行

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

我在解码器线程中使用swscale将YUV数据包转换为rgb,并使用了您的方法。运行完美。
p.SetRenderHint(QPainter::SmoothPixmapTransform,1)
-setRenderHint应该是小写的。Qt Designer说这里什么是
QGLWidget
,没有这样的文件?很好的例子,节省了我很多时间@BahramdunAdil,
QGLWidget
已被弃用,并被
QOpenGLWidget
取代。它稍有不同,但对于这个简单的示例,它的工作原理应该类似。