18#include <QtCore/qdebug.h>
19#include <QtCore/qlist.h>
20#include <QtCore/qmutex.h>
21#include <QtCore/qsemaphore.h>
23#include <QtMultimedia/qaudioformat.h>
24#include <QtMultimedia/qvideoframe.h>
25#include <QtMultimedia/private/qtmultimediaglobal_p.h>
26#include <QtMultimedia/private/qmultimediautils_p.h>
27#include <QtMultimedia/private/qplatformmediaplayer_p.h>
28#include <QtMultimedia/private/qsharedhandle_p.h>
31#include <gst/app/gstappsink.h>
32#include <gst/app/gstappsrc.h>
33#include <gst/video/video-info.h>
38#ifdef __cpp_lib_three_way_comparison
42#if QT_CONFIG(gstreamer_photography)
43# define GST_USE_UNSTABLE_API
44# include <gst/interfaces/photography.h>
45# undef GST_USE_UNSTABLE_API
63#define QGST_DEFINE_CAST_TRAITS(ClassName, MACRO_LABEL)
65 struct GstObjectTraits<ClassName>
67 using Type = ClassName;
69 static bool isObjectOfType(U *arg)
71 return GST_IS_##MACRO_LABEL(arg);
74 static Type *cast(U *arg)
76 return GST_##MACRO_LABEL##_CAST(arg);
79 static Type *checked_cast(U *arg)
81 return GST_##MACRO_LABEL(arg);
84 static_assert(true, "ensure semicolon")
86#define QGST_DEFINE_CAST_TRAITS_FOR_INTERFACE(ClassName, MACRO_LABEL)
88 struct GstObjectTraits<ClassName>
90 using Type = ClassName;
92 static bool isObjectOfType(U *arg)
94 return GST_IS_##MACRO_LABEL(arg);
97 static Type *cast(U *arg)
99 return checked_cast(arg);
101 template <typename U>
102 static Type *checked_cast(U *arg)
104 return GST_##MACRO_LABEL(arg);
107 static_assert(true, "ensure semicolon")
127 template <
typename U>
132 template <
typename U>
137 template <
typename U>
144#undef QGST_DEFINE_CAST_TRAITS
145#undef QGST_DEFINE_CAST_TRAITS_FOR_INTERFACE
149template <
typename DestinationType,
typename SourceType>
153 return arg && Traits::isObjectOfType(arg);
156template <
typename DestinationType,
typename SourceType>
160 if (arg && Traits::isObjectOfType(arg))
161 return Traits::cast(arg);
165template <
typename DestinationType,
typename SourceType>
170 Q_ASSERT(Traits::isObjectOfType(arg));
171 return Traits::cast(arg);
184#ifdef __cpp_impl_three_way_comparison
189 return std::tie(min, max) == std::tie(rhs.min, rhs.max);
202#ifdef __cpp_lib_three_way_comparison
227 bool operator==(
const QGString &str)
const {
return asStringView() == str.asStringView(); }
228 bool operator==(
const QLatin1StringView str)
const {
return asStringView() == str; }
229 bool operator==(
const QByteArrayView str)
const {
return asByteArrayView() == str; }
231 bool operator!=(
const QGString &str)
const {
return asStringView() != str.asStringView(); }
232 bool operator!=(
const QLatin1StringView str)
const {
return asStringView() != str; }
233 bool operator!=(
const QByteArrayView str)
const {
return asByteArrayView() != str; }
237 return lhs.asStringView() < rhs.asStringView();
241 return lhs.asStringView() < rhs;
245 return lhs.asByteArrayView() < rhs;
249 return lhs < rhs.asStringView();
253 return lhs < rhs.asByteArrayView();
264 explicit QGValue(
const GValue *v);
275 return value ?
static_cast<T *>(g_value_get_pointer(value)) :
nullptr;
324 static GstCaps *
ref(GstCaps *arg)
noexcept {
return gst_caps_ref(arg); }
325 static bool unref(GstCaps *arg)
noexcept
352 void addPixelFormats(
const QList<QVideoFrameFormat::PixelFormat> &formats,
const char *modifier =
nullptr);
368 gst_object_ref_sink(arg);
371 static bool unref(GstObject *arg)
noexcept
373 gst_object_unref(arg);
392 void set(
const char *property,
const char *str);
393 void set(
const char *property,
bool b);
394 void set(
const char *property, int32_t i);
395 void set(
const char *property, uint32_t i);
396 void set(
const char *property, int64_t i);
397 void set(
const char *property, uint64_t i);
398 void set(
const char *property,
double d);
401 void set(
const char *property,
void *object, GDestroyNotify destroyFunction);
403 template <
typename Object>
404 void set(
const char *property, Object *object, GDestroyNotify destroyFunction)
406 set(property,
static_cast<
void *>(object), destroyFunction);
409 template <
typename Object>
410 void set(
const char *property, std::unique_ptr<Object> object)
412 set(property,
static_cast<
void *>(object.release()), qDeleteFromVoidPointer<Object>);
415 template <
typename T>
418 delete reinterpret_cast<T *>(ptr);
423 bool getBool(
const char *property)
const;
425 int getInt(
const char *property)
const;
428 float getFloat(
const char *property)
const;
429 double getDouble(
const char *property)
const;
431 void *
getObject(
const char *property)
const;
433 template <
typename T>
437 return reinterpret_cast<T *>(rawObject);
499 explicit QGstPad(GstPad *pad, RefMode mode);
526 template <
auto Member,
typename T>
527 void addProbe(T *instance, GstPadProbeType type);
529 template <
typename Functor>
532 template <
auto Member,
typename T>
535 template <
typename Functor>
546 explicit QGstClock(GstClock *clock, RefMode mode);
565 explicit QGstElement(GstElement *element, RefMode mode);
569 const char *name =
nullptr);
605 template <
auto Member,
typename T>
610 static void callback(GstElement *e, GstPad *pad, gpointer userData)
612 (
static_cast<T *>(userData)->*Member)(QGstElement(e, NeedsRef),
613 QGstPad(pad, NeedsRef));
617 return connect(
"pad-added", G_CALLBACK(Impl::callback), instance);
619 template <
auto Member,
typename T>
624 static void callback(GstElement *e, GstPad *pad, gpointer userData)
626 (
static_cast<T *>(userData)->*Member)(QGstElement(e, NeedsRef),
627 QGstPad(pad, NeedsRef));
631 return connect(
"pad-removed", G_CALLBACK(Impl::callback), instance);
633 template <
auto Member,
typename T>
638 static void callback(GstElement *e, gpointer userData)
640 (
static_cast<T *>(userData)->*Member)(QGstElement(e, NeedsRef));
644 return connect(
"no-more-pads", G_CALLBACK(Impl::callback), instance);
660 QGstQueryHandle &positionQuery()
const;
661 mutable QGstQueryHandle m_positionQuery;
666template <
auto Member,
typename T>
669 auto callback = [](GstPad *pad, GstPadProbeInfo *info, gpointer userData) {
670 return (
static_cast<T *>(userData)->*Member)(QGstPad(pad, NeedsRef), info);
673 gst_pad_add_probe(pad(), type, callback, instance,
nullptr);
676template <
typename Functor>
679 using namespace std::chrono_literals;
684 std::once_flag onceFlag;
689 std::call_once(onceFlag, [&] {
695 CallbackData cd{ QSemaphore{}, {}, std::forward<Functor>(work) };
697 auto callback = [](GstPad *, GstPadProbeInfo *, gpointer p) {
698 auto cd =
reinterpret_cast<CallbackData *>(p);
700 cd->waitDone.release();
701 return GST_PAD_PROBE_REMOVE;
704 gulong probe = gst_pad_add_probe(pad(), GST_PAD_PROBE_TYPE_IDLE, callback, &cd,
nullptr);
708 bool success = cd.waitDone.try_acquire_for(250ms);
716 success = cd.waitDone.try_acquire_for(1s);
723 qWarning() <<
"QGstPad::doInIdleProbe blocked for 1s. Executing the pad probe manually";
725 gst_pad_remove_probe(pad(), probe);
729template <
auto Member,
typename T>
732 auto callback = [](GstPad *, GstPadProbeInfo *info, gpointer userData) {
733 if (GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_EOS)
734 return GST_PAD_PROBE_PASS;
735 (
static_cast<T *>(userData)->*Member)();
736 return GST_PAD_PROBE_REMOVE;
739 gst_pad_add_probe(pad(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, callback, instance,
nullptr);
741template <
typename Functor>
744 using namespace std::chrono_literals;
746 GstPadDirection direction = gst_pad_get_direction(pad());
749 case GstPadDirection::GST_PAD_SINK: {
756 case GstPadDirection::GST_PAD_SRC: {
758 if (parent().state(1s) == GstState::GST_STATE_PLAYING)
770template <
typename... Ts>
774 bool link_success = [&] {
775 if constexpr (
sizeof...(Ts) == 2)
776 return gst_element_link(ts.element()...);
778 return gst_element_link_many(ts.element()...,
nullptr);
781 if (Q_UNLIKELY(!link_success)) {
782 qWarning() <<
"qLinkGstElements: could not link elements: "
783 << std::initializer_list<
const char *>{
784 (GST_ELEMENT_NAME(ts.element()))...,
789template <
typename... Ts>
793 if constexpr (
sizeof...(Ts) == 2)
794 gst_element_unlink(ts.element()...);
796 gst_element_unlink_many(ts.element()...,
nullptr);
812 const char *name =
nullptr,
813 bool ghostUnlinkedPads =
false);
815 const char *name =
nullptr,
816 bool ghostUnlinkedPads =
false);
818 template <
typename... Ts>
821 if constexpr (
sizeof...(Ts) == 1)
822 gst_bin_add(bin(), ts.element()...);
824 gst_bin_add_many(bin(), ts.element()...,
nullptr);
827 template <
typename... Ts>
830 if constexpr (
sizeof...(Ts) == 1)
831 gst_bin_remove(bin(), ts.element()...);
833 gst_bin_remove_many(bin(), ts.element()...,
nullptr);
836 template <
typename... Ts>
840 bool stateChangeSuccessful = (ts.setStateSync(GST_STATE_NULL) && ...);
841 Q_ASSERT(stateChangeSuccessful);
853 void dumpGraph(
const char *fileNamePrefix)
const;
909# if GST_CHECK_VERSION(1
, 24
, 0
)
914 void setCallbacks(GstAppSinkCallbacks &callbacks, gpointer user_data, GDestroyNotify notify);
935 void setCallbacks(GstAppSrcCallbacks &callbacks, gpointer user_data, GDestroyNotify notify);
947template <
typename Arg,
typename... Args>
950 QGstElementFactoryHandle factory = QGstElement::findFactory(arg);
952 return qGstErrorMessageCannotFindElement(arg);
954 if constexpr (
sizeof...(args) != 0)
955 return qGstErrorMessageIfElementsNotAvailable(args...);
960template <
typename Functor>
963 guint size = gst_stream_collection_get_size(collection);
964 for (guint index = 0; index != size; ++index)
965 f(gst_stream_collection_get_stream(collection, index));
968template <
typename Functor>
971 qForeachStreamInCollection(collection.get(), std::forward<Functor>(f));
979struct hash<QT_PREPEND_NAMESPACE(QGstElement)>
981 using argument_type = QT_PREPEND_NAMESPACE(QGstElement);
982 using result_type = size_t;
983 result_type
operator()(
const argument_type &e)
const noexcept
985 return std::hash<
void *>{}(e.element());
QGObjectHandlerConnection & operator=(const QGObjectHandlerConnection &)=default
QGObjectHandlerConnection & operator=(QGObjectHandlerConnection &&)=default
QGObjectHandlerConnection(QGstObject object, gulong handler)
QGObjectHandlerConnection()=default
QGObjectHandlerConnection(const QGObjectHandlerConnection &)=default
QGObjectHandlerConnection(QGObjectHandlerConnection &&)=default
~QGObjectHandlerScopedConnection()
QGObjectHandlerScopedConnection(const QGObjectHandlerScopedConnection &)=delete
QGObjectHandlerScopedConnection & operator=(const QGObjectHandlerScopedConnection &)=delete
QGObjectHandlerScopedConnection(QGObjectHandlerScopedConnection &&)=default
QGObjectHandlerScopedConnection()=default
QGObjectHandlerScopedConnection(QGObjectHandlerConnection connection)
QGObjectHandlerScopedConnection & operator=(QGObjectHandlerScopedConnection &&)=default
std::optional< int > toInt64() const
std::optional< QGRange< int > > toIntRange() const
std::optional< int > toInt() const
QList< QAudioFormat::SampleFormat > getSampleFormats() const
QGstStructureView toStructure() const
std::optional< QGRange< float > > getFractionRange() const
const char * toString() const
std::optional< float > getFraction() const
QGValue at(int index) const
std::optional< bool > toBool() const
QGstSampleHandle pullSample()
void setCallbacks(GstAppSinkCallbacks &callbacks, gpointer user_data, GDestroyNotify notify)
GstAppSink * appSink() const
void setCaps(const QGstCaps &caps)
QGstAppSink(const QGstAppSink &)=default
QGstAppSink(QGstAppSink &&) noexcept=default
static QGstAppSink create(const char *name)
QGstAppSink(GstAppSink *, RefMode)
QGstAppSink & operator=(QGstAppSink &&) noexcept=default
QGstAppSink & operator=(const QGstAppSink &)=default
static QGstAppSrc create(const char *name)
QGstAppSrc & operator=(const QGstAppSrc &)=default
GstFlowReturn pushBuffer(GstBuffer *)
QGstAppSrc(const QGstAppSrc &)=default
void setCallbacks(GstAppSrcCallbacks &callbacks, gpointer user_data, GDestroyNotify notify)
QGstAppSrc & operator=(QGstAppSrc &&) noexcept=default
QGstAppSrc(GstAppSrc *, RefMode)
QGstAppSrc(QGstAppSrc &&) noexcept=default
GstAppSrc * appSrc() const
QGstBaseSink & operator=(const QGstBaseSink &)=default
QGstBaseSink(GstBaseSink *, RefMode)
QGstBaseSink(const QGstBaseSink &)=default
GstBaseSink * baseSink() const
QGstBaseSink(QGstBaseSink &&) noexcept=default
QGstBaseSink & operator=(QGstBaseSink &&) noexcept=default
QGstBaseSrc(QGstBaseSrc &&) noexcept=default
QGstBaseSrc & operator=(QGstBaseSrc &&) noexcept=default
QGstBaseSrc(const QGstBaseSrc &)=default
QGstBaseSrc & operator=(const QGstBaseSrc &)=default
QGstBaseSrc(GstBaseSrc *, RefMode)
GstBaseSrc * baseSrc() const
void addUnlinkedGhostPads(GstPadDirection)
QGstBin(QGstBin &&) noexcept=default
QGstBin & operator=(const QGstBin &)=default
QGstElement findByName(const char *)
void dumpGraph(const char *fileNamePrefix) const
void recalculateLatency()
static QGstBin create(const char *name)
void addGhostPad(const QGstElement &child, const char *name)
std::enable_if_t<(std::is_base_of_v< QGstElement, std::remove_reference_t< Ts > > &&...), void > stopAndRemoveElements(Ts &&...ts)
QGstBin & operator=(QGstBin &&) noexcept=default
static QGstBin createFromPipelineDescription(const char *pipelineDescription, const char *name=nullptr, bool ghostUnlinkedPads=false)
QGstBin(const QGstBin &)=default
static QGstBin createFromFactory(const char *factory, const char *name)
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void > add(const Ts &...ts)
void addGhostPad(const char *name, const QGstPad &pad)
QGstBin(GstBin *bin, RefMode mode=NeedsRef)
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void > remove(const Ts &...ts)
static QGstBin createFromPipelineDescription(const QByteArray &pipelineDescription, const char *name=nullptr, bool ghostUnlinkedPads=false)
void addPixelFormats(const QList< QVideoFrameFormat::PixelFormat > &formats, const char *modifier=nullptr)
MemoryFormat memoryFormat() const
QGstCaps & operator=(QGstCaps &&) noexcept=default
static QGstCaps fromCameraFormat(const QCameraFormat &format)
void setResolution(QSize)
QGstCaps & operator=(const QGstCaps &)=default
QGstCaps(const QGstCaps &)=default
QGstCaps(QGstCaps &&) noexcept=default
QGstStructureView at(int index) const
QGstClock(GstClock *clock, RefMode mode)
GstClockTime time() const
QGstClock(const QGstObject &o)
void setBaseTime(GstClockTime time) const
GstStateChangeReturn setState(GstState state)
static QGstElement createFromFactory(const QGstElementFactoryHandle &, const char *name=nullptr)
std::optional< std::chrono::nanoseconds > position() const
static QGstElement createFromDevice(const QGstDeviceHandle &, const char *name=nullptr)
QGstElement & operator=(QGstElement &&) noexcept=default
QGObjectHandlerConnection onPadRemoved(T *instance)
GstElement * element() const
static QGstElementFactoryHandle findFactory(const QByteArray &name)
QGstElement(GstElement *element, RefMode mode)
void lockState(bool locked)
QGstElement(const QGstElement &)=default
QGstPad getRequestPad(const char *name) const
QGstElement(QGstElement &&) noexcept=default
bool waitForAsyncStateChangeComplete(std::chrono::nanoseconds timeout=std::chrono::seconds(5)) const
std::optional< bool > canSeek() const
std::optional< std::chrono::nanoseconds > duration() const
bool finishStateChange(std::chrono::nanoseconds timeout=std::chrono::seconds(5))
bool setStateSync(GstState state, std::chrono::nanoseconds timeout=std::chrono::seconds(1))
bool isStateLocked() const
void sendEvent(GstEvent *event) const
void dumpPipelineGraph(const char *filename) const
QGstElement & operator=(const QGstElement &)=default
GstClockTime baseTime() const
static QGstElement createFromPipelineDescription(const QByteArray &)
void releaseRequestPad(const QGstPad &pad) const
static QGstElement createFromFactory(GstElementFactory *, const char *name=nullptr)
bool syncStateWithParent()
static QGstElement createFromDevice(GstDevice *, const char *name=nullptr)
QGstPad staticPad(const char *name) const
QGstBin getParentBin() const
std::optional< std::chrono::milliseconds > positionInMs() const
QGObjectHandlerConnection onPadAdded(T *instance)
static QGstElement createFromFactory(const char *factory, const char *name=nullptr)
bool hasAsyncStateChange(std::chrono::nanoseconds timeout=std::chrono::seconds(0)) const
static QGstElementFactoryHandle findFactory(const char *)
QGstElement getParent() const
QGObjectHandlerConnection onNoMorePads(T *instance)
QGstPipeline getPipeline() const
static QGstElement createFromPipelineDescription(const char *)
GstState state(std::chrono::nanoseconds timeout=std::chrono::seconds(0)) const
std::optional< std::chrono::milliseconds > durationInMs() const
T * getObject(const char *property) const
void set(const char *property, double d)
QGObjectHandlerConnection connect(const char *name, GCallback callback, gpointer userData)
void * getObject(const char *property) const
double getDouble(const char *property) const
QGstObject & operator=(const QGstObject &)=default
int getInt(const char *property) const
void set(const char *property, int32_t i)
QLatin1StringView name() const
void set(const char *property, const QGstObject &o)
static void qDeleteFromVoidPointer(void *ptr)
QGString getString(const char *property) const
void disconnect(gulong handlerId)
QGstObject getGstObject(const char *property) const
QLatin1StringView typeName() const
void set(const char *property, const char *str)
bool getBool(const char *property) const
QGstObject & operator=(QGstObject &&) noexcept=default
void set(const char *property, void *object, GDestroyNotify destroyFunction)
void set(const char *property, std::unique_ptr< Object > object)
void set(const char *property, Object *object, GDestroyNotify destroyFunction)
void set(const char *property, bool b)
QGstObject(const QGstObject &)=default
quint64 getUInt64(const char *property) const
QGstStructureView getStructure(const char *property) const
qint64 getInt64(const char *property) const
void set(const char *property, const QGstCaps &c)
float getFloat(const char *property) const
QGstObject(QGstObject &&) noexcept=default
uint getUInt(const char *property) const
GstObject * object() const
bool link(const QGstPad &sink) const
GstEvent * stickyEvent(GstEventType type)
void modifyPipelineInIdleProbe(Functor &&f)
QGstTagListHandle tags() const
QGstPad & operator=(QGstPad &&) noexcept=default
QGstPad(const QGstObject &o)
QGstPad(const QGstPad &)=default
QGstCaps queryCaps() const
void doInIdleProbe(Functor &&work)
QGstPad(GstPad *pad, RefMode mode)
QGstPad(QGstPad &&) noexcept=default
void sendFlushStartStop(bool resetTime)
QGString streamId() const
QGstPad & operator=(const QGstPad &)=default
void addProbe(T *instance, GstPadProbeType type)
std::optional< QPlatformMediaPlayer::TrackType > inferTrackTypeFromName() const
void addEosProbe(T *instance)
bool sendEvent(GstEvent *event)
QGstCaps currentCaps() const
QGstElement parent() const
bool unlink(const QGstPad &sink) const
QGstStructureView(const QUniqueGstStructureHandle &)
QGRange< float > frameRateRange() const
QGValue operator[](const char *fieldname) const
QVideoFrameFormat::PixelFormat pixelFormat() const
const GstStructure * structure
QUniqueGstStructureHandle clone() const
std::optional< QGRange< QSize > > resolutionRange() const
QGstreamerMessage getMessage()
std::optional< Fraction > pixelAspectRatio() const
QGstTagListHandle tags() const
QByteArrayView name() const
QGstStructureView(const GstStructure *)
void setSourceDevice(QIODevice *device) override
QAudioFormat audioFormat() const override
~QGstreamerAudioDecoder() override
QIODevice * sourceDevice() const override
void setSource(const QUrl &fileName) override
qint64 duration() const override
QUrl source() const override
void setAudioFormat(const QAudioFormat &format) override
static QMaybe< QPlatformAudioDecoder * > create(QAudioDecoder *parent)
QAudioBuffer read() override
qint64 position() const override
bool processBusMessage(const QGstreamerMessage &message) override
bool canReadQrc() const override
Combined button and popup list for selecting options.
DestinationType * qGstCheckedCast(SourceType *arg)
#define QGST_DEFINE_CAST_TRAITS(ClassName, MACRO_LABEL)
void qForeachStreamInCollection(GstStreamCollection *collection, Functor &&f)
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void > qLinkGstElements(const Ts &...ts)
GstClockTime qGstClockTimeFromChrono(std::chrono::nanoseconds ns)
bool qIsGstObjectOfType(SourceType *arg)
DestinationType * qGstSafeCast(SourceType *arg)
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void > qUnlinkGstElements(const Ts &...ts)
QString qGstErrorMessageCannotFindElement(std::string_view element)
std::optional< QString > qGstErrorMessageIfElementsNotAvailable(const Arg &arg, Args... args)
#define QGST_DEFINE_CAST_TRAITS_FOR_INTERFACE(ClassName, MACRO_LABEL)
void qForeachStreamInCollection(const QGstStreamCollectionHandle &collection, Functor &&f)
@ GST_PLAY_FLAG_SOFT_VOLUME
@ GST_PLAY_FLAG_BUFFERING
@ GST_PLAY_FLAG_NATIVE_AUDIO
@ GST_PLAY_FLAG_NATIVE_VIDEO
bool operator==(const QGRange &rhs) const
friend bool operator<(const QGString &lhs, const QGString &rhs)
friend bool operator<(const QLatin1StringView lhs, const QGString &rhs)
bool operator==(const QGString &str) const
QString toQString() const
bool operator!=(const QLatin1StringView str) const
bool operator!=(const QGString &str) const
QLatin1StringView asStringView() const
friend bool operator<(const QGString &lhs, const QLatin1StringView rhs)
bool operator==(const QLatin1StringView str) const
QByteArrayView asByteArrayView() const
static constexpr Type invalidValue() noexcept
static bool unref(GstCaps *arg) noexcept
static GstCaps * ref(GstCaps *arg) noexcept
static bool unref(GstObject *arg) noexcept
static GstObject * ref(GstObject *arg) noexcept
static constexpr Type invalidValue() noexcept
result_type operator()(const argument_type &e) const noexcept