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 <QtCore/QMutex>
4#include <QtCore/QQueue>
5#include <QtCore/QThread>
6#include <QtCore/QTimer>
7#include <QtCore/QWaitCondition>
8
9#include <glib.h>
10#include <gst/gstelement.h>
11#include <gst/gstpad.h>
12
13#include "VideoReceiver.h"
14
15typedef std::function<void()> Task;
16
17/*===========================================================================*/
18
19class GstVideoWorker : public QThread
20{
21 Q_OBJECT
22
23public:
24 explicit GstVideoWorker(QObject *parent = nullptr);
26 bool needDispatch() const;
27 void dispatch(Task task);
28 void shutdown();
29
30private:
31 void run() final;
32
33 QWaitCondition _taskQueueUpdate;
34 QMutex _taskQueueSync;
35 QQueue<Task> _taskQueue;
36 bool _shutdown = false;
37};
38
39/*===========================================================================*/
40
41typedef struct _GstElement GstElement;
42
44{
45 Q_OBJECT
46 Q_PROPERTY(QString decoderName READ decoderName NOTIFY decoderStatsChanged)
47 Q_PROPERTY(quint64 processedFrames READ processedFrames NOTIFY decoderStatsChanged)
48 Q_PROPERTY(quint64 droppedFrames READ droppedFrames NOTIFY decoderStatsChanged)
49 Q_PROPERTY(qint64 currentJitterNs READ currentJitterNs NOTIFY decoderStatsChanged)
50 Q_PROPERTY(double qosProportion READ qosProportion NOTIFY decoderStatsChanged)
51 Q_PROPERTY(int qosQuality READ qosQuality NOTIFY decoderStatsChanged)
52
53public:
54 explicit GstVideoReceiver(QObject *parent = nullptr);
56
57 QString decoderName() const { return _decoderName; }
58 quint64 processedFrames() const { return _processedFrames; }
59 quint64 droppedFrames() const { return _droppedFrames; }
60 qint64 currentJitterNs() const { return _currentJitterNs; }
61 double qosProportion() const { return _qosProportion; }
62 int qosQuality() const { return _qosQuality; }
63
64public slots:
65 void start(uint32_t timeout) override;
66 void stop() override;
67 void startDecoding(void *sink) override;
68 void stopDecoding() override;
69 void startRecording(const QString &videoFile, FILE_FORMAT format) override;
70 void stopRecording() override;
71 void takeScreenshot(const QString &imageFile) override;
72
73signals:
76
77private slots:
78 void _watchdog();
79 void _handleEOS();
80
81private:
82 GstElement *_makeSource(const QString &input);
83 GstElement *_makeDecoder();
84 GstElement *_makeFileSink(const QString &videoFile, FILE_FORMAT format);
85
86 void _onNewSourcePad(GstPad *pad);
87 void _onNewDecoderPad(GstPad *pad);
88 bool _addDecoder(GstElement *src);
89 void _ensureVideoSinkInPipeline();
90 bool _addVideoSink(GstPad *pad);
91 void _noteTeeFrame();
92 void _noteVideoSinkFrame();
93 void _noteEndOfStream();
96 bool _unlinkBranch(GstElement *from);
97 void _shutdownDecodingBranch();
98 void _shutdownRecordingBranch();
99 void _logDecodebin3SelectedCodec(GstElement *decodebin3);
100
101 bool _needDispatch();
102 void _dispatchSignal(Task emitter);
103
104 static gboolean _onBusMessage(GstBus *bus, GstMessage *message, gpointer user_data);
105 static void _onNewPad(GstElement *element, GstPad *pad, gpointer data);
106 static void _wrapWithGhostPad(GstElement *element, GstPad *pad, gpointer data);
107 static void _linkPad(GstElement *element, GstPad *pad, gpointer data);
108 static gboolean _padProbe(GstElement *element, GstPad *pad, gpointer user_data);
109#if !defined(QGC_GST_BUILD_VERSION_MAJOR) || (QGC_GST_BUILD_VERSION_MAJOR == 1 && QGC_GST_BUILD_VERSION_MINOR < 28)
110 static gboolean _filterParserCaps(GstElement *bin, GstPad *pad, GstElement *element, GstQuery *query, gpointer data);
111#endif
112 static GstPadProbeReturn _teeProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
113 static GstPadProbeReturn _videoSinkProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
114 static GstPadProbeReturn _eosProbe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
115 static GstPadProbeReturn _keyframeWatch(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
116
117 GstElement *_decoder = nullptr;
118 GstElement *_decoderValve = nullptr;
119 GstElement *_fileSink = nullptr;
120 GstElement *_pipeline = nullptr;
121 GstElement *_recorderValve = nullptr;
122 GstElement *_source = nullptr;
123 GstElement *_tee = nullptr;
124 GstElement *_videoSink = nullptr;
125 GstVideoWorker *_worker = nullptr;
126 gulong _teeProbeId = 0;
127 gulong _videoSinkProbeId = 0;
128 gulong _eosProbeId = 0;
129 GstPad *_eosProbePad = nullptr; // ref-held: probe install pad, kept so removal targets the right pad regardless of _decoder lifecycle
130 gulong _keyframeWatchId = 0;
131 bool _recordingStopRequested = false;
132
133 QString _decoderName;
134 quint64 _processedFrames = 0;
135 quint64 _droppedFrames = 0;
136 qint64 _currentJitterNs = 0;
137 double _qosProportion = 1.0;
138 int _qosQuality = 1000000;
139
140 static constexpr const char *_kFileMux[FILE_FORMAT_MAX + 1] = {
141 "matroskamux",
142 "qtmux",
143 "mp4mux"
144 };
145};
std::function< void()> Task
struct _GstElement GstElement
void stopDecoding() override
void takeScreenshot(const QString &imageFile) override
int qosQuality() const
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