使用 QAbstractVideoSurface 在屏幕上显示[关闭]

问题描述 投票:0回答:1

我正在尝试使用 QAbstractVideoSurface 的子类在屏幕上显示相机图片,但我对此没有经验。

如果有人能解释如何做,我将不胜感激。

c++ qt videochat
1个回答
24
投票

QAbstractVideoSurface
是视频帧的生产者和消费者之间的接口。 首先,您只需实现两个函数:

  1. supportedPixelFormats
    以便制作者可以为
    QVideoFrame
  2. 选择合适的格式
  3. present
    这是显示\显示此框架的更通用措辞

假设您想使用经典的

QWidget
进行显示。在这种情况下,您可以选择使用
QImage
在小部件上绘图。

首先 Qt 保证在大多数平台上绘制 RGB24(或 BGR24)的

QImage
。所以

QList<QVideoFrame::PixelFormat> LabelBasedVideoSurface::supportedPixelFormats(
        QAbstractVideoBuffer::HandleType handleType) const
{
    if (handleType == QAbstractVideoBuffer::NoHandle) {
        return QList<QVideoFrame::PixelFormat>()
                << QVideoFrame::Format_RGB24;
    } else {
        return QList<QVideoFrame::PixelFormat>();
    }
}

现在要呈现 QVideoFrame,您将其数据映射到 QImage,并将 QImage 绘制到小部件。为简单起见,我将使用

QLabel
,我可以直接访问它(无信号无插槽)。

bool LabelBasedVideoSurface::present(const QVideoFrame &frame)
{
    if (notMyFormat(frame.pixelFormat())) {
        setError(IncorrectFormatError);
        return false;
    } else {

        QVideoFrame frametodraw(frame);

        if(!frametodraw.map(QAbstractVideoBuffer::ReadOnly))
        {
           setError(ResourceError);
           return false;
        } 

         //this is a shallow operation. it just refer the frame buffer
         QImage image(
                frametodraw.bits(),
                frametodraw.width(),
                frametodraw.height(),
                frametodraw.bytesPerLine(),
                QImage::Format_RGB444);

        mylabel->resize(image.size());

        //QPixmap::fromImage create a new buffer for the pixmap
        mylabel->setPixmap(QPixmap::fromImage(image));

        //we can release the data
        frametodraw.unmap();

        mylabel->update();

        return true;
    }
}

这个例子显然不是最优的。

  1. 由于
    QVideoFrame
    可能存储在视频内存中,因此不需要花费金钱,因为我们正在使用像素图进行绘制。
  2. 从图像到像素图的转换是不必要的。

您可以编写自己的小部件,并实现paintEvent以获得更好的性能。此外,您对

present()
的行为方式有多种设计自由。例如:

  • 是否是非遮挡面,即当前完成时已显示框架。上面的意思是使用
    mylabel->repaint()
    而不是
    mylabel->update()
  • 当您无法完成演示时会发生什么。您可能想绘制一个空白框,而不是返回可能停止音乐的错误。
© www.soinside.com 2019 - 2024. All rights reserved.