Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1-only */
2 : /**
3 : * GStreamer/NNStreamer tensor_debug
4 : * Copyright (C) 2022 MyungJoo Ham <myungjoo.ham@samsung.com>
5 : */
6 : /**
7 : * @file gsttensor_debug.c
8 : * @date 23 Sep 2022
9 : * @brief GStreamer plugin to help debug tensor streams.
10 : *
11 : * @see https://github.com/nnstreamer/nnstreamer
12 : * @author MyungJoo Ham <myungjoo.ham@samsung.com>
13 : * @bug No known bugs except for NYI items
14 : */
15 :
16 : /**
17 : * SECTION:element-tensor_debug
18 : *
19 : * A filter that generates debug messages for developer at the insertion
20 : * point of the given pipeline. An application writer using an nnstreamer
21 : * pipeline can use tensor_debug to debug or get profile information in their
22 : * applications.
23 : *
24 : * Note that this does not support other/tensor, but only supports other/tensors.
25 : *
26 : * <refsect2>
27 : * <title>Example launch line</title>
28 : * |[
29 : * gst-launch-1.0 videotestsrc ! video/x-raw,format=RGB,width=640,height=480 ! tensor_converter ! tensor_debug output-method=console-info capability=always ! tensor_sink
30 : * ]|
31 : * </refsect2>
32 : */
33 :
34 : #ifdef HAVE_CONFIG_H
35 : #include <config.h>
36 : #endif
37 :
38 : #include <string.h>
39 : #include <nnstreamer_log.h>
40 : #include <nnstreamer_util.h>
41 : #include "gsttensor_debug.h"
42 : #include "tensor_meta.h"
43 :
44 : /**
45 : * @brief Macro for debug mode.
46 : */
47 : #ifndef DBG
48 : #define DBG (!self->silent)
49 : #endif
50 :
51 : GST_DEBUG_CATEGORY_STATIC (gst_tensor_debug_debug);
52 : #define GST_CAT_DEFAULT gst_tensor_debug_debug
53 :
54 : /**
55 : * This is a new element created after the obsoletion of other/tensor.
56 : * Use other/tensors if you want to use tensor_debug
57 : */
58 : #define CAPS_STRING GST_TENSORS_CAP_MAKE(GST_TENSOR_FORMAT_ALL)
59 :
60 : /**
61 : * @brief The capabilities of the inputs
62 : */
63 : static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
64 : GST_PAD_SINK,
65 : GST_PAD_ALWAYS,
66 : GST_STATIC_CAPS (CAPS_STRING));
67 :
68 : /**
69 : * @brief The capabilities of the outputs
70 : */
71 : static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
72 : GST_PAD_SRC,
73 : GST_PAD_ALWAYS,
74 : GST_STATIC_CAPS (CAPS_STRING));
75 :
76 : /**
77 : * @brief tensor_debug properties
78 : */
79 : enum
80 : {
81 : PROP_0,
82 : PROP_SILENT,
83 : PROP_OUTPUT,
84 : PROP_CAP,
85 : PROP_META,
86 : };
87 :
88 : #define C_FLAGS(v) ((guint) v)
89 :
90 : #define TENSOR_DEBUG_TYPE_OUTPUT_FLAGS (tensor_debug_output_flags_get_type())
91 : /**
92 : * @brief Flags for output_mode of GstTensorDebug
93 : */
94 : static GType
95 0 : tensor_debug_output_flags_get_type (void)
96 : {
97 : static GType type = G_TYPE_INVALID;
98 :
99 0 : if (type == G_TYPE_INVALID) {
100 : static const GFlagsValue values[] = {
101 : {C_FLAGS (TDBG_OUTPUT_DISABLED),
102 : "Disable log output and write. Do not add other flags to have this flag effective.",
103 : "disabled"},
104 : {C_FLAGS (TDBG_OUTPUT_CONSOLE_I),
105 : "Console output with info. Cannot combine with other console flags",
106 : "console-info"},
107 : {C_FLAGS (TDBG_OUTPUT_CONSOLE_W),
108 : "Console output with warning. Cannot combine with other console flags",
109 : "console-warn"},
110 : {C_FLAGS (TDBG_OUTPUT_CONSOLE_E),
111 : "Console output with error. Cannot combine with other console flags",
112 : "console-error"},
113 : {C_FLAGS (TDBG_OUTPUT_GSTDBG_I),
114 : "Gstlog output with info. Cannot combine with other gstdbg flags",
115 : "gstdebug-info"},
116 : {C_FLAGS (TDBG_OUTPUT_GSTDBG_W),
117 : "Gstlog output with warning. Cannot combine with other gstdbg flags",
118 : "gstdebug-warn"},
119 : {C_FLAGS (TDBG_OUTPUT_GSTDBG_E),
120 : "Gstlog output with error. Cannot combine with other gstdbg flags",
121 : "gstdebug-error"},
122 : {C_FLAGS (TDBG_OUTPUT_CIRCULARBUF),
123 : "Store at gsttensor_debug circular buffer so that it can be retrieved by the application later (NYI)",
124 : "circularbuf"},
125 : {C_FLAGS (TDBG_OUTPUT_FILEWRITE),
126 : "Write to a file (NYI)", "filewrite"},
127 : {0, NULL, NULL}
128 : };
129 0 : type = g_flags_register_static ("gtd_output", values);
130 : }
131 :
132 0 : return type;
133 : }
134 :
135 : #define DEFAULT_TENSOR_DEBUG_OUTPUT_FLAGS (TDBG_OUTPUT_CONSOLE_I)
136 :
137 : #define TENSOR_DEBUG_TYPE_CAPS (tensor_debug_cap_get_type())
138 : /**
139 : * @brief Enums for cap_mode of GstTensorDebug
140 : */
141 : static GType
142 0 : tensor_debug_cap_get_type (void)
143 : {
144 : static GType type = G_TYPE_INVALID;
145 0 : if (type == G_TYPE_INVALID) {
146 : static GEnumValue values[] = {
147 : {TDBG_CAP_DISABLED, "disabled", "Do not log stream capability"},
148 : {TDBG_CAP_SHOW_UPDATE, "updates",
149 : "Log stream capability if it is updated or initialized."},
150 : {TDBG_CAP_SHOW_UPDATE_F, "updates-full",
151 : "Log stream capability if the capability or dimensions of flexible/sparse tensors are updated. Logs dimension info of flexible/sparse tensors as well."},
152 : {TDBG_CAP_SHOW_ALWAYS, "always",
153 : "Always, log stream capability and tensor dimension information."},
154 : {0, NULL, NULL}
155 : };
156 0 : type = g_enum_register_static ("gtd_cap", values);
157 : }
158 0 : return type;
159 : }
160 :
161 : #define DEFAULT_TENSOR_DEBUG_CAP (TDBG_CAP_SHOW_UPDATE_F)
162 :
163 : #define TENSOR_DEBUG_TYPE_META_FLAGS (tensor_debug_meta_flags_get_type())
164 : /**
165 : * @brief Flags for meta_mode of GstTensorDebug
166 : */
167 : static GType
168 0 : tensor_debug_meta_flags_get_type (void)
169 : {
170 : static GType type = G_TYPE_INVALID;
171 :
172 0 : if (type == G_TYPE_INVALID) {
173 : static const GFlagsValue values[] = {
174 : {C_FLAGS (TDBG_META_DISABLED),
175 : "Do not log stream metadata.", "disabled"},
176 : {C_FLAGS (TDBG_META_TIMESTAMP), "Log timestamp information", "timestamp"},
177 : {C_FLAGS (TDBG_META_QUERYSERVER),
178 : "Log tensor-query-server related information", "queryserver"},
179 : {0, NULL, NULL}
180 : };
181 0 : type = g_flags_register_static ("gtd_meta", values);
182 : }
183 0 : return type;
184 : }
185 :
186 : #define DEFAULT_TENSOR_DEBUG_META_FLAGS (TDBG_META_DISABLED)
187 :
188 : /**
189 : * @brief Flag to print minimized log.
190 : */
191 : #define DEFAULT_SILENT TRUE
192 :
193 : #define gst_tensor_debug_parent_class parent_class
194 864 : G_DEFINE_TYPE (GstTensorDebug, gst_tensor_debug, GST_TYPE_BASE_TRANSFORM);
195 :
196 : /* gobject vmethods */
197 : static void gst_tensor_debug_set_property (GObject * object,
198 : guint prop_id, const GValue * value, GParamSpec * pspec);
199 : static void gst_tensor_debug_get_property (GObject * object,
200 : guint prop_id, GValue * value, GParamSpec * pspec);
201 : static void gst_tensor_debug_finalize (GObject * object);
202 :
203 : /* gstbasetransform vmethods */
204 : static GstFlowReturn gst_tensor_debug_transform_ip (GstBaseTransform * trans,
205 : GstBuffer * buffer);
206 : static GstCaps *gst_tensor_debug_fixate_caps (GstBaseTransform * trans,
207 : GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
208 : static gboolean gst_tensor_debug_set_caps (GstBaseTransform * trans,
209 : GstCaps * incaps, GstCaps * outcaps);
210 :
211 : /**
212 : * @brief Initialize the tensor_debug's class.
213 : */
214 : static void
215 0 : gst_tensor_debug_class_init (GstTensorDebugClass * klass)
216 : {
217 : GObjectClass *object_class;
218 : GstElementClass *element_class;
219 : GstBaseTransformClass *trans_class;
220 :
221 0 : GST_DEBUG_CATEGORY_INIT (gst_tensor_debug_debug, "tensor_debug", 0,
222 : "Element to provide debug information of other/tensors streams. If this is enabled, the pipeline performance and overhead may be deteriorated significantly.");
223 :
224 0 : trans_class = (GstBaseTransformClass *) klass;
225 0 : object_class = (GObjectClass *) klass;
226 0 : element_class = (GstElementClass *) klass;
227 :
228 : /* GObjectClass vmethods */
229 0 : object_class->set_property = gst_tensor_debug_set_property;
230 0 : object_class->get_property = gst_tensor_debug_get_property;
231 0 : object_class->finalize = gst_tensor_debug_finalize;
232 :
233 : /**
234 : * GstTensorDebug::silent:
235 : *
236 : * The flag to enable/disable debugging messages.
237 : */
238 0 : g_object_class_install_property (object_class, PROP_SILENT,
239 : g_param_spec_boolean ("silent", "silent", "Produce verbose output",
240 : DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
241 :
242 : /**
243 : * GstTensorDebug::output:
244 : *
245 : * The combination of enums configuring output methods.
246 : * @todo check the behavior of name and nick (output methods vs output)
247 : */
248 0 : g_object_class_install_property (object_class, PROP_OUTPUT,
249 : g_param_spec_flags ("output-method", "output",
250 : "Output methods for debug/profile contents. Different methods can be enabled simultaneously.",
251 : TENSOR_DEBUG_TYPE_OUTPUT_FLAGS, DEFAULT_TENSOR_DEBUG_OUTPUT_FLAGS,
252 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
253 :
254 : /**
255 : * GstTensorDebug::cap:
256 : *
257 : * The logging preference of the stream capability (GSTCAP).
258 : */
259 0 : g_object_class_install_property (object_class, PROP_CAP,
260 : g_param_spec_enum ("capability", "cap",
261 : "The logging preference for stream capability (GSTCAP)",
262 : TENSOR_DEBUG_TYPE_CAPS, DEFAULT_TENSOR_DEBUG_CAP,
263 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
264 :
265 : /**
266 : * GstTensorDebug::meta:
267 : *
268 : * The logging preference of in-stream metadata (GSTMETA).
269 : */
270 0 : g_object_class_install_property (object_class, PROP_META,
271 : g_param_spec_flags ("metadata", "meta",
272 : "The logging preference for stream metadata (GstMeta)",
273 : TENSOR_DEBUG_TYPE_META_FLAGS, DEFAULT_TENSOR_DEBUG_META_FLAGS,
274 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
275 :
276 :
277 : /* set pad template */
278 0 : gst_element_class_add_pad_template (element_class,
279 : gst_static_pad_template_get (&src_factory));
280 0 : gst_element_class_add_pad_template (element_class,
281 : gst_static_pad_template_get (&sink_factory));
282 :
283 0 : gst_element_class_set_static_metadata (element_class,
284 : "TensorDebug",
285 : "Filter/Tensor",
286 : "Help debug or profile a tensor stream by logging the desired details of other/tensors. Users may log the details to console, files, or memory buffers.",
287 : "MyungJoo Ham <myungjoo.ham@samsung.com>");
288 :
289 : /* GstBaseTransform vmethods */
290 0 : trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_tensor_debug_transform_ip);
291 :
292 0 : trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_tensor_debug_fixate_caps);
293 0 : trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_tensor_debug_set_caps);
294 :
295 : /* GstBaseTransform Property */
296 0 : trans_class->passthrough_on_same_caps = TRUE;
297 : /** This won't modify the contents! */
298 0 : trans_class->transform_ip_on_passthrough = TRUE;
299 : /** call transform_ip although it's passthrough */
300 :
301 : /**
302 : * Note.
303 : * Without transform_caps and with passthrough_on_same_caps = TRUE,
304 : * This element is not allowed to touch the contents, but can inspect
305 : * the contents with transform_ip by setting transform_ip_on_passthrough.
306 : */
307 0 : }
308 :
309 : /**
310 : * @brief Initialize tensor_debug element.
311 : */
312 : static void
313 0 : gst_tensor_debug_init (GstTensorDebug * self)
314 : {
315 : /** init properties */
316 0 : self->silent = DEFAULT_SILENT;
317 0 : self->output_mode = DEFAULT_TENSOR_DEBUG_OUTPUT_FLAGS;
318 0 : self->cap_mode = DEFAULT_TENSOR_DEBUG_CAP;
319 0 : self->meta_mode = DEFAULT_TENSOR_DEBUG_META_FLAGS;
320 :
321 0 : }
322 :
323 : /**
324 : * @brief Function to finalize instance.
325 : */
326 : static void
327 0 : gst_tensor_debug_finalize (GObject * object)
328 : {
329 0 : G_OBJECT_CLASS (parent_class)->finalize (object);
330 0 : }
331 :
332 : /**
333 : * @brief Setter for tensor_debug properties.
334 : */
335 : static void
336 0 : gst_tensor_debug_set_property (GObject * object, guint prop_id,
337 : const GValue * value, GParamSpec * pspec)
338 : {
339 0 : GstTensorDebug *self = GST_TENSOR_DEBUG (object);
340 :
341 0 : switch (prop_id) {
342 0 : case PROP_SILENT:
343 0 : self->silent = g_value_get_boolean (value);
344 0 : silent_debug (self, "Set silent = %d", self->silent);
345 0 : break;
346 0 : case PROP_OUTPUT:
347 0 : self->output_mode = g_value_get_flags (value);
348 0 : silent_debug (self, "Set output = %x", self->output_mode);
349 0 : break;
350 0 : case PROP_CAP:
351 0 : self->cap_mode = g_value_get_enum (value);
352 0 : silent_debug (self, "Set cap = %x", self->cap_mode);
353 0 : break;
354 0 : case PROP_META:
355 0 : self->meta_mode = g_value_get_flags (value);
356 0 : silent_debug (self, "Set meta = %x", self->meta_mode);
357 0 : break;
358 0 : default:
359 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
360 0 : break;
361 : }
362 0 : }
363 :
364 : /**
365 : * @brief Getter for tensor_debug properties.
366 : */
367 : static void
368 0 : gst_tensor_debug_get_property (GObject * object, guint prop_id,
369 : GValue * value, GParamSpec * pspec)
370 : {
371 0 : GstTensorDebug *self = GST_TENSOR_DEBUG (object);
372 :
373 0 : switch (prop_id) {
374 0 : case PROP_SILENT:
375 0 : g_value_set_boolean (value, self->silent);
376 0 : break;
377 0 : case PROP_OUTPUT:
378 0 : g_value_set_flags (value, self->output_mode);
379 0 : break;
380 0 : case PROP_CAP:
381 0 : g_value_set_enum (value, self->cap_mode);
382 0 : break;
383 0 : case PROP_META:
384 0 : g_value_set_flags (value, self->meta_mode);
385 0 : break;
386 0 : default:
387 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
388 0 : break;
389 : }
390 0 : }
391 :
392 : /**
393 : * @brief The core function that provides debug output based
394 : * on the contents.
395 : */
396 : static void
397 0 : _gst_tensor_debug_output (GstTensorDebug * self, GstBuffer * buffer)
398 : {
399 : UNUSED (self);
400 : UNUSED (buffer);
401 : /** @todo NYI: do the debug task */
402 0 : }
403 :
404 : /**
405 : * @brief in-place transform
406 : */
407 : static GstFlowReturn
408 0 : gst_tensor_debug_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
409 : {
410 0 : GstTensorDebug *self = GST_TENSOR_DEBUG (trans);
411 :
412 0 : _gst_tensor_debug_output (self, buffer);
413 :
414 0 : return GST_FLOW_OK;
415 : }
416 :
417 : /**
418 : * @brief fixate caps. required vmethod of GstBaseTransform.
419 : */
420 : static GstCaps *
421 0 : gst_tensor_debug_fixate_caps (GstBaseTransform * trans,
422 : GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
423 : {
424 : UNUSED (trans);
425 : UNUSED (direction);
426 : UNUSED (caps);
427 :
428 0 : return gst_caps_fixate (othercaps);
429 : }
430 :
431 : /**
432 : * @brief set caps. required vmethod of GstBaseTransform.
433 : */
434 : static gboolean
435 0 : gst_tensor_debug_set_caps (GstBaseTransform * trans,
436 : GstCaps * in_caps, GstCaps * out_caps)
437 : {
438 : UNUSED (trans);
439 :
440 0 : return gst_caps_can_intersect (in_caps, out_caps);
441 : }
|