您现在的位置是:首页 >技术交流 >qt6 qml 显示yuv数据图像网站首页技术交流

qt6 qml 显示yuv数据图像

Lj2_jOker 2023-05-31 00:00:03
简介qt6 qml 显示yuv数据图像

利用qml中的VideoOutput来显示yuv数据

import QtMultimedia

	VideoOutput {
        id: videoOutput
        anchors.fill: parent
        Component.onCompleted: {
            Config.setSink(videoOutput.videoSink)
        }
    }

在VideoOutput创建完成时,将VideoOutput的videoSink指针传入到c++里面

Config.cpp中的setSink函数

    Q_INVOKABLE void setSink(QObject *_Sink)
    {
        qDebug() << _Sink;
        sink = (QVideoSink *)_Sink;
        emit sinkChanged();
    }

如果你不知道怎么将c++类添加到qml属性里:

#include <QQmlContext>
int main(int argc, char *argv[])
{
	·········
	
	QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    
	QQmlContext *ctx = engine.rootContext();
	ctx->setContextProperty("Config", config);
	
	engine.load(url);
	
	·········

然后在你接收yuv数据的代码中

	static void frameCallback(void *context, unsigned char **data, const int &pix_fmt, const int &width, const int &height)
    {
        Config *config = (Config *)context;
        if (config)
        {
            if (config->frame.isNull())
            {
                QVideoFrameFormat::PixelFormat pixel;
                switch (pix_fmt) {
                case vp::__yuv420p: { pixel = QVideoFrameFormat::Format_YUV420P; }  break;
                default: { pixel = QVideoFrameFormat::Format_Invalid; } break;
                }

                qDebug() << pixel << width << height;
                config->frame.reset(new QVideoFrame(QVideoFrameFormat(QSize(width, height), pixel)));
            }

            config->frame->map(QVideoFrame::ReadWrite);
            for(int i = 0; i < config->frame->planeCount(); i ++) {
                memcpy(config->frame->bits(i), data[i], config->frame->mappedBytes(i));
            }
            config->frame->unmap();

            if (config->sink)
                emit config->sink->videoFrameChanged(*config->frame.data());

        }
    }

config->frame为QVideoFrame
这里只针对yuv420p进行初始化
在QVideoFrame初始化的时候, QVideoFrameFormat::PixelFormat对应你的图像数据格式

按照以往的方法,先将yuv转为rgb然后在传入QQuickImageProvider
在qml通过Image来显示
这样的方法比较麻烦,现在通过VideoOutput显示将节省很多代码
性能的话没有做测试对比

VideoOutput输出的图像比例可以调整fillMode属性

注意在.pro添加multimedia模块

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。