4#include <common/qgst_p.h>
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>
12#if QT_CONFIG(linux_dmabuf)
13# include <common/qgstdmabufvideobuffer_p.h>
16#include <QtCore/qdebug.h>
17#include <QtMultimedia/private/qvideoframe_p.h>
18#include <QtMultimedia/qcameradevice.h>
20#if QT_CONFIG(gstreamer_gl)
21# include <gst/gl/gstglmemory.h>
28#if QT_CONFIG(gstreamer_gl_egl) && QT_CONFIG(linux_dmabuf)
29# include <gst/allocators/gstdmabuf.h>
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 },
64 { QVideoFrameFormat::Format_Y16, GST_VIDEO_FORMAT_GRAY16_BE },
65 { QVideoFrameFormat::Format_P010, GST_VIDEO_FORMAT_P010_10BE },
70void appendDmaDrmPixelFormats(QGstCaps &caps,
const QList<QVideoFrameFormat::PixelFormat> &formats)
72 GValue drmFormatList = {};
73 g_value_init(&drmFormatList, GST_TYPE_LIST);
75 for (QVideoFrameFormat::PixelFormat format : formats) {
76 const GstVideoFormat gstFormat = qGstVideoFormatFromPixelFormat(format);
77 if (gstFormat == GST_VIDEO_FORMAT_UNKNOWN)
80 const guint32 fourcc =
81 gst_video_dma_drm_fourcc_from_format(gstFormat);
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);
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);
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);
110 for (
const VideoFormat &formatPair : qt_videoFormatLookup)
111 if (formatPair.pixelFormat == format)
112 return formatPair.gstFormat;
114 return GST_VIDEO_FORMAT_UNKNOWN;
119 for (
const VideoFormat &formatPair : qt_videoFormatLookup)
120 if (formatPair.gstFormat == format)
121 return formatPair.pixelFormat;
123 return QVideoFrameFormat::Format_Invalid;
137 if (!G_VALUE_HOLDS_BOOLEAN(value))
139 return g_value_get_boolean(value);
144 if (!G_VALUE_HOLDS_INT(value))
146 return g_value_get_int(value);
151 if (!G_VALUE_HOLDS_INT64(value))
153 return g_value_get_int64(value);
158 return value ? g_value_get_string(value) :
nullptr;
163 if (!GST_VALUE_HOLDS_FRACTION(value))
165 return (
float)gst_value_get_fraction_numerator(value)
166 / (
float)gst_value_get_fraction_denominator(value);
171 if (!GST_VALUE_HOLDS_FRACTION_RANGE(value))
175 return QGRange<
float>{ *min.getFraction(), *max.getFraction() };
180 if (!GST_VALUE_HOLDS_INT_RANGE(value))
182 return QGRange<
int>{ gst_value_get_int_range_min(value), gst_value_get_int_range_max(value) };
187 if (!value || !GST_VALUE_HOLDS_STRUCTURE(value))
188 return QGstStructureView(
nullptr);
194 if (!value || !GST_VALUE_HOLDS_CAPS(value))
196 return QGstCaps(gst_caps_copy(gst_value_get_caps(value)), QGstCaps::HasRef);
201 return value && GST_VALUE_HOLDS_LIST(value);
206 return gst_value_list_get_size(value);
211 return QGValue{ gst_value_list_get_value(value, index) };
225 return QUniqueGstStructureHandle{ gst_structure_copy(structure) };
235 return gst_structure_get_name(structure);
240 return QGValue{ gst_structure_get_value(structure, fieldname) };
254 QGstTagListHandle tagList;
255 gst_structure_get(structure,
"tags", GST_TYPE_TAG_LIST, &tagList,
nullptr);
264 if (structure && gst_structure_get_int(structure,
"width", &w)
265 && gst_structure_get_int(structure,
"height", &h)) {
275 QList<QVideoFrameFormat::PixelFormat> pixelFormats;
280 auto appendFromGstVideoFormat = [&](GstVideoFormat format) {
281 const QVideoFrameFormat::PixelFormat pixelFormat = qPixelFormatFromGstVideoFormat(format);
282 if (pixelFormat == QVideoFrameFormat::Format_Invalid)
285 if (!pixelFormats.contains(pixelFormat))
286 pixelFormats.append(pixelFormat);
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))
296 const char *drmFormatString = g_value_get_string(value);
297 if (!drmFormatString)
300 guint64 modifier = 0;
301 const guint32 fourcc = gst_video_dma_drm_fourcc_from_string(drmFormatString,
305 qWarning() <<
"Ignoring drm-format modifier when mapping to Qt PixelFormat:"
307 appendFromGstVideoFormat(gst_video_dma_drm_fourcc_to_format(fourcc));
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));
316 parseDrmFormat(drmFormatValue);
319 if (!pixelFormats.isEmpty())
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))
327 const char *formatString = g_value_get_string(value);
330 appendFromGstVideoFormat(gst_video_format_from_string(formatString));
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));
338 parseFormat(formatValue);
341 }
else if (gst_structure_has_name(structure,
"image/jpeg")) {
342 pixelFormats.append(QVideoFrameFormat::Format_Jpeg);
353 std::optional<
float> minRate;
354 std::optional<
float> maxRate;
356 auto extractFraction = [](
const GValue *v) ->
float {
357 return (
float)gst_value_get_fraction_numerator(v)
358 / (
float)gst_value_get_fraction_denominator(v);
360 auto extractFrameRate = [&](
const GValue *v) {
361 auto insert = [&](
float min,
float max) {
362 if (!maxRate || max > maxRate)
364 if (!minRate || min < minRate)
368 if (GST_VALUE_HOLDS_FRACTION(v)) {
369 float rate = extractFraction(v);
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));
378 const GValue *gstFrameRates = gst_structure_get_value(structure,
"framerate");
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));
386 extractFrameRate(gstFrameRates);
389 const GValue *min = gst_structure_get_value(structure,
"min-framerate");
390 const GValue *max = gst_structure_get_value(structure,
"max-framerate");
392 minRate = extractFraction(min);
393 maxRate = extractFraction(max);
397 if (!minRate || !maxRate)
401 minRate.value_or(*maxRate),
402 maxRate.value_or(*minRate),
411 const GValue *width = gst_structure_get_value(structure,
"width");
412 const GValue *height = gst_structure_get_value(structure,
"height");
414 if (!width || !height)
417 for (
const GValue *v : { width, height })
418 if (!GST_VALUE_HOLDS_INT_RANGE(v))
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);
426 return QGRange<QSize>{
427 QSize(minWidth, minHeight),
428 QSize(maxWidth, maxHeight),
434 GstMessage *message =
nullptr;
435 gst_structure_get(structure,
"message", GST_TYPE_MESSAGE, &message,
nullptr);
436 return QGstreamerMessage(message, QGstreamerMessage::HasRef);
443 if (gst_structure_get_fraction(structure,
"pixel-aspect-ratio", &numerator, &denominator)) {
455 QSize size = resolution();
456 if (!size.isValid()) {
457 qWarning() << Q_FUNC_INFO <<
"invalid resolution when querying nativeSize";
471 GstVideoInfo vidInfo;
472 std::optional<guint64> dmaDrmModifier;
475 GstVideoInfoDmaDrm videoInfoDmaDrm;
476 if (gst_video_info_dma_drm_from_caps(&videoInfoDmaDrm, get())) {
477 dmaDrmModifier = videoInfoDmaDrm.drm_modifier;
479 if (!gst_video_info_dma_drm_to_video_info(&videoInfoDmaDrm, &vidInfo))
484 if (!gst_video_info_from_caps(&vidInfo, get()))
492 const char *capsFeatures)
494 if (!gst_caps_is_writable(get()))
495 *
this = QGstCaps(gst_caps_make_writable(release()), QGstCaps::RefMode::HasRef);
498 if (qstrcmp(capsFeatures, GST_CAPS_FEATURE_MEMORY_DMABUF) == 0)
499 appendDmaDrmPixelFormats(*
this, formats);
503 g_value_init(&list, GST_TYPE_LIST);
505 for (QVideoFrameFormat::PixelFormat format : formats) {
506 const GstVideoFormat gstFormat = qGstVideoFormatFromPixelFormat(format);
507 if (gstFormat == GST_VIDEO_FORMAT_UNKNOWN)
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);
518 structure.setFractionRange(
"framerate", Fraction{ 0, 1 }, Fraction{ INT_MAX, 1 });
521 structure.setValue(
"format", &list);
523 gst_caps_append_structure(get(), structure.release());
524 g_value_unset(&list);
527 gst_caps_set_features(get(),
size() - 1,
528 gst_caps_features_from_string(capsFeatures));
533 Q_ASSERT(resolution.isValid());
535 g_value_init(&width, G_TYPE_INT);
536 g_value_set_int(&width, resolution.width());
538 g_value_init(&height, G_TYPE_INT);
539 g_value_set_int(&height, resolution.height());
541 gst_caps_set_value(caps(),
"width", &width);
542 gst_caps_set_value(caps(),
"height", &height);
547 QSize size = format.resolution();
550 if (format.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
553 jpegStructure
.setInt("height", size.height()
);
555 gst_caps_append_structure(caps.get(), jpegStructure.release());
559 const GstVideoFormat gstFormat = qGstVideoFormatFromPixelFormat(format.pixelFormat());
560 if (gstFormat == GST_VIDEO_FORMAT_UNKNOWN)
564 rawStructure
.setString("format", gst_video_format_to_string(gstFormat)
);
568 gst_caps_append_structure(caps.get(), rawStructure.release());
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());
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));
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());
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));
605 gst_caps_copy(caps()),
612 auto *features = gst_caps_get_features(get(), 0);
613 if (gst_caps_features_contains(features,
"memory:GLMemory"))
615 if (gst_caps_features_contains(features,
"memory:DMABuf"))
622 return int(gst_caps_get_size(get()));
628 gst_caps_get_structure(get(), index),
639 return QGstCaps(gst_caps_new_empty(), HasRef);
646 g_object_set(get(), property, str,
nullptr);
651 g_object_set(get(), property, gboolean(b),
nullptr);
656 g_object_set(get(), property, guint(i),
nullptr);
661 g_object_set(get(), property, gint(i),
nullptr);
666 g_object_set(get(), property, gint64(i),
nullptr);
671 g_object_set(get(), property, guint64(i),
nullptr);
676 g_object_set(get(), property, gdouble(d),
nullptr);
681 g_object_set(get(), property, o.object(),
nullptr);
686 g_object_set(get(), property, c.caps(),
nullptr);
689void QGstObject::
set(
const char *property,
void *object, GDestroyNotify destroyFunction)
691 g_object_set_data_full(qGstCheckedCast<GObject>(get()), property, object, destroyFunction);
697 g_object_get(get(), property, &s,
nullptr);
703 GstStructure *s =
nullptr;
704 g_object_get(get(), property, &s,
nullptr);
711 g_object_get(get(), property, &b,
nullptr);
718 g_object_get(get(), property, &i,
nullptr);
725 g_object_get(get(), property, &i,
nullptr);
732 g_object_get(get(), property, &i,
nullptr);
739 g_object_get(get(), property, &i,
nullptr);
746 g_object_get(get(), property, &d,
nullptr);
753 g_object_get(get(), property, &d,
nullptr);
759 GstObject *o =
nullptr;
760 g_object_get(get(), property, &o,
nullptr);
761 return QGstObject(o, HasRef);
766 return g_object_get_data(qGstCheckedCast<GObject>(get()), property);
774 g_signal_connect(get(), name, callback, userData),
780 g_signal_handler_disconnect(get(), handlerId);
785 return G_OBJECT_TYPE(get());
790 return QLatin1StringView{
802 using namespace Qt::StringLiterals;
804 return get() ? QLatin1StringView{ GST_OBJECT_NAME(get()) } :
"(null)"_L1;
819 object.disconnect(handlerId);
821 handlerId = invalidHandlerId;
836 connection.disconnect();
841 connection.disconnect();
864 return QGstCaps(gst_pad_get_current_caps(pad()), QGstCaps::HasRef);
869 return QGstCaps(gst_pad_query_caps(pad(),
nullptr), QGstCaps::HasRef);
874 QGstTagListHandle tagList;
875 g_object_get(object(),
"tags", &tagList,
nullptr);
882 gst_pad_get_stream_id(pad()),
888 using namespace Qt::Literals;
889 using TrackType = QPlatformMediaPlayer::TrackType;
891 QLatin1StringView padName = name();
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;
905 return gst_pad_is_linked(pad());
910 return gst_pad_link(pad(), sink.pad()) == GST_PAD_LINK_OK;
915 return gst_pad_unlink(pad(), sink.pad());
929 return QGstPad(gst_pad_get_peer(pad()), HasRef);
934 return QGstElement(gst_pad_get_parent_element(pad()), HasRef);
939 return qGstCheckedCast<GstPad>(object());
944 return gst_pad_get_sticky_event(pad(), type, 0);
949 return gst_pad_send_event(pad(), event);
954 GstEvent *flushStart = gst_event_new_flush_start();
955 gboolean ret = sendEvent(flushStart);
957 qWarning(
"failed to send flush-start event");
961 GstEvent *flushStop = gst_event_new_flush_stop(resetTime);
962 ret = sendEvent(flushStop);
964 qWarning(
"failed to send flush-stop event");
969 using namespace std::chrono_literals;
971 GstState state =
parent().state(1s);
973 if (state != GST_STATE_PAUSED)
999 return qGstCheckedCast<GstClock>(object());
1004 return gst_clock_get_time(clock());
1019 GstElement *element = gst_element_factory_make(factory, name);
1023 qWarning() <<
"Failed to make element" << name <<
"from factory" << factory;
1024 return QGstElement{};
1037 gst_element_factory_create(factory, name),
1050 return createFromDevice(device.get(), name);
1056 gst_device_create_element(device, name),
1057 QGstElement::NeedsRef,
1063 QUniqueGErrorHandle error;
1065 gst_parse_launch(str, &error),
1066 QGstElement::NeedsRef,
1070 qWarning() <<
"gst_parse_launch error:" << error;
1082 return QGstElementFactoryHandle{
1083 gst_element_factory_find(name),
1084 QGstElementFactoryHandle::HasRef,
1088QGstElementFactoryHandle
QGstElement::findFactory(
const QByteArray &name)
1090 return findFactory(name.constData());
1095 GstElementFactory *factory = gst_element_get_factory(element());
1099 const char *name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
1100 return name ? QByteArrayView{name} : QByteArrayView{};
1105 return QGstPad(gst_element_get_static_pad(element(), name), HasRef);
1120 return QGstPad(gst_element_request_pad_simple(element(), name), HasRef);
1125 return gst_element_release_request_pad(element(), pad.pad());
1130 using namespace std::chrono_literals;
1133 GstStateChangeReturn change =
1134 gst_element_get_state(element(), &state,
nullptr, timeout.count());
1136 if (Q_UNLIKELY(change == GST_STATE_CHANGE_ASYNC))
1137 qWarning() <<
"QGstElement::state detected an asynchronous state change. Return value not "
1145 return gst_element_set_state(element(), state);
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());
1154 if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL) {
1155 qWarning() <<
"Could not change state of" << name() <<
"to" << state << change;
1158 return change == GST_STATE_CHANGE_SUCCESS || change == GST_STATE_CHANGE_NO_PREROLL;
1163 Q_ASSERT(element());
1164 return gst_element_sync_state_with_parent(element()) == TRUE;
1169 GstState state, pending;
1170 GstStateChangeReturn change =
1171 gst_element_get_state(element(), &state, &pending, timeout.count());
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;
1177 return change == GST_STATE_CHANGE_SUCCESS;
1183 GstStateChangeReturn change =
1184 gst_element_get_state(element(), &state,
nullptr, timeout.count());
1185 return change == GST_STATE_CHANGE_ASYNC;
1188bool QGstElement::waitForAsyncStateChangeComplete(
std::chrono::nanoseconds timeout)
const
1190 using namespace std::chrono_literals;
1192 if (!hasAsyncStateChange())
1197 std::this_thread::sleep_for(10ms);
1203 gst_element_set_locked_state(element(), locked);
1208 return gst_element_is_locked_state(element());
1213 gst_element_send_event(element(), event);
1218 sendEvent(gst_event_new_eos());
1224 if (!gst_element_query_duration(element(), GST_FORMAT_TIME, &d)) {
1225 qDebug() <<
"QGstElement: failed to query duration";
1226 return std::nullopt;
1228 return std::chrono::nanoseconds{ d };
1233 using namespace std::chrono;
1234 auto dur = duration();
1236 return round<milliseconds>(*dur);
1237 return std::nullopt;
1242 QGstQueryHandle &query = positionQuery();
1245 if (gst_element_query(element(), query.get())) {
1246 gst_query_parse_position(query.get(),
nullptr, &pos);
1247 return std::chrono::nanoseconds{ pos };
1250 qDebug() <<
"QGstElement: failed to query position";
1251 return std::nullopt;
1256 using namespace std::chrono;
1257 auto pos = position();
1259 return round<milliseconds>(*pos);
1260 return std::nullopt;
1265 QGstQueryHandle query{
1266 gst_query_new_seeking(GST_FORMAT_TIME),
1267 QGstQueryHandle::HasRef,
1269 gboolean canSeek =
false;
1270 gst_query_parse_seeking(query.get(),
nullptr, &canSeek,
nullptr,
nullptr);
1272 if (gst_element_query(element(), query.get())) {
1273 gst_query_parse_seeking(query.get(),
nullptr, &canSeek,
nullptr,
nullptr);
1276 return std::nullopt;
1281 return gst_element_get_base_time(element());
1286 gst_element_set_base_time(element(), time);
1291 return GST_ELEMENT_CAST(get());
1297 qGstCheckedCast<GstElement>(gst_element_get_parent(object())),
1298 QGstElement::HasRef,
1305 qGstCheckedCast<GstBin>(gst_element_get_parent(object())),
1306 QGstElement::HasRef,
1315 if (greatAncestor) {
1316 ancestor =
std::move(greatAncestor);
1319 if (GST_IS_BIN(ancestor.element())) {
1321 qGstSafeCast<GstBin>(ancestor.element()),
1333 if (GST_IS_PIPELINE(rootBin.get())) {
1334 return QGstPipeline{
1335 qGstSafeCast<GstPipeline>(rootBin.element()),
1336 QGstPipeline::NeedsRef,
1339 qWarning() <<
"QGstElement::getPipeline failed for element:" << *
this;
1340 return QGstPipeline{};
1346 if (QGstBin parent = getParentBin())
1347 parent.remove(*
this);
1352 static const bool dumpEnabled = qEnvironmentVariableIsSet(
"GST_DEBUG_DUMP_DOT_DIR");
1358QGstQueryHandle &
QGstElement::positionQuery()
const
1360 if (Q_UNLIKELY(!m_positionQuery))
1361 m_positionQuery = QGstQueryHandle{
1362 gst_query_new_position(GST_FORMAT_TIME),
1363 QGstQueryHandle::HasRef,
1366 return m_positionQuery;
1373 return QGstBin(gst_bin_new(name), NeedsRef);
1379 Q_ASSERT(GST_IS_BIN(element.element()));
1381 GST_BIN(element.release()),
1387 const char *name,
bool ghostUnlinkedPads)
1393 bool ghostUnlinkedPads)
1395 QUniqueGErrorHandle error;
1397 GstElement *element =
1398 gst_parse_bin_from_description_full(pipelineDescription, ghostUnlinkedPads,
1399 nullptr, GST_PARSE_FLAG_NONE, &error);
1402 qWarning() <<
"Failed to make element from pipeline description" << pipelineDescription
1408 gst_element_set_name(element, name);
1426 return qGstCheckedCast<GstBin>(object());
1436 gst_element_add_pad(element(), gst_ghost_pad_new(name, pad.pad()));
1441 Q_ASSERT(direction != GstPadDirection::GST_PAD_UNKNOWN);
1445 gst_bin_find_unlinked_pad(bin(), direction),
1452 addGhostPad(unlinkedPad.name().constData(), unlinkedPad);
1458 return gst_bin_sync_children_states(bin());
1466 if (includeTimestamp)
1467 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(bin(), GST_DEBUG_GRAPH_SHOW_VERBOSE, fileNamePrefix);
1469 GST_DEBUG_BIN_TO_DOT_FILE(bin(), GST_DEBUG_GRAPH_SHOW_VERBOSE, fileNamePrefix);
1475 gst_bin_get_by_name(bin(), name),
1476 QGstElement::NeedsRef,
1482 gst_bin_recalculate_latency(bin());
1497 gst_base_sink_set_sync(baseSink(), arg ? TRUE : FALSE);
1502 return qGstCheckedCast<GstBaseSink>(element());
1517 return qGstCheckedCast<GstBaseSrc>(element());
1534 qGstCheckedCast<GstAppSink>(created.element()),
1535 QGstAppSink::NeedsRef,
1541 return qGstCheckedCast<GstAppSink>(element());
1544# if GST_CHECK_VERSION(1
, 24
, 0
)
1545void QGstAppSink::setMaxBufferTime(std::chrono::nanoseconds ns)
1547 gst_app_sink_set_max_time(appSink(), qGstClockTimeFromChrono(ns));
1553 gst_app_sink_set_max_buffers(appSink(), n);
1558 gst_app_sink_set_caps(appSink(), caps.caps());
1562 GDestroyNotify notify)
1564 gst_app_sink_set_callbacks(appSink(), &callbacks, user_data, notify);
1569 return QGstSampleHandle{
1570 gst_app_sink_pull_sample(appSink()),
1571 QGstSampleHandle::HasRef,
1589 qGstCheckedCast<GstAppSrc>(created.element()),
1590 QGstAppSrc::NeedsRef,
1596 return qGstCheckedCast<GstAppSrc>(element());
1600 GDestroyNotify notify)
1602 gst_app_src_set_callbacks(appSrc(), &callbacks, user_data, notify);
1607 return gst_app_src_push_buffer(appSrc(), buffer);
1612 return QStringLiteral(
"Could not find the %1 GStreamer element")
1613 .arg(QLatin1StringView(element));
1618 auto &vidInfo = qtVideoInfo.gstVideoInfo;
1619 GstVideoFormat gstFormat = GST_VIDEO_INFO_FORMAT(&vidInfo);
1621 auto pixelFormat = qPixelFormatFromGstVideoFormat(gstFormat);
1622 if (pixelFormat == QVideoFrameFormat::Format_Invalid)
1623 return QVideoFrameFormat();
1625 QVideoFrameFormat format(QSize(vidInfo.width, vidInfo.height), pixelFormat);
1627 if (vidInfo.fps_d > 0)
1628 format.setStreamFrameRate(qreal(vidInfo.fps_n) / vidInfo.fps_d);
1630 QVideoFrameFormat::ColorRange range = QVideoFrameFormat::ColorRange_Unknown;
1631 switch (vidInfo.colorimetry.range) {
1632 case GST_VIDEO_COLOR_RANGE_UNKNOWN:
1634 case GST_VIDEO_COLOR_RANGE_0_255:
1635 range = QVideoFrameFormat::ColorRange_Full;
1637 case GST_VIDEO_COLOR_RANGE_16_235:
1638 range = QVideoFrameFormat::ColorRange_Video;
1641 format.setColorRange(range);
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:
1649 case GST_VIDEO_COLOR_MATRIX_BT709:
1650 colorSpace = QVideoFrameFormat::ColorSpace_BT709;
1652 case GST_VIDEO_COLOR_MATRIX_BT601:
1653 colorSpace = QVideoFrameFormat::ColorSpace_BT601;
1655 case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
1656 colorSpace = QVideoFrameFormat::ColorSpace_AdobeRgb;
1658 case GST_VIDEO_COLOR_MATRIX_BT2020:
1659 colorSpace = QVideoFrameFormat::ColorSpace_BT2020;
1662 format.setColorSpace(colorSpace);
1664 QVideoFrameFormat::ColorTransfer transfer = QVideoFrameFormat::ColorTransfer_Unknown;
1665 switch (vidInfo.colorimetry.transfer) {
1666 case GST_VIDEO_TRANSFER_UNKNOWN:
1668 case GST_VIDEO_TRANSFER_GAMMA10:
1669 transfer = QVideoFrameFormat::ColorTransfer_Linear;
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;
1677 case GST_VIDEO_TRANSFER_GAMMA18:
1678 case GST_VIDEO_TRANSFER_GAMMA20:
1680 case GST_VIDEO_TRANSFER_BT709:
1681 case GST_VIDEO_TRANSFER_BT2020_12:
1682 transfer = QVideoFrameFormat::ColorTransfer_BT709;
1684 case GST_VIDEO_TRANSFER_GAMMA28:
1685 transfer = QVideoFrameFormat::ColorTransfer_Gamma28;
1687 case GST_VIDEO_TRANSFER_LOG100:
1688 case GST_VIDEO_TRANSFER_LOG316:
1690 case GST_VIDEO_TRANSFER_SMPTE2084:
1691 transfer = QVideoFrameFormat::ColorTransfer_ST2084;
1693 case GST_VIDEO_TRANSFER_ARIB_STD_B67:
1694 transfer = QVideoFrameFormat::ColorTransfer_STD_B67;
1696 case GST_VIDEO_TRANSFER_BT2020_10:
1697 transfer = QVideoFrameFormat::ColorTransfer_BT709;
1699 case GST_VIDEO_TRANSFER_BT601:
1700 transfer = QVideoFrameFormat::ColorTransfer_BT601;
1703 format.setColorTransfer(transfer);
1714 [[maybe_unused]] GstMemory *mem = gst_buffer_peek_memory(buffer, 0);
1716#if QT_CONFIG(gstreamer_gl_egl) && QT_CONFIG(linux_dmabuf)
1717 if (gst_is_dmabuf_memory(mem))
1718 memoryFormat = QGstCaps::DMABuf;
1720#if QT_CONFIG(gstreamer_gl)
1721 if (gst_is_gl_memory(mem))
1722 memoryFormat = QGstCaps::GLTexture;
1724 return memoryFormat;
1728 const QVideoFrameFormat &format)
1730#if QT_CONFIG(linux_dmabuf)
1731 if (
auto dmaBufBuffer = QGstDmaBufVideoBuffer::create(buffer, videoInfo, format))
1732 return QVideoFramePrivate::createFrame(std::move(dmaBufBuffer), format);
1734 auto videoBuffer =
std::make_unique<QGstVideoBuffer>(
std::move(buffer), videoInfo, format);
1735 return QVideoFramePrivate::createFrame(std::move(videoBuffer), format);
1740 auto format = qVideoFrameFormatFromGstVideoInfo(videoInfo);
1741 return qCreateFrameFromGstBuffer(std::move(buffer), videoInfo, format);
QGObjectHandlerConnection(QGstObject object, gulong handler)
~QGObjectHandlerScopedConnection()
QGObjectHandlerScopedConnection(QGObjectHandlerConnection connection)
std::optional< int > toInt64() const
std::optional< QGRange< int > > toIntRange() const
std::optional< int > toInt() const
QGstStructureView toStructure() const
std::optional< QGRange< float > > getFractionRange() const
const char * toString() const
std::optional< float > getFraction() const
QGValue at(int index) const
std::optional< bool > toBool() const
QGstSampleHandle pullSample()
void setCallbacks(GstAppSinkCallbacks &callbacks, gpointer user_data, GDestroyNotify notify)
GstAppSink * appSink() const
void setCaps(const QGstCaps &caps)
static QGstAppSink create(const char *name)
QGstAppSink(GstAppSink *, RefMode)
static QGstAppSrc create(const char *name)
void setCallbacks(GstAppSrcCallbacks &callbacks, gpointer user_data, GDestroyNotify notify)
QGstAppSrc(GstAppSrc *, RefMode)
GstAppSrc * appSrc() const
QGstBaseSink(GstBaseSink *, RefMode)
GstBaseSink * baseSink() const
QGstBaseSrc(GstBaseSrc *, RefMode)
GstBaseSrc * baseSrc() const
void addUnlinkedGhostPads(GstPadDirection)
void dumpGraph(const char *fileNamePrefix, bool includeTimestamp=true) const
QGstElement findByName(const char *)
void recalculateLatency()
static QGstBin create(const char *name)
void addGhostPad(const QGstElement &child, const char *name)
static QGstBin createFromPipelineDescription(const char *pipelineDescription, const char *name=nullptr, bool ghostUnlinkedPads=false)
static QGstBin createFromFactory(const char *factory, const char *name)
void addGhostPad(const char *name, const QGstPad &pad)
QGstBin(GstBin *bin, RefMode mode=NeedsRef)
MemoryFormat memoryFormat() const
std::optional< QGstVideoInfo > videoInfo() const
static QGstCaps fromCameraFormat(const QCameraFormat &format)
void setResolution(QSize)
void addPixelFormats(const QList< QVideoFrameFormat::PixelFormat > &formats, const char *capsFeatures=nullptr)
QGstStructureView at(int index) const
QGstClock(GstClock *clock, RefMode mode)
GstClockTime time() const
QGstClock(const QGstObject &o)
void setBaseTime(GstClockTime time) const
GstStateChangeReturn setState(GstState state)
std::optional< std::chrono::nanoseconds > position() const
GstElement * element() const
QGstElement(GstElement *element, RefMode mode)
void lockState(bool locked)
QGstBin getRootBin() const
QGstPad getRequestPad(const char *name) const
std::optional< bool > canSeek() const
std::optional< std::chrono::nanoseconds > duration() const
bool isStateLocked() const
void sendEvent(GstEvent *event) const
void dumpPipelineGraph(const char *filename) const
GstClockTime baseTime() const
QByteArrayView factoryName() const
void releaseRequestPad(const QGstPad &pad) const
bool syncStateWithParent()
QGstPad staticPad(const char *name) const
QGstBin getParentBin() const
std::optional< std::chrono::milliseconds > positionInMs() const
static QGstElement createFromFactory(const char *factory, const char *name=nullptr)
QGstElement getParent() const
QGstPipeline getPipeline() const
static QGstElement createFromPipelineDescription(const char *)
std::optional< std::chrono::milliseconds > durationInMs() const
void set(const char *property, double d)
QGObjectHandlerConnection connect(const char *name, GCallback callback, gpointer userData)
void * getObject(const char *property) const
double getDouble(const char *property) const
int getInt(const char *property) const
void set(const char *property, int32_t i)
QLatin1StringView name() const
void set(const char *property, const QGstObject &o)
QGString getString(const char *property) const
void disconnect(gulong handlerId)
QGstObject getGstObject(const char *property) const
QLatin1StringView typeName() const
void set(const char *property, const char *str)
bool getBool(const char *property) const
QGstObject & operator=(QGstObject &&) noexcept=default
void set(const char *property, void *object, GDestroyNotify destroyFunction)
void set(const char *property, bool b)
quint64 getUInt64(const char *property) const
QGstStructureView getStructure(const char *property) const
qint64 getInt64(const char *property) const
void set(const char *property, const QGstCaps &c)
float getFloat(const char *property) const
uint getUInt(const char *property) const
GstObject * object() const
bool link(const QGstPad &sink) const
GstEvent * stickyEvent(GstEventType type)
QGstTagListHandle tags() const
QGstPad(const QGstObject &o)
QGstCaps queryCaps() const
QGstPad(GstPad *pad, RefMode mode)
void sendFlushStartStop(bool resetTime)
QGString streamId() const
std::optional< QPlatformMediaPlayer::TrackType > inferTrackTypeFromName() const
bool sendEvent(GstEvent *event)
QGstCaps currentCaps() const
QGstElement parent() const
bool unlink(const QGstPad &sink) const
QGstStructureView(const QUniqueGstStructureHandle &)
QGRange< float > frameRateRange() const
QGValue operator[](const char *fieldname) const
QUniqueGstStructureHandle clone() const
QList< QVideoFrameFormat::PixelFormat > pixelFormats() const
std::optional< QGRange< QSize > > resolutionRange() const
QGstreamerMessage getMessage()
std::optional< Fraction > pixelAspectRatio() const
QGstTagListHandle tags() const
QByteArrayView name() const
QGstStructureView(const GstStructure *)
QSize qCalculateFrameSizeGStreamer(QSize resolution, Fraction par)
constexpr std::array< VideoFormat, 19 > qt_videoFormatLookup
QGstCaps::MemoryFormat qMemoryFormatFromGstBuffer(GstBuffer *buffer)
QVideoFrame qCreateFrameFromGstBuffer(QGstBufferHandle buffer, const QGstVideoInfo &videoInfo, const QVideoFrameFormat &format)
QVideoFrameFormat qVideoFrameFormatFromGstVideoInfo(const QGstVideoInfo &vidInfo)
#define QT_GSTREAMER_SUPPORTS_GST_VIDEO_FORMAT_DMA_DRM
GstVideoFormat qGstVideoFormatFromPixelFormat(QVideoFrameFormat::PixelFormat format)
QString qGstErrorMessageCannotFindElement(std::string_view element)
QVideoFrame qCreateFrameFromGstBuffer(QGstBufferHandle buffer, const QGstVideoInfo &videoInfo)
QVideoFrameFormat::PixelFormat qPixelFormatFromGstVideoFormat(GstVideoFormat format)
typedefQT_BEGIN_NAMESPACE struct _GstBuffer GstBuffer
void setInt(const char *field, int value)
void setIntRange(const char *field, int min, int max)
void setString(const char *field, const char *value)
QGstStructure(const char *name)