在Qt中显示解码视频帧的最有效方法是什么?
c++
image-processing
5
0

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

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

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

谢谢。

参考资料:
Stack Overflow
收藏
评论
共 3 个回答
高赞 时间 活跃

根据您的OpenGL /着色技术,您可以尝试将视频帧复制到纹理,将纹理映射到矩形(或其他任何样式,.. fun!)并在OpenGL场景中显示。不是最直接的方法,而是最快的方法,因为您是直接写入图形内存(如SDL)。我也建议只使用YCbCR,因为此格式是压缩的(颜色,Y =完整Cb,Cr是帧的1/4),因此显示一个帧需要较少的内存+较少的复制。我不是直接使用Qts GL,而是间接在Qt中使用GL(相对于OSG),并且可以实时显示约7-11个全高清(1440 x 1080)视频。

收藏
评论

我对gtkmm(gtk + C ++包装)有同样的问题。除了使用SDL覆盖图之外,最好的解决方案是直接更新小部件的图像缓冲区,然后请求重绘。但是我不知道Qt是否可行...

我的2美分

收藏
评论

感谢您的回答,但是我终于重新审视了这个问题,并提出了一个相当简单的解决方案,可以提供良好的性能。它涉及从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);
}

这样,我仍然必须将YUV 420P转换为RGB32,但是ffmpeg在libswscale中具有非常快速的转换实现。主要收益来自两件事:

  • 无需软件扩展。缩放在视频卡上完成(如果有)
  • QPainter::drawImage()函数中发生的从QImageQPixmap转换是以原始图像分辨率执行的,而不是按比例缩放的全屏分辨率。

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

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号