Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgst.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company 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#include <common/qgst_p.h>
8
9#include <QtCore/qdebug.h>
10#include <QtMultimedia/qcameradevice.h>
11
12#include <array>
13
15
16namespace {
17
23
24constexpr std::array<VideoFormat, 19> qt_videoFormatLookup{ {
25 { QVideoFrameFormat::Format_YUV420P, GST_VIDEO_FORMAT_I420 },
26 { QVideoFrameFormat::Format_YUV422P, GST_VIDEO_FORMAT_Y42B },
27 { QVideoFrameFormat::Format_YV12, GST_VIDEO_FORMAT_YV12 },
28 { QVideoFrameFormat::Format_UYVY, GST_VIDEO_FORMAT_UYVY },
29 { QVideoFrameFormat::Format_YUYV, GST_VIDEO_FORMAT_YUY2 },
30 { QVideoFrameFormat::Format_NV12, GST_VIDEO_FORMAT_NV12 },
31 { QVideoFrameFormat::Format_NV21, GST_VIDEO_FORMAT_NV21 },
32 { QVideoFrameFormat::Format_AYUV, GST_VIDEO_FORMAT_AYUV },
33 { QVideoFrameFormat::Format_Y8, GST_VIDEO_FORMAT_GRAY8 },
34 { QVideoFrameFormat::Format_XRGB8888, GST_VIDEO_FORMAT_xRGB },
35 { QVideoFrameFormat::Format_XBGR8888, GST_VIDEO_FORMAT_xBGR },
36 { QVideoFrameFormat::Format_RGBX8888, GST_VIDEO_FORMAT_RGBx },
37 { QVideoFrameFormat::Format_BGRX8888, GST_VIDEO_FORMAT_BGRx },
38 { QVideoFrameFormat::Format_ARGB8888, GST_VIDEO_FORMAT_ARGB },
39 { QVideoFrameFormat::Format_ABGR8888, GST_VIDEO_FORMAT_ABGR },
40 { QVideoFrameFormat::Format_RGBA8888, GST_VIDEO_FORMAT_RGBA },
41 { QVideoFrameFormat::Format_BGRA8888, GST_VIDEO_FORMAT_BGRA },
42#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
43 { QVideoFrameFormat::Format_Y16, GST_VIDEO_FORMAT_GRAY16_LE },
44 { QVideoFrameFormat::Format_P010, GST_VIDEO_FORMAT_P010_10LE },
45#else
46 { QVideoFrameFormat::Format_Y16, GST_VIDEO_FORMAT_GRAY16_BE },
47 { QVideoFrameFormat::Format_P010, GST_VIDEO_FORMAT_P010_10BE },
48#endif
49} };
50
52{
53 for (size_t i = 0; i < qt_videoFormatLookup.size(); ++i)
54 if (qt_videoFormatLookup[i].pixelFormat == format)
55 return int(i);
56
57 return -1;
58}
59
60int indexOfVideoFormat(GstVideoFormat format)
61{
62 for (size_t i = 0; i < qt_videoFormatLookup.size(); ++i)
63 if (qt_videoFormatLookup[i].gstFormat == format)
64 return int(i);
65
66 return -1;
67}
68
69} // namespace
70
71// QGValue
72
73QGValue::QGValue(const GValue *v) : value(v) { }
74
75bool QGValue::isNull() const
76{
77 return !value;
78}
79
80std::optional<bool> QGValue::toBool() const
81{
82 if (!G_VALUE_HOLDS_BOOLEAN(value))
83 return std::nullopt;
84 return g_value_get_boolean(value);
85}
86
87std::optional<int> QGValue::toInt() const
88{
89 if (!G_VALUE_HOLDS_INT(value))
90 return std::nullopt;
91 return g_value_get_int(value);
92}
93
94std::optional<int> QGValue::toInt64() const
95{
96 if (!G_VALUE_HOLDS_INT64(value))
97 return std::nullopt;
98 return g_value_get_int64(value);
99}
100
101const char *QGValue::toString() const
102{
103 return value ? g_value_get_string(value) : nullptr;
104}
105
106std::optional<float> QGValue::getFraction() const
107{
108 if (!GST_VALUE_HOLDS_FRACTION(value))
109 return std::nullopt;
110 return (float)gst_value_get_fraction_numerator(value)
111 / (float)gst_value_get_fraction_denominator(value);
112}
113
114std::optional<QGRange<float>> QGValue::getFractionRange() const
115{
116 if (!GST_VALUE_HOLDS_FRACTION_RANGE(value))
117 return std::nullopt;
118 QGValue min = QGValue{ gst_value_get_fraction_range_min(value) };
119 QGValue max = QGValue{ gst_value_get_fraction_range_max(value) };
120 return QGRange<float>{ *min.getFraction(), *max.getFraction() };
121}
122
123std::optional<QGRange<int>> QGValue::toIntRange() const
124{
125 if (!GST_VALUE_HOLDS_INT_RANGE(value))
126 return std::nullopt;
127 return QGRange<int>{ gst_value_get_int_range_min(value), gst_value_get_int_range_max(value) };
128}
129
131{
132 if (!value || !GST_VALUE_HOLDS_STRUCTURE(value))
133 return QGstStructure();
134 return QGstStructure(gst_value_get_structure(value));
135}
136
138{
139 if (!value || !GST_VALUE_HOLDS_CAPS(value))
140 return {};
141 return QGstCaps(gst_caps_copy(gst_value_get_caps(value)), QGstCaps::HasRef);
142}
143
144bool QGValue::isList() const
145{
146 return value && GST_VALUE_HOLDS_LIST(value);
147}
148
150{
151 return gst_value_list_get_size(value);
152}
153
155{
156 return QGValue{ gst_value_list_get_value(value, index) };
157}
158
159// QGstStructure
160
161QGstStructure::QGstStructure(const GstStructure *s) : structure(s) { }
162
164{
165 if (structure)
166 gst_structure_free(const_cast<GstStructure *>(structure));
167 structure = nullptr;
168}
169
171{
172 return !structure;
173}
174
176{
177 return gst_structure_get_name(structure);
178}
179
181{
182 return QGValue{ gst_structure_get_value(structure, name) };
183}
184
186{
187 return gst_structure_copy(structure);
188}
189
191{
192 QSize size;
193
194 int w, h;
195 if (structure && gst_structure_get_int(structure, "width", &w)
196 && gst_structure_get_int(structure, "height", &h)) {
197 size.rwidth() = w;
198 size.rheight() = h;
199 }
200
201 return size;
202}
203
205{
207
208 if (!structure)
209 return pixelFormat;
210
211 if (gst_structure_has_name(structure, "video/x-raw")) {
212 const gchar *s = gst_structure_get_string(structure, "format");
213 if (s) {
214 GstVideoFormat format = gst_video_format_from_string(s);
215 int index = indexOfVideoFormat(format);
216
217 if (index != -1)
218 pixelFormat = qt_videoFormatLookup[index].pixelFormat;
219 }
220 } else if (gst_structure_has_name(structure, "image/jpeg")) {
222 }
223
224 return pixelFormat;
225}
226
227QGRange<float> QGstStructure::frameRateRange() const
228{
229 float minRate = 0.;
230 float maxRate = 0.;
231
232 if (!structure)
233 return { 0.f, 0.f };
234
235 auto extractFraction = [](const GValue *v) -> float {
236 return (float)gst_value_get_fraction_numerator(v)
237 / (float)gst_value_get_fraction_denominator(v);
238 };
239 auto extractFrameRate = [&](const GValue *v) {
240 auto insert = [&](float min, float max) {
241 if (max > maxRate)
242 maxRate = max;
243 if (min < minRate)
244 minRate = min;
245 };
246
247 if (GST_VALUE_HOLDS_FRACTION(v)) {
248 float rate = extractFraction(v);
249 insert(rate, rate);
250 } else if (GST_VALUE_HOLDS_FRACTION_RANGE(v)) {
251 auto *min = gst_value_get_fraction_range_max(v);
252 auto *max = gst_value_get_fraction_range_max(v);
253 insert(extractFraction(min), extractFraction(max));
254 }
255 };
256
257 const GValue *gstFrameRates = gst_structure_get_value(structure, "framerate");
258 if (gstFrameRates) {
259 if (GST_VALUE_HOLDS_LIST(gstFrameRates)) {
260 guint nFrameRates = gst_value_list_get_size(gstFrameRates);
261 for (guint f = 0; f < nFrameRates; ++f) {
262 extractFrameRate(gst_value_list_get_value(gstFrameRates, f));
263 }
264 } else {
265 extractFrameRate(gstFrameRates);
266 }
267 } else {
268 const GValue *min = gst_structure_get_value(structure, "min-framerate");
269 const GValue *max = gst_structure_get_value(structure, "max-framerate");
270 if (min && max) {
271 minRate = extractFraction(min);
272 maxRate = extractFraction(max);
273 }
274 }
275
276 return { minRate, maxRate };
277}
278
280{
281 GstMessage *message = nullptr;
282 gst_structure_get(structure, "message", GST_TYPE_MESSAGE, &message, nullptr);
284}
285
286std::optional<Fraction> QGstStructure::pixelAspectRatio() const
287{
288 gint numerator;
289 gint denominator;
290 if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &numerator, &denominator)) {
291 return Fraction{
292 numerator,
293 denominator,
294 };
295 }
296
297 return std::nullopt;
298}
299
300// QTBUG-125249: gstreamer tries "to keep the input height (because of interlacing)". Can we align
301// the behavior between gstreamer and ffmpeg?
302static QSize qCalculateFrameSizeGStreamer(QSize resolution, Fraction par)
303{
304 if (par.numerator == par.denominator || par.numerator < 1 || par.denominator < 1)
305 return resolution;
306
307 return QSize{
308 resolution.width() * par.numerator / par.denominator,
309 resolution.height(),
310 };
311}
312
314{
316 if (!size.isValid()) {
317 qWarning() << Q_FUNC_INFO << "invalid resolution when querying nativeSize";
318 return size;
319 }
320
321 std::optional<Fraction> par = pixelAspectRatio();
322 if (par)
324 return size;
325}
326
327// QGstCaps
328
329std::optional<std::pair<QVideoFrameFormat, GstVideoInfo>> QGstCaps::formatAndVideoInfo() const
330{
331 GstVideoInfo vidInfo;
332
333 bool success = gst_video_info_from_caps(&vidInfo, get());
334 if (!success)
335 return std::nullopt;
336
337 int index = indexOfVideoFormat(vidInfo.finfo->format);
338 if (index == -1)
339 return std::nullopt;
340
341 QVideoFrameFormat format(QSize(vidInfo.width, vidInfo.height),
342 qt_videoFormatLookup[index].pixelFormat);
343
344 if (vidInfo.fps_d > 0)
345 format.setStreamFrameRate(qreal(vidInfo.fps_n) / vidInfo.fps_d);
346
348 switch (vidInfo.colorimetry.range) {
349 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
350 break;
351 case GST_VIDEO_COLOR_RANGE_0_255:
353 break;
354 case GST_VIDEO_COLOR_RANGE_16_235:
356 break;
357 }
358 format.setColorRange(range);
359
361 switch (vidInfo.colorimetry.matrix) {
362 case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
363 case GST_VIDEO_COLOR_MATRIX_RGB:
364 case GST_VIDEO_COLOR_MATRIX_FCC:
365 break;
366 case GST_VIDEO_COLOR_MATRIX_BT709:
368 break;
369 case GST_VIDEO_COLOR_MATRIX_BT601:
371 break;
372 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
374 break;
375 case GST_VIDEO_COLOR_MATRIX_BT2020:
377 break;
378 }
379 format.setColorSpace(colorSpace);
380
382 switch (vidInfo.colorimetry.transfer) {
383 case GST_VIDEO_TRANSFER_UNKNOWN:
384 break;
385 case GST_VIDEO_TRANSFER_GAMMA10:
387 break;
388 case GST_VIDEO_TRANSFER_GAMMA22:
389 case GST_VIDEO_TRANSFER_SMPTE240M:
390 case GST_VIDEO_TRANSFER_SRGB:
391 case GST_VIDEO_TRANSFER_ADOBERGB:
393 break;
394 case GST_VIDEO_TRANSFER_GAMMA18:
395 case GST_VIDEO_TRANSFER_GAMMA20:
396 // not quite, but best fit
397 case GST_VIDEO_TRANSFER_BT709:
398 case GST_VIDEO_TRANSFER_BT2020_12:
400 break;
401 case GST_VIDEO_TRANSFER_GAMMA28:
403 break;
404 case GST_VIDEO_TRANSFER_LOG100:
405 case GST_VIDEO_TRANSFER_LOG316:
406 break;
407#if GST_CHECK_VERSION(1, 18, 0)
408 case GST_VIDEO_TRANSFER_SMPTE2084:
410 break;
411 case GST_VIDEO_TRANSFER_ARIB_STD_B67:
413 break;
414 case GST_VIDEO_TRANSFER_BT2020_10:
416 break;
417 case GST_VIDEO_TRANSFER_BT601:
419 break;
420#endif
421 }
422 format.setColorTransfer(transfer);
423
424 return std::pair{
425 std::move(format),
426 vidInfo,
427 };
428}
429
430void QGstCaps::addPixelFormats(const QList<QVideoFrameFormat::PixelFormat> &formats,
431 const char *modifier)
432{
433 if (!gst_caps_is_writable(get()))
434 *this = QGstCaps(gst_caps_make_writable(release()), QGstCaps::RefMode::HasRef);
435
436 GValue list = {};
437 g_value_init(&list, GST_TYPE_LIST);
438
440 int index = indexOfVideoFormat(format);
441 if (index == -1)
442 continue;
443 GValue item = {};
444
445 g_value_init(&item, G_TYPE_STRING);
446 g_value_set_string(&item,
447 gst_video_format_to_string(qt_videoFormatLookup[index].gstFormat));
448 gst_value_list_append_value(&list, &item);
449 g_value_unset(&item);
450 }
451
452 auto *structure = gst_structure_new("video/x-raw", "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
453 INT_MAX, 1, "width", GST_TYPE_INT_RANGE, 1, INT_MAX,
454 "height", GST_TYPE_INT_RANGE, 1, INT_MAX, nullptr);
455 gst_structure_set_value(structure, "format", &list);
456 gst_caps_append_structure(get(), structure);
457 g_value_unset(&list);
458
459 if (modifier)
460 gst_caps_set_features(get(), size() - 1, gst_caps_features_from_string(modifier));
461}
462
464{
465 Q_ASSERT(resolution.isValid());
466 GValue width{};
467 g_value_init(&width, G_TYPE_INT);
468 g_value_set_int(&width, resolution.width());
469 GValue height{};
470 g_value_init(&height, G_TYPE_INT);
471 g_value_set_int(&height, resolution.height());
472
473 gst_caps_set_value(caps(), "width", &width);
474 gst_caps_set_value(caps(), "height", &height);
475}
476
478{
479 QSize size = format.resolution();
480 GstStructure *structure = nullptr;
481 if (format.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
482 structure = gst_structure_new("image/jpeg", "width", G_TYPE_INT, size.width(), "height",
483 G_TYPE_INT, size.height(), nullptr);
484 } else {
485 int index = indexOfVideoFormat(format.pixelFormat());
486 if (index < 0)
487 return {};
488 auto gstFormat = qt_videoFormatLookup[index].gstFormat;
489 structure = gst_structure_new("video/x-raw", "format", G_TYPE_STRING,
490 gst_video_format_to_string(gstFormat), "width", G_TYPE_INT,
491 size.width(), "height", G_TYPE_INT, size.height(), nullptr);
492 }
493 auto caps = QGstCaps::create();
494 gst_caps_append_structure(caps.get(), structure);
495 return caps;
496}
497
499{
500 return QGstCaps{
501 gst_caps_copy(caps()),
503 };
504}
505
507{
508 auto *features = gst_caps_get_features(get(), 0);
509 if (gst_caps_features_contains(features, "memory:GLMemory"))
510 return GLTexture;
511 if (gst_caps_features_contains(features, "memory:DMABuf"))
512 return DMABuf;
513 return CpuMemory;
514}
515
516int QGstCaps::size() const
517{
518 return int(gst_caps_get_size(get()));
519}
520
522{
523 return gst_caps_get_structure(get(), index);
524}
525
526GstCaps *QGstCaps::caps() const
527{
528 return get();
529}
530
532{
533 return QGstCaps(gst_caps_new_empty(), HasRef);
534}
535
536// QGstObject
537
538void QGstObject::set(const char *property, const char *str)
539{
540 g_object_set(get(), property, str, nullptr);
541}
542
543void QGstObject::set(const char *property, bool b)
544{
545 g_object_set(get(), property, gboolean(b), nullptr);
546}
547
548void QGstObject::set(const char *property, uint i)
549{
550 g_object_set(get(), property, guint(i), nullptr);
551}
552
553void QGstObject::set(const char *property, int i)
554{
555 g_object_set(get(), property, gint(i), nullptr);
556}
557
559{
560 g_object_set(get(), property, gint64(i), nullptr);
561}
564{
565 g_object_set(get(), property, guint64(i), nullptr);
566}
567
568void QGstObject::set(const char *property, double d)
569{
570 g_object_set(get(), property, gdouble(d), nullptr);
571}
572
573void QGstObject::set(const char *property, const QGstObject &o)
574{
575 g_object_set(get(), property, o.object(), nullptr);
576}
577
578void QGstObject::set(const char *property, const QGstCaps &c)
579{
580 g_object_set(get(), property, c.caps(), nullptr);
581}
582
584{
585 char *s = nullptr;
586 g_object_get(get(), property, &s, nullptr);
587 return QGString(s);
588}
589
591{
592 GstStructure *s = nullptr;
593 g_object_get(get(), property, &s, nullptr);
594 return QGstStructure(s);
595}
596
597bool QGstObject::getBool(const char *property) const
598{
599 gboolean b = false;
600 g_object_get(get(), property, &b, nullptr);
601 return b;
602}
603
605{
606 guint i = 0;
607 g_object_get(get(), property, &i, nullptr);
608 return i;
609}
610
611int QGstObject::getInt(const char *property) const
612{
613 gint i = 0;
614 g_object_get(get(), property, &i, nullptr);
615 return i;
616}
617
619{
620 guint64 i = 0;
621 g_object_get(get(), property, &i, nullptr);
622 return i;
623}
624
626{
627 gint64 i = 0;
628 g_object_get(get(), property, &i, nullptr);
629 return i;
630}
631
632float QGstObject::getFloat(const char *property) const
633{
634 gfloat d = 0;
635 g_object_get(get(), property, &d, nullptr);
636 return d;
637}
638
639double QGstObject::getDouble(const char *property) const
640{
641 gdouble d = 0;
642 g_object_get(get(), property, &d, nullptr);
643 return d;
644}
645
647{
648 GstObject *o = nullptr;
649 g_object_get(get(), property, &o, nullptr);
650 return QGstObject(o, HasRef);
651}
652
653QGObjectHandlerConnection QGstObject::connect(const char *name, GCallback callback,
654 gpointer userData)
655{
657 *this,
658 g_signal_connect(get(), name, callback, userData),
659 };
660}
661
662void QGstObject::disconnect(gulong handlerId)
663{
664 g_signal_handler_disconnect(get(), handlerId);
665}
666
667GType QGstObject::type() const
668{
669 return G_OBJECT_TYPE(get());
670}
671
672const char *QGstObject::typeName() const
673{
674 return g_type_name(type());
675}
676
677GstObject *QGstObject::object() const
678{
679 return get();
680}
681
682const char *QGstObject::name() const
683{
684 return get() ? GST_OBJECT_NAME(get()) : "(null)";
685}
686
687// QGObjectHandlerConnection
688
690 : object{ std::move(object) }, handlerId{ handlerId }
691{
692}
693
695{
696 if (!object)
697 return;
698
699 object.disconnect(handlerId);
700 object = {};
701 handlerId = invalidHandlerId;
702}
703
704// QGObjectHandlerScopedConnection
705
713
718
723
724// QGstPad
725
727 : QGstPad{
728 qGstSafeCast<GstPad>(o.object()),
729 QGstElement::NeedsRef,
730 }
731{
732}
733
734QGstPad::QGstPad(GstPad *pad, RefMode mode)
735 : QGstObject{
736 qGstCheckedCast<GstObject>(pad),
737 mode,
738 }
739{
740}
741
743{
744 return QGstCaps(gst_pad_get_current_caps(pad()), QGstCaps::HasRef);
745}
746
748{
749 return QGstCaps(gst_pad_query_caps(pad(), nullptr), QGstCaps::HasRef);
750}
751
753{
754 return gst_pad_is_linked(pad());
755}
756
757bool QGstPad::link(const QGstPad &sink) const
758{
759 return gst_pad_link(pad(), sink.pad()) == GST_PAD_LINK_OK;
760}
761
762bool QGstPad::unlink(const QGstPad &sink) const
763{
764 return gst_pad_unlink(pad(), sink.pad());
765}
766
768{
769 return unlink(peer());
770}
771
773{
774 return QGstPad(gst_pad_get_peer(pad()), HasRef);
775}
776
778{
779 return QGstElement(gst_pad_get_parent_element(pad()), HasRef);
780}
781
782GstPad *QGstPad::pad() const
783{
784 return qGstCheckedCast<GstPad>(object());
785}
786
787GstEvent *QGstPad::stickyEvent(GstEventType type)
788{
789 return gst_pad_get_sticky_event(pad(), type, 0);
790}
791
793{
794 return gst_pad_send_event(pad(), event);
795}
796
797// QGstClock
798
800 : QGstClock{
801 qGstSafeCast<GstClock>(o.object()),
802 QGstElement::NeedsRef,
803 }
804{
805}
806
807QGstClock::QGstClock(GstClock *clock, RefMode mode)
808 : QGstObject{
809 qGstCheckedCast<GstObject>(clock),
810 mode,
811 }
812{
813}
814
815GstClock *QGstClock::clock() const
816{
817 return qGstCheckedCast<GstClock>(object());
818}
819
820GstClockTime QGstClock::time() const
821{
822 return gst_clock_get_time(clock());
823}
824
825// QGstElement
826
827QGstElement::QGstElement(GstElement *element, RefMode mode)
828 : QGstObject{
829 qGstCheckedCast<GstObject>(element),
830 mode,
831 }
832{
833}
834
836{
837 GstElement *element = gst_element_factory_make(factory, name);
838
839#ifndef QT_NO_DEBUG
840 if (!element) {
841 qWarning() << "Failed to make element" << name << "from factory" << factory;
842 return QGstElement{};
843 }
844#endif
845
846 return QGstElement{
847 element,
848 NeedsRef,
849 };
850}
851
853{
854 return QGstElement{
855 gst_element_factory_create(factory, name),
856 NeedsRef,
857 };
858}
859
865
870
872{
873 return QGstElement{
874 gst_device_create_element(device, name),
876 };
877}
878
880{
883 gst_parse_launch(str, &error),
885 };
886
887 if (error) // error does not mean that the element could not be constructed
888 qWarning() << "gst_parse_launch error:" << error;
889
890 return element;
891}
892
897
899{
900 return QGstPad(gst_element_get_static_pad(element(), name), HasRef);
901}
902
904{
905 return staticPad("src");
906}
907
909{
910 return staticPad("sink");
911}
912
914{
915#if GST_CHECK_VERSION(1, 19, 1)
916 return QGstPad(gst_element_request_pad_simple(element(), name), HasRef);
917#else
918 return QGstPad(gst_element_get_request_pad(element(), name), HasRef);
919#endif
920}
921
923{
924 return gst_element_release_request_pad(element(), pad.pad());
925}
926
927GstState QGstElement::state(std::chrono::nanoseconds timeout) const
928{
929 using namespace std::chrono_literals;
930
931 GstState state;
932 GstStateChangeReturn change =
933 gst_element_get_state(element(), &state, nullptr, timeout.count());
934
935 if (Q_UNLIKELY(change == GST_STATE_CHANGE_ASYNC))
936 qWarning() << "QGstElement::state detected an asynchronous state change. Return value not "
937 "reliable";
938
939 return state;
940}
941
942GstStateChangeReturn QGstElement::setState(GstState state)
943{
944 return gst_element_set_state(element(), state);
945}
946
947bool QGstElement::setStateSync(GstState state, std::chrono::nanoseconds timeout)
948{
949 if (state == GST_STATE_NULL) {
950 // QTBUG-125251: when changing pipeline state too quickly between NULL->PAUSED->NULL there
951 // may be a pending task to activate pads while we try to switch to NULL. This can cause an
952 // assertion failure in gstreamer. we therefore finish the state change when called on a bin
953 // or pipeline.
954 if (qIsGstObjectOfType<GstBin>(element()))
956 }
957
958 GstStateChangeReturn change = gst_element_set_state(element(), state);
959 if (change == GST_STATE_CHANGE_ASYNC)
960 change = gst_element_get_state(element(), nullptr, &state, timeout.count());
961
962 if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL) {
963 qWarning() << "Could not change state of" << name() << "to" << state << change;
964 dumpPipelineGraph("setStatSyncFailure");
965 }
966 return change == GST_STATE_CHANGE_SUCCESS;
967}
968
970{
971 Q_ASSERT(element());
972 return gst_element_sync_state_with_parent(element()) == TRUE;
973}
974
975bool QGstElement::finishStateChange(std::chrono::nanoseconds timeout)
976{
977 GstState state, pending;
978 GstStateChangeReturn change =
979 gst_element_get_state(element(), &state, &pending, timeout.count());
980
981 if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL) {
982 qWarning() << "Could not finish change state of" << name() << change << state << pending;
983 dumpPipelineGraph("finishStateChangeFailure");
984 }
985 return change == GST_STATE_CHANGE_SUCCESS;
986}
987
988void QGstElement::lockState(bool locked)
989{
990 gst_element_set_locked_state(element(), locked);
991}
992
994{
995 return gst_element_is_locked_state(element());
996}
997
998void QGstElement::sendEvent(GstEvent *event) const
999{
1000 gst_element_send_event(element(), event);
1001}
1002
1004{
1005 sendEvent(gst_event_new_eos());
1006}
1007
1008GstClockTime QGstElement::baseTime() const
1009{
1010 return gst_element_get_base_time(element());
1011}
1012
1013void QGstElement::setBaseTime(GstClockTime time) const
1014{
1015 gst_element_set_base_time(element(), time);
1016}
1017
1018GstElement *QGstElement::element() const
1019{
1020 return GST_ELEMENT_CAST(get());
1021}
1022
1024{
1025 return QGstElement{
1026 qGstCheckedCast<GstElement>(gst_element_get_parent(object())),
1028 };
1029}
1030
1032{
1033 QGstElement ancestor = *this;
1034 for (;;) {
1035 QGstElement greatAncestor = ancestor.getParent();
1036 if (greatAncestor) {
1037 ancestor = std::move(greatAncestor);
1038 continue;
1039 }
1040
1041 return QGstPipeline{
1042 qGstSafeCast<GstPipeline>(ancestor.element()),
1044 };
1045 }
1046}
1047
1048void QGstElement::dumpPipelineGraph(const char *filename) const
1049{
1050 static const bool dumpEnabled = qEnvironmentVariableIsSet("GST_DEBUG_DUMP_DOT_DIR");
1051 if (dumpEnabled) {
1052 QGstPipeline pipeline = getPipeline();
1053 if (pipeline)
1054 pipeline.dumpGraph(filename);
1055 }
1056}
1057
1058// QGstBin
1059
1061{
1062 return QGstBin(gst_bin_new(name), NeedsRef);
1063}
1064
1066{
1068 Q_ASSERT(GST_IS_BIN(element.element()));
1069 return QGstBin{
1070 GST_BIN(element.release()),
1071 RefMode::HasRef,
1072 };
1073}
1074
1076 const char *name, bool ghostUnlinkedPads)
1077{
1078 return createFromPipelineDescription(pipelineDescription.constData(), name, ghostUnlinkedPads);
1079}
1080
1081QGstBin QGstBin::createFromPipelineDescription(const char *pipelineDescription, const char *name,
1082 bool ghostUnlinkedPads)
1083{
1085
1086 GstElement *element =
1087 gst_parse_bin_from_description_full(pipelineDescription, ghostUnlinkedPads,
1088 /*context=*/nullptr, GST_PARSE_FLAG_NONE, &error);
1089
1090 if (!element) {
1091 qWarning() << "Failed to make element from pipeline description" << pipelineDescription
1092 << error;
1093 return QGstBin{};
1094 }
1095
1096 if (name)
1097 gst_element_set_name(element, name);
1098
1099 return QGstBin{
1100 element,
1101 NeedsRef,
1102 };
1103}
1104
1105QGstBin::QGstBin(GstBin *bin, RefMode mode)
1106 : QGstElement{
1107 qGstCheckedCast<GstElement>(bin),
1108 mode,
1109 }
1110{
1111}
1112
1113GstBin *QGstBin::bin() const
1114{
1115 return qGstCheckedCast<GstBin>(object());
1116}
1117
1119{
1120 addGhostPad(name, child.staticPad(name));
1121}
1122
1123void QGstBin::addGhostPad(const char *name, const QGstPad &pad)
1124{
1125 gst_element_add_pad(element(), gst_ghost_pad_new(name, pad.pad()));
1126}
1127
1129{
1130 return gst_bin_sync_children_states(bin());
1131}
1132
1133void QGstBin::dumpGraph(const char *fileNamePrefix)
1134{
1135 if (isNull())
1136 return;
1137
1138 GST_DEBUG_BIN_TO_DOT_FILE(bin(), GST_DEBUG_GRAPH_SHOW_VERBOSE, fileNamePrefix);
1139}
1140
1142{
1143 return QGstElement{
1144 gst_bin_get_by_name(bin(), name),
1146 };
1147}
1148
1149// QGstBaseSink
1150
1151QGstBaseSink::QGstBaseSink(GstBaseSink *element, RefMode mode)
1152 : QGstElement{
1153 qGstCheckedCast<GstElement>(element),
1154 mode,
1155 }
1156{
1157}
1158
1160{
1161 gst_base_sink_set_sync(baseSink(), arg ? TRUE : FALSE);
1162}
1163
1164GstBaseSink *QGstBaseSink::baseSink() const
1165{
1166 return qGstCheckedCast<GstBaseSink>(element());
1167}
1168
1169// QGstBaseSrc
1170
1171QGstBaseSrc::QGstBaseSrc(GstBaseSrc *element, RefMode mode)
1172 : QGstElement{
1173 qGstCheckedCast<GstElement>(element),
1174 mode,
1175 }
1176{
1177}
1178
1179GstBaseSrc *QGstBaseSrc::baseSrc() const
1180{
1181 return qGstCheckedCast<GstBaseSrc>(element());
1182}
1183
1184#if QT_CONFIG(gstreamer_app)
1185
1186// QGstAppSink
1187
1188QGstAppSink::QGstAppSink(GstAppSink *element, RefMode mode)
1189 : QGstBaseSink{
1190 qGstCheckedCast<GstBaseSink>(element),
1191 mode,
1192 }
1193{
1194}
1195
1196QGstAppSink QGstAppSink::create(const char *name)
1197{
1198 QGstElement created = QGstElement::createFromFactory("appsink", name);
1199 return QGstAppSink{
1200 qGstCheckedCast<GstAppSink>(created.element()),
1201 QGstAppSink::NeedsRef,
1202 };
1203}
1204
1205GstAppSink *QGstAppSink::appSink() const
1206{
1207 return qGstCheckedCast<GstAppSink>(element());
1208}
1209
1210# if GST_CHECK_VERSION(1, 24, 0)
1211void QGstAppSink::setMaxBufferTime(std::chrono::nanoseconds ns)
1212{
1213 gst_app_sink_set_max_time(appSink(), qGstClockTimeFromChrono(ns));
1214}
1215# endif
1216
1217void QGstAppSink::setMaxBuffers(int n)
1218{
1219 gst_app_sink_set_max_buffers(appSink(), n);
1220}
1221
1222void QGstAppSink::setCaps(const QGstCaps &caps)
1223{
1224 gst_app_sink_set_caps(appSink(), caps.caps());
1225}
1226
1227void QGstAppSink::setCallbacks(GstAppSinkCallbacks &callbacks, gpointer user_data,
1228 GDestroyNotify notify)
1229{
1230 gst_app_sink_set_callbacks(appSink(), &callbacks, user_data, notify);
1231}
1232
1233QGstSampleHandle QGstAppSink::pullSample()
1234{
1235 return QGstSampleHandle{
1236 gst_app_sink_pull_sample(appSink()),
1238 };
1239}
1240
1241// QGstAppSrc
1242
1243QGstAppSrc::QGstAppSrc(GstAppSrc *element, RefMode mode)
1244 : QGstBaseSrc{
1245 qGstCheckedCast<GstBaseSrc>(element),
1246 mode,
1247 }
1248{
1249}
1250
1251QGstAppSrc QGstAppSrc::create(const char *name)
1252{
1253 QGstElement created = QGstElement::createFromFactory("appsrc", name);
1254 return QGstAppSrc{
1255 qGstCheckedCast<GstAppSrc>(created.element()),
1256 QGstAppSrc::NeedsRef,
1257 };
1258}
1259
1260GstAppSrc *QGstAppSrc::appSrc() const
1261{
1262 return qGstCheckedCast<GstAppSrc>(element());
1263}
1264
1265void QGstAppSrc::setCallbacks(GstAppSrcCallbacks &callbacks, gpointer user_data,
1266 GDestroyNotify notify)
1267{
1268 gst_app_src_set_callbacks(appSrc(), &callbacks, user_data, notify);
1269}
1270
1271GstFlowReturn QGstAppSrc::pushBuffer(GstBuffer *buffer)
1272{
1273 return gst_app_src_push_buffer(appSrc(), buffer);
1274}
1275
1276#endif
1277
IOBluetoothDevice * device
\inmodule QtCore
Definition qbytearray.h:57
The QCameraFormat class describes a video format supported by a camera device. \inmodule QtMultimedia...
QGObjectHandlerConnection()=default
std::optional< int > toInt64() const
Definition qgst.cpp:94
std::optional< QGRange< int > > toIntRange() const
Definition qgst.cpp:123
std::optional< int > toInt() const
Definition qgst.cpp:87
int listSize() const
Definition qgst.cpp:149
bool isList() const
Definition qgst.cpp:144
std::optional< QGRange< float > > getFractionRange() const
Definition qgst.cpp:114
const char * toString() const
Definition qgst.cpp:101
QGstStructure toStructure() const
Definition qgst.cpp:130
const GValue * value
Definition qgst_p.h:196
std::optional< float > getFraction() const
Definition qgst.cpp:106
QGValue at(int index) const
Definition qgst.cpp:154
bool isNull() const
Definition qgst.cpp:75
QGstCaps toCaps() const
Definition qgst.cpp:137
std::optional< bool > toBool() const
Definition qgst.cpp:80
QGValue(const GValue *v)
Definition qgst.cpp:73
void setSync(bool)
Definition qgst.cpp:1159
QGstBaseSink(GstBaseSink *, RefMode)
Definition qgst.cpp:1151
GstBaseSink * baseSink() const
Definition qgst.cpp:1164
QGstBaseSrc(GstBaseSrc *, RefMode)
Definition qgst.cpp:1171
GstBaseSrc * baseSrc() const
Definition qgst.cpp:1179
void dumpGraph(const char *fileNamePrefix)
Definition qgst.cpp:1133
QGstElement findByName(const char *)
Definition qgst.cpp:1141
GstBin * bin() const
Definition qgst.cpp:1113
static QGstBin create(const char *name)
Definition qgst.cpp:1060
void addGhostPad(const QGstElement &child, const char *name)
Definition qgst.cpp:1118
QGstBin(const QGstBin &)=default
static QGstBin createFromFactory(const char *factory, const char *name)
Definition qgst.cpp:1065
bool syncChildrenState()
Definition qgst.cpp:1128
static QGstBin createFromPipelineDescription(const QByteArray &pipelineDescription, const char *name=nullptr, bool ghostUnlinkedPads=false)
Definition qgst.cpp:1075
void addPixelFormats(const QList< QVideoFrameFormat::PixelFormat > &formats, const char *modifier=nullptr)
Definition qgst.cpp:430
MemoryFormat memoryFormat() const
Definition qgst.cpp:506
std::optional< std::pair< QVideoFrameFormat, GstVideoInfo > > formatAndVideoInfo() const
Definition qgst.cpp:329
int size() const
Definition qgst.cpp:516
static QGstCaps fromCameraFormat(const QCameraFormat &format)
Definition qgst.cpp:477
static QGstCaps create()
Definition qgst.cpp:531
GstCaps * caps() const
Definition qgst.cpp:526
void setResolution(QSize)
Definition qgst.cpp:463
QGstStructure at(int index) const
Definition qgst.cpp:521
MemoryFormat
Definition qgst_p.h:353
@ DMABuf
Definition qgst_p.h:353
@ CpuMemory
Definition qgst_p.h:353
@ GLTexture
Definition qgst_p.h:353
QGstCaps(const QGstCaps &)=default
QGstCaps copy() const
Definition qgst.cpp:498
GstClockTime time() const
Definition qgst.cpp:820
QGstClock()=default
GstClock * clock() const
Definition qgst.cpp:815
void setBaseTime(GstClockTime time) const
Definition qgst.cpp:1013
GstStateChangeReturn setState(GstState state)
Definition qgst.cpp:942
static QGstElement createFromDevice(const QGstDeviceHandle &, const char *name=nullptr)
Definition qgst.cpp:866
GstElement * element() const
Definition qgst.cpp:1018
void lockState(bool locked)
Definition qgst.cpp:988
QGstElement(const QGstElement &)=default
QGstPad getRequestPad(const char *name) const
Definition qgst.cpp:913
bool finishStateChange(std::chrono::nanoseconds timeout=std::chrono::seconds(5))
Definition qgst.cpp:975
bool setStateSync(GstState state, std::chrono::nanoseconds timeout=std::chrono::seconds(1))
Definition qgst.cpp:947
bool isStateLocked() const
Definition qgst.cpp:993
void sendEvent(GstEvent *event) const
Definition qgst.cpp:998
void dumpPipelineGraph(const char *filename) const
Definition qgst.cpp:1048
GstClockTime baseTime() const
Definition qgst.cpp:1008
void releaseRequestPad(const QGstPad &pad) const
Definition qgst.cpp:922
bool syncStateWithParent()
Definition qgst.cpp:969
QGstPad sink() const
Definition qgst.cpp:908
QGstPad staticPad(const char *name) const
Definition qgst.cpp:898
void sendEos() const
Definition qgst.cpp:1003
static QGstElement createFromFactory(const char *factory, const char *name=nullptr)
Definition qgst.cpp:835
QGstElement getParent() const
Definition qgst.cpp:1023
QGstPipeline getPipeline() const
Definition qgst.cpp:1031
static QGstElement createFromPipelineDescription(const char *)
Definition qgst.cpp:879
GstState state(std::chrono::nanoseconds timeout=std::chrono::seconds(0)) const
Definition qgst.cpp:927
QGstPad src() const
Definition qgst.cpp:903
QGstStructure getStructure(const char *property) const
Definition qgst.cpp:590
QGObjectHandlerConnection connect(const char *name, GCallback callback, gpointer userData)
Definition qgst.cpp:653
double getDouble(const char *property) const
Definition qgst.cpp:639
const char * name() const
Definition qgst.cpp:682
int getInt(const char *property) const
Definition qgst.cpp:611
QGString getString(const char *property) const
Definition qgst.cpp:583
void disconnect(gulong handlerId)
Definition qgst.cpp:662
const char * typeName() const
Definition qgst.cpp:672
QGstObject getObject(const char *property) const
Definition qgst.cpp:646
void set(const char *property, const char *str)
Definition qgst.cpp:538
bool getBool(const char *property) const
Definition qgst.cpp:597
GType type() const
Definition qgst.cpp:667
QGstObject(const QGstObject &)=default
quint64 getUInt64(const char *property) const
Definition qgst.cpp:618
qint64 getInt64(const char *property) const
Definition qgst.cpp:625
float getFloat(const char *property) const
Definition qgst.cpp:632
uint getUInt(const char *property) const
Definition qgst.cpp:604
GstObject * object() const
Definition qgst.cpp:677
bool link(const QGstPad &sink) const
Definition qgst.cpp:757
GstEvent * stickyEvent(GstEventType type)
Definition qgst.cpp:787
bool isLinked() const
Definition qgst.cpp:752
bool unlinkPeer() const
Definition qgst.cpp:767
QGstPad(const QGstPad &)=default
QGstCaps queryCaps() const
Definition qgst.cpp:747
GstPad * pad() const
Definition qgst.cpp:782
bool sendEvent(GstEvent *event)
Definition qgst.cpp:792
QGstCaps currentCaps() const
Definition qgst.cpp:742
QGstElement parent() const
Definition qgst.cpp:777
bool unlink(const QGstPad &sink) const
Definition qgst.cpp:762
QGstPad peer() const
Definition qgst.cpp:772
void dumpGraph(const char *fileName)
QSize resolution() const
Definition qgst.cpp:190
QSize nativeSize() const
Definition qgst.cpp:313
QGstStructure copy() const
Definition qgst.cpp:185
QGstreamerMessage getMessage()
Definition qgst.cpp:279
const GstStructure * structure
Definition qgst_p.h:315
QGRange< float > frameRateRange() const
Definition qgst.cpp:227
void free()
Definition qgst.cpp:163
std::optional< Fraction > pixelAspectRatio() const
Definition qgst.cpp:286
QByteArrayView name() const
Definition qgst.cpp:175
QGstStructure()=default
QGValue operator[](const char *name) const
Definition qgst.cpp:180
QVideoFrameFormat::PixelFormat pixelFormat() const
Definition qgst.cpp:204
bool isNull() const
Definition qgst.cpp:170
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:127
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1246
The QVideoFrameFormat class specifies the stream format of a video presentation surface.
ColorSpace
Enumerates the color space of video frames.
ColorTransfer
\value ColorTransfer_Unknown The color transfer function is unknown.
PixelFormat
Enumerates video data types.
ColorRange
Describes the color range used by the video data.
QString str
[2]
cache insert(employee->id(), employee)
else opt state
[0]
EGLint EGLint * formats
Combined button and popup list for selecting options.
constexpr std::array< VideoFormat, 19 > qt_videoFormatLookup
Definition qgst.cpp:24
int indexOfVideoFormat(QVideoFrameFormat::PixelFormat format)
Definition qgst.cpp:51
#define Q_UNLIKELY(x)
#define Q_FUNC_INFO
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void * user_data
DBusConnection const char DBusError * error
DBusConnection * connection
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall * pending
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static QSize qCalculateFrameSizeGStreamer(QSize resolution, Fraction par)
Definition qgst.cpp:302
DestinationType * qGstCheckedCast(SourceType *arg)
Definition qgst_p.h:164
GstClockTime qGstClockTimeFromChrono(std::chrono::nanoseconds ns)
Definition qgst_p.h:812
DestinationType * qGstSafeCast(SourceType *arg)
Definition qgst_p.h:155
#define qWarning
Definition qlogging.h:166
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLenum mode
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint object
[3]
GLbitfield GLuint64 timeout
[4]
GLfloat GLfloat f
GLsizei range
GLenum GLuint buffer
GLint GLsizei width
GLenum type
GLuint GLsizei const GLchar * message
GLuint name
GLfloat n
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
struct _cl_event * event
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLuint GLenum * rate
GLsizei GLenum GLboolean sink
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
PromiseCallbacks callbacks
Definition qstdweb.cpp:275
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
const char property[13]
Definition qwizard.cpp:101
QList< int > list
[14]
QGraphicsItem * item
QItemEditorFactory * factory
QLayoutItem * child
[0]
QVideoFrameFormat::PixelFormat pixelFormat
Definition qgst.cpp:20