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
46{
47 Q_OBJECT
48 Q_PROPERTY(QString decoderName READ decoderName NOTIFY decoderStatsChanged)
49 Q_PROPERTY(quint64 processedFrames READ processedFrames NOTIFY decoderStatsChanged)
50 Q_PROPERTY(quint64 droppedFrames READ droppedFrames NOTIFY decoderStatsChanged)
51 Q_PROPERTY(qint64 currentJitterNs READ currentJitterNs NOTIFY decoderStatsChanged)
52 Q_PROPERTY(double qosProportion READ qosProportion NOTIFY decoderStatsChanged)
53 Q_PROPERTY(int qosQuality READ qosQuality NOTIFY decoderStatsChanged)
54
55public:
56 explicit GstVideoReceiver(QObject *parent = nullptr);
58
59 QString decoderName() const { QMutexLocker locker(&_decoderNameMutex); return _decoderName; }
60 quint64 processedFrames() const { return _processedFrames.load(std::memory_order_relaxed); }
61 quint64 droppedFrames() const { return _droppedFrames.load(std::memory_order_relaxed); }
62 qint64 currentJitterNs() const { return _currentJitterNs.load(std::memory_order_relaxed); }
63 double qosProportion() const { return _qosProportion.load(std::memory_order_relaxed); }
64 int qosQuality() const { return _qosQuality.load(std::memory_order_relaxed); }
65
66public slots:
67 void start(uint32_t timeout) override;
68 void stop() override;
69 void startDecoding(void *sink) override;
70 void stopDecoding() override;
71 void startRecording(const QString &videoFile, FILE_FORMAT format) override;
72 void stopRecording() override;
73 void takeScreenshot(const QString &imageFile) override;
74
78 Q_INVOKABLE void dumpPipelineGraph(const QString &tag = QStringLiteral("manual"));
79
80signals:
82
83private slots:
84 void _watchdog();
85 void _handleEOS();
86
87private:
88 GstElement *_makeDecoder();
89 GstElement *_makeFileSink(const QString &videoFile, FILE_FORMAT format);
90
91 void _onNewSourcePad(GstPad *pad);
92 void _onNewDecoderPad(GstPad *pad);
93 bool _addDecoder(GstElement *src);
94 void _ensureVideoSinkInPipeline();
95 bool _addVideoSink(GstPad *pad);
96 void _noteTeeFrame();
97 void _noteVideoSinkFrame();
98 void _noteEndOfStream();
101 bool _unlinkBranch(GstElement *from);
102 void _shutdownDecodingBranch();
103 void _shutdownRecordingBranch();
104 void _logDecodebin3SelectedCodec(GstElement *decodebin3);
105
106 bool _needDispatch();
107
111 void _scheduleReconnect(const char *reason);
112
116 GstElement *_acquirePipelineRef() const;
117
118 static gboolean _onBusMessage(GstBus *bus, GstMessage *message, gpointer user_data);
119 static void _onNewPad(GstElement *element, GstPad *pad, gpointer data);
120 static GstPadProbeReturn _teeProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
121 static GstPadProbeReturn _videoSinkProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
122 static GstPadProbeReturn _eosProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
123 static GstPadProbeReturn _keyframeWatch(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
124
125 GstElement *_decoder = nullptr;
126 GstElement *_decoderValve = nullptr;
127 GstElement *_fileSink = nullptr;
128 GstElement *_pipeline = nullptr;
129 mutable QMutex _pipelineMutex; // serializes _pipeline mutation (worker) vs read in _onBusMessage (streaming thread)
130 GstElement *_recorderValve = nullptr;
131 GstElement *_source = nullptr;
132 GstElement *_tee = nullptr;
133 GstElement *_videoSink = nullptr;
134 GstVideoWorker *_worker = nullptr;
135 std::atomic<int> _reconnectAttempts = 0;
136 std::atomic<quint64> _reconnectEpoch = 0;
137 std::atomic<quint64> _sourceFrameCount =
138 0;
139 gulong _teeProbeId = 0;
140 gulong _videoSinkProbeId = 0;
141 gulong _eosProbeId = 0;
142 GstPad *_eosProbePad = nullptr; // ref-held: probe install pad, kept so removal targets the right pad regardless of _decoder lifecycle
143 gulong _keyframeWatchId = 0;
144 bool _recordingStopRequested = false;
145
146 mutable QMutex _decoderNameMutex; // QString refcount isn't thread-safe across reader/writer threads
147 QString _decoderName;
148 std::atomic<quint64> _processedFrames{0}; // written on streaming thread (QOS), read on GUI
149 std::atomic<quint64> _droppedFrames{0};
150 std::atomic<qint64> _currentJitterNs{0};
151 std::atomic<double> _qosProportion{1.0};
152 std::atomic<int> _qosQuality{1000000};
153 std::atomic<bool> _qosStatsDirty{false}; // set per QOS message (streaming thread), drained by _watchdog's 1 Hz emit
154
155 static constexpr const char *_kFileMux[FILE_FORMAT_MAX + 1] = {
156 "matroskamux",
157 "qtmux",
158 "mp4mux"
159 };
160};
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
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