QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GstVideoReceiver.h
Go to the documentation of this file.
1#pragma once
2
3#include <atomic>
4
5#include <QtCore/QMutex>
6#include <QtCore/QQueue>
7#include <QtCore/QThread>
8#include <QtCore/QTimer>
9#include <QtCore/QWaitCondition>
10
11#include <glib.h>
12#include <gst/gstelement.h>
13#include <gst/gstpad.h>
14
15#include "VideoReceiver.h"
16
17typedef std::function<void()> Task;
18
19/*===========================================================================*/
20
21class GstVideoWorker : public QThread
22{
23 Q_OBJECT
24
25public:
26 explicit GstVideoWorker(QObject *parent = nullptr);
28 bool needDispatch() const;
29 void dispatch(Task task);
30 void shutdown();
31
32private:
33 void run() final;
34
35 QWaitCondition _taskQueueUpdate;
36 QMutex _taskQueueSync;
37 QQueue<Task> _taskQueue;
38 bool _shutdown = false;
39};
40
41/*===========================================================================*/
42
43typedef struct _GstElement GstElement;
44
45class GStreamerTest;
46
48{
49 Q_OBJECT
50 Q_PROPERTY(QString decoderName READ decoderName NOTIFY decoderStatsChanged)
51 Q_PROPERTY(quint64 processedFrames READ processedFrames NOTIFY decoderStatsChanged)
52 Q_PROPERTY(quint64 droppedFrames READ droppedFrames NOTIFY decoderStatsChanged)
53 Q_PROPERTY(qint64 currentJitterNs READ currentJitterNs NOTIFY decoderStatsChanged)
54 Q_PROPERTY(double qosProportion READ qosProportion NOTIFY decoderStatsChanged)
55 Q_PROPERTY(int qosQuality READ qosQuality NOTIFY decoderStatsChanged)
56
57public:
58 explicit GstVideoReceiver(QObject *parent = nullptr);
60
61 QString decoderName() const { QMutexLocker locker(&_decoderNameMutex); return _decoderName; }
62 quint64 processedFrames() const { return _processedFrames.load(std::memory_order_relaxed); }
63 quint64 droppedFrames() const { return _droppedFrames.load(std::memory_order_relaxed); }
64 qint64 currentJitterNs() const { return _currentJitterNs.load(std::memory_order_relaxed); }
65 double qosProportion() const { return _qosProportion.load(std::memory_order_relaxed); }
66 int qosQuality() const { return _qosQuality.load(std::memory_order_relaxed); }
67
68public slots:
69 void start(uint32_t timeout) override;
70 void stop() override;
71 void startDecoding(void *sink) override;
72 void stopDecoding() override;
73 void startRecording(const QString &videoFile, FILE_FORMAT format) override;
74 void stopRecording() override;
75 void takeScreenshot(const QString &imageFile) override;
76
80 Q_INVOKABLE void dumpPipelineGraph(const QString &tag = QStringLiteral("manual"));
81
82signals:
84
85private slots:
86 void _watchdog();
87 void _handleEOS();
88
89private:
90 friend class GStreamerTest;
91
92 QString _redactedUri() const;
93 GstElement *_makeDecoder();
94 static GstElement* _makeFileSink(const QString& videoFile, FILE_FORMAT format, const GstCaps* inputCaps);
95
96 void _onNewSourcePad(GstPad *pad);
97 void _onNewDecoderPad(GstPad *pad);
98 bool _addDecoder(GstElement *src);
99 void _ensureVideoSinkInPipeline();
100 bool _addVideoSink(GstPad *pad);
101 void _noteTeeFrame();
102 void _noteVideoSinkFrame();
103 void _noteEndOfStream();
106 bool _unlinkBranch(GstElement *from);
107 void _shutdownDecodingBranch();
108 void _shutdownRecordingBranch();
109 void _logDecodebin3SelectedCodec(GstElement *decodebin3);
110
111 bool _needDispatch();
112
116 void _scheduleReconnect(const char *reason);
117
121 GstElement *_acquirePipelineRef() const;
122
123 static gboolean _onBusMessage(GstBus *bus, GstMessage *message, gpointer user_data);
124 static void _onNewPad(GstElement *element, GstPad *pad, gpointer data);
125 static GstPadProbeReturn _teeProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
126 static GstPadProbeReturn _videoSinkProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
127 static GstPadProbeReturn _eosProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
128 static GstPadProbeReturn _keyframeWatch(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
129
130 GstElement *_decoder = nullptr;
131 GstElement *_decoderValve = nullptr;
132 GstElement *_fileSink = nullptr;
133 GstElement *_pipeline = nullptr;
134 mutable QMutex _pipelineMutex; // serializes _pipeline mutation (worker) vs read in _onBusMessage (streaming thread)
135 GstElement *_recorderValve = nullptr;
136 GstElement *_source = nullptr;
137 GstElement *_tee = nullptr;
138 GstElement *_videoSink = nullptr;
139 GstVideoWorker *_worker = nullptr;
140 std::atomic<int> _reconnectAttempts = 0;
141 std::atomic<quint64> _reconnectEpoch = 0;
142 std::atomic<quint64> _sourceFrameCount =
143 0;
144 gulong _teeProbeId = 0;
145 gulong _videoSinkProbeId = 0;
146 gulong _eosProbeId = 0;
147 GstPad *_eosProbePad = nullptr; // ref-held: probe install pad, kept so removal targets the right pad regardless of _decoder lifecycle
148 gulong _keyframeWatchId = 0;
149 bool _recordingStopRequested = false;
150
151 mutable QMutex _decoderNameMutex; // QString refcount isn't thread-safe across reader/writer threads
152 QString _decoderName;
153 std::atomic<quint64> _processedFrames{0}; // written on streaming thread (QOS), read on GUI
154 std::atomic<quint64> _droppedFrames{0};
155 std::atomic<qint64> _currentJitterNs{0};
156 std::atomic<double> _qosProportion{1.0};
157 std::atomic<int> _qosQuality{1000000};
158 std::atomic<bool> _qosStatsDirty{false}; // set per QOS message (streaming thread), drained by _watchdog's 1 Hz emit
159
160 static constexpr const char *_kFileMux[FILE_FORMAT_MAX + 1] = {
161 "matroskamux",
162 "qtmux",
163 "mp4mux"
164 };
165};
std::function< void()> Task
struct _GstElement GstElement
void stopDecoding() override
void takeScreenshot(const QString &imageFile) override
int qosQuality() const
Q_INVOKABLE void dumpPipelineGraph(const QString &tag=QStringLiteral("manual"))
void decoderStatsChanged()
QString decoderName() const
void start(uint32_t timeout) override
double qosProportion() const
friend class GStreamerTest
quint64 processedFrames() const
void stopRecording() override
void startRecording(const QString &videoFile, FILE_FORMAT format) override
void stop() override
void startDecoding(void *sink) override
quint64 droppedFrames() const
qint64 currentJitterNs() const
void dispatch(Task task)
bool needDispatch() const
VideoSinkHandle sink() const