Doxygen Book
gsttensor_rate.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: LGPL-2.1-only */
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46 
47 #include <nnstreamer_log.h>
48 #include <nnstreamer_util.h>
49 
50 #include "gsttensor_rate.h"
51 
55 #ifndef DBG
56 #define DBG (!self->silent)
57 #endif
58 
59 #ifndef ABSDIFF
60 #define ABSDIFF(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
61 #endif
62 
63 GST_DEBUG_CATEGORY_STATIC (gst_tensor_rate_debug);
64 #define GST_CAT_DEFAULT gst_tensor_rate_debug
65 
66 #define CAPS_STRING GST_TENSOR_CAP_DEFAULT "; " GST_TENSORS_CAP_DEFAULT
67 
68 #define GST_TENSOR_RATE_SCALED_TIME(self, count)\
69  gst_util_uint64_scale (count,\
70  self->to_rate_denominator * GST_SECOND, self->to_rate_numerator)
71 
73 #define DEFAULT_SILENT TRUE
74 #define DEFAULT_THROTTLE TRUE
75 
79 enum
80 {
89 };
90 
94 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
95  GST_PAD_SINK,
96  GST_PAD_ALWAYS,
97  GST_STATIC_CAPS (CAPS_STRING));
98 
102 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
103  GST_PAD_SRC,
104  GST_PAD_ALWAYS,
105  GST_STATIC_CAPS (CAPS_STRING));
106 
107 static GParamSpec *pspec_drop = NULL;
108 static GParamSpec *pspec_duplicate = NULL;
109 
110 #define gst_tensor_rate_parent_class parent_class
111 G_DEFINE_TYPE (GstTensorRate, gst_tensor_rate, GST_TYPE_BASE_TRANSFORM);
112 
113 /* GObject vmethod implementations */
114 static void gst_tensor_rate_set_property (GObject * object, guint prop_id,
115  const GValue * value, GParamSpec * pspec);
116 static void gst_tensor_rate_get_property (GObject * object, guint prop_id,
117  GValue * value, GParamSpec * pspec);
118 static void gst_tensor_rate_finalize (GObject * object);
119 
120 /* GstBaseTransform vmethod implementations */
121 static GstFlowReturn gst_tensor_rate_transform_ip (GstBaseTransform * trans,
122  GstBuffer * buffer);
123 static GstCaps *gst_tensor_rate_transform_caps (GstBaseTransform * trans,
124  GstPadDirection direction, GstCaps * caps, GstCaps * _rate);
125 static GstCaps *gst_tensor_rate_fixate_caps (GstBaseTransform * trans,
126  GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
127 static gboolean gst_tensor_rate_set_caps (GstBaseTransform * trans,
128  GstCaps * incaps, GstCaps * outcaps);
129 static void gst_tensor_rate_swap_prev (GstTensorRate * self,
130  GstBuffer * buffer, gint64 time);
131 static GstFlowReturn gst_tensor_rate_flush_prev (GstTensorRate * self,
132  gboolean duplicate, GstClockTime next_intime);
133 
134 static void gst_tensor_rate_notify_drop (GstTensorRate * self);
136 
137 static gboolean gst_tensor_rate_start (GstBaseTransform * trans);
138 static gboolean gst_tensor_rate_stop (GstBaseTransform * trans);
139 static gboolean gst_tensor_rate_sink_event (GstBaseTransform * trans,
140  GstEvent * event);
141 
142 static void gst_tensor_rate_install_properties (GObjectClass * gobject_class);
143 
147 static void
149 {
150  GObjectClass *gobject_class;
151  GstElementClass *gstelement_class;
152  GstBaseTransformClass *trans_class;
153 
154  GST_DEBUG_CATEGORY_INIT (gst_tensor_rate_debug, "tensor_rate", 0,
155  "Tensor Rate to control streams based on tensor(s) values");
156 
157  trans_class = (GstBaseTransformClass *) klass;
158  gstelement_class = (GstElementClass *) trans_class;
159  gobject_class = (GObjectClass *) gstelement_class;
160 
161  gobject_class->set_property = gst_tensor_rate_set_property;
162  gobject_class->get_property = gst_tensor_rate_get_property;
163  gobject_class->finalize = gst_tensor_rate_finalize;
164 
165  gst_tensor_rate_install_properties (gobject_class);
166 
167  gst_element_class_set_details_simple (gstelement_class,
168  "TensorRate",
169  "Filter/Tensor",
170  "Adjusts a framerate of incoming tensors",
171  "Dongju Chae <dongju.chae@samsung.com>");
172 
173  gst_element_class_add_pad_template (gstelement_class,
174  gst_static_pad_template_get (&src_factory));
175  gst_element_class_add_pad_template (gstelement_class,
176  gst_static_pad_template_get (&sink_factory));
177 
178  trans_class->passthrough_on_same_caps = TRUE;
179  trans_class->transform_ip_on_passthrough = TRUE;
180 
181  /* Processing units */
182  trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_tensor_rate_transform_ip);
183 
184  /* Negotiation units */
185  trans_class->transform_caps =
186  GST_DEBUG_FUNCPTR (gst_tensor_rate_transform_caps);
187  trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_tensor_rate_fixate_caps);
188  trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_tensor_rate_set_caps);
189 
190  /* setup sink event */
191  trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_tensor_rate_sink_event);
192 
193  /* start/stop to call open/close */
194  trans_class->start = GST_DEBUG_FUNCPTR (gst_tensor_rate_start);
195  trans_class->stop = GST_DEBUG_FUNCPTR (gst_tensor_rate_stop);
196 }
197 
201 static GstFlowReturn
202 gst_tensor_rate_push_buffer (GstTensorRate * self, GstBuffer * outbuf,
203  gboolean duplicate, GstClockTime next_intime)
204 {
205  GstFlowReturn res;
206  GstClockTime push_ts;
207  UNUSED (next_intime);
208 
209  GST_BUFFER_OFFSET (outbuf) = self->out;
210  GST_BUFFER_OFFSET_END (outbuf) = self->out + 1;
211  GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DISCONT);
212 
213  if (duplicate)
214  GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
215  else
216  GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_GAP);
217 
218  /* this is the timestamp we put on the buffer */
219  push_ts = self->next_ts;
220 
221  self->out++;
222  self->out_frame_count++;
223 
224  if (self->to_rate_numerator) {
225  GstClockTimeDiff duration;
226 
227  duration = GST_TENSOR_RATE_SCALED_TIME (self, self->out_frame_count);
228 
229  /* interpolate next expected timestamp in the segment */
230  self->next_ts = self->segment.base + self->segment.start +
231  self->base_ts + duration;
232 
233  GST_BUFFER_DURATION (outbuf) = self->next_ts - push_ts;
234  } else {
237  g_assert (GST_BUFFER_PTS_IS_VALID (outbuf));
238  g_assert (GST_BUFFER_DURATION_IS_VALID (outbuf));
239  g_assert (GST_BUFFER_DURATION (outbuf) != 0);
240 
241  self->next_ts = GST_BUFFER_PTS (outbuf) + GST_BUFFER_DURATION (outbuf);
242  }
243 
244  /* adapt for looping, bring back to time in current segment. */
245  GST_BUFFER_TIMESTAMP (outbuf) = push_ts - self->segment.base;
246 
247  silent_debug (self, "old is best, dup, pushing buffer outgoing ts %"
248  GST_TIME_FORMAT, GST_TIME_ARGS (push_ts));
249 
250  res = gst_pad_push (GST_BASE_TRANSFORM_SRC_PAD (self), outbuf);
251 
252  return res;
253 }
254 
258 static GstFlowReturn
259 gst_tensor_rate_flush_prev (GstTensorRate * self, gboolean duplicate,
260  GstClockTime next_intime)
261 {
262  GstBuffer *outbuf;
263 
264  if (!self->prevbuf) {
265  ml_logi ("got EOS before any buffer was received");
266  return GST_FLOW_OK;
267  }
268 
269  outbuf = gst_buffer_ref (self->prevbuf);
270  /* make sure we can write to the metadata */
271  outbuf = gst_buffer_make_writable (outbuf);
272 
273  return gst_tensor_rate_push_buffer (self, outbuf, duplicate, next_intime);
274 }
275 
279 static void
280 gst_tensor_rate_swap_prev (GstTensorRate * self, GstBuffer * buffer,
281  gint64 time)
282 {
283  silent_debug (self, "swap_prev: storing buffer %p in prev", buffer);
284 
285  if (self->prevbuf)
286  gst_buffer_unref (self->prevbuf);
287  self->prevbuf = buffer != NULL ? gst_buffer_ref (buffer) : NULL;
288  self->prev_ts = time;
289 }
290 
294 static void
296 {
297  self->in = 0;
298  self->out = 0;
299  self->drop = 0;
300  self->dup = 0;
301 
302  self->out_frame_count = 0;
303 
304  self->base_ts = 0;
305  self->next_ts = GST_CLOCK_TIME_NONE;
306  self->last_ts = GST_CLOCK_TIME_NONE;
307 
308  self->sent_qos_on_passthrough = FALSE;
309 
310  gst_tensor_rate_swap_prev (self, NULL, 0);
311 }
312 
316 static void
318 {
319  gst_tensor_rate_reset (self);
320 
321  self->silent = DEFAULT_SILENT;
322  self->throttle = DEFAULT_THROTTLE;
323 
324  /* decided from caps negotiation */
325  self->from_rate_numerator = 0;
326  self->from_rate_denominator = 0;
327  self->to_rate_numerator = 0;
328  self->to_rate_denominator = 0;
329 
330  /* specified from property */
331  self->rate_n = -1;
332  self->rate_d = -1;
333 
334  gst_segment_init (&self->segment, GST_FORMAT_TIME);
335 }
336 
340 static void
341 gst_tensor_rate_finalize (GObject * object)
342 {
343  G_OBJECT_CLASS (parent_class)->finalize (object);
344 }
345 
349 static void
350 gst_tensor_rate_set_property (GObject * object, guint prop_id,
351  const GValue * value, GParamSpec * pspec)
352 {
353  GstTensorRate *self = GST_TENSOR_RATE (object);
354 
355  GST_OBJECT_LOCK (self);
356 
357  switch (prop_id) {
358  case PROP_SILENT:
359  self->silent = g_value_get_boolean (value);
360  break;
361  case PROP_THROTTLE:
362  self->throttle = g_value_get_boolean (value);
363  break;
364  case PROP_FRAMERATE:
365  {
366  const gchar *str = g_value_get_string (value);
367  gchar **strv = g_strsplit (str, "/", -1);
368  gint rate_n, rate_d;
369 
370  if (g_strv_length (strv) != 2) {
371  ml_loge ("Please specify a proper 'framerate' property");
372  goto done;
373  }
374 
375  rate_n = (gint) g_ascii_strtoll (strv[0], NULL, 10);
376  if (errno == ERANGE || rate_n < 0) {
377  ml_loge ("Invalid frame rate numerator in 'framerate'");
378  goto done;
379  }
380 
381  rate_d = (gint) g_ascii_strtoll (strv[1], NULL, 10);
382  if (errno == ERANGE || rate_d <= 0) {
383  ml_loge ("Invalid frame rate denominator in 'framerate'");
384  goto done;
385  }
386 
387  self->rate_n = rate_n;
388  self->rate_d = rate_d;
389 
390  done:
391  g_strfreev (strv);
392  break;
393  }
394 
395  default:
396  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
397  break;
398  }
399 
400  GST_OBJECT_UNLOCK (self);
401 }
402 
406 static void
407 gst_tensor_rate_get_property (GObject * object, guint prop_id,
408  GValue * value, GParamSpec * pspec)
409 {
410  GstTensorRate *self = GST_TENSOR_RATE (object);
411 
412  GST_OBJECT_LOCK (self);
413 
414  switch (prop_id) {
415  case PROP_IN:
416  g_value_set_uint64 (value, self->in);
417  break;
418  case PROP_OUT:
419  g_value_set_uint64 (value, self->out);
420  break;
421  case PROP_DROP:
422  g_value_set_uint64 (value, self->drop);
423  break;
424  case PROP_DUP:
425  g_value_set_uint64 (value, self->dup);
426  break;
427  case PROP_SILENT:
428  g_value_set_boolean (value, self->silent);
429  break;
430  case PROP_THROTTLE:
431  g_value_set_boolean (value, self->throttle);
432  break;
433  case PROP_FRAMERATE:
434  if (self->rate_n < 0 || self->rate_d <= 0) {
435  g_value_set_string (value, "");
436  } else {
437  gchar *str = g_strdup_printf ("%d/%d", self->rate_n, self->rate_d);
438  g_value_take_string (value, str);
439  }
440  break;
441  default:
442  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
443  break;
444  }
445 
446  GST_OBJECT_UNLOCK (self);
447 }
448 
449 #define THROTTLE_DELAY_RATIO (0.999)
450 
454 static void
455 gst_tensor_rate_send_qos_throttle (GstTensorRate * self, GstClockTime timestamp)
456 {
457  GstPad *sinkpad = GST_BASE_TRANSFORM_SINK_PAD (&self->element);
458  GstClockTimeDiff delay;
459  GstEvent *event;
460 
461  delay = GST_TENSOR_RATE_SCALED_TIME (self, 1);
462  delay = (GstClockTimeDiff) (((gdouble) delay) * THROTTLE_DELAY_RATIO);
463 
464  event = gst_event_new_qos (GST_QOS_TYPE_THROTTLE,
465  0.9 , delay, timestamp);
466 
467  silent_debug (self, "Send throttling event with delay: %" GST_TIME_FORMAT,
468  GST_TIME_ARGS (delay));
469 
470  gst_pad_push_event (sinkpad, event);
471 }
472 
476 static GstFlowReturn
477 gst_tensor_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
478 {
479  GstTensorRate *self = GST_TENSOR_RATE (trans);
480  GstFlowReturn res = GST_BASE_TRANSFORM_FLOW_DROPPED;
481  GstClockTime intime, in_ts, in_dur;
482 
483  /* make sure the denominators are not 0 */
484  if (self->from_rate_denominator == 0 || self->to_rate_denominator == 0) {
485  ml_loge ("No framerate negotiated");
486  return GST_FLOW_NOT_NEGOTIATED;
487  }
488 
489  /* tensor streams do not support reverse playback */
490  if (G_UNLIKELY (self->segment.rate < 0.0)) {
491  ml_loge ("Unsupported reverse playback\n");
492  return GST_FLOW_ERROR;
493  }
494 
495  in_ts = GST_BUFFER_TIMESTAMP (buffer);
496  in_dur = GST_BUFFER_DURATION (buffer);
497 
498  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (in_ts))) {
499  in_ts = self->last_ts;
500  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (in_ts))) {
501  ml_logw ("Discard an invalid buffer");
502  return GST_BASE_TRANSFORM_FLOW_DROPPED;
503  }
504  }
505 
506  self->in++;
507 
508  /* update the last timestamp */
509  self->last_ts = in_ts;
510  if (GST_CLOCK_TIME_IS_VALID (in_dur))
511  self->last_ts += in_dur;
512 
513  silent_debug (self, "got buffer with timestamp %" GST_TIME_FORMAT,
514  GST_TIME_ARGS (in_ts));
515 
516  intime = in_ts + self->segment.base;
517 
518  /* let's send a QoS event even if pass-through is used on the same caps */
519  if (gst_base_transform_is_passthrough (trans)) {
520  if (!self->sent_qos_on_passthrough) {
521  self->sent_qos_on_passthrough = TRUE;
522  gst_tensor_rate_send_qos_throttle (self, intime);
523  }
524 
525  self->out++;
526  return GST_FLOW_OK;
527  }
528 
529  /* we need to have two buffers to compare */
530  if (self->prevbuf == NULL) {
531  gst_tensor_rate_swap_prev (self, buffer, intime);
532  if (!GST_CLOCK_TIME_IS_VALID (self->next_ts)) {
533  self->next_ts = intime;
534  self->base_ts = in_ts - self->segment.start;
535  self->out_frame_count = 0;
536  }
537  } else {
538  GstClockTime prevtime;
539  gint64 diff1 = 0, diff2 = 0;
540  guint count = 0;
541 
542  prevtime = self->prev_ts;
543 
544  silent_debug (self, "BEGINNING prev buf %" GST_TIME_FORMAT " new buf %"
545  GST_TIME_FORMAT " outgoing ts %" GST_TIME_FORMAT,
546  GST_TIME_ARGS (prevtime), GST_TIME_ARGS (intime),
547  GST_TIME_ARGS (self->next_ts));
548 
549  /* drop new buffer if it's before previous one */
550  if (intime < prevtime) {
551  silent_debug (self, "The new buffer (%" GST_TIME_FORMAT ") is before "
552  "the previous buffer (%" GST_TIME_FORMAT
553  "). Dropping new buffer.", GST_TIME_ARGS (intime),
554  GST_TIME_ARGS (prevtime));
555  self->drop++;
556 
557  if (!self->silent)
559 
560  return GST_BASE_TRANSFORM_FLOW_DROPPED;
561  }
562 
563  /* got 2 buffers, see which one is the best */
564  do {
565  GstClockTime next_ts;
566 
567  /* Make sure that we have a duration for previous buffer */
568  if (!GST_BUFFER_DURATION_IS_VALID (self->prevbuf))
569  GST_BUFFER_DURATION (self->prevbuf) =
570  intime > prevtime ? intime - prevtime : 0;
571 
572  next_ts = self->base_ts + (self->next_ts - self->base_ts);
573 
574  diff1 = ABSDIFF (prevtime, next_ts);
575  diff2 = ABSDIFF (intime, next_ts);
576 
577  silent_debug (self, "diff with prev %" GST_TIME_FORMAT
578  " diff with new %" GST_TIME_FORMAT " outgoing ts %"
579  GST_TIME_FORMAT, GST_TIME_ARGS (diff1),
580  GST_TIME_ARGS (diff2), GST_TIME_ARGS (next_ts));
581 
582  /* output first one when its the best */
583  if (diff1 <= diff2) {
584  GstFlowReturn r;
585  count++;
586 
587  /* on error the _flush function posted a warning already */
588  if ((r = gst_tensor_rate_flush_prev (self,
589  count > 1, intime)) != GST_FLOW_OK) {
590  return r;
591  }
592  }
593 
598  } while (diff1 < diff2);
599 
600  /* if we outputted the first buffer more then once, we have dups */
601  if (count > 1) {
602  self->dup += count - 1;
603  if (!self->silent)
605  }
606  /* if we didn't output the first buffer, we have a drop */
607  else if (count == 0) {
608  self->drop++;
609 
610  if (!self->silent)
612 
613  gst_tensor_rate_send_qos_throttle (self, intime);
614  }
615 
616  /* swap in new one when it's the best */
617  gst_tensor_rate_swap_prev (self, buffer, intime);
618  }
619 
620  return res;
621 }
622 
633 static GstCaps *
634 gst_tensor_rate_transform_caps (GstBaseTransform * trans,
635  GstPadDirection direction, GstCaps * caps, GstCaps * filter)
636 {
637  GstTensorRate *self = GST_TENSOR_RATE (trans);
638  GstCaps *result = gst_caps_new_empty ();
639  guint i;
640 
641  silent_debug (self, "Direction = %d\n", direction);
642  silent_debug_caps (self, caps, "from");
643  silent_debug_caps (self, filter, "filter");
644 
645  for (i = 0; i < gst_caps_get_size (caps); i++) {
646  GstStructure *s, *const_s = gst_caps_get_structure (caps, i);
647 
648  s = gst_structure_copy (const_s);
649 
650  /* when a target framerate is specified */
651  if (direction == GST_PAD_SINK && self->rate_n >= 0 && self->rate_d > 0) {
652  gst_structure_set (s, "framerate", GST_TYPE_FRACTION,
653  self->rate_n, self->rate_d, NULL);
654  } else {
655  gst_structure_set (s, "framerate", GST_TYPE_FRACTION_RANGE,
656  0, 1, G_MAXINT, 1, NULL);
657  }
658 
659  result = gst_caps_merge_structure_full (result, s,
660  gst_caps_features_copy (gst_caps_get_features (caps, i)));
661  }
662 
663  if (filter && gst_caps_get_size (filter) > 0) {
664  GstCaps *intersection =
665  gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
666 
667  gst_caps_unref (result);
668  result = intersection;
669  }
670 
671  silent_debug_caps (self, result, "to");
672 
673  return result;
674 }
675 
679 static GstCaps *
680 gst_tensor_rate_fixate_caps (GstBaseTransform * trans,
681  GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
682 {
683  GstStructure *s;
684  gint num, denom;
685  UNUSED (trans);
686  UNUSED (direction);
687 
688  s = gst_caps_get_structure (caps, 0);
689  if (G_UNLIKELY (!gst_structure_get_fraction (s, "framerate", &num, &denom)))
690  return othercaps;
691 
692  othercaps = gst_caps_truncate (othercaps);
693  othercaps = gst_caps_make_writable (othercaps);
694 
695  s = gst_caps_get_structure (othercaps, 0);
696  gst_structure_fixate_field_nearest_fraction (s, "framerate", num, denom);
697 
698  return gst_caps_fixate (othercaps);
699 }
700 
704 static gboolean
705 gst_tensor_rate_set_caps (GstBaseTransform * trans,
706  GstCaps * in_caps, GstCaps * out_caps)
707 {
708  GstTensorRate *self = GST_TENSOR_RATE (trans);
709  GstStructure *structure;
710  gint rate_numerator, rate_denominator;
711 
712  silent_debug (self,
713  "setcaps called in: %" GST_PTR_FORMAT " out: %" GST_PTR_FORMAT, in_caps,
714  out_caps);
715 
716  structure = gst_caps_get_structure (in_caps, 0);
717 
718  if (!gst_structure_get_fraction (structure, "framerate",
719  &rate_numerator, &rate_denominator))
720  goto no_framerate;
721 
722  self->from_rate_numerator = rate_numerator;
723  self->from_rate_denominator = rate_denominator;
724 
725  structure = gst_caps_get_structure (out_caps, 0);
726 
727  if (!gst_structure_get_fraction (structure, "framerate",
728  &rate_numerator, &rate_denominator))
729  goto no_framerate;
730 
731  if (self->to_rate_numerator)
732  self->base_ts += GST_TENSOR_RATE_SCALED_TIME (self, self->out_frame_count);
733 
734  self->out_frame_count = 0;
735  self->to_rate_numerator = rate_numerator;
736  self->to_rate_denominator = rate_denominator;
737 
742  silent_debug (self, "swapping old buffers");
743  gst_tensor_rate_swap_prev (self, NULL, GST_CLOCK_TIME_NONE);
744  self->last_ts = GST_CLOCK_TIME_NONE;
745 
746  return TRUE;
747 
748 no_framerate:
749  silent_debug (self, "no framerate specified");
750  return FALSE;
751 }
752 
757 static void
759 {
760  g_object_notify_by_pspec ((GObject *) self, pspec_drop);
761 }
762 
767 static void
769 {
770  g_object_notify_by_pspec ((GObject *) self, pspec_duplicate);
771 }
772 
773 #define MAGIC_LIMIT 25
774 
780 static gboolean
781 gst_tensor_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
782 {
783  GstTensorRate *self = GST_TENSOR_RATE (trans);
784 
785  switch (GST_EVENT_TYPE (event)) {
786  case GST_EVENT_SEGMENT:
787  {
788  GstSegment segment;
789  gint seqnum;
790 
791  silent_debug (self, "Got %s",
792  gst_event_type_get_name (GST_EVENT_TYPE (event)));
793 
794  gst_event_copy_segment (event, &segment);
795  if (segment.format != GST_FORMAT_TIME) {
796  ml_loge ("Got segment but doesn't have GST_FORMAT_TIME value");
797  return FALSE;
798  }
799 
800  /* close up the previous segment, if appropriate */
801  if (self->prevbuf) {
802  gint count = 0;
803  GstFlowReturn res;
804 
805  res = GST_FLOW_OK;
811  while (res == GST_FLOW_OK && count <= MAGIC_LIMIT
812  && ((GST_CLOCK_TIME_IS_VALID (self->segment.stop)
813  && GST_CLOCK_TIME_IS_VALID (self->next_ts)
814  && self->next_ts - self->segment.base <
815  self->segment.stop) || count < 1)) {
816  res =
817  gst_tensor_rate_flush_prev (self, count > 0, GST_CLOCK_TIME_NONE);
818  count++;
819  }
820  if (count > 1) {
821  self->dup += count - 1;
822  if (!self->silent)
824  }
825  /* clean up for the new one; _chain will resume from the new start */
826  gst_tensor_rate_swap_prev (self, NULL, 0);
827  }
828 
829  self->base_ts = 0;
830  self->out_frame_count = 0;
831  self->next_ts = GST_CLOCK_TIME_NONE;
832 
833  gst_segment_copy_into (&segment, &self->segment);
834 
835  silent_debug (self, "updated segment: %" GST_SEGMENT_FORMAT,
836  &self->segment);
837 
838  seqnum = gst_event_get_seqnum (event);
839  gst_event_unref (event);
840  event = gst_event_new_segment (&segment);
841  gst_event_set_seqnum (event, seqnum);
842 
843  break;
844  }
845  case GST_EVENT_SEGMENT_DONE:
846  case GST_EVENT_EOS:
847  {
848  gint count = 0;
849  GstFlowReturn res = GST_FLOW_OK;
850 
851  silent_debug (self, "Got %s",
852  gst_event_type_get_name (GST_EVENT_TYPE (event)));
853 
854  /* If the segment has a stop position, fill the segment */
855  if (GST_CLOCK_TIME_IS_VALID (self->segment.stop)) {
861  while (res == GST_FLOW_OK && count <= MAGIC_LIMIT
862  && (GST_CLOCK_TIME_IS_VALID (self->segment.stop)
863  && GST_CLOCK_TIME_IS_VALID (self->next_ts)
864  && (self->next_ts - self->segment.base < self->segment.stop))) {
865  res = gst_tensor_rate_flush_prev (self, count > 0,
866  GST_CLOCK_TIME_NONE);
867  count++;
868  }
869  } else if (self->prevbuf) {
874  if (GST_BUFFER_DURATION_IS_VALID (self->prevbuf)) {
875  GstClockTime end_ts =
876  self->next_ts + GST_BUFFER_DURATION (self->prevbuf);
877 
878  while (res == GST_FLOW_OK && count <= MAGIC_LIMIT &&
879  ((GST_CLOCK_TIME_IS_VALID (self->segment.stop)
880  && GST_CLOCK_TIME_IS_VALID (self->next_ts)
881  && self->next_ts - self->segment.base < end_ts)
882  || count < 1)) {
883  res =
884  gst_tensor_rate_flush_prev (self, count > 0,
885  GST_CLOCK_TIME_NONE);
886  count++;
887  }
888  } else {
889  res = gst_tensor_rate_flush_prev (self, FALSE, GST_CLOCK_TIME_NONE);
890  count = 1;
891  }
892  }
893 
894  if (count > 1) {
895  self->dup += count - 1;
896  if (!self->silent)
898  }
899 
900  break;
901  }
902  case GST_EVENT_FLUSH_STOP:
903  /* also resets the segment */
904  silent_debug (self, "Got %s",
905  gst_event_type_get_name (GST_EVENT_TYPE (event)));
906  gst_tensor_rate_reset (self);
907  break;
908  case GST_EVENT_GAP:
909  /* no gaps after tensor rate, ignore the event */
910  silent_debug (self, "Got %s",
911  gst_event_type_get_name (GST_EVENT_TYPE (event)));
912  gst_event_unref (event);
913  return TRUE;
914  default:
915  break;
916  }
917 
918  /* other events are handled in the default event handler */
919  return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
920 }
921 
927 static gboolean
928 gst_tensor_rate_start (GstBaseTransform * trans)
929 {
930  GstTensorRate *self = GST_TENSOR_RATE (trans);
931  gst_tensor_rate_reset (self);
932  return TRUE;
933 }
934 
940 static gboolean
941 gst_tensor_rate_stop (GstBaseTransform * trans)
942 {
943  GstTensorRate *self = GST_TENSOR_RATE (trans);
944  gst_tensor_rate_reset (self);
945  return TRUE;
946 }
947 
952 static void
953 gst_tensor_rate_install_properties (GObjectClass * object_class)
954 {
955  /* PROP_IN */
956  g_object_class_install_property (object_class, PROP_IN,
957  g_param_spec_uint64 ("in", "In",
958  "Number of input frames",
959  0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
960 
961  /* PROP_OUT */
962  g_object_class_install_property (object_class, PROP_OUT,
963  g_param_spec_uint64 ("out", "Out",
964  "Number of output frames",
965  0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
966 
967  /* PROP_DUP */
968  pspec_duplicate = g_param_spec_uint64 ("duplicate", "Duplicate",
969  "Number of duplicated frames", 0,
970  G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
971  g_object_class_install_property (object_class, PROP_DUP, pspec_duplicate);
972 
973  /* PROP_DROP */
974  pspec_drop =
975  g_param_spec_uint64 ("drop", "Drop", "Number of dropped frames", 0,
976  G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
977  g_object_class_install_property (object_class, PROP_DROP, pspec_drop);
978 
979  /* PROP_SILENT */
980  g_object_class_install_property (object_class, PROP_SILENT,
981  g_param_spec_boolean ("silent", "Silent",
982  "Don't produce verbose output including dropped/duplicated frames",
983  DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
984 
985  /* PROP_THROTTLE */
986  g_object_class_install_property (object_class, PROP_THROTTLE,
987  g_param_spec_boolean ("throttle", "Throttle",
988  "Send QoS events to upstream elements to limit a incoming data rate",
989  DEFAULT_THROTTLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
990 
991  /* PROP_FRAMERATE */
992  g_object_class_install_property (object_class, PROP_FRAMERATE,
993  g_param_spec_string ("framerate", "Framerate",
994  "Specify a target framerate to adjust (e.g., framerate=10/1). "
995  "Otherwise, the latest processing time will be a target interval.",
996  "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
997 }
gst_tensor_rate_stop
static gboolean gst_tensor_rate_stop(GstBaseTransform *trans)
Called when the element stops processing. optional vmethod of BaseTransform.
Definition: gsttensor_rate.c:941
GST_DEBUG_CATEGORY_STATIC
GST_DEBUG_CATEGORY_STATIC(gst_tensor_rate_debug)
pspec_duplicate
static GParamSpec * pspec_duplicate
Definition: gsttensor_rate.c:108
g_assert
g_assert(sizeof(DTYPE_UNSIGNED)==sizeof(DTYPE_SIGNED))
GST_TENSOR_RATE_SCALED_TIME
#define GST_TENSOR_RATE_SCALED_TIME(self, count)
Definition: gsttensor_rate.c:68
ml_logw
#define ml_logw
Definition: nnstreamer_log.h:77
gst_tensor_rate_class_init
static void gst_tensor_rate_class_init(GstTensorRateClass *klass)
initialize the tensor_rate's class (GST Standard)
Definition: gsttensor_rate.c:148
gsttensor_rate.h
GStreamer plugin to adjust tensor rate.
FALSE
return FALSE
Definition: gsttensor_transform.c:590
result
case tensor_data_s gboolean * result
Definition: gsttensor_if.c:839
gst_tensor_rate_reset
static void gst_tensor_rate_reset(GstTensorRate *self)
reset variables of the element (GST Standard)
Definition: gsttensor_rate.c:295
gst_tensor_rate_init
static void gst_tensor_rate_init(GstTensorRate *self)
initialize the new element (GST Standard)
Definition: gsttensor_rate.c:317
gst_tensor_rate_push_buffer
static GstFlowReturn gst_tensor_rate_push_buffer(GstTensorRate *self, GstBuffer *outbuf, gboolean duplicate, GstClockTime next_intime)
push the buffer to src pad
Definition: gsttensor_rate.c:202
PROP_THROTTLE
@ PROP_THROTTLE
Definition: gsttensor_rate.c:87
DEFAULT_SILENT
#define DEFAULT_SILENT
default parameters
Definition: gsttensor_rate.c:73
nnstreamer_log.h
Internal log util for NNStreamer plugins and native APIs.
PROP_0
@ PROP_0
Definition: gsttensor_rate.c:81
THROTTLE_DELAY_RATIO
#define THROTTLE_DELAY_RATIO
Definition: gsttensor_rate.c:449
gst_tensor_rate_sink_event
static gboolean gst_tensor_rate_sink_event(GstBaseTransform *trans, GstEvent *event)
Event handler for sink pad of tensor rate.
Definition: gsttensor_rate.c:781
gst_tensor_rate_notify_duplicate
static void gst_tensor_rate_notify_duplicate(GstTensorRate *self)
notify a frame duplicate event
Definition: gsttensor_rate.c:768
_GstTensorRate
Tensor Rate data structure.
Definition: gsttensor_rate.h:37
MAGIC_LIMIT
#define MAGIC_LIMIT
Definition: gsttensor_rate.c:773
PROP_SILENT
@ PROP_SILENT
Definition: gsttensor_rate.c:86
silent_debug
#define silent_debug(self,...)
Macro for debug message.
Definition: tensor_common.h:276
gst_tensor_rate_notify_drop
static void gst_tensor_rate_notify_drop(GstTensorRate *self)
notify a frame drop event
Definition: gsttensor_rate.c:758
gst_tensor_rate_fixate_caps
static GstCaps * gst_tensor_rate_fixate_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *othercaps)
fixate caps. required vmethod of GstBaseTransform.
Definition: gsttensor_rate.c:680
_GstTensorRateClass
GstTensorRateClass inherits GstElementClass.
Definition: gsttensor_rate.h:70
gst_tensor_rate_transform_caps
static GstCaps * gst_tensor_rate_transform_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *_rate)
configure tensor-srcpad cap from "proposed" cap. (GST Standard)
Definition: gsttensor_rate.c:634
g_value_set_string
g_value_set_string(value, self->option[opnum - 1])
opnum: \
CAPS_STRING
#define CAPS_STRING
Definition: gsttensor_rate.c:66
gst_tensor_rate_start
static gboolean gst_tensor_rate_start(GstBaseTransform *trans)
Called when the element starts processing. optional vmethod of BaseTransform.
Definition: gsttensor_rate.c:928
ABSDIFF
#define ABSDIFF(a, b)
Definition: gsttensor_rate.c:60
ml_logi
#define ml_logi
Definition: nnstreamer_log.h:76
silent_debug_caps
#define silent_debug_caps(self, caps, msg)
Macro for capability debug message.
Definition: tensor_common.h:285
ml_loge
#define ml_loge
Definition: nnstreamer_log.h:78
TRUE
return TRUE
Definition: gsttensor_if.c:897
UNUSED
#define UNUSED(expr)
Definition: mqttcommon.h:19
PROP_OUT
@ PROP_OUT
Definition: gsttensor_rate.c:83
nnstreamer_util.h
Optional NNStreamer utility functions for sub-plugin writers and users.
DEFAULT_THROTTLE
#define DEFAULT_THROTTLE
Definition: gsttensor_rate.c:74
G_DEFINE_TYPE
G_DEFINE_TYPE(GstTensorRate, gst_tensor_rate, GST_TYPE_BASE_TRANSFORM)
gst_tensor_rate_finalize
static void gst_tensor_rate_finalize(GObject *object)
Function to finalize instance. (GST Standard)
Definition: gsttensor_rate.c:341
PROP_DROP
@ PROP_DROP
Definition: gsttensor_rate.c:85
gst_tensor_rate_get_property
static void gst_tensor_rate_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
Getter for tensor_rate properties.
Definition: gsttensor_rate.c:407
GST_TENSOR_RATE
#define GST_TENSOR_RATE(obj)
Definition: gsttensor_rate.h:25
gst_tensor_rate_install_properties
static void gst_tensor_rate_install_properties(GObjectClass *gobject_class)
Installs all the properties for tensor_rate.
Definition: gsttensor_rate.c:953
PROP_IN
@ PROP_IN
Definition: gsttensor_rate.c:82
sink_factory
static GstStaticPadTemplate sink_factory
The capabilities of the inputs.
Definition: gsttensor_rate.c:94
gst_tensor_rate_send_qos_throttle
static void gst_tensor_rate_send_qos_throttle(GstTensorRate *self, GstClockTime timestamp)
send throttling qos event to upstream elements
Definition: gsttensor_rate.c:455
pspec_drop
static GParamSpec * pspec_drop
Definition: gsttensor_rate.c:107
PROP_DUP
@ PROP_DUP
Definition: gsttensor_rate.c:84
gst_tensor_rate_swap_prev
static void gst_tensor_rate_swap_prev(GstTensorRate *self, GstBuffer *buffer, gint64 time)
swap a previous buffer
Definition: gsttensor_rate.c:280
gst_tensor_rate_set_caps
static gboolean gst_tensor_rate_set_caps(GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps)
set caps. required vmethod of GstBaseTransform.
Definition: gsttensor_rate.c:705
gst_tensor_rate_transform_ip
static GstFlowReturn gst_tensor_rate_transform_ip(GstBaseTransform *trans, GstBuffer *buffer)
in-place transform
Definition: gsttensor_rate.c:477
src_factory
static GstStaticPadTemplate src_factory
The capabilities of the outputs.
Definition: gsttensor_rate.c:102
gst_tensor_rate_flush_prev
static GstFlowReturn gst_tensor_rate_flush_prev(GstTensorRate *self, gboolean duplicate, GstClockTime next_intime)
flush the oldest buffer
Definition: gsttensor_rate.c:259
gst_tensor_rate_set_property
static void gst_tensor_rate_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
Setter for tensor_rate properties.
Definition: gsttensor_rate.c:350
PROP_FRAMERATE
@ PROP_FRAMERATE
Definition: gsttensor_rate.c:88