1// Copyright (C) 2016 Jolla Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QGSTVIDEORENDERERSINK_P_H
5#define QGSTVIDEORENDERERSINK_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtMultimedia/qvideoframeformat.h>
19#include <QtMultimedia/qvideoframe.h>
20#include <QtMultimedia/private/qtmultimediaglobal_p.h>
21#include <QtCore/qcoreevent.h>
22#include <QtCore/qlist.h>
23#include <QtCore/qmutex.h>
24#include <QtCore/qpointer.h>
25#include <QtCore/qqueue.h>
26#include <QtCore/qwaitcondition.h>
27
28#include <gst/video/gstvideosink.h>
29#include <gst/video/video.h>
30
31#include <common/qgstvideobuffer_p.h>
32#include <common/qgst_p.h>
33
34QT_BEGIN_NAMESPACE
35
36namespace QGstUtils {
37
38template <typename T>
39class QConcurrentQueue
40{
41public:
42 qsizetype enqueue(T value)
43 {
44 QMutexLocker locker(&mutex);
45 queue.append(std::move(value));
46 return queue.size();
47 }
48
49 std::optional<T> dequeue()
50 {
51 QMutexLocker locker(&mutex);
52 if (queue.isEmpty())
53 return std::nullopt;
54
55 return queue.takeFirst();
56 }
57
58 void clear()
59 {
60 QMutexLocker locker(&mutex);
61 queue.clear();
62 }
63
64private:
65 QMutex mutex;
66 QList<T> queue;
67};
68
69} // namespace QGstUtils
70
71class QGstVideoRenderer : public QObject
72{
73 struct RenderBufferState
74 {
75 QGstBufferHandle buffer;
76 QVideoFrameFormat format;
77 QGstCaps::MemoryFormat memoryFormat;
78
79 bool operator==(const RenderBufferState &rhs) const
80 {
81 return std::tie(args: buffer, args: format, args: memoryFormat)
82 == std::tie(args: rhs.buffer, args: rhs.format, args: rhs.memoryFormat);
83 }
84 };
85
86 static constexpr QEvent::Type renderFramesEvent = static_cast<QEvent::Type>(QEvent::User + 100);
87 static constexpr QEvent::Type stopEvent = static_cast<QEvent::Type>(QEvent::User + 101);
88
89public:
90 explicit QGstVideoRenderer(QGstreamerVideoSink *);
91 ~QGstVideoRenderer();
92
93 const QGstCaps &caps();
94
95 bool start(const QGstCaps &);
96 void stop();
97 void unlock();
98 bool proposeAllocation(GstQuery *);
99 GstFlowReturn render(GstBuffer *);
100 bool query(GstQuery *);
101 void gstEvent(GstEvent *);
102
103 void setActive(bool);
104
105private:
106 void updateCurrentVideoFrame(QVideoFrame);
107
108 void notify();
109 static QGstCaps createSurfaceCaps(QGstreamerVideoSink *);
110
111 void customEvent(QEvent *) override;
112 void handleNewBuffer(RenderBufferState);
113
114 void gstEventHandleTag(GstEvent *);
115 void gstEventHandleEOS(GstEvent *);
116 void gstEventHandleFlushStart(GstEvent *);
117 void gstEventHandleFlushStop(GstEvent *);
118
119 QMutex m_sinkMutex;
120 QGstreamerVideoSink *m_sink = nullptr; // written only from qt thread. so only readers on
121 // worker threads need to acquire the lock
122
123 // --- only accessed from gstreamer thread
124 const QGstCaps m_surfaceCaps;
125 QVideoFrameFormat m_format;
126 GstVideoInfo m_videoInfo{};
127 QGstCaps::MemoryFormat m_memoryFormat = QGstCaps::CpuMemory;
128
129 // --- only accessed from qt thread
130 QVideoFrame m_currentPipelineFrame;
131 QVideoFrame m_currentVideoFrame;
132 bool m_isActive{ false };
133
134 RenderBufferState m_currentState;
135 QGstUtils::QConcurrentQueue<RenderBufferState> m_bufferQueue;
136 bool m_flushing{ false };
137};
138
139class QGstVideoRendererSinkElement;
140
141class QGstVideoRendererSink
142{
143public:
144 GstVideoSink parent{};
145
146 static QGstVideoRendererSinkElement createSink(QGstreamerVideoSink *surface);
147
148private:
149 static void setSink(QGstreamerVideoSink *surface);
150
151 static GType get_type();
152 static void class_init(gpointer g_class, gpointer class_data);
153 static void base_init(gpointer g_class);
154 static void instance_init(GTypeInstance *instance, gpointer g_class);
155
156 static void finalize(GObject *object);
157
158 static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition);
159
160 static GstCaps *get_caps(GstBaseSink *sink, GstCaps *filter);
161 static gboolean set_caps(GstBaseSink *sink, GstCaps *caps);
162
163 static gboolean propose_allocation(GstBaseSink *sink, GstQuery *query);
164
165 static gboolean stop(GstBaseSink *sink);
166
167 static gboolean unlock(GstBaseSink *sink);
168
169 static GstFlowReturn show_frame(GstVideoSink *sink, GstBuffer *buffer);
170 static gboolean query(GstBaseSink *element, GstQuery *query);
171 static gboolean event(GstBaseSink *element, GstEvent *event);
172
173 friend class QGstVideoRendererSinkElement;
174
175 QGstVideoRenderer *renderer = nullptr;
176};
177
178class QGstVideoRendererSinkClass
179{
180public:
181 GstVideoSinkClass parent_class;
182};
183
184class QGstVideoRendererSinkElement : public QGstBaseSink
185{
186public:
187 using QGstBaseSink::QGstBaseSink;
188
189 explicit QGstVideoRendererSinkElement(QGstVideoRendererSink *, RefMode);
190
191 QGstVideoRendererSinkElement(const QGstVideoRendererSinkElement &) = default;
192 QGstVideoRendererSinkElement(QGstVideoRendererSinkElement &&) noexcept = default;
193 QGstVideoRendererSinkElement &operator=(const QGstVideoRendererSinkElement &) = default;
194 QGstVideoRendererSinkElement &operator=(QGstVideoRendererSinkElement &&) noexcept = default;
195
196 void setActive(bool);
197
198 QGstVideoRendererSink *qGstVideoRendererSink() const;
199};
200
201QT_END_NAMESPACE
202
203#endif
204

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtmultimedia/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink_p.h