![](/img/trans.png)
[英]How to convert 'QVideoFrame' with YUV data to 'QVideoframe' with RGBA32 data in Qt?
[英]convert QVideoFrame to QImage
我想从QMediaPlayer
获取每一帧并将其转换为QImage
(或cv::Mat
)
所以我使用了来自QVideoProbe
videoFrameProbed
信号:
connect(&video_probe_, &QVideoProbe::videoFrameProbed,
[this](const QVideoFrame& currentFrame){
//QImage img = ??
}
但是我没有找到从QVideoFrame
获取QImage
任何方法!
如何将QVideoFrame
转换为QImage
?!
您可以使用 QImage 的构造函数:
QImage img( currentFrame.bits(),
currentFrame.width(),
currentFrame.height(),
currentFrame.bytesPerLine(),
imageFormat);
您可以从pixelFormat
的QVideoFrame
获取imageFormat
的QVideoFrame
:
QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(currentFrame.pixelFormat());
对于 QCamera 输出,该方法并不总是有效。 特别是,当给定 QVideoFrame::Format_Jpeg 时,QVideoFrame::imageFormatFromPixelFormat() 返回 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;
}
Qt 有一个私有函数qt_imageFromVideoFrame
用于将QVideoFrame
转换为QImage
。 如果你想使用它,你需要:
QT += multimedia multimedia-private
到您的.pro
文件中#include "private/qvideoframe_p.h"
添加到您的.cpp
文件然后你可以使用带有以下签名的qt_imageFromVideoFrame
:
QImage qt_imageFromVideoFrame(const QVideoFrame& f);
请注意标题中的警告:
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
该实现使用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
对于在发现 Qt5.15.0 中不再存在 qt 私有函数“qt_imageFromVideoFrame”后到这里结束的任何人,您现在可以使用新实现的方法 QImage QVideoFrame::image()。
QImage img = frame.image();
我已经在 Ubuntu 上测试过它并且它有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.