将QVideoFrame转换为QImage

时间:2015-01-07 22:30:36

标签: c++ qt qimage

我希望从QMediaPlayer获取每个帧并将其转换为QImage(或cv::Mat

所以我使用了来自videoFrameProbed的{​​{1}}信号:

QVideoProbe

但我没有找到任何方法从connect(&video_probe_, &QVideoProbe::videoFrameProbed, [this](const QVideoFrame& currentFrame){ //QImage img = ?? } 获取QImage

如何将QVideoFrame转换为QVideoFrame?!

4 个答案:

答案 0 :(得分:8)

您可以使用QImage的构造函数:

 QImage img( currentFrame.bits(),
             currentFrame.width(),
             currentFrame.height(),
             currentFrame.bytesPerLine(),
             imageFormat);

您可以从[{1}}的{​​{1}}获得imageFormat的位置:

pixelFormat

答案 1 :(得分:5)

对于QCamera输出,该方法并不总是有效。特别是,QVideoFrame :: imageFormatFromPixelFormat()在给定QVideoFrame :: Format_Jpeg时返回QImage :: Format_Invalid,这是我的QCamera中出现的内容。但这有效:

QImage Camera::imageFromVideoFrame(const QVideoFrame& buffer) const
{
    QImage img;
    QVideoFrame frame(buffer);  // make a copy we can call map (non-const) on
    frame.map(QAbstractVideoBuffer::ReadOnly);
    QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(
                frame.pixelFormat());
    // BUT the frame.pixelFormat() is QVideoFrame::Format_Jpeg, and this is
    // mapped to QImage::Format_Invalid by
    // QVideoFrame::imageFormatFromPixelFormat
    if (imageFormat != QImage::Format_Invalid) {
        img = QImage(frame.bits(),
                     frame.width(),
                     frame.height(),
                     // frame.bytesPerLine(),
                     imageFormat);
    } else {
        // e.g. JPEG
        int nbytes = frame.mappedBytes();
        img = QImage::fromData(frame.bits(), nbytes);
    }
    frame.unmap();
    return img;
}

答案 2 :(得分:1)

在很多情况下,Qt都具有将QVideoFrame转换为QImage的私有功能。如果要使用它,则需要像向前声明一样标头:

QImage qt_imageFromVideoFrame( const QVideoFrame& f );

这适用于大多数情况,包括来自YUV的转化。但是,对于Android,您确实需要使用OpenGL调用来从GLTexture检索图像。下面演示了如何获取ARGB32格式的QImage:

#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QQmlContext>

QImage qt_imageFromVideoFrame( const QVideoFrame& f );

QImage QVideoFrameToQImage( const QVideoFrame& videoFrame )
{
    if ( videoFrame.handleType() == QAbstractVideoBuffer::NoHandle )
    {
        QImage image = qt_imageFromVideoFrame( videoFrame );
        if ( image.isNull() )
        {
            return QImage();
        }
        if ( image.format() != QImage::Format_ARGB32 )
        {
            image = image.convertToFormat( QImage::Format_ARGB32 );
        }
        return image;
    }

    if ( videoFrame.handleType() == QAbstractVideoBuffer::GLTextureHandle )
    {
        QImage image( videoFrame.width(),  videoFrame.height(), QImage::Format_ARGB32 );
        GLuint textureId = static_cast<GLuint>( videoFrame.handle().toInt() );
        QOpenGLContext* ctx = QOpenGLContext::currentContext();
        QOpenGLFunctions* f = ctx->functions();
        GLuint fbo;
        f->glGenFramebuffers( 1, &fbo );
        GLint prevFbo;
        f->glGetIntegerv( GL_FRAMEBUFFER_BINDING, &prevFbo );
        f->glBindFramebuffer( GL_FRAMEBUFFER, fbo );
        f->glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0 );
        f->glReadPixels( 0, 0,  videoFrame.width(),  videoFrame.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.bits() );
        f->glBindFramebuffer( GL_FRAMEBUFFER, static_cast<GLuint>( prevFbo ) );
        return image;
    }

    return QImage();
}

答案 3 :(得分:1)

对于发现在Qt5.15.0中不再存在qt私有函数“ qt_imageFromVideoFrame”之后到此处结束的任何人,您现在可以使用新实现的方法QImage QVideoFrame :: image()。

QImage img = frame.image();

我已经在Ubuntu上对其进行了测试,并且可以正常工作。