【qml】QML使用VideoOutput渲染视频

Qt帮助文档对VideoOutput的source属性的描述:
This property holds the source item providing the video frames like MediaPlayer or Camera.
If you are extending your own C++ classes to interoperate with VideoOutput, you can either provide a QObject based class with a mediaObject property that exposes a QMediaObject derived class that has a QVideoRendererControl available, or you can provide a QObject based class with a writable videoSurface property that can accept a QAbstractVideoSurface based class and can follow the correct protocol to deliver QVideoFrames to it.
这里使用的第二种方法。

创建一个继承于QObject的类(class RtspPlayer : public QObject)。
声明QAbstractVideoSurface *videoSurface属性:
Q_PROPERTY(QAbstractVideoSurface *videoSurface READ videoSurface WRITE setVideoSurface)
public:
inline QAbstractVideoSurface *videoSurface() { return m_surface; }
void setVideoSurface(QAbstractVideoSurface *surface);
private:
QAbstractVideoSurface *m_surface;
1
2
3
4
5
6
解码视频,将获得视频帧传递给m_surface:
void RtspPlayer::setVideoSurface(QAbstractVideoSurface *surface)
{
//qDebug() << surface->supportedPixelFormats();

if (m_surface == surface)
    return;

if (m_surface && m_surface->isActive()) {
    m_surface->stop();
}

m_surface = surface;

if (m_surface)
    m_surface->start(m_format);

}

void RtspPlayer::onNewVideoFrameReceived(const QVideoFrame &frame)
{
if (m_surface)
m_surface->present(frame);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
源码:
头文件

#ifndef RTSPPLAYER_H
#define RTSPPLAYER_H

#include
#include
#include
#include
#include “RtspDecoder.h”

class RtspPlayer : public QObject
{
Q_OBJECT
Q_PROPERTY(QAbstractVideoSurface *videoSurface READ videoSurface WRITE setVideoSurface)
Q_PROPERTY(RtspDecoder *decoder READ decoder WRITE setDecoder NOTIFY decoderChanged)
Q_PROPERTY(int width READ width NOTIFY widthChanged)
Q_PROPERTY(int height READ height NOTIFY heightChanged)

public:
explicit RtspPlayer(QObject *parent = nullptr);
~RtspPlayer();

inline QAbstractVideoSurface *videoSurface() { return m_surface; }
void setVideoSurface(QAbstractVideoSurface *surface);

inline RtspDecoder *decoder() const { return m_decoder; }
void setDecoder(RtspDecoder *decoder);

inline int width() const;
inline int height() const;

signals:
void decoderChanged(RtspDecoder *decoder);

void widthChanged(int width);
void heightChanged(int height);

public slots:
void onFrameSizeChanged(int width, int height);
void onNewVideoFrameReceived(const QVideoFrame &frame);

protected:
void setWidth(int width);
void setHeight(int height);
void setSize(int width, int height);

private:
QVideoSurfaceFormat m_format;
QAbstractVideoSurface *m_surface;
RtspDecoder *m_decoder;
};

int RtspPlayer::width() const
{
return m_format.frameSize().width();
}

int RtspPlayer::height() const
{
return m_format.frameSize().height();
}

#endif // RTSPPLAYER_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
源文件:

#include “RtspPlayer.h”
#include
#include

RtspPlayer::RtspPlayer(QObject *parent)
QObject(parent)
, m_format(QSize(0, 0), QVideoFrame::Format_YUV420P)
, m_surface(nullptr)
, m_decoder(nullptr)
{

}

RtspPlayer::~RtspPlayer()
{

}

void RtspPlayer::setVideoSurface(QAbstractVideoSurface *surface)
{
//qDebug() << surface->supportedPixelFormats();

if (m_surface == surface)
    return;

if (m_surface && m_surface->isActive()) {
    m_surface->stop();
}

m_surface = surface;

if (m_surface)
    m_surface->start(m_format);

}

void RtspPlayer::setDecoder(RtspDecoder *decoder)
{
if (m_decoder == decoder)
return;

if (m_decoder) {
    disconnect(m_decoder, SIGNAL(frameSizeChanged(int,int)),
               this, SLOT(onFrameSizeChanged(int,int)));

    disconnect(m_decoder, SIGNAL(newVideoFrame(QVideoFrame)),
               this, SLOT(onNewVideoFrameReceived(QVideoFrame)));
}

if (decoder) {
    connect(decoder, SIGNAL(frameSizeChanged(int,int)),
            this, SLOT(onFrameSizeChanged(int,int)));

    connect(decoder, SIGNAL(newVideoFrame(QVideoFrame)),
            this, SLOT(onNewVideoFrameReceived(QVideoFrame)));

    onFrameSizeChanged(decoder->width(), decoder->height());
} else {
    if (m_surface)
        m_surface->stop();
}

m_decoder = decoder;

emit decoderChanged(m_decoder);

}

void RtspPlayer::onFrameSizeChanged(int width, int height)
{
m_format.setFrameSize(width, height);

emit widthChanged(width);
emit heightChanged(height);

if (m_surface)
    m_surface->start(m_format);

}

void RtspPlayer::onNewVideoFrameReceived(const QVideoFrame &frame)
{
if (m_surface)
m_surface->present(frame);
}

void RtspPlayer::setWidth(int width)
{
if (this->width() == width)
return;

m_format.setFrameSize(width, this->height());

emit widthChanged(width);

}

void RtspPlayer::setHeight(int height)
{
if (this->height() == height)
return;

m_format.setFrameSize(this->width(), height);

emit heightChanged(height);

}

void RtspPlayer::setSize(int width, int height)
{
m_format.setFrameSize(width, height);

emit widthChanged(width);
emit heightChanged(height);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
VideoOutput {
source: …
}

你可能感兴趣的:(【qml】QML使用VideoOutput渲染视频)