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 if (!value)
457 return dbg << "null";
458
459 switch (G_VALUE_TYPE(value)) {
460 case G_TYPE_STRING:
461 return dbg << g_value_get_string(value);
462 case G_TYPE_BOOLEAN:
463 return dbg << g_value_get_boolean(value);
464 case G_TYPE_ULONG:
465 return dbg << g_value_get_ulong(value);
466 case G_TYPE_LONG:
467 return dbg << g_value_get_long(value);
468 case G_TYPE_UINT:
469 return dbg << g_value_get_uint(value);
470 case G_TYPE_INT:
471 return dbg << g_value_get_int(value);
472 case G_TYPE_UINT64:
473 return dbg << g_value_get_uint64(value);
474 case G_TYPE_INT64:
475 return dbg << g_value_get_int64(value);
476 case G_TYPE_FLOAT:
477 return dbg << g_value_get_float(value);
478 case G_TYPE_DOUBLE:
479 return dbg << g_value_get_double(value);
480 default:
481 break;
482 }
483
484 if (GST_VALUE_HOLDS_BITMASK(value)) {
485 QDebugStateSaver saver(dbg);
486 return dbg << Qt::hex << gst_value_get_bitmask(value);
487 }
488
489 if (GST_VALUE_HOLDS_FRACTION(value))
490 return dbg << gst_value_get_fraction_numerator(value) << "/"
491 << gst_value_get_fraction_denominator(value);
492
493 if (GST_VALUE_HOLDS_CAPS(value))
494 return dbg << gst_value_get_caps(value);
495
496 if (GST_VALUE_HOLDS_STRUCTURE(value))
497 return dbg << gst_value_get_structure(value);
498
499 if (GST_VALUE_HOLDS_ARRAY(value)) {
500 const guint size = gst_value_array_get_size(value);
501 const guint last = size - 1;
502 dbg << "[";
503 for (guint index = 0; index != size; ++index) {
504 dbg << gst_value_array_get_value(value, index);
505 if (index != last)
506 dbg << ", ";
507 }
508 dbg << "}";
509 return dbg;
510 }
511
512 if (G_VALUE_TYPE(value) == GST_TYPE_PAD_DIRECTION) {
513 GstPadDirection direction = static_cast<GstPadDirection>(g_value_get_enum(value));
514 return dbg << direction;
515 }
516
517 if (G_VALUE_TYPE(value) == GST_TYPE_PAD_TEMPLATE) {
518 GstPadTemplate *padTemplate = static_cast<GstPadTemplate *>(g_value_get_object(value));
519 return dbg << padTemplate;
520 }
521
522 dbg << "(not implemented: " << G_VALUE_TYPE_NAME(value) << ")";
523
524 return dbg;
525}
526
527QDebug operator<<(QDebug dbg, const GError *error)
528{
529 return dbg << error->message;
530}
531
538
540 : msg{
541 m,
542 }
543{
544}
545
547{
548 std::optional<QDebugStateSaver> saver(dbg);
549 dbg.nospace();
550
551 switch (GST_MESSAGE_TYPE(m.msg)) {
552 case GST_MESSAGE_ERROR: {
553 QUniqueGErrorHandle err;
554 QGString debug;
555 gst_message_parse_error(m.msg, &err, &debug);
556 dbg << err << " (" << debug << ")";
557 return dbg;
558 }
559
560 case GST_MESSAGE_WARNING: {
561 QUniqueGErrorHandle err;
562 QGString debug;
563 gst_message_parse_warning(m.msg, &err, &debug);
564 dbg << err << " (" << debug << ")";
565 return dbg;
566 }
567
568 case GST_MESSAGE_INFO: {
569 QUniqueGErrorHandle err;
570 QGString debug;
571 gst_message_parse_info(m.msg, &err, &debug);
572
573 dbg << err << " (" << debug << ")";
574 return dbg;
575 }
576
577 case GST_MESSAGE_STATE_CHANGED: {
578 GstState oldState;
579 GstState newState;
580 GstState pending;
581
582 gst_message_parse_state_changed(m.msg, &oldState, &newState, &pending);
583
584 dbg << oldState << " -> " << newState;
585 if (pending != GST_STATE_VOID_PENDING)
586 dbg << " (pending: " << pending << ")";
587 return dbg;
588 }
589
590 default: {
591 saver.reset();
592 return dbg << m.msg;
593 }
594 }
595}
596
597QDebug operator<<(QDebug dbg, GstPlayMessage type)
598{
599 return dbg << gst_play_message_get_name(type);
600}
601
602QDebug operator<<(QDebug dbg, GstPlayState state)
603{
604 return dbg << gst_play_state_get_name(state);
605}
606
613
615 : msg{
616 m,
617 }
618{
619}
620
622{
623 using namespace std::chrono;
624 Q_ASSERT(gst_play_is_play_message(m.msg));
625
626 std::optional<QDebugStateSaver> saver(dbg);
627
628 GstPlayMessage type;
629 gst_play_message_parse_type(m.msg, &type);
630
631 switch (type) {
632 case GST_PLAY_MESSAGE_URI_LOADED:
633 case GST_PLAY_MESSAGE_END_OF_STREAM:
634 case GST_PLAY_MESSAGE_MEDIA_INFO_UPDATED:
635 case GST_PLAY_MESSAGE_VOLUME_CHANGED:
636 case GST_PLAY_MESSAGE_MUTE_CHANGED:
637 case GST_PLAY_MESSAGE_SEEK_DONE:
638 return dbg << type;
639
640 case GST_PLAY_MESSAGE_POSITION_UPDATED: {
641 GstClockTime position;
642 gst_play_message_parse_position_updated(m.msg, &position);
643 return dbg << type << nanoseconds(position);
644 }
645 case GST_PLAY_MESSAGE_DURATION_CHANGED: {
646 GstClockTime duration;
647 gst_play_message_parse_duration_updated(m.msg, &duration);
648 return dbg << type << nanoseconds(duration);
649 }
650
651 case GST_PLAY_MESSAGE_STATE_CHANGED: {
652 GstPlayState state;
653 gst_play_message_parse_state_changed(m.msg, &state);
654 return dbg << type << state;
655 }
656 case GST_PLAY_MESSAGE_BUFFERING: {
657 guint percent;
658 gst_play_message_parse_buffering_percent(m.msg, &percent);
659 return dbg << type << percent;
660 }
661 case GST_PLAY_MESSAGE_ERROR: {
662 QUniqueGErrorHandle err;
663 QUniqueGstStructureHandle details;
664 gst_play_message_parse_error(m.msg, &err, &details);
665 return dbg << type << err << details.get();
666 }
667 case GST_PLAY_MESSAGE_WARNING: {
668 QUniqueGErrorHandle err;
669 QUniqueGstStructureHandle details;
670 gst_play_message_parse_warning(m.msg, &err, &details);
671 return dbg << type << err << details.get();
672 };
673
674 case GST_PLAY_MESSAGE_VIDEO_DIMENSIONS_CHANGED: {
675 guint width, height;
676 gst_play_message_parse_video_dimensions_changed(m.msg, &width, &height);
677 return dbg << type << QSize(width, height);
678 }
679 default:
680 Q_UNREACHABLE_RETURN(dbg);
681 }
682}
683
684QT_END_NAMESPACE
Combined button and popup list for selecting options.
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
Definition qcore_mac.mm:207
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)