42 #define DBG (!self->silent)
45 #define silent_debug_config(self,c,msg) do { \
49 dim_str = gst_tensor_get_dimension_string ((c)->info.info[0].dimension); \
50 GST_DEBUG_OBJECT (self, msg " type=%d dim=%s rate=%d/%d", (c)->info.info[0].type, dim_str, (c)->rate_n, (c)->rate_d); \
57 #define GST_CAT_DEFAULT gst_tensor_aggregator_debug
76 #define DEFAULT_SILENT TRUE
81 #define DEFAULT_FRAMES_IN 1
86 #define DEFAULT_FRAMES_OUT 1
91 #define DEFAULT_FRAMES_FLUSH 0
96 #define DEFAULT_FRAMES_DIMENSION (NNS_TENSOR_RANK_LIMIT - 1)
101 #define DEFAULT_CONCAT TRUE
106 #define CAPS_STRING GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_WITH_NUM ("1")
111 static GstStaticPadTemplate
sink_template = GST_STATIC_PAD_TEMPLATE (
"sink",
119 static GstStaticPadTemplate
src_template = GST_STATIC_PAD_TEMPLATE (
"src",
124 #define gst_tensor_aggregator_parent_class parent_class
129 guint prop_id,
const GValue * value, GParamSpec * pspec);
131 guint prop_id, GValue * value, GParamSpec * pspec);
134 GstObject * parent, GstEvent * event);
136 GstObject * parent, GstQuery * query);
138 GstObject * parent, GstQuery * query);
140 GstObject * parent, GstBuffer * buf);
141 static GstStateChangeReturn
143 GstStateChange transition);
147 GstPad * pad, GstCaps * filter);
149 const GstCaps * caps);
157 GObjectClass *object_class;
158 GstElementClass *element_class;
160 GST_DEBUG_CATEGORY_INIT (gst_tensor_aggregator_debug,
"tensor_aggregator", 0,
161 "Element to aggregate tensor stream");
163 object_class = (GObjectClass *) klass;
164 element_class = (GstElementClass *) klass;
178 g_param_spec_uint (
"frames-in",
"Frames in input",
179 "The number of frames in incoming buffer", 1, G_MAXUINT,
189 g_param_spec_uint (
"frames-out",
"Frames in output",
190 "The number of frames in outgoing buffer", 1, G_MAXUINT,
201 g_param_spec_uint (
"frames-flush",
"Frames to flush",
202 "The number of frames to flush (0 to flush all output)", 0, G_MAXUINT,
213 g_param_spec_uint (
"frames-dim",
"Dimension index of frames",
214 "The dimension index of frames in tensor",
216 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
224 g_object_class_install_property (object_class,
PROP_CONCAT,
225 g_param_spec_boolean (
"concat",
"Concat",
"Concatenate output buffer",
233 g_object_class_install_property (object_class,
PROP_SILENT,
234 g_param_spec_boolean (
"silent",
"Silent",
"Produce verbose output",
237 gst_element_class_set_static_metadata (element_class,
240 "Element to aggregate tensor stream",
"Samsung Electronics Co., Ltd.");
242 gst_element_class_add_pad_template (element_class,
244 gst_element_class_add_pad_template (element_class,
257 self->sinkpad = gst_pad_new_from_static_template (&
sink_template,
"sink");
258 gst_pad_set_event_function (self->sinkpad,
260 gst_pad_set_query_function (self->sinkpad,
262 gst_pad_set_chain_function (self->sinkpad,
264 GST_PAD_SET_PROXY_CAPS (self->sinkpad);
265 gst_element_add_pad (GST_ELEMENT (
self), self->sinkpad);
268 self->srcpad = gst_pad_new_from_static_template (&
src_template,
"src");
269 gst_pad_set_query_function (self->srcpad,
271 GST_PAD_SET_PROXY_CAPS (self->srcpad);
272 gst_element_add_pad (GST_ELEMENT (
self), self->srcpad);
282 self->tensor_configured =
FALSE;
304 g_hash_table_destroy (self->adapter_table);
306 G_OBJECT_CLASS (parent_class)->finalize (
object);
314 const GValue * value, GParamSpec * pspec)
322 self->frames_in = g_value_get_uint (value);
325 self->frames_out = g_value_get_uint (value);
328 self->frames_flush = g_value_get_uint (value);
331 self->frames_dim = g_value_get_uint (value);
334 self->concat = g_value_get_boolean (value);
337 self->silent = g_value_get_boolean (value);
340 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
350 GValue * value, GParamSpec * pspec)
358 g_value_set_uint (value, self->frames_in);
361 g_value_set_uint (value, self->frames_out);
364 g_value_set_uint (value, self->frames_flush);
367 g_value_set_uint (value, self->frames_dim);
370 g_value_set_boolean (value, self->concat);
373 g_value_set_boolean (value, self->silent);
376 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
392 GST_DEBUG_OBJECT (
self,
"Received %s event: %" GST_PTR_FORMAT,
393 GST_EVENT_TYPE_NAME (event), event);
395 switch (GST_EVENT_TYPE (event)) {
401 gst_event_parse_caps (event, &in_caps);
405 gboolean ret =
FALSE;
411 ret = gst_pad_set_caps (self->srcpad, out_caps);
413 gst_event_unref (event);
414 gst_caps_unref (out_caps);
420 case GST_EVENT_FLUSH_STOP:
427 return gst_pad_event_default (pad, parent, event);
441 GST_DEBUG_OBJECT (
self,
"Received %s query: %" GST_PTR_FORMAT,
442 GST_QUERY_TYPE_NAME (query), query);
444 switch (GST_QUERY_TYPE (query)) {
450 gst_query_parse_caps (query, &filter);
453 gst_query_set_caps_result (query, caps);
454 gst_caps_unref (caps);
457 case GST_QUERY_ACCEPT_CAPS:
460 GstCaps *template_caps;
461 gboolean res =
FALSE;
463 gst_query_parse_accept_caps (query, &caps);
466 if (gst_caps_is_fixed (caps)) {
467 template_caps = gst_pad_get_pad_template_caps (pad);
469 res = gst_caps_can_intersect (template_caps, caps);
470 gst_caps_unref (template_caps);
473 gst_query_set_accept_caps_result (query, res);
480 return gst_pad_query_default (pad, parent, query);
494 GST_DEBUG_OBJECT (
self,
"Received %s query: %" GST_PTR_FORMAT,
495 GST_QUERY_TYPE_NAME (query), query);
497 switch (GST_QUERY_TYPE (query)) {
503 gst_query_parse_caps (query, &filter);
506 gst_query_set_caps_result (query, caps);
507 gst_caps_unref (caps);
514 return gst_pad_query_default (pad, parent, query);
550 if (self->concat && self->frames_out > 1) {
573 GstMapInfo src_info, dest_info;
576 gsize src_idx, dest_idx;
582 srcbuf = gst_buffer_copy (outbuf);
583 outbuf = gst_buffer_make_writable (outbuf);
585 if (!gst_buffer_map (srcbuf, &src_info, GST_MAP_READ)) {
586 ml_logf (
"Failed to map source buffer with tensor_aggregator.\n");
587 gst_buffer_unref (srcbuf);
590 if (!gst_buffer_map (outbuf, &dest_info, GST_MAP_WRITE)) {
591 ml_logf (
"Failed to map destination buffer with tensor_aggregator.\n");
592 gst_buffer_unmap (srcbuf, &src_info);
593 gst_buffer_unref (srcbuf);
774 for (f = 0; f <=
self->frames_dim; f++) {
778 src_idx = dest_idx = 0;
781 for (f = 0; f <
self->frames_out; f++) {
783 src_info.data + src_idx + (frame_size * f), block_size);
784 dest_idx += block_size;
787 src_idx += block_size;
790 g_assert (dest_idx <= dest_info.size);
791 }
while (src_idx < frame_size);
793 gst_buffer_unmap (srcbuf, &src_info);
794 gst_buffer_unmap (outbuf, &dest_info);
796 gst_buffer_unref (srcbuf);
811 info =
self->out_config.info.info[0];
813 info.
dimension[
self->frames_dim] /=
self->frames_out;
817 (
"Invalid output capability of tensor_aggregator. Frame size = %"
818 G_GSIZE_FORMAT
"\n", frame_size);
819 return GST_FLOW_ERROR;
825 return GST_FLOW_ERROR;
828 return gst_pad_push (self->srcpad, outbuf);
838 GstFlowReturn ret = GST_FLOW_OK;
840 gsize avail, buf_size, frame_size, out_size;
841 guint frames_in, frames_out, frames_flush;
842 GstClockTime duration;
848 buf_size = gst_buffer_get_size (buf);
849 g_return_val_if_fail (buf_size > 0, GST_FLOW_ERROR);
851 frames_in =
self->frames_in;
852 frames_out =
self->frames_out;
853 frames_flush =
self->frames_flush;
854 frame_size = buf_size / frames_in;
856 if (frames_in == frames_out) {
864 duration = GST_BUFFER_DURATION (buf);
865 if (GST_CLOCK_TIME_IS_VALID (duration)) {
867 duration = gst_util_uint64_scale_int (duration, frames_out, frames_in);
870 gst_adapter_push (adapter, buf);
872 out_size = frame_size * frames_out;
875 while ((avail = gst_adapter_available (adapter)) >= out_size &&
876 ret == GST_FLOW_OK) {
878 GstClockTime pts, dts;
879 guint64 pts_dist, dts_dist;
882 pts = gst_adapter_prev_pts (adapter, &pts_dist);
883 dts = gst_adapter_prev_dts (adapter, &dts_dist);
892 fn =
self->in_config.rate_n;
893 fd =
self->in_config.rate_d;
895 if (fn > 0 && fd > 0) {
896 if (GST_CLOCK_TIME_IS_VALID (pts)) {
898 gst_util_uint64_scale_int (pts_dist * fd, GST_SECOND,
902 if (GST_CLOCK_TIME_IS_VALID (dts)) {
904 gst_util_uint64_scale_int (dts_dist * fd, GST_SECOND,
910 outbuf = gst_adapter_get_buffer (adapter, out_size);
911 outbuf = gst_buffer_make_writable (outbuf);
914 GST_BUFFER_PTS (outbuf) = pts;
915 GST_BUFFER_DTS (outbuf) = dts;
916 GST_BUFFER_DURATION (outbuf) = duration;
921 if (frames_flush > 0) {
922 flush = frame_size * frames_flush;
937 gst_adapter_flush (adapter, flush);
946 static GstStateChangeReturn
948 GstStateChange transition)
951 GstStateChangeReturn ret;
955 switch (transition) {
956 case GST_STATE_CHANGE_READY_TO_PAUSED:
963 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
965 switch (transition) {
966 case GST_STATE_CHANGE_PAUSED_TO_READY:
997 if (pad == self->sinkpad) {
998 config = &
self->in_config;
1000 config = &
self->out_config;
1009 if (caps && filter) {
1010 GstCaps *intersection;
1013 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1015 gst_caps_unref (caps);
1016 caps = intersection;
1027 const GstCaps * caps)
1029 GstStructure *structure;
1035 g_return_val_if_fail (caps != NULL,
FALSE);
1036 g_return_val_if_fail (gst_caps_is_fixed (caps),
FALSE);
1038 structure = gst_caps_get_structure (caps, 0);
1042 GST_ERROR_OBJECT (
self,
"Cannot configure tensor info");
1051 count = (
self->frames_out +
self->frames_in - 1) / self->frames_in;
1052 if (self->frames_in * count < self->frames_flush) {
1053 GST_ERROR_OBJECT (
self,
"Cannot flush frames");
1057 self->in_config = config;
1068 (_info->
dimension[self->frames_dim] % self->frames_in) != 0) {
1069 GST_ERROR_OBJECT (
self,
"Cannot update dimension in output tensor");
1072 per_frame = _info->
dimension[
self->frames_dim] /
self->frames_in;
1074 _info->
dimension[
self->frames_dim] = per_frame *
self->frames_out;
1075 self->out_config = config;
1076 self->tensor_configured =
TRUE;