Qt有一个名为qt_imageFromVideoFrame
的私有函数,用于将QVideoFrame
转换为QImage
。如果您想使用它,需要:
- 在您的
.pro
文件中添加QT += multimedia multimedia-private
- 在您的
.cpp
文件中添加#include "private/qvideoframe_p.h"
然后您就可以使用以下签名的qt_imageFromVideoFrame
函数:
QImage qt_imageFromVideoFrame(const QVideoFrame& f);
请注意头文件中的警告:
实现使用
QVideoFrame::map()
并对位进行低级别操作。转换器处理多种条件,包括 YUV。
qt_imageFromVideoFrame
在几乎所有平台上都有效,如Windows、macOS、Linux和iOS。唯一不太可靠的平台是Android。在那里,你需要使用OpenGL调用来提取VideoFrame。此外,在Android上,您需要在最后调用
QImage:rgbSwapped()
,因为 QImage 存储图像的格式为 ARGB,而 OpenGL 检索到的格式为 ABGR。
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 ) return 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.rgbSwapped();
}
return QImage();
}
我在GitHub上有一个完整的应用程序,其中包括上述函数的实现:
https://github.com/stephenquan/MyVideoFilterApp/blob/master/QVideoFrameToQImage.cpp