Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
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>
5
6#include <common/qgst_debug_p.h>
7#include <common/qgstpipeline_p.h>
8#include <common/qgstreamermessage_p.h>
9#include <common/qgstutils_p.h>
10#include <common/qgstvideobuffer_p.h>
11
12#if QT_CONFIG(linux_dmabuf)
13# include <common/qgstdmabufvideobuffer_p.h>
14#endif
15
16#include <QtCore/qdebug.h>
17#include <QtMultimedia/private/qvideoframe_p.h>
18#include <QtMultimedia/qcameradevice.h>
19
20#if QT_CONFIG(gstreamer_gl)
21# include <gst/gl/gstglmemory.h>
22#endif
23
24#include <array>
25#include <thread>
26
27// DMA support
28#if QT_CONFIG(gstreamer_gl_egl) && QT_CONFIG(linux_dmabuf)
29# include <gst/allocators/gstdmabuf.h>
30#endif
31
32QT_BEGIN_NAMESPACE
33
34namespace {
35
41
42constexpr std::array<VideoFormat, 19> qt_videoFormatLookup{ {
43 { QVideoFrameFormat::Format_YUV420P, GST_VIDEO_FORMAT_I420 },
44 { QVideoFrameFormat::Format_YUV422P, GST_VIDEO_FORMAT_Y42B },
45 { QVideoFrameFormat::Format_YV12, GST_VIDEO_FORMAT_YV12 },
46 { QVideoFrameFormat::Format_UYVY, GST_VIDEO_FORMAT_UYVY },
47 { QVideoFrameFormat::Format_YUYV, GST_VIDEO_FORMAT_YUY2 },
48 { QVideoFrameFormat::Format_NV12, GST_VIDEO_FORMAT_NV12 },
49 { QVideoFrameFormat::Format_NV21, GST_VIDEO_FORMAT_NV21 },
50 { QVideoFrameFormat::Format_AYUV, GST_VIDEO_FORMAT_AYUV },
51 { QVideoFrameFormat::Format_Y8, GST_VIDEO_FORMAT_GRAY8 },
52 { QVideoFrameFormat::Format_XRGB8888, GST_VIDEO_FORMAT_xRGB },
53 { QVideoFrameFormat::Format_XBGR8888, GST_VIDEO_FORMAT_xBGR },
54 { QVideoFrameFormat::Format_RGBX8888, GST_VIDEO_FORMAT_RGBx },
55 { QVideoFrameFormat::Format_BGRX8888, GST_VIDEO_FORMAT_BGRx },
56 { QVideoFrameFormat::Format_ARGB8888, GST_VIDEO_FORMAT_ARGB },
57 { QVideoFrameFormat::Format_ABGR8888, GST_VIDEO_FORMAT_ABGR },
58 { QVideoFrameFormat::Format_RGBA8888, GST_VIDEO_FORMAT_RGBA },
59 { QVideoFrameFormat::Format_BGRA8888, GST_VIDEO_FORMAT_BGRA },
60#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
61 { QVideoFrameFormat::Format_Y16, GST_VIDEO_FORMAT_GRAY16_LE },
62 { QVideoFrameFormat::Format_P010, GST_VIDEO_FORMAT_P010_10LE },
63#else
64 { QVideoFrameFormat::Format_Y16, GST_VIDEO_FORMAT_GRAY16_BE },
65 { QVideoFrameFormat::Format_P010, GST_VIDEO_FORMAT_P010_10BE },
66#endif
67} };
68
70void appendDmaDrmPixelFormats(QGstCaps &caps, const QList<QVideoFrameFormat::PixelFormat> &formats)
71{
72 GValue drmFormatList = {};
73 g_value_init(&drmFormatList, GST_TYPE_LIST);
74
75 for (QVideoFrameFormat::PixelFormat format : formats) {
76 const GstVideoFormat gstFormat = qGstVideoFormatFromPixelFormat(format);
77 if (gstFormat == GST_VIDEO_FORMAT_UNKNOWN)
78 continue;
79
80 const guint32 fourcc =
81 gst_video_dma_drm_fourcc_from_format(gstFormat);
82 if (!fourcc)
83 continue;
84
85 GValue drmFormat = {};
86 g_value_init(&drmFormat, G_TYPE_STRING);
87 g_value_take_string(&drmFormat, gst_video_dma_drm_fourcc_to_string(fourcc, 0));
88 gst_value_list_append_value(&drmFormatList, &drmFormat);
89 g_value_unset(&drmFormat);
90 }
91
92 QGstStructure dmaDrmStructure{ "video/x-raw" };
93 dmaDrmStructure.setString("format", gst_video_format_to_string(GST_VIDEO_FORMAT_DMA_DRM));
94 dmaDrmStructure.setFractionRange("framerate", Fraction{ 0, 1 }, Fraction{ INT_MAX, 1 });
95 dmaDrmStructure.setIntRange("width", 1, INT_MAX);
96 dmaDrmStructure.setIntRange("height", 1, INT_MAX);
97 dmaDrmStructure.setValue("drm-format", &drmFormatList);
98
99 gst_caps_append_structure(caps.get(), dmaDrmStructure.release());
100 gst_caps_set_features(caps.get(), caps.size() - 1,
101 gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
102 g_value_unset(&drmFormatList);
103}
104#endif
105
106} // namespace
107
108GstVideoFormat qGstVideoFormatFromPixelFormat(QVideoFrameFormat::PixelFormat format)
109{
110 for (const VideoFormat &formatPair : qt_videoFormatLookup)
111 if (formatPair.pixelFormat == format)
112 return formatPair.gstFormat;
113
114 return GST_VIDEO_FORMAT_UNKNOWN;
115}
116
118{
119 for (const VideoFormat &formatPair : qt_videoFormatLookup)
120 if (formatPair.gstFormat == format)
121 return formatPair.pixelFormat;
122
123 return QVideoFrameFormat::Format_Invalid;
124}
125
126// QGValue
127
128QGValue::QGValue(const GValue *v) : value(v) { }
129
130bool QGValue::isNull() const
131{
132 return !value;
133}
134
135std::optional<bool> QGValue::toBool() const
136{
137 if (!G_VALUE_HOLDS_BOOLEAN(value))
138 return std::nullopt;
139 return g_value_get_boolean(value);
140}
141
142std::optional<int> QGValue::toInt() const
143{
144 if (!G_VALUE_HOLDS_INT(value))
145 return std::nullopt;
146 return g_value_get_int(value);
147}
148
149std::optional<int> QGValue::toInt64() const
150{
151 if (!G_VALUE_HOLDS_INT64(value))
152 return std::nullopt;
153 return g_value_get_int64(value);
154}
155
156const char *QGValue::toString() const
157{
158 return value ? g_value_get_string(value) : nullptr;
159}
160
161std::optional<float> QGValue::getFraction() const
162{
163 if (!GST_VALUE_HOLDS_FRACTION(value))
164 return std::nullopt;
165 return (float)gst_value_get_fraction_numerator(value)
166 / (float)gst_value_get_fraction_denominator(value);
167}
168
169std::optional<QGRange<float>> QGValue::getFractionRange() const
170{
171 if (!GST_VALUE_HOLDS_FRACTION_RANGE(value))
172 return std::nullopt;
173 QGValue min = QGValue{ gst_value_get_fraction_range_min(value) };
174 QGValue max = QGValue{ gst_value_get_fraction_range_max(value) };
175 return QGRange<float>{ *min.getFraction(), *max.getFraction() };
176}
177
178std::optional<QGRange<int>> QGValue::toIntRange() const
179{
180 if (!GST_VALUE_HOLDS_INT_RANGE(value))
181 return std::nullopt;
182 return QGRange<int>{ gst_value_get_int_range_min(value), gst_value_get_int_range_max(value) };
183}
184
186{
187 if (!value || !GST_VALUE_HOLDS_STRUCTURE(value))
188 return QGstStructureView(nullptr);
189 return QGstStructureView(gst_value_get_structure(value));
190}
191
193{
194 if (!value || !GST_VALUE_HOLDS_CAPS(value))
195 return {};
196 return QGstCaps(gst_caps_copy(gst_value_get_caps(value)), QGstCaps::HasRef);
197}
198
199bool QGValue::isList() const
200{
201 return value && GST_VALUE_HOLDS_LIST(value);
202}
203
204int QGValue::listSize() const
205{
206 return gst_value_list_get_size(value);
207}
208
209QGValue QGValue::at(int index) const
210{
211 return QGValue{ gst_value_list_get_value(value, index) };
212}
213
214// QGstStructureView
215
216QGstStructureView::QGstStructureView(const GstStructure *s) : structure(s) { }
217
218QGstStructureView::QGstStructureView(const QUniqueGstStructureHandle &handle)
219 : QGstStructureView{ handle.get() }
220{
221}
222
224{
225 return QUniqueGstStructureHandle{ gst_structure_copy(structure) };
226}
227
229{
230 return !structure;
231}
232
234{
235 return gst_structure_get_name(structure);
236}
237
238QGValue QGstStructureView::operator[](const char *fieldname) const
239{
240 return QGValue{ gst_structure_get_value(structure, fieldname) };
241}
242
244{
245 return operator[]("caps").toCaps();
246}
247
249{
250 QGValue tags = operator[]("tags");
251 if (tags.isNull())
252 return {};
253
254 QGstTagListHandle tagList;
255 gst_structure_get(structure, "tags", GST_TYPE_TAG_LIST, &tagList, nullptr);
256 return tagList;
257}
258
260{
261 QSize size;
262
263 int w, h;
264 if (structure && gst_structure_get_int(structure, "width", &w)
265 && gst_structure_get_int(structure, "height", &h)) {
266 size.rwidth() = w;
267 size.rheight() = h;
268 }
269
270 return size;
271}
272
274{
275 QList<QVideoFrameFormat::PixelFormat> pixelFormats;
276
277 if (!structure)
278 return pixelFormats;
279
280 auto appendFromGstVideoFormat = [&](GstVideoFormat format) {
281 const QVideoFrameFormat::PixelFormat pixelFormat = qPixelFormatFromGstVideoFormat(format);
282 if (pixelFormat == QVideoFrameFormat::Format_Invalid)
283 return;
284
285 if (!pixelFormats.contains(pixelFormat))
286 pixelFormats.append(pixelFormat);
287 };
288
289 if (gst_structure_has_name(structure, "video/x-raw")) {
291 if (const GValue *drmFormatValue = gst_structure_get_value(structure, "drm-format")) {
292 auto parseDrmFormat = [&](const GValue *value) {
293 if (!value || !G_VALUE_HOLDS_STRING(value))
294 return;
295
296 const char *drmFormatString = g_value_get_string(value);
297 if (!drmFormatString)
298 return;
299
300 guint64 modifier = 0;
301 const guint32 fourcc = gst_video_dma_drm_fourcc_from_string(drmFormatString,
302 &modifier);
303 if (fourcc) {
304 if (modifier != 0)
305 qWarning() << "Ignoring drm-format modifier when mapping to Qt PixelFormat:"
306 << drmFormatString;
307 appendFromGstVideoFormat(gst_video_dma_drm_fourcc_to_format(fourcc));
308 }
309 };
310
311 if (GST_VALUE_HOLDS_LIST(drmFormatValue)) {
312 const guint listSize = gst_value_list_get_size(drmFormatValue);
313 for (guint i = 0; i < listSize; ++i)
314 parseDrmFormat(gst_value_list_get_value(drmFormatValue, i));
315 } else {
316 parseDrmFormat(drmFormatValue);
317 }
318
319 if (!pixelFormats.isEmpty())
320 return pixelFormats; // Skip checking "format" field when "drm-format" succeeds
321 }
322#endif
323 if (const GValue *formatValue = gst_structure_get_value(structure, "format")) {
324 auto parseFormat = [&](const GValue *value) {
325 if (!value || !G_VALUE_HOLDS_STRING(value))
326 return;
327 const char *formatString = g_value_get_string(value);
328 if (!formatString)
329 return;
330 appendFromGstVideoFormat(gst_video_format_from_string(formatString));
331 };
332
333 if (GST_VALUE_HOLDS_LIST(formatValue)) {
334 const guint listSize = gst_value_list_get_size(formatValue);
335 for (guint i = 0; i < listSize; ++i)
336 parseFormat(gst_value_list_get_value(formatValue, i));
337 } else {
338 parseFormat(formatValue);
339 }
340 }
341 } else if (gst_structure_has_name(structure, "image/jpeg")) {
342 pixelFormats.append(QVideoFrameFormat::Format_Jpeg);
343 }
344
345 return pixelFormats;
346}
347
349{
350 if (!structure)
351 return { 0.f, 0.f };
352
353 std::optional<float> minRate;
354 std::optional<float> maxRate;
355
356 auto extractFraction = [](const GValue *v) -> float {
357 return (float)gst_value_get_fraction_numerator(v)
358 / (float)gst_value_get_fraction_denominator(v);
359 };
360 auto extractFrameRate = [&](const GValue *v) {
361 auto insert = [&](float min, float max) {
362 if (!maxRate || max > maxRate)
363 maxRate = max;
364 if (!minRate || min < minRate)
365 minRate = min;
366 };
367
368 if (GST_VALUE_HOLDS_FRACTION(v)) {
369 float rate = extractFraction(v);
370 insert(rate, rate);
371 } else if (GST_VALUE_HOLDS_FRACTION_RANGE(v)) {
372 const GValue *min = gst_value_get_fraction_range_min(v);
373 const GValue *max = gst_value_get_fraction_range_max(v);
374 insert(extractFraction(min), extractFraction(max));
375 }
376 };
377
378 const GValue *gstFrameRates = gst_structure_get_value(structure, "framerate");
379 if (gstFrameRates) {
380 if (GST_VALUE_HOLDS_LIST(gstFrameRates)) {
381 guint nFrameRates = gst_value_list_get_size(gstFrameRates);
382 for (guint f = 0; f < nFrameRates; ++f) {
383 extractFrameRate(gst_value_list_get_value(gstFrameRates, f));
384 }
385 } else {
386 extractFrameRate(gstFrameRates);
387 }
388 } else {
389 const GValue *min = gst_structure_get_value(structure, "min-framerate");
390 const GValue *max = gst_structure_get_value(structure, "max-framerate");
391 if (min && max) {
392 minRate = extractFraction(min);
393 maxRate = extractFraction(max);
394 }
395 }
396
397 if (!minRate || !maxRate)
398 return { 0.f, 0.f };
399
400 return {
401 minRate.value_or(*maxRate),
402 maxRate.value_or(*minRate),
403 };
404}
405
407{
408 if (!structure)
409 return std::nullopt;
410
411 const GValue *width = gst_structure_get_value(structure, "width");
412 const GValue *height = gst_structure_get_value(structure, "height");
413
414 if (!width || !height)
415 return std::nullopt;
416
417 for (const GValue *v : { width, height })
418 if (!GST_VALUE_HOLDS_INT_RANGE(v))
419 return std::nullopt;
420
421 int minWidth = gst_value_get_int_range_min(width);
422 int maxWidth = gst_value_get_int_range_max(width);
423 int minHeight = gst_value_get_int_range_min(height);
424 int maxHeight = gst_value_get_int_range_max(height);
425
426 return QGRange<QSize>{
427 QSize(minWidth, minHeight),
428 QSize(maxWidth, maxHeight),
429 };
430}
431
433{
434 GstMessage *message = nullptr;
435 gst_structure_get(structure, "message", GST_TYPE_MESSAGE, &message, nullptr);
436 return QGstreamerMessage(message, QGstreamerMessage::HasRef);
437}
438
440{
441 gint numerator;
442 gint denominator;
443 if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &numerator, &denominator)) {
444 return Fraction{
445 numerator,
446 denominator,
447 };
448 }
449
450 return std::nullopt;
451}
452
454{
455 QSize size = resolution();
456 if (!size.isValid()) {
457 qWarning() << Q_FUNC_INFO << "invalid resolution when querying nativeSize";
458 return size;
459 }
460
461 std::optional<Fraction> par = pixelAspectRatio();
462 if (par)
464 return size;
465}
466
467// QGstCaps
468
470{
471 GstVideoInfo vidInfo;
472 std::optional<guint64> dmaDrmModifier;
473
475 GstVideoInfoDmaDrm videoInfoDmaDrm;
476 if (gst_video_info_dma_drm_from_caps(&videoInfoDmaDrm, get())) {
477 dmaDrmModifier = videoInfoDmaDrm.drm_modifier;
478 // Sets vidInfo‘s format based on drm_fourcc from videoInfoDmaDrm:
479 if (!gst_video_info_dma_drm_to_video_info(&videoInfoDmaDrm, &vidInfo))
480 return std::nullopt;
481 } else
482#endif
483 {
484 if (!gst_video_info_from_caps(&vidInfo, get()))
485 return std::nullopt;
486 }
487
488 return QGstVideoInfo{vidInfo, dmaDrmModifier};
489}
490
491void QGstCaps::addPixelFormats(const QList<QVideoFrameFormat::PixelFormat> &formats,
492 const char *capsFeatures)
493{
494 if (!gst_caps_is_writable(get()))
495 *this = QGstCaps(gst_caps_make_writable(release()), QGstCaps::RefMode::HasRef);
496
498 if (qstrcmp(capsFeatures, GST_CAPS_FEATURE_MEMORY_DMABUF) == 0)
499 appendDmaDrmPixelFormats(*this, formats);
500#endif
501
502 GValue list = {};
503 g_value_init(&list, GST_TYPE_LIST);
504
505 for (QVideoFrameFormat::PixelFormat format : formats) {
506 const GstVideoFormat gstFormat = qGstVideoFormatFromPixelFormat(format);
507 if (gstFormat == GST_VIDEO_FORMAT_UNKNOWN)
508 continue;
509 GValue item = {};
510
511 g_value_init(&item, G_TYPE_STRING);
512 g_value_set_string(&item, gst_video_format_to_string(gstFormat));
513 gst_value_list_append_value(&list, &item);
514 g_value_unset(&item);
515 }
516
517 QGstStructure structure{ "video/x-raw" };
518 structure.setFractionRange("framerate", Fraction{ 0, 1 }, Fraction{ INT_MAX, 1 });
519 structure.setIntRange("width", 1, INT_MAX);
520 structure.setIntRange("height", 1, INT_MAX);
521 structure.setValue("format", &list);
522
523 gst_caps_append_structure(get(), structure.release());
524 g_value_unset(&list);
525
526 if (capsFeatures)
527 gst_caps_set_features(get(), size() - 1,
528 gst_caps_features_from_string(capsFeatures));
529}
530
531void QGstCaps::setResolution(QSize resolution)
532{
533 Q_ASSERT(resolution.isValid());
534 GValue width{};
535 g_value_init(&width, G_TYPE_INT);
536 g_value_set_int(&width, resolution.width());
537 GValue height{};
538 g_value_init(&height, G_TYPE_INT);
539 g_value_set_int(&height, resolution.height());
540
541 gst_caps_set_value(caps(), "width", &width);
542 gst_caps_set_value(caps(), "height", &height);
543}
544
545QGstCaps QGstCaps::fromCameraFormat(const QCameraFormat &format)
546{
547 QSize size = format.resolution();
548 auto caps = QGstCaps::create();
549
550 if (format.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
551 QGstStructure jpegStructure("image/jpeg");
552 jpegStructure.setInt("width", size.width());
553 jpegStructure.setInt("height", size.height());
554
555 gst_caps_append_structure(caps.get(), jpegStructure.release());
556 return caps;
557 }
558
559 const GstVideoFormat gstFormat = qGstVideoFormatFromPixelFormat(format.pixelFormat());
560 if (gstFormat == GST_VIDEO_FORMAT_UNKNOWN)
561 return {};
562
563 QGstStructure rawStructure("video/x-raw");
564 rawStructure.setString("format", gst_video_format_to_string(gstFormat));
565 rawStructure.setInt("width", size.width());
566 rawStructure.setInt("height", size.height());
567
568 gst_caps_append_structure(caps.get(), rawStructure.release());
569
571 if (const guint32 fourcc = gst_video_dma_drm_fourcc_from_format(gstFormat)) {
572 if (QGString drmFormat{gst_video_dma_drm_fourcc_to_string(fourcc, 0)}) {
573 QGstStructure drmFormatDmabufRawStructure("video/x-raw");
574 drmFormatDmabufRawStructure.setString(
575 "format", gst_video_format_to_string(GST_VIDEO_FORMAT_DMA_DRM));
576 drmFormatDmabufRawStructure.setString("drm-format", drmFormat.get());
577 drmFormatDmabufRawStructure.setInt("width", size.width());
578 drmFormatDmabufRawStructure.setInt("height", size.height());
579
580 gst_caps_append_structure(caps.get(), drmFormatDmabufRawStructure.release());
581 gst_caps_set_features(
582 caps.get(), caps.size() - 1,
583 gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
584 }
585 }
586#endif
587
588#if QT_CONFIG(gstreamer_gl_egl) && QT_CONFIG(linux_dmabuf)
589 QGstStructure dmabufRawStructure("video/x-raw");
590 dmabufRawStructure.setString("format", gst_video_format_to_string(gstFormat));
591 dmabufRawStructure.setInt("width", size.width());
592 dmabufRawStructure.setInt("height", size.height());
593
594 gst_caps_append_structure(caps.get(), dmabufRawStructure.release());
595 gst_caps_set_features(caps.get(), caps.size() - 1,
596 gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_DMABUF));
597#endif
598
599 return caps;
600}
601
603{
604 return QGstCaps{
605 gst_caps_copy(caps()),
606 QGstCaps::HasRef,
607 };
608}
609
611{
612 auto *features = gst_caps_get_features(get(), 0);
613 if (gst_caps_features_contains(features, "memory:GLMemory"))
614 return GLTexture;
615 if (gst_caps_features_contains(features, "memory:DMABuf"))
616 return DMABuf;
617 return CpuMemory;
618}
619
620int QGstCaps::size() const
621{
622 return int(gst_caps_get_size(get()));
623}
624
626{
627 return QGstStructureView{
628 gst_caps_get_structure(get(), index),
629 };
630}
631
633{
634 return get();
635}
636
638{
639 return QGstCaps(gst_caps_new_empty(), HasRef);
640}
641
642// QGstObject
643
644void QGstObject::set(const char *property, const char *str)
645{
646 g_object_set(get(), property, str, nullptr);
647}
648
649void QGstObject::set(const char *property, bool b)
650{
651 g_object_set(get(), property, gboolean(b), nullptr);
652}
653
654void QGstObject::set(const char *property, uint32_t i)
655{
656 g_object_set(get(), property, guint(i), nullptr);
657}
658
659void QGstObject::set(const char *property, int32_t i)
660{
661 g_object_set(get(), property, gint(i), nullptr);
662}
663
664void QGstObject::set(const char *property, int64_t i)
665{
666 g_object_set(get(), property, gint64(i), nullptr);
667}
668
669void QGstObject::set(const char *property, uint64_t i)
670{
671 g_object_set(get(), property, guint64(i), nullptr);
672}
673
674void QGstObject::set(const char *property, double d)
675{
676 g_object_set(get(), property, gdouble(d), nullptr);
677}
678
679void QGstObject::set(const char *property, const QGstObject &o)
680{
681 g_object_set(get(), property, o.object(), nullptr);
682}
683
684void QGstObject::set(const char *property, const QGstCaps &c)
685{
686 g_object_set(get(), property, c.caps(), nullptr);
687}
688
689void QGstObject::set(const char *property, void *object, GDestroyNotify destroyFunction)
690{
691 g_object_set_data_full(qGstCheckedCast<GObject>(get()), property, object, destroyFunction);
692}
693
694QGString QGstObject::getString(const char *property) const
695{
696 char *s = nullptr;
697 g_object_get(get(), property, &s, nullptr);
698 return QGString(s);
699}
700
701QGstStructureView QGstObject::getStructure(const char *property) const
702{
703 GstStructure *s = nullptr;
704 g_object_get(get(), property, &s, nullptr);
705 return QGstStructureView(s);
706}
707
708bool QGstObject::getBool(const char *property) const
709{
710 gboolean b = false;
711 g_object_get(get(), property, &b, nullptr);
712 return b;
713}
714
715uint QGstObject::getUInt(const char *property) const
716{
717 guint i = 0;
718 g_object_get(get(), property, &i, nullptr);
719 return i;
720}
721
722int QGstObject::getInt(const char *property) const
723{
724 gint i = 0;
725 g_object_get(get(), property, &i, nullptr);
726 return i;
727}
728
729quint64 QGstObject::getUInt64(const char *property) const
730{
731 guint64 i = 0;
732 g_object_get(get(), property, &i, nullptr);
733 return i;
734}
735
736qint64 QGstObject::getInt64(const char *property) const
737{
738 gint64 i = 0;
739 g_object_get(get(), property, &i, nullptr);
740 return i;
741}
742
743float QGstObject::getFloat(const char *property) const
744{
745 gfloat d = 0;
746 g_object_get(get(), property, &d, nullptr);
747 return d;
748}
749
750double QGstObject::getDouble(const char *property) const
751{
752 gdouble d = 0;
753 g_object_get(get(), property, &d, nullptr);
754 return d;
755}
756
757QGstObject QGstObject::getGstObject(const char *property) const
758{
759 GstObject *o = nullptr;
760 g_object_get(get(), property, &o, nullptr);
761 return QGstObject(o, HasRef);
762}
763
764void *QGstObject::getObject(const char *property) const
765{
766 return g_object_get_data(qGstCheckedCast<GObject>(get()), property);
767}
768
769QGObjectHandlerConnection QGstObject::connect(const char *name, GCallback callback,
770 gpointer userData)
771{
773 *this,
774 g_signal_connect(get(), name, callback, userData),
775 };
776}
777
778void QGstObject::disconnect(gulong handlerId)
779{
780 g_signal_handler_disconnect(get(), handlerId);
781}
782
784{
785 return G_OBJECT_TYPE(get());
786}
787
789{
790 return QLatin1StringView{
791 g_type_name(type()),
792 };
793}
794
796{
797 return get();
798}
799
801{
802 using namespace Qt::StringLiterals;
803
804 return get() ? QLatin1StringView{ GST_OBJECT_NAME(get()) } : "(null)"_L1;
805}
806
807// QGObjectHandlerConnection
808
810 : object{ std::move(object) }, handlerId{ handlerId }
811{
812}
813
815{
816 if (!object)
817 return;
818
819 object.disconnect(handlerId);
820 object = {};
821 handlerId = invalidHandlerId;
822}
823
824// QGObjectHandlerScopedConnection
825
833
835{
836 connection.disconnect();
837}
838
840{
841 connection.disconnect();
842}
843
844// QGstPad
845
847 : QGstPad{
850 }
851{
852}
853
854QGstPad::QGstPad(GstPad *pad, RefMode mode)
855 : QGstObject{
857 mode,
858 }
859{
860}
861
863{
864 return QGstCaps(gst_pad_get_current_caps(pad()), QGstCaps::HasRef);
865}
866
868{
869 return QGstCaps(gst_pad_query_caps(pad(), nullptr), QGstCaps::HasRef);
870}
871
873{
874 QGstTagListHandle tagList;
875 g_object_get(object(), "tags", &tagList, nullptr);
876 return tagList;
877}
878
880{
881 return QGString{
882 gst_pad_get_stream_id(pad()),
883 };
884}
885
887{
888 using namespace Qt::Literals;
889 using TrackType = QPlatformMediaPlayer::TrackType;
890
891 QLatin1StringView padName = name();
892
893 if (padName.startsWith("video_"_L1))
894 return TrackType::VideoStream;
895 if (padName.startsWith("audio_"_L1))
896 return TrackType::AudioStream;
897 if (padName.startsWith("text_"_L1))
898 return TrackType::SubtitleStream;
899
900 return std::nullopt;
901}
902
903bool QGstPad::isLinked() const
904{
905 return gst_pad_is_linked(pad());
906}
907
908bool QGstPad::link(const QGstPad &sink) const
909{
910 return gst_pad_link(pad(), sink.pad()) == GST_PAD_LINK_OK;
911}
912
913bool QGstPad::unlink(const QGstPad &sink) const
914{
915 return gst_pad_unlink(pad(), sink.pad());
916}
917
918bool QGstPad::unlinkPeer() const
919{
920 QGstPad peerPad = peer();
921 if (peerPad)
922 return GST_PAD_IS_SRC(pad()) ? unlink(peerPad) : peerPad.unlink(*this);
923
924 return true;
925}
926
928{
929 return QGstPad(gst_pad_get_peer(pad()), HasRef);
930}
931
933{
934 return QGstElement(gst_pad_get_parent_element(pad()), HasRef);
935}
936
938{
939 return qGstCheckedCast<GstPad>(object());
940}
941
942GstEvent *QGstPad::stickyEvent(GstEventType type)
943{
944 return gst_pad_get_sticky_event(pad(), type, 0);
945}
946
947bool QGstPad::sendEvent(GstEvent *event)
948{
949 return gst_pad_send_event(pad(), event);
950}
951
952void QGstPad::sendFlushStartStop(bool resetTime)
953{
954 GstEvent *flushStart = gst_event_new_flush_start();
955 gboolean ret = sendEvent(flushStart);
956 if (!ret) {
957 qWarning("failed to send flush-start event");
958 return;
959 }
960
961 GstEvent *flushStop = gst_event_new_flush_stop(resetTime);
962 ret = sendEvent(flushStop);
963 if (!ret)
964 qWarning("failed to send flush-stop event");
965}
966
968{
969 using namespace std::chrono_literals;
970
971 GstState state = parent().state(1s);
972
973 if (state != GST_STATE_PAUSED)
974 return;
975
976 sendFlushStartStop(/*resetTime=*/true);
977}
978
979// QGstClock
980
982 : QGstClock{
985 }
986{
987}
988
989QGstClock::QGstClock(GstClock *clock, RefMode mode)
990 : QGstObject{
992 mode,
993 }
994{
995}
996
998{
999 return qGstCheckedCast<GstClock>(object());
1000}
1001
1003{
1004 return gst_clock_get_time(clock());
1005}
1006
1007// QGstElement
1008
1009QGstElement::QGstElement(GstElement *element, RefMode mode)
1010 : QGstObject{
1012 mode,
1013 }
1014{
1015}
1016
1017QGstElement QGstElement::createFromFactory(const char *factory, const char *name)
1018{
1019 GstElement *element = gst_element_factory_make(factory, name);
1020
1021#ifndef QT_NO_DEBUG
1022 if (!element) {
1023 qWarning() << "Failed to make element" << name << "from factory" << factory;
1024 return QGstElement{};
1025 }
1026#endif
1027
1028 return QGstElement{
1029 element,
1030 NeedsRef,
1031 };
1032}
1033
1034QGstElement QGstElement::createFromFactory(GstElementFactory *factory, const char *name)
1035{
1036 return QGstElement{
1037 gst_element_factory_create(factory, name),
1038 NeedsRef,
1039 };
1040}
1041
1042QGstElement QGstElement::createFromFactory(const QGstElementFactoryHandle &factory,
1043 const char *name)
1044{
1045 return createFromFactory(factory.get(), name);
1046}
1047
1048QGstElement QGstElement::createFromDevice(const QGstDeviceHandle &device, const char *name)
1049{
1050 return createFromDevice(device.get(), name);
1051}
1052
1053QGstElement QGstElement::createFromDevice(GstDevice *device, const char *name)
1054{
1055 return QGstElement{
1056 gst_device_create_element(device, name),
1057 QGstElement::NeedsRef,
1058 };
1059}
1060
1062{
1063 QUniqueGErrorHandle error;
1064 QGstElement element{
1065 gst_parse_launch(str, &error),
1066 QGstElement::NeedsRef,
1067 };
1068
1069 if (error) // error does not mean that the element could not be constructed
1070 qWarning() << "gst_parse_launch error:" << error;
1071
1072 return element;
1073}
1074
1075QGstElement QGstElement::createFromPipelineDescription(const QByteArray &str)
1076{
1077 return createFromPipelineDescription(str.constData());
1078}
1079
1080QGstElementFactoryHandle QGstElement::findFactory(const char *name)
1081{
1082 return QGstElementFactoryHandle{
1083 gst_element_factory_find(name),
1084 QGstElementFactoryHandle::HasRef,
1085 };
1086}
1087
1088QGstElementFactoryHandle QGstElement::findFactory(const QByteArray &name)
1089{
1090 return findFactory(name.constData());
1091}
1092
1094{
1095 GstElementFactory *factory = gst_element_get_factory(element());
1096 if (!factory)
1097 return {};
1098
1099 const char *name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
1100 return name ? QByteArrayView{name} : QByteArrayView{};
1101}
1102
1103QGstPad QGstElement::staticPad(const char *name) const
1104{
1105 return QGstPad(gst_element_get_static_pad(element(), name), HasRef);
1106}
1107
1109{
1110 return staticPad("src");
1111}
1112
1114{
1115 return staticPad("sink");
1116}
1117
1118QGstPad QGstElement::getRequestPad(const char *name) const
1119{
1120 return QGstPad(gst_element_request_pad_simple(element(), name), HasRef);
1121}
1122
1124{
1125 return gst_element_release_request_pad(element(), pad.pad());
1126}
1127
1128GstState QGstElement::state(std::chrono::nanoseconds timeout) const
1129{
1130 using namespace std::chrono_literals;
1131
1132 GstState state;
1133 GstStateChangeReturn change =
1134 gst_element_get_state(element(), &state, nullptr, timeout.count());
1135
1136 if (Q_UNLIKELY(change == GST_STATE_CHANGE_ASYNC))
1137 qWarning() << "QGstElement::state detected an asynchronous state change. Return value not "
1138 "reliable";
1139
1140 return state;
1141}
1142
1144{
1145 return gst_element_set_state(element(), state);
1146}
1147
1148bool QGstElement::setStateSync(GstState state, std::chrono::nanoseconds timeout)
1149{
1150 GstStateChangeReturn change = gst_element_set_state(element(), state);
1151 if (change == GST_STATE_CHANGE_ASYNC)
1152 change = gst_element_get_state(element(), nullptr, &state, timeout.count());
1153
1154 if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL) {
1155 qWarning() << "Could not change state of" << name() << "to" << state << change;
1156 dumpPipelineGraph("setStateSyncFailure");
1157 }
1158 return change == GST_STATE_CHANGE_SUCCESS || change == GST_STATE_CHANGE_NO_PREROLL;
1159}
1160
1162{
1163 Q_ASSERT(element());
1164 return gst_element_sync_state_with_parent(element()) == TRUE;
1165}
1166
1167bool QGstElement::finishStateChange(std::chrono::nanoseconds timeout)
1168{
1169 GstState state, pending;
1170 GstStateChangeReturn change =
1171 gst_element_get_state(element(), &state, &pending, timeout.count());
1172
1173 if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL) {
1174 qWarning() << "Could not finish change state of" << name() << change << state << pending;
1175 dumpPipelineGraph("finishStateChangeFailure");
1176 }
1177 return change == GST_STATE_CHANGE_SUCCESS;
1178}
1179
1180bool QGstElement::hasAsyncStateChange(std::chrono::nanoseconds timeout) const
1181{
1182 GstState state;
1183 GstStateChangeReturn change =
1184 gst_element_get_state(element(), &state, nullptr, timeout.count());
1185 return change == GST_STATE_CHANGE_ASYNC;
1186}
1187
1188bool QGstElement::waitForAsyncStateChangeComplete(std::chrono::nanoseconds timeout) const
1189{
1190 using namespace std::chrono_literals;
1191 for (;;) {
1192 if (!hasAsyncStateChange())
1193 return true;
1194 timeout -= 10ms;
1195 if (timeout < 0ms)
1196 return false;
1197 std::this_thread::sleep_for(10ms);
1198 }
1199}
1200
1201void QGstElement::lockState(bool locked)
1202{
1203 gst_element_set_locked_state(element(), locked);
1204}
1205
1207{
1208 return gst_element_is_locked_state(element());
1209}
1210
1211void QGstElement::sendEvent(GstEvent *event) const
1212{
1213 gst_element_send_event(element(), event);
1214}
1215
1217{
1218 sendEvent(gst_event_new_eos());
1219}
1220
1221std::optional<std::chrono::nanoseconds> QGstElement::duration() const
1222{
1223 gint64 d;
1224 if (!gst_element_query_duration(element(), GST_FORMAT_TIME, &d)) {
1225 qDebug() << "QGstElement: failed to query duration";
1226 return std::nullopt;
1227 }
1228 return std::chrono::nanoseconds{ d };
1229}
1230
1231std::optional<std::chrono::milliseconds> QGstElement::durationInMs() const
1232{
1233 using namespace std::chrono;
1234 auto dur = duration();
1235 if (dur)
1236 return round<milliseconds>(*dur);
1237 return std::nullopt;
1238}
1239
1240std::optional<std::chrono::nanoseconds> QGstElement::position() const
1241{
1242 QGstQueryHandle &query = positionQuery();
1243
1244 gint64 pos;
1245 if (gst_element_query(element(), query.get())) {
1246 gst_query_parse_position(query.get(), nullptr, &pos);
1247 return std::chrono::nanoseconds{ pos };
1248 }
1249
1250 qDebug() << "QGstElement: failed to query position";
1251 return std::nullopt;
1252}
1253
1254std::optional<std::chrono::milliseconds> QGstElement::positionInMs() const
1255{
1256 using namespace std::chrono;
1257 auto pos = position();
1258 if (pos)
1259 return round<milliseconds>(*pos);
1260 return std::nullopt;
1261}
1262
1263std::optional<bool> QGstElement::canSeek() const
1264{
1265 QGstQueryHandle query{
1266 gst_query_new_seeking(GST_FORMAT_TIME),
1267 QGstQueryHandle::HasRef,
1268 };
1269 gboolean canSeek = false;
1270 gst_query_parse_seeking(query.get(), nullptr, &canSeek, nullptr, nullptr);
1271
1272 if (gst_element_query(element(), query.get())) {
1273 gst_query_parse_seeking(query.get(), nullptr, &canSeek, nullptr, nullptr);
1274 return canSeek;
1275 }
1276 return std::nullopt;
1277}
1278
1280{
1281 return gst_element_get_base_time(element());
1282}
1283
1284void QGstElement::setBaseTime(GstClockTime time) const
1285{
1286 gst_element_set_base_time(element(), time);
1287}
1288
1290{
1291 return GST_ELEMENT_CAST(get());
1292}
1293
1295{
1296 return QGstElement{
1297 qGstCheckedCast<GstElement>(gst_element_get_parent(object())),
1298 QGstElement::HasRef,
1299 };
1300}
1301
1303{
1304 return QGstBin{
1305 qGstCheckedCast<GstBin>(gst_element_get_parent(object())),
1306 QGstElement::HasRef,
1307 };
1308}
1309
1311{
1312 QGstElement ancestor = *this;
1313 for (;;) {
1314 QGstElement greatAncestor = ancestor.getParent();
1315 if (greatAncestor) {
1316 ancestor = std::move(greatAncestor);
1317 continue;
1318 }
1319 if (GST_IS_BIN(ancestor.element())) {
1320 return QGstBin{
1321 qGstSafeCast<GstBin>(ancestor.element()),
1322 QGstBin::NeedsRef,
1323 };
1324 } else {
1325 return QGstBin{};
1326 }
1327 }
1328}
1329
1331{
1332 QGstBin rootBin = getRootBin();
1333 if (GST_IS_PIPELINE(rootBin.get())) {
1334 return QGstPipeline{
1335 qGstSafeCast<GstPipeline>(rootBin.element()),
1336 QGstPipeline::NeedsRef,
1337 };
1338 } else {
1339 qWarning() << "QGstElement::getPipeline failed for element:" << *this;
1340 return QGstPipeline{};
1341 }
1342}
1343
1345{
1346 if (QGstBin parent = getParentBin())
1347 parent.remove(*this);
1348}
1349
1350void QGstElement::dumpPipelineGraph(const char *filename) const
1351{
1352 static const bool dumpEnabled = qEnvironmentVariableIsSet("GST_DEBUG_DUMP_DOT_DIR");
1353 if (dumpEnabled) {
1355 }
1356}
1357
1358QGstQueryHandle &QGstElement::positionQuery() const
1359{
1360 if (Q_UNLIKELY(!m_positionQuery))
1361 m_positionQuery = QGstQueryHandle{
1362 gst_query_new_position(GST_FORMAT_TIME),
1363 QGstQueryHandle::HasRef,
1364 };
1365
1366 return m_positionQuery;
1367}
1368
1369// QGstBin
1370
1371QGstBin QGstBin::create(const char *name)
1372{
1373 return QGstBin(gst_bin_new(name), NeedsRef);
1374}
1375
1376QGstBin QGstBin::createFromFactory(const char *factory, const char *name)
1377{
1378 QGstElement element = QGstElement::createFromFactory(factory, name);
1379 Q_ASSERT(GST_IS_BIN(element.element()));
1380 return QGstBin{
1381 GST_BIN(element.release()),
1382 RefMode::HasRef,
1383 };
1384}
1385
1386QGstBin QGstBin::createFromPipelineDescription(const QByteArray &pipelineDescription,
1387 const char *name, bool ghostUnlinkedPads)
1388{
1389 return createFromPipelineDescription(pipelineDescription.constData(), name, ghostUnlinkedPads);
1390}
1391
1392QGstBin QGstBin::createFromPipelineDescription(const char *pipelineDescription, const char *name,
1393 bool ghostUnlinkedPads)
1394{
1395 QUniqueGErrorHandle error;
1396
1397 GstElement *element =
1398 gst_parse_bin_from_description_full(pipelineDescription, ghostUnlinkedPads,
1399 /*context=*/nullptr, GST_PARSE_FLAG_NONE, &error);
1400
1401 if (!element) {
1402 qWarning() << "Failed to make element from pipeline description" << pipelineDescription
1403 << error;
1404 return QGstBin{};
1405 }
1406
1407 if (name)
1408 gst_element_set_name(element, name);
1409
1410 return QGstBin{
1411 element,
1412 NeedsRef,
1413 };
1414}
1415
1416QGstBin::QGstBin(GstBin *bin, RefMode mode)
1417 : QGstElement{
1419 mode,
1420 }
1421{
1422}
1423
1425{
1426 return qGstCheckedCast<GstBin>(object());
1427}
1428
1429void QGstBin::addGhostPad(const QGstElement &child, const char *name)
1430{
1431 addGhostPad(name, child.staticPad(name));
1432}
1433
1434void QGstBin::addGhostPad(const char *name, const QGstPad &pad)
1435{
1436 gst_element_add_pad(element(), gst_ghost_pad_new(name, pad.pad()));
1437}
1438
1439void QGstBin::addUnlinkedGhostPads(GstPadDirection direction)
1440{
1441 Q_ASSERT(direction != GstPadDirection::GST_PAD_UNKNOWN);
1442
1443 for (;;) {
1444 QGstPad unlinkedPad{
1445 gst_bin_find_unlinked_pad(bin(), direction),
1446 QGstPad::HasRef,
1447 };
1448
1449 if (!unlinkedPad)
1450 return;
1451
1452 addGhostPad(unlinkedPad.name().constData(), unlinkedPad);
1453 }
1454}
1455
1457{
1458 return gst_bin_sync_children_states(bin());
1459}
1460
1461void QGstBin::dumpGraph(const char *fileNamePrefix, bool includeTimestamp) const
1462{
1463 if (!get())
1464 return;
1465
1466 if (includeTimestamp)
1467 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(bin(), GST_DEBUG_GRAPH_SHOW_VERBOSE, fileNamePrefix);
1468 else
1469 GST_DEBUG_BIN_TO_DOT_FILE(bin(), GST_DEBUG_GRAPH_SHOW_VERBOSE, fileNamePrefix);
1470}
1471
1473{
1474 return QGstElement{
1475 gst_bin_get_by_name(bin(), name),
1476 QGstElement::NeedsRef,
1477 };
1478}
1479
1481{
1482 gst_bin_recalculate_latency(bin());
1483}
1484
1485// QGstBaseSink
1486
1487QGstBaseSink::QGstBaseSink(GstBaseSink *element, RefMode mode)
1488 : QGstElement{
1490 mode,
1491 }
1492{
1493}
1494
1495void QGstBaseSink::setSync(bool arg)
1496{
1497 gst_base_sink_set_sync(baseSink(), arg ? TRUE : FALSE);
1498}
1499
1501{
1502 return qGstCheckedCast<GstBaseSink>(element());
1503}
1504
1505// QGstBaseSrc
1506
1507QGstBaseSrc::QGstBaseSrc(GstBaseSrc *element, RefMode mode)
1508 : QGstElement{
1510 mode,
1511 }
1512{
1513}
1514
1516{
1517 return qGstCheckedCast<GstBaseSrc>(element());
1518}
1519
1520// QGstAppSink
1521
1522QGstAppSink::QGstAppSink(GstAppSink *element, RefMode mode)
1523 : QGstBaseSink{
1525 mode,
1526 }
1527{
1528}
1529
1531{
1532 QGstElement created = QGstElement::createFromFactory("appsink", name);
1533 return QGstAppSink{
1534 qGstCheckedCast<GstAppSink>(created.element()),
1535 QGstAppSink::NeedsRef,
1536 };
1537}
1538
1540{
1541 return qGstCheckedCast<GstAppSink>(element());
1542}
1543
1544# if GST_CHECK_VERSION(1, 24, 0)
1545void QGstAppSink::setMaxBufferTime(std::chrono::nanoseconds ns)
1546{
1547 gst_app_sink_set_max_time(appSink(), qGstClockTimeFromChrono(ns));
1548}
1549# endif
1550
1552{
1553 gst_app_sink_set_max_buffers(appSink(), n);
1554}
1555
1556void QGstAppSink::setCaps(const QGstCaps &caps)
1557{
1558 gst_app_sink_set_caps(appSink(), caps.caps());
1559}
1560
1561void QGstAppSink::setCallbacks(GstAppSinkCallbacks &callbacks, gpointer user_data,
1562 GDestroyNotify notify)
1563{
1564 gst_app_sink_set_callbacks(appSink(), &callbacks, user_data, notify);
1565}
1566
1568{
1569 return QGstSampleHandle{
1570 gst_app_sink_pull_sample(appSink()),
1571 QGstSampleHandle::HasRef,
1572 };
1573}
1574
1575// QGstAppSrc
1576
1577QGstAppSrc::QGstAppSrc(GstAppSrc *element, RefMode mode)
1578 : QGstBaseSrc{
1580 mode,
1581 }
1582{
1583}
1584
1585QGstAppSrc QGstAppSrc::create(const char *name)
1586{
1587 QGstElement created = QGstElement::createFromFactory("appsrc", name);
1588 return QGstAppSrc{
1589 qGstCheckedCast<GstAppSrc>(created.element()),
1590 QGstAppSrc::NeedsRef,
1591 };
1592}
1593
1595{
1596 return qGstCheckedCast<GstAppSrc>(element());
1597}
1598
1599void QGstAppSrc::setCallbacks(GstAppSrcCallbacks &callbacks, gpointer user_data,
1600 GDestroyNotify notify)
1601{
1602 gst_app_src_set_callbacks(appSrc(), &callbacks, user_data, notify);
1603}
1604
1605GstFlowReturn QGstAppSrc::pushBuffer(GstBuffer *buffer)
1606{
1607 return gst_app_src_push_buffer(appSrc(), buffer);
1608}
1609
1611{
1612 return QStringLiteral("Could not find the %1 GStreamer element")
1613 .arg(QLatin1StringView(element));
1614}
1615
1616QVideoFrameFormat qVideoFrameFormatFromGstVideoInfo(const QGstVideoInfo &qtVideoInfo)
1617{
1618 auto &vidInfo = qtVideoInfo.gstVideoInfo;
1619 GstVideoFormat gstFormat = GST_VIDEO_INFO_FORMAT(&vidInfo);
1620
1621 auto pixelFormat = qPixelFormatFromGstVideoFormat(gstFormat);
1622 if (pixelFormat == QVideoFrameFormat::Format_Invalid)
1623 return QVideoFrameFormat();
1624
1625 QVideoFrameFormat format(QSize(vidInfo.width, vidInfo.height), pixelFormat);
1626
1627 if (vidInfo.fps_d > 0)
1628 format.setStreamFrameRate(qreal(vidInfo.fps_n) / vidInfo.fps_d);
1629
1630 QVideoFrameFormat::ColorRange range = QVideoFrameFormat::ColorRange_Unknown;
1631 switch (vidInfo.colorimetry.range) {
1632 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
1633 break;
1634 case GST_VIDEO_COLOR_RANGE_0_255:
1635 range = QVideoFrameFormat::ColorRange_Full;
1636 break;
1637 case GST_VIDEO_COLOR_RANGE_16_235:
1638 range = QVideoFrameFormat::ColorRange_Video;
1639 break;
1640 }
1641 format.setColorRange(range);
1642
1643 QVideoFrameFormat::ColorSpace colorSpace = QVideoFrameFormat::ColorSpace_Undefined;
1644 switch (vidInfo.colorimetry.matrix) {
1645 case GST_VIDEO_COLOR_MATRIX_UNKNOWN:
1646 case GST_VIDEO_COLOR_MATRIX_RGB:
1647 case GST_VIDEO_COLOR_MATRIX_FCC:
1648 break;
1649 case GST_VIDEO_COLOR_MATRIX_BT709:
1650 colorSpace = QVideoFrameFormat::ColorSpace_BT709;
1651 break;
1652 case GST_VIDEO_COLOR_MATRIX_BT601:
1653 colorSpace = QVideoFrameFormat::ColorSpace_BT601;
1654 break;
1655 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
1656 colorSpace = QVideoFrameFormat::ColorSpace_AdobeRgb;
1657 break;
1658 case GST_VIDEO_COLOR_MATRIX_BT2020:
1659 colorSpace = QVideoFrameFormat::ColorSpace_BT2020;
1660 break;
1661 }
1662 format.setColorSpace(colorSpace);
1663
1664 QVideoFrameFormat::ColorTransfer transfer = QVideoFrameFormat::ColorTransfer_Unknown;
1665 switch (vidInfo.colorimetry.transfer) {
1666 case GST_VIDEO_TRANSFER_UNKNOWN:
1667 break;
1668 case GST_VIDEO_TRANSFER_GAMMA10:
1669 transfer = QVideoFrameFormat::ColorTransfer_Linear;
1670 break;
1671 case GST_VIDEO_TRANSFER_GAMMA22:
1672 case GST_VIDEO_TRANSFER_SMPTE240M:
1673 case GST_VIDEO_TRANSFER_SRGB:
1674 case GST_VIDEO_TRANSFER_ADOBERGB:
1675 transfer = QVideoFrameFormat::ColorTransfer_Gamma22;
1676 break;
1677 case GST_VIDEO_TRANSFER_GAMMA18:
1678 case GST_VIDEO_TRANSFER_GAMMA20:
1679 // not quite, but best fit
1680 case GST_VIDEO_TRANSFER_BT709:
1681 case GST_VIDEO_TRANSFER_BT2020_12:
1682 transfer = QVideoFrameFormat::ColorTransfer_BT709;
1683 break;
1684 case GST_VIDEO_TRANSFER_GAMMA28:
1685 transfer = QVideoFrameFormat::ColorTransfer_Gamma28;
1686 break;
1687 case GST_VIDEO_TRANSFER_LOG100:
1688 case GST_VIDEO_TRANSFER_LOG316:
1689 break;
1690 case GST_VIDEO_TRANSFER_SMPTE2084:
1691 transfer = QVideoFrameFormat::ColorTransfer_ST2084;
1692 break;
1693 case GST_VIDEO_TRANSFER_ARIB_STD_B67:
1694 transfer = QVideoFrameFormat::ColorTransfer_STD_B67;
1695 break;
1696 case GST_VIDEO_TRANSFER_BT2020_10:
1697 transfer = QVideoFrameFormat::ColorTransfer_BT709;
1698 break;
1699 case GST_VIDEO_TRANSFER_BT601:
1700 transfer = QVideoFrameFormat::ColorTransfer_BT601;
1701 break;
1702 }
1703 format.setColorTransfer(transfer);
1704
1705 return format;
1706}
1707
1709{
1710 Q_ASSERT(buffer);
1711
1713
1714 [[maybe_unused]] GstMemory *mem = gst_buffer_peek_memory(buffer, 0);
1715
1716#if QT_CONFIG(gstreamer_gl_egl) && QT_CONFIG(linux_dmabuf)
1717 if (gst_is_dmabuf_memory(mem))
1718 memoryFormat = QGstCaps::DMABuf;
1719#endif
1720#if QT_CONFIG(gstreamer_gl)
1721 if (gst_is_gl_memory(mem))
1722 memoryFormat = QGstCaps::GLTexture;
1723#endif
1724 return memoryFormat;
1725}
1726
1727QVideoFrame qCreateFrameFromGstBuffer(QGstBufferHandle buffer, const QGstVideoInfo &videoInfo,
1728 const QVideoFrameFormat &format)
1729{
1730#if QT_CONFIG(linux_dmabuf)
1731 if (auto dmaBufBuffer = QGstDmaBufVideoBuffer::create(buffer, videoInfo, format))
1732 return QVideoFramePrivate::createFrame(std::move(dmaBufBuffer), format);
1733#endif
1734 auto videoBuffer = std::make_unique<QGstVideoBuffer>(std::move(buffer), videoInfo, format);
1735 return QVideoFramePrivate::createFrame(std::move(videoBuffer), format);
1736}
1737
1738QVideoFrame qCreateFrameFromGstBuffer(QGstBufferHandle buffer, const QGstVideoInfo &videoInfo)
1739{
1740 auto format = qVideoFrameFormatFromGstVideoInfo(videoInfo);
1741 return qCreateFrameFromGstBuffer(std::move(buffer), videoInfo, format);
1742}
1743
1744QT_END_NAMESPACE
QGObjectHandlerConnection(QGstObject object, gulong handler)
Definition qgst.cpp:809
QGObjectHandlerScopedConnection(QGObjectHandlerConnection connection)
Definition qgst.cpp:826
std::optional< int > toInt64() const
Definition qgst.cpp:149
std::optional< QGRange< int > > toIntRange() const
Definition qgst.cpp:178
std::optional< int > toInt() const
Definition qgst.cpp:142
int listSize() const
Definition qgst.cpp:204
bool isList() const
Definition qgst.cpp:199
QGstStructureView toStructure() const
Definition qgst.cpp:185
std::optional< QGRange< float > > getFractionRange() const
Definition qgst.cpp:169
const char * toString() const
Definition qgst.cpp:156
std::optional< float > getFraction() const
Definition qgst.cpp:161
QGValue at(int index) const
Definition qgst.cpp:209
bool isNull() const
Definition qgst.cpp:130
QGstCaps toCaps() const
Definition qgst.cpp:192
std::optional< bool > toBool() const
Definition qgst.cpp:135
QGValue(const GValue *v)
Definition qgst.cpp:128
QGstSampleHandle pullSample()
Definition qgst.cpp:1567
void setCallbacks(GstAppSinkCallbacks &callbacks, gpointer user_data, GDestroyNotify notify)
Definition qgst.cpp:1561
GstAppSink * appSink() const
Definition qgst.cpp:1539
void setCaps(const QGstCaps &caps)
Definition qgst.cpp:1556
void setMaxBuffers(int)
Definition qgst.cpp:1551
static QGstAppSink create(const char *name)
Definition qgst.cpp:1530
QGstAppSink(GstAppSink *, RefMode)
Definition qgst.cpp:1522
static QGstAppSrc create(const char *name)
Definition qgst.cpp:1585
void setCallbacks(GstAppSrcCallbacks &callbacks, gpointer user_data, GDestroyNotify notify)
Definition qgst.cpp:1599
QGstAppSrc(GstAppSrc *, RefMode)
Definition qgst.cpp:1577
GstAppSrc * appSrc() const
Definition qgst.cpp:1594
void setSync(bool)
Definition qgst.cpp:1495
QGstBaseSink(GstBaseSink *, RefMode)
Definition qgst.cpp:1487
GstBaseSink * baseSink() const
Definition qgst.cpp:1500
QGstBaseSrc(GstBaseSrc *, RefMode)
Definition qgst.cpp:1507
GstBaseSrc * baseSrc() const
Definition qgst.cpp:1515
void addUnlinkedGhostPads(GstPadDirection)
Definition qgst.cpp:1439
void dumpGraph(const char *fileNamePrefix, bool includeTimestamp=true) const
Definition qgst.cpp:1461
QGstElement findByName(const char *)
Definition qgst.cpp:1472
void recalculateLatency()
Definition qgst.cpp:1480
GstBin * bin() const
Definition qgst.cpp:1424
static QGstBin create(const char *name)
Definition qgst.cpp:1371
void addGhostPad(const QGstElement &child, const char *name)
Definition qgst.cpp:1429
static QGstBin createFromPipelineDescription(const char *pipelineDescription, const char *name=nullptr, bool ghostUnlinkedPads=false)
Definition qgst.cpp:1392
static QGstBin createFromFactory(const char *factory, const char *name)
Definition qgst.cpp:1376
void addGhostPad(const char *name, const QGstPad &pad)
Definition qgst.cpp:1434
bool syncChildrenState()
Definition qgst.cpp:1456
QGstBin(GstBin *bin, RefMode mode=NeedsRef)
Definition qgst.cpp:1416
MemoryFormat memoryFormat() const
Definition qgst.cpp:610
std::optional< QGstVideoInfo > videoInfo() const
Definition qgst.cpp:469
int size() const
Definition qgst.cpp:620
static QGstCaps fromCameraFormat(const QCameraFormat &format)
Definition qgst.cpp:545
static QGstCaps create()
Definition qgst.cpp:637
GstCaps * caps() const
Definition qgst.cpp:632
void setResolution(QSize)
Definition qgst.cpp:531
MemoryFormat
Definition qgst_p.h:394
@ DMABuf
Definition qgst_p.h:394
@ CpuMemory
Definition qgst_p.h:394
@ GLTexture
Definition qgst_p.h:394
QGstCaps copy() const
Definition qgst.cpp:602
void addPixelFormats(const QList< QVideoFrameFormat::PixelFormat > &formats, const char *capsFeatures=nullptr)
Definition qgst.cpp:491
QGstStructureView at(int index) const
Definition qgst.cpp:625
QGstClock(GstClock *clock, RefMode mode)
Definition qgst.cpp:989
GstClockTime time() const
Definition qgst.cpp:1002
GstClock * clock() const
Definition qgst.cpp:997
QGstClock(const QGstObject &o)
Definition qgst.cpp:981
void setBaseTime(GstClockTime time) const
Definition qgst.cpp:1284
GstStateChangeReturn setState(GstState state)
Definition qgst.cpp:1143
std::optional< std::chrono::nanoseconds > position() const
Definition qgst.cpp:1240
GstElement * element() const
Definition qgst.cpp:1289
void removeFromParent()
Definition qgst.cpp:1344
QGstElement(GstElement *element, RefMode mode)
Definition qgst.cpp:1009
void lockState(bool locked)
Definition qgst.cpp:1201
QGstBin getRootBin() const
Definition qgst.cpp:1310
QGstPad getRequestPad(const char *name) const
Definition qgst.cpp:1118
std::optional< bool > canSeek() const
Definition qgst.cpp:1263
std::optional< std::chrono::nanoseconds > duration() const
Definition qgst.cpp:1221
bool isStateLocked() const
Definition qgst.cpp:1206
void sendEvent(GstEvent *event) const
Definition qgst.cpp:1211
void dumpPipelineGraph(const char *filename) const
Definition qgst.cpp:1350
GstClockTime baseTime() const
Definition qgst.cpp:1279
QByteArrayView factoryName() const
Definition qgst.cpp:1093
void releaseRequestPad(const QGstPad &pad) const
Definition qgst.cpp:1123
bool syncStateWithParent()
Definition qgst.cpp:1161
QGstPad sink() const
Definition qgst.cpp:1113
QGstPad staticPad(const char *name) const
Definition qgst.cpp:1103
void sendEos() const
Definition qgst.cpp:1216
QGstBin getParentBin() const
Definition qgst.cpp:1302
std::optional< std::chrono::milliseconds > positionInMs() const
Definition qgst.cpp:1254
static QGstElement createFromFactory(const char *factory, const char *name=nullptr)
Definition qgst.cpp:1017
QGstElement getParent() const
Definition qgst.cpp:1294
QGstPipeline getPipeline() const
Definition qgst.cpp:1330
static QGstElement createFromPipelineDescription(const char *)
Definition qgst.cpp:1061
QGstPad src() const
Definition qgst.cpp:1108
std::optional< std::chrono::milliseconds > durationInMs() const
Definition qgst.cpp:1231
void set(const char *property, double d)
Definition qgst.cpp:674
QGObjectHandlerConnection connect(const char *name, GCallback callback, gpointer userData)
Definition qgst.cpp:769
void * getObject(const char *property) const
Definition qgst.cpp:764
double getDouble(const char *property) const
Definition qgst.cpp:750
int getInt(const char *property) const
Definition qgst.cpp:722
void set(const char *property, int32_t i)
Definition qgst.cpp:659
QLatin1StringView name() const
Definition qgst.cpp:800
void set(const char *property, const QGstObject &o)
Definition qgst.cpp:679
QGString getString(const char *property) const
Definition qgst.cpp:694
void disconnect(gulong handlerId)
Definition qgst.cpp:778
QGstObject getGstObject(const char *property) const
Definition qgst.cpp:757
QLatin1StringView typeName() const
Definition qgst.cpp:788
void set(const char *property, const char *str)
Definition qgst.cpp:644
bool getBool(const char *property) const
Definition qgst.cpp:708
GType type() const
Definition qgst.cpp:783
QGstObject & operator=(QGstObject &&) noexcept=default
void set(const char *property, void *object, GDestroyNotify destroyFunction)
Definition qgst.cpp:689
void set(const char *property, bool b)
Definition qgst.cpp:649
quint64 getUInt64(const char *property) const
Definition qgst.cpp:729
QGstStructureView getStructure(const char *property) const
Definition qgst.cpp:701
qint64 getInt64(const char *property) const
Definition qgst.cpp:736
void set(const char *property, const QGstCaps &c)
Definition qgst.cpp:684
float getFloat(const char *property) const
Definition qgst.cpp:743
uint getUInt(const char *property) const
Definition qgst.cpp:715
GstObject * object() const
Definition qgst.cpp:795
bool link(const QGstPad &sink) const
Definition qgst.cpp:908
GstEvent * stickyEvent(GstEventType type)
Definition qgst.cpp:942
QGstTagListHandle tags() const
Definition qgst.cpp:872
QGstPad(const QGstObject &o)
Definition qgst.cpp:846
bool isLinked() const
Definition qgst.cpp:903
bool unlinkPeer() const
Definition qgst.cpp:918
QGstCaps queryCaps() const
Definition qgst.cpp:867
GstPad * pad() const
Definition qgst.cpp:937
QGstPad(GstPad *pad, RefMode mode)
Definition qgst.cpp:854
void sendFlushIfPaused()
Definition qgst.cpp:967
void sendFlushStartStop(bool resetTime)
Definition qgst.cpp:952
QGString streamId() const
Definition qgst.cpp:879
std::optional< QPlatformMediaPlayer::TrackType > inferTrackTypeFromName() const
Definition qgst.cpp:886
bool sendEvent(GstEvent *event)
Definition qgst.cpp:947
QGstCaps currentCaps() const
Definition qgst.cpp:862
QGstElement parent() const
Definition qgst.cpp:932
bool unlink(const QGstPad &sink) const
Definition qgst.cpp:913
QGstPad peer() const
Definition qgst.cpp:927
QGstStructureView(const QUniqueGstStructureHandle &)
Definition qgst.cpp:218
bool isNull() const
Definition qgst.cpp:228
QGRange< float > frameRateRange() const
Definition qgst.cpp:348
QSize nativeSize() const
Definition qgst.cpp:453
QGValue operator[](const char *fieldname) const
Definition qgst.cpp:238
QUniqueGstStructureHandle clone() const
Definition qgst.cpp:223
QList< QVideoFrameFormat::PixelFormat > pixelFormats() const
Definition qgst.cpp:273
std::optional< QGRange< QSize > > resolutionRange() const
Definition qgst.cpp:406
QGstreamerMessage getMessage()
Definition qgst.cpp:432
QGstCaps caps() const
Definition qgst.cpp:243
std::optional< Fraction > pixelAspectRatio() const
Definition qgst.cpp:439
QGstTagListHandle tags() const
Definition qgst.cpp:248
QSize resolution() const
Definition qgst.cpp:259
QByteArrayView name() const
Definition qgst.cpp:233
QGstStructureView(const GstStructure *)
Definition qgst.cpp:216
QSize qCalculateFrameSizeGStreamer(QSize resolution, Fraction par)
constexpr std::array< VideoFormat, 19 > qt_videoFormatLookup
Definition qgst.cpp:42
QGstCaps::MemoryFormat qMemoryFormatFromGstBuffer(GstBuffer *buffer)
Definition qgst.cpp:1708
QVideoFrame qCreateFrameFromGstBuffer(QGstBufferHandle buffer, const QGstVideoInfo &videoInfo, const QVideoFrameFormat &format)
Definition qgst.cpp:1727
QVideoFrameFormat qVideoFrameFormatFromGstVideoInfo(const QGstVideoInfo &vidInfo)
Definition qgst.cpp:1616
#define QT_GSTREAMER_SUPPORTS_GST_VIDEO_FORMAT_DMA_DRM
Definition qgst_p.h:38
GstVideoFormat qGstVideoFormatFromPixelFormat(QVideoFrameFormat::PixelFormat format)
Definition qgst.cpp:108
QString qGstErrorMessageCannotFindElement(std::string_view element)
Definition qgst.cpp:1610
QVideoFrame qCreateFrameFromGstBuffer(QGstBufferHandle buffer, const QGstVideoInfo &videoInfo)
Definition qgst.cpp:1738
QVideoFrameFormat::PixelFormat qPixelFormatFromGstVideoFormat(GstVideoFormat format)
Definition qgst.cpp:117
typedefQT_BEGIN_NAMESPACE struct _GstBuffer GstBuffer
void setInt(const char *field, int value)
Definition qgst_p.h:203
void setIntRange(const char *field, int min, int max)
Definition qgst_p.h:213
void setString(const char *field, const char *value)
Definition qgst_p.h:208
QGstStructure(const char *name)
Definition qgst_p.h:198
QVideoFrameFormat::PixelFormat pixelFormat
Definition qgst.cpp:38