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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtmultimedia/src/plugins/multimedia/gstreamer/common/qgst_debug.cpp