修改并显示QAbstractVideoSurface中获取的QVideoFrame

Modifing and displaying QVideoFrames obtained in QAbstractVideoSurface

我有一个用 QT 编写的非常简单的应用程序,我想在其中使用 QMediaPlayer 显示电影,但在显示任何帧之前,我想在其上检测一些对象并标记它们在上面画一个矩形。

我在 http://doc.qt.io/qt-5/videooverview.html 中读到我可以通过 subclassing QAbstractVideoSurface 访问每一帧,所以我修改了它。

class VideoSurface : public QAbstractVideoSurface {
    Q_OBJECT

    bool present(const QVideoFrame &frame) override {
        if (surfaceFormat().pixelFormat() != frame.pixelFormat()
                || surfaceFormat().frameSize() != frame.size()) {
            setError(IncorrectFormatError);
            stop();

            return false;
        } else {
            currentFrame = frame;

            return true;
        }
    }

    ...
}

现在,我收到这个成员函数框架,我想通过在我检测到对象的地方绘制矩形来修改它,然后我想将它们显示在屏幕上(最好是在某些小部件上)。

我该怎么做?

  1. 我的 VideoSurface class 是否应该包含 QWidget 作为成员?或者我应该 subclass QWidget 包含 VideoSurface?

  2. 在这两种情况下,如何显示此帧?我应该先将它转换为 QImage 然后再显示吗(这对我来说很方便,因为我的检测系统正在使用 QImage,但它是否有效)?我知道我不能从绘画事件外部绘画,所以我不能在 present 函数中绘画,那么这个绘画函数到底应该在哪里,我该如何调用它?

  3. 我应该在哪里检测那些对象并修改框架?在present函数中,还是在绘图函数中?

  1. 这取决于您,取决于您喜欢如何构建 classes。我更愿意有一个单独的小部件,它包含一个指向您的 VideoSurface 的指针,并绘制由 VideoSurface 的某些成员函数返回的数据(取决于您在 2 中的解决方案。)

  2. a) QImage 对于某些用途来说足够高效,如果您已经在检测代码中使用它,那么您已经在内存中拥有了所有内容并且可以对其进行处理。与所有与性能相关的担忧一样:测试并查看性能是否足够好。如果不是,您可能还必须考虑以不同的方式进行检测。我参与了一个项目,在该项目中,我们处理了从移动设备上的相机流上的类似 VideoSurface 转换而来的 QImage(对于分辨率相对较低的图像),并且性能足够好,我们还没有费心使用其他技术。该项目 (Neuronify) is hosted here 中 VideoSurface class 的源代码。 b) 您的 present() 函数可以发出一个信号,您可以从其他对象连接到该信号,这些对象从 VideoSurface 获取最新数据并保留它直到调用它们的绘制函数。或者您可以将数据直接应用到某些接受图像数据的小部件。有关示例,请参阅 Use of QAbstractVideoSurface

  3. 同样,这取决于您 :) 但是,如果您需要在某个时候提高性能,您可能希望在不同的线程上进行这项工作,以防止 GUI 在您执行操作时锁定正在处理数据。如果这样做,您需要决定是否必须处理每一帧,或者某些帧是否可以跳过处理以提高播放的 FPS。在后一种情况下,您可能不应该在 present() 函数中执行此操作,因为这可能会使媒体播放器无法在您处理旧帧时为您提供更多帧。