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_debug.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 "qgst_debug_p.h"
6
7#include <gst/gstclock.h>
8
10
11// NOLINTBEGIN(performance-unnecessary-value-param)
12
13QDebug operator<<(QDebug dbg, const QGString &str)
14{
15 return dbg << str.get();
16}
17
18QDebug operator<<(QDebug dbg, const QGstCaps &caps)
19{
20 return dbg << caps.caps();
21}
22
23QDebug operator<<(QDebug dbg, const QGstStructureView &structure)
24{
25 return dbg << structure.structure;
26}
27
28QDebug operator<<(QDebug dbg, const QUniqueGstStructureHandle &structure)
29{
30 return dbg << QGstStructureView{structure};
31}
32
33QDebug operator<<(QDebug dbg, const QGValue &value)
34{
35 return dbg << value.value;
36}
37
38QDebug operator<<(QDebug dbg, const QGstreamerMessage &msg)
39{
40 return dbg << msg.message();
41}
42
43QDebug operator<<(QDebug dbg, const QUniqueGErrorHandle &handle)
44{
45 return dbg << handle.get();
46}
47
48QDebug operator<<(QDebug dbg, const QUniqueGStringHandle &handle)
49{
50 return dbg << handle.get();
51}
52
53QDebug operator<<(QDebug dbg, const QGstStreamCollectionHandle &handle)
54{
55 return dbg << handle.get();
56}
57
58QDebug operator<<(QDebug dbg, const QGstStreamHandle &handle)
59{
60 return dbg << handle.get();
61}
62
63QDebug operator<<(QDebug dbg, const QGstTagListHandle &handle)
64{
65 return dbg << handle.get();
66}
67
68QDebug operator<<(QDebug dbg, const QGstElement &element)
69{
70 return dbg << element.element();
71}
72
73QDebug operator<<(QDebug dbg, const QGstPad &pad)
74{
75 return dbg << pad.pad();
76}
77
78QDebug operator<<(QDebug dbg, const GstCaps *caps)
79{
80 if (caps)
81 return dbg << QGString(gst_caps_to_string(caps));
82 else
83 return dbg << "null";
84}
85
86QDebug operator<<(QDebug dbg, const GstVideoInfo *info)
87{
88 return dbg << QGstCaps{
89 gst_video_info_to_caps(info),
90 QGstCaps::NeedsRef,
91 };
92}
93
94QDebug operator<<(QDebug dbg, const GstStructure *structure)
95{
96 if (structure)
97 return dbg << QGString(gst_structure_to_string(structure));
98 else
99 return dbg << "null";
100}
101
102QDebug operator<<(QDebug dbg, const GstObject *object)
103{
104 if (!object)
105 return dbg << "null";
106
107 dbg << QGString{gst_object_get_name(const_cast<GstObject*>(object))};
108
109 {
110 QDebugStateSaver saver(dbg);
111 dbg.nospace();
112
113 dbg << "{";
114
115 guint numProperties;
116 GParamSpec **properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(object), &numProperties);
117
118 for (guint i = 0; i < numProperties; i++) {
119 GParamSpec *param = properties[i];
120
121 const gchar *name = g_param_spec_get_name(param);
122 constexpr bool trace_blurb = false;
123 if constexpr (trace_blurb) {
124 const gchar *blurb = g_param_spec_get_blurb(param);
125 dbg << name << " (" << blurb << "): ";
126 } else
127 dbg << name << ": ";
128
129 bool readable = bool(param->flags & G_PARAM_READABLE);
130 if (!readable) {
131 dbg << "(not readable)";
132 } else if (QLatin1StringView(name) == QLatin1StringView("parent")) {
133 if (object->parent)
134 dbg << QGString{ gst_object_get_name(object->parent) };
135 else
136 dbg << "(none)";
137 } else {
138 GValue value = {};
139 g_object_get_property(&const_cast<GstObject *>(object)->object, param->name,
140 &value);
141 dbg << &value;
142 }
143 if (i != numProperties - 1)
144 dbg << ", ";
145 }
146
147 dbg << "}";
148
149 g_free(properties);
150 }
151 return dbg;
152}
153
154QDebug operator<<(QDebug dbg, const GstElement *element)
155{
156 return dbg << GST_OBJECT_CAST(element); // LATER: output other members?
157}
158
159QDebug operator<<(QDebug dbg, const GstPad *pad)
160{
161 return dbg << GST_OBJECT_CAST(pad); // LATER: output other members?
162}
163
164QDebug operator<<(QDebug dbg, const GstDevice *device)
165{
166 if (!device)
167 return dbg << "null";
168
169 GstDevice *d = const_cast<GstDevice *>(device);
170 QDebugStateSaver saver(dbg);
171 dbg.nospace();
172
173 dbg << gst_device_get_display_name(d) << "(" << gst_device_get_device_class(d) << ") ";
174 dbg << "Caps: " << QGstCaps{ gst_device_get_caps(d), QGstCaps::NeedsRef, } << ", ";
175 dbg << "Properties: " << QUniqueGstStructureHandle{ gst_device_get_properties(d) }.get();
176 return dbg;
177}
178
179namespace {
180
181struct Timepoint
182{
183 explicit Timepoint(guint64 us) : ts{ us } { }
184 guint64 ts;
185};
186
187QDebug operator<<(QDebug dbg, Timepoint ts)
188{
189 char buffer[128];
190 snprintf(buffer, sizeof(buffer), "%" GST_TIME_FORMAT, GST_TIME_ARGS(ts.ts));
191 dbg << buffer;
192 return dbg;
193}
194
195} // namespace
196
197QDebug operator<<(QDebug dbg, const GstMessage *msg)
198{
199 QDebugStateSaver saver(dbg);
200 dbg.nospace();
201
202 dbg << GST_MESSAGE_TYPE_NAME(msg) << ", Source: " << GST_MESSAGE_SRC_NAME(msg);
203 if (GST_MESSAGE_TIMESTAMP(msg) != 0xFFFFFFFFFFFFFFFF)
204 dbg << ", Timestamp: " << GST_MESSAGE_TIMESTAMP(msg);
205
206 switch (msg->type) {
207 case GST_MESSAGE_ERROR: {
208 QUniqueGErrorHandle err;
209 QGString debug;
210 gst_message_parse_error(const_cast<GstMessage *>(msg), &err, &debug);
211
212 dbg << ", Error: " << err << " (" << debug << ")";
213 break;
214 }
215
216 case GST_MESSAGE_WARNING: {
217 QUniqueGErrorHandle err;
218 QGString debug;
219 gst_message_parse_warning(const_cast<GstMessage *>(msg), &err, &debug);
220
221 dbg << ", Warning: " << err << " (" << debug << ")";
222 break;
223 }
224
225 case GST_MESSAGE_INFO: {
226 QUniqueGErrorHandle err;
227 QGString debug;
228 gst_message_parse_info(const_cast<GstMessage *>(msg), &err, &debug);
229
230 dbg << ", Info: " << err << " (" << debug << ")";
231 break;
232 }
233
234 case GST_MESSAGE_TAG: {
235 QGstTagListHandle tagList;
236 gst_message_parse_tag(const_cast<GstMessage *>(msg), &tagList);
237
238 dbg << ", Tags: " << tagList;
239 break;
240 }
241
242 case GST_MESSAGE_QOS: {
243 gboolean live;
244 guint64 running_time;
245 guint64 stream_time;
246 guint64 timestamp;
247 guint64 duration;
248
249 gst_message_parse_qos(const_cast<GstMessage *>(msg), &live, &running_time, &stream_time,
250 &timestamp, &duration);
251
252 dbg << ", Live: " << bool(live) << ", Running time: " << Timepoint{ running_time }
253 << ", Stream time: " << Timepoint{ stream_time }
254 << ", Timestamp: " << Timepoint{ timestamp } << ", Duration: " << Timepoint{ duration };
255 break;
256 }
257
258 case GST_MESSAGE_STATE_CHANGED: {
259 GstState oldState;
260 GstState newState;
261 GstState pending;
262
263 gst_message_parse_state_changed(const_cast<GstMessage *>(msg), &oldState, &newState,
264 &pending);
265
266 dbg << ", Transition: " << oldState << "->" << newState;
267
268 if (pending != GST_STATE_VOID_PENDING)
269 dbg << ", Pending State: " << pending;
270 break;
271 }
272
273 case GST_MESSAGE_STREAM_COLLECTION: {
274 QGstStreamCollectionHandle collection;
275 gst_message_parse_stream_collection(const_cast<GstMessage *>(msg), &collection);
276
277 dbg << ", " << collection;
278 break;
279 }
280
281 case GST_MESSAGE_STREAMS_SELECTED: {
282 QGstStreamCollectionHandle collection;
283 gst_message_parse_streams_selected(const_cast<GstMessage *>(msg), &collection);
284
285 dbg << ", " << collection;
286 break;
287 }
288
289 case GST_MESSAGE_STREAM_STATUS: {
290 GstStreamStatusType streamStatus;
291 gst_message_parse_stream_status(const_cast<GstMessage *>(msg), &streamStatus, nullptr);
292
293 dbg << ", Stream Status: " << streamStatus;
294 break;
295 }
296
297 case GST_MESSAGE_BUFFERING: {
298 int progress = 0;
299 gst_message_parse_buffering(const_cast<GstMessage *>(msg), &progress);
300
301 dbg << ", Buffering: " << progress << "%";
302 break;
303 }
304
305 case GST_MESSAGE_SEGMENT_START: {
306 gint64 pos;
307 GstFormat fmt{};
308 gst_message_parse_segment_start(const_cast<GstMessage *>(msg), &fmt, &pos);
309
310 switch (fmt) {
311 case GST_FORMAT_TIME: {
312 dbg << ", Position: " << std::chrono::nanoseconds{ pos };
313 break;
314 }
315 case GST_FORMAT_BYTES: {
316 dbg << ", Position: " << pos << "Bytes";
317 break;
318 }
319 default: {
320 dbg << ", Position: " << pos;
321 break;
322 }
323 }
324
325 break;
326 }
327
328 default:
329 break;
330 }
331 return dbg;
332}
333
334QDebug operator<<(QDebug dbg, const GstTagList *tagList)
335{
336 if (tagList)
337 dbg << QGString{ gst_tag_list_to_string(tagList) };
338 else
339 dbg << "NULL";
340
341 return dbg;
342}
343
344QDebug operator<<(QDebug dbg, const GstQuery *query)
345{
346 dbg << GST_QUERY_TYPE_NAME(query);
347 return dbg;
348}
349
350QDebug operator<<(QDebug dbg, const GstEvent *event)
351{
352 dbg << GST_EVENT_TYPE_NAME(event);
353 return dbg;
354}
355
356QDebug operator<<(QDebug dbg, const GstPadTemplate *padTemplate)
357{
358 QGstCaps caps = padTemplate
359 ? QGstCaps{ gst_pad_template_get_caps(const_cast<GstPadTemplate *>(padTemplate)), QGstCaps::HasRef, }
360 : QGstCaps{};
361
362 dbg << caps;
363 return dbg;
364}
365
366QDebug operator<<(QDebug dbg, const GstStreamCollection *streamCollection)
367{
368 QDebugStateSaver saver(dbg);
369 dbg.nospace();
370
371 GstStreamCollection *collection = const_cast<GstStreamCollection *>(streamCollection);
372 dbg << "Stream Collection: {";
373
374 qForeachStreamInCollection(collection, [&](GstStream *stream) {
375 dbg << stream << ", ";
376 });
377
378 dbg << "}";
379 return dbg;
380}
381
382QDebug operator<<(QDebug dbg, const GstStream *cstream)
383{
384 GstStream *stream = const_cast<GstStream *>(cstream);
385
386 QDebugStateSaver saver(dbg);
387 dbg.nospace();
388
389 dbg << gst_stream_get_stream_id(stream) << " (" << gst_stream_get_stream_type(stream) << ")";
390
391 return dbg;
392}
393
394QDebug operator<<(QDebug dbg, GstState state)
395{
396 return dbg << gst_element_state_get_name(state);
397}
398
399QDebug operator<<(QDebug dbg, GstStateChange transition)
400{
401 return dbg << gst_state_change_get_name(transition);
402}
403
404QDebug operator<<(QDebug dbg, GstStateChangeReturn stateChangeReturn)
405{
406 return dbg << gst_element_state_change_return_get_name(stateChangeReturn);
407}
408
409QDebug operator<<(QDebug dbg, GstMessageType type)
410{
411 return dbg << gst_message_type_get_name(type);
412}
413
414#define ADD_ENUM_SWITCH(value)
415 case value:
416 return dbg << #value;
417 static_assert(true, "enforce semicolon")
418
419QDebug operator<<(QDebug dbg, GstPadDirection direction)
420{
421 switch (direction) {
422 ADD_ENUM_SWITCH(GST_PAD_UNKNOWN);
423 ADD_ENUM_SWITCH(GST_PAD_SRC);
424 ADD_ENUM_SWITCH(GST_PAD_SINK);
425 default:
426 Q_UNREACHABLE_RETURN(dbg);
427 }
428}
429
430QDebug operator<<(QDebug dbg, GstStreamStatusType type)
431{
432 switch (type) {
433 ADD_ENUM_SWITCH(GST_STREAM_STATUS_TYPE_CREATE);
434 ADD_ENUM_SWITCH(GST_STREAM_STATUS_TYPE_ENTER);
435 ADD_ENUM_SWITCH(GST_STREAM_STATUS_TYPE_LEAVE);
436 ADD_ENUM_SWITCH(GST_STREAM_STATUS_TYPE_DESTROY);
437 ADD_ENUM_SWITCH(GST_STREAM_STATUS_TYPE_START);
438 ADD_ENUM_SWITCH(GST_STREAM_STATUS_TYPE_PAUSE);
439 ADD_ENUM_SWITCH(GST_STREAM_STATUS_TYPE_STOP);
440 default:
441 Q_UNREACHABLE_RETURN(dbg);
442 }
443 return dbg;
444}
445
446#undef ADD_ENUM_SWITCH
447
448QDebug operator<<(QDebug dbg, GstStreamType streamType)
449{
450 dbg << gst_stream_type_get_name(streamType);
451 return dbg;
452}
453
454QDebug operator<<(QDebug dbg, const GValue *value)
455{
456 switch (G_VALUE_TYPE(value)) {
457 case G_TYPE_STRING:
458 return dbg << g_value_get_string(value);
459 case G_TYPE_BOOLEAN:
460 return dbg << g_value_get_boolean(value);
461 case G_TYPE_ULONG:
462 return dbg << g_value_get_ulong(value);
463 case G_TYPE_LONG:
464 return dbg << g_value_get_long(value);
465 case G_TYPE_UINT:
466 return dbg << g_value_get_uint(value);
467 case G_TYPE_INT:
468 return dbg << g_value_get_int(value);
469 case G_TYPE_UINT64:
470 return dbg << g_value_get_uint64(value);
471 case G_TYPE_INT64:
472 return dbg << g_value_get_int64(value);
473 case G_TYPE_FLOAT:
474 return dbg << g_value_get_float(value);
475 case G_TYPE_DOUBLE:
476 return dbg << g_value_get_double(value);
477 default:
478 break;
479 }
480
481 if (GST_VALUE_HOLDS_BITMASK(value)) {
482 QDebugStateSaver saver(dbg);
483 return dbg << Qt::hex << gst_value_get_bitmask(value);
484 }
485
486 if (GST_VALUE_HOLDS_FRACTION(value))
487 return dbg << gst_value_get_fraction_numerator(value) << "/"
488 << gst_value_get_fraction_denominator(value);
489
490 if (GST_VALUE_HOLDS_CAPS(value))
491 return dbg << gst_value_get_caps(value);
492
493 if (GST_VALUE_HOLDS_STRUCTURE(value))
494 return dbg << gst_value_get_structure(value);
495
496 if (GST_VALUE_HOLDS_ARRAY(value)) {
497 const guint size = gst_value_array_get_size(value);
498 const guint last = size - 1;
499 dbg << "[";
500 for (guint index = 0; index != size; ++index) {
501 dbg << gst_value_array_get_value(value, index);
502 if (index != last)
503 dbg << ", ";
504 }
505 dbg << "}";
506 return dbg;
507 }
508
509 if (G_VALUE_TYPE(value) == GST_TYPE_PAD_DIRECTION) {
510 GstPadDirection direction = static_cast<GstPadDirection>(g_value_get_enum(value));
511 return dbg << direction;
512 }
513
514 if (G_VALUE_TYPE(value) == GST_TYPE_PAD_TEMPLATE) {
515 GstPadTemplate *padTemplate = static_cast<GstPadTemplate *>(g_value_get_object(value));
516 return dbg << padTemplate;
517 }
518
519 dbg << "(not implemented: " << G_VALUE_TYPE_NAME(value) << ")";
520
521 return dbg;
522}
523
524QDebug operator<<(QDebug dbg, const GError *error)
525{
526 return dbg << error->message;
527}
528
535
537 : msg{
538 m,
539 }
540{
541}
542
544{
545 std::optional<QDebugStateSaver> saver(dbg);
546 dbg.nospace();
547
548 switch (GST_MESSAGE_TYPE(m.msg)) {
549 case GST_MESSAGE_ERROR: {
550 QUniqueGErrorHandle err;
551 QGString debug;
552 gst_message_parse_error(m.msg, &err, &debug);
553 dbg << err << " (" << debug << ")";
554 return dbg;
555 }
556
557 case GST_MESSAGE_WARNING: {
558 QUniqueGErrorHandle err;
559 QGString debug;
560 gst_message_parse_warning(m.msg, &err, &debug);
561 dbg << err << " (" << debug << ")";
562 return dbg;
563 }
564
565 case GST_MESSAGE_INFO: {
566 QUniqueGErrorHandle err;
567 QGString debug;
568 gst_message_parse_info(m.msg, &err, &debug);
569
570 dbg << err << " (" << debug << ")";
571 return dbg;
572 }
573
574 case GST_MESSAGE_STATE_CHANGED: {
575 GstState oldState;
576 GstState newState;
577 GstState pending;
578
579 gst_message_parse_state_changed(m.msg, &oldState, &newState, &pending);
580
581 dbg << oldState << " -> " << newState;
582 if (pending != GST_STATE_VOID_PENDING)
583 dbg << " (pending: " << pending << ")";
584 return dbg;
585 }
586
587 default: {
588 saver.reset();
589 return dbg << m.msg;
590 }
591 }
592}
593
594QDebug operator<<(QDebug dbg, GstPlayMessage type)
595{
596 return dbg << gst_play_message_get_name(type);
597}
598
599QDebug operator<<(QDebug dbg, GstPlayState state)
600{
601 return dbg << gst_play_state_get_name(state);
602}
603
610
612 : msg{
613 m,
614 }
615{
616}
617
619{
620 using namespace std::chrono;
621 Q_ASSERT(gst_play_is_play_message(m.msg));
622
623 std::optional<QDebugStateSaver> saver(dbg);
624
625 GstPlayMessage type;
626 gst_play_message_parse_type(m.msg, &type);
627
628 switch (type) {
629 case GST_PLAY_MESSAGE_URI_LOADED:
630 case GST_PLAY_MESSAGE_END_OF_STREAM:
631 case GST_PLAY_MESSAGE_MEDIA_INFO_UPDATED:
632 case GST_PLAY_MESSAGE_VOLUME_CHANGED:
633 case GST_PLAY_MESSAGE_MUTE_CHANGED:
634 case GST_PLAY_MESSAGE_SEEK_DONE:
635 return dbg << type;
636
637 case GST_PLAY_MESSAGE_POSITION_UPDATED: {
638 GstClockTime position;
639 gst_play_message_parse_position_updated(m.msg, &position);
640 return dbg << type << nanoseconds(position);
641 }
642 case GST_PLAY_MESSAGE_DURATION_CHANGED: {
643 GstClockTime duration;
644 gst_play_message_parse_duration_updated(m.msg, &duration);
645 return dbg << type << nanoseconds(duration);
646 }
647
648 case GST_PLAY_MESSAGE_STATE_CHANGED: {
649 GstPlayState state;
650 gst_play_message_parse_state_changed(m.msg, &state);
651 return dbg << type << state;
652 }
653 case GST_PLAY_MESSAGE_BUFFERING: {
654 guint percent;
655 gst_play_message_parse_buffering_percent(m.msg, &percent);
656 return dbg << type << percent;
657 }
658 case GST_PLAY_MESSAGE_ERROR: {
659 QUniqueGErrorHandle err;
660 QUniqueGstStructureHandle details;
661 gst_play_message_parse_error(m.msg, &err, &details);
662 return dbg << type << err << details.get();
663 }
664 case GST_PLAY_MESSAGE_WARNING: {
665 QUniqueGErrorHandle err;
666 QUniqueGstStructureHandle details;
667 gst_play_message_parse_warning(m.msg, &err, &details);
668 return dbg << type << err << details.get();
669 };
670
671 case GST_PLAY_MESSAGE_VIDEO_DIMENSIONS_CHANGED: {
672 guint width, height;
673 gst_play_message_parse_video_dimensions_changed(m.msg, &width, &height);
674 return dbg << type << QSize(width, height);
675 }
676 default:
677 Q_UNREACHABLE_RETURN(dbg);
678 }
679}
680
681QT_END_NAMESPACE
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
Definition qcore_mac.mm:201
QDebug operator<<(QDebug dbg, const QFileInfo &fi)
#define ADD_ENUM_SWITCH(value)
QDebug operator<<(QDebug, const QGstCaps &)
QDebug operator<<(QDebug, const QGstPlayMessageAdaptor &)
QDebug operator<<(QDebug, const QGstPad &)
QDebug operator<<(QDebug, const QGstElement &)
QDebug operator<<(QDebug, const QGValue &)
QDebug operator<<(QDebug, const QGstreamerMessage &)
QDebug operator<<(QDebug, const QGstStructureView &)
QDebug operator<<(QDebug, const QCompactGstMessageAdaptor &)
QDebug operator<<(QDebug debug, QIODevice::OpenMode modes)
QCompactGstMessageAdaptor(const QGstreamerMessage &m)
QCompactGstMessageAdaptor(GstMessage *m)
QGstPlayMessageAdaptor(const QGstreamerMessage &m)
QGstPlayMessageAdaptor(GstMessage *m)