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() override;
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 QGstUtils::QConcurrentQueue<RenderBufferState> m_bufferQueue;
135 bool m_flushing{ false };
136};
137
138class QGstVideoRendererSinkElement;
139
140class QGstVideoRendererSink
141{
142public:
143 GstVideoSink parent{};
144
145 static QGstVideoRendererSinkElement createSink(QGstreamerVideoSink *surface);
146
147private:
148 static void setSink(QGstreamerVideoSink *surface);
149
150 static GType get_type();
151 static void class_init(gpointer g_class, gpointer class_data);
152 static void base_init(gpointer g_class);
153 static void instance_init(GTypeInstance *instance, gpointer g_class);
154
155 static void finalize(GObject *object);
156
157 static GstStateChangeReturn change_state(GstElement *element, GstStateChange transition);
158
159 static GstCaps *get_caps(GstBaseSink *sink, GstCaps *filter);
160 static gboolean set_caps(GstBaseSink *sink, GstCaps *caps);
161
162 static gboolean propose_allocation(GstBaseSink *sink, GstQuery *query);
163
164 static gboolean stop(GstBaseSink *sink);
165
166 static gboolean unlock(GstBaseSink *sink);
167
168 static GstFlowReturn show_frame(GstVideoSink *sink, GstBuffer *buffer);
169 static gboolean query(GstBaseSink *element, GstQuery *query);
170 static gboolean event(GstBaseSink *element, GstEvent *event);
171
172 friend class QGstVideoRendererSinkElement;
173
174 QGstVideoRenderer *renderer = nullptr;
175};
176
177class QGstVideoRendererSinkClass
178{
179public:
180 GstVideoSinkClass parent_class;
181};
182
183class QGstVideoRendererSinkElement : public QGstBaseSink
184{
185public:
186 using QGstBaseSink::QGstBaseSink;
187
188 explicit QGstVideoRendererSinkElement(QGstVideoRendererSink *, RefMode);
189
190 QGstVideoRendererSinkElement(const QGstVideoRendererSinkElement &) = default;
191 QGstVideoRendererSinkElement(QGstVideoRendererSinkElement &&) noexcept = default;
192 QGstVideoRendererSinkElement &operator=(const QGstVideoRendererSinkElement &) = default;
193 QGstVideoRendererSinkElement &operator=(QGstVideoRendererSinkElement &&) noexcept = default;
194
195 void setActive(bool);
196
197 QGstVideoRendererSink *qGstVideoRendererSink() const;
198};
199
200QT_END_NAMESPACE
201
202#endif
203

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