使用QAbstractVideoSurface

时间:2014-10-07 06:14:31

标签: c++ qt videochat

我想用QT制作视频会议应用。我是新手。如果有人有这方面的例子,我会很感激。

现在,我正在尝试使用qabstractvideosurface的子类在屏幕上显示相机图片。任何人都知道如何做到这一点?

1 个答案:

答案 0 :(得分:17)

QAbstractVideoSurface是视频帧的制作者和消费者之间的接口。 您只需要实现两个函数:

  1. supportedPixelFormats,以便制作人可以为QVideoFrame
  2. 选择合适的格式
  3. present这是show \ display this frame
  4. 的更通用的措辞

    假设您想要使用经典的QWidget进行显示。在这种情况下,您可以选择使用QImage在小部件上绘图。

    第一个Qt保证在大多数平台上绘制一个QImage RGB24(或BGR24)。所以

    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. 从图像到像素图的转换是不必要的。
    3. 您可以编写自己的小部件,并实现paintEvent以获得更好的性能。此外,您对present()的行为方式有几个设计自由。例如:

      • 是否是非阻挡表面,即当存在完成时框架已经显示。上面的意思是使用mylabel->repaint()而不是mylabel->update()
      • 当您无法完成演示时会发生什么。您可能想要绘制一个空白帧而不是返回可能会停止音乐的错误。