69 #define GST_CAT_DEFAULT gst_tensor_crop_debug
84 #define DEFAULT_SILENT TRUE
89 #define DEFAULT_LATENESS (-1)
94 static GstStaticPadTemplate
raw_template = GST_STATIC_PAD_TEMPLATE (
"raw",
103 static GstStaticPadTemplate
info_template = GST_STATIC_PAD_TEMPLATE (
"info",
111 static GstStaticPadTemplate
src_template = GST_STATIC_PAD_TEMPLATE (
"src",
116 #define gst_tensor_crop_parent_class parent_class
121 const GValue * value, GParamSpec * pspec);
123 GValue * value, GParamSpec * pspec);
125 GstStateChange transition);
129 GstCollectData *
data, GstEvent * event, gpointer user_data);
139 GObjectClass *object_class;
140 GstElementClass *element_class;
142 GST_DEBUG_CATEGORY_INIT (gst_tensor_crop_debug,
"tensor_crop", 0,
143 "Element to crop the regions of incoming tensor");
145 object_class = (GObjectClass *) klass;
146 element_class = (GstElementClass *) klass;
159 g_object_class_install_property (object_class,
PROP_LATENESS,
160 g_param_spec_int (
"lateness",
"Lateness",
161 "The time difference between raw and info buffer in milliseconds",
163 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
170 g_object_class_install_property (object_class,
PROP_SILENT,
171 g_param_spec_boolean (
"silent",
"Silent",
"Produce verbose output",
174 element_class->change_state =
177 gst_element_class_add_pad_template (element_class,
179 gst_element_class_add_pad_template (element_class,
181 gst_element_class_add_pad_template (element_class,
184 gst_element_class_set_static_metadata (element_class,
187 "Element to crop the regions of incoming tensor",
188 "Samsung Electronics Co., Ltd.");
211 walk =
self->collect->
data;
217 walk = g_slist_next (walk);
221 self->send_stream_start =
TRUE;
231 self->sinkpad_raw = gst_pad_new_from_static_template (&
raw_template,
"raw");
232 gst_element_add_pad (GST_ELEMENT (
self), self->sinkpad_raw);
236 gst_element_add_pad (GST_ELEMENT (
self), self->sinkpad_info);
238 self->collect = gst_collect_pads_new ();
239 gst_collect_pads_set_function (self->collect,
241 gst_collect_pads_set_event_function (self->collect,
244 gst_collect_pads_add_pad (self->collect, self->sinkpad_raw,
246 gst_collect_pads_add_pad (self->collect, self->sinkpad_info,
250 self->srcpad = gst_pad_new_from_static_template (&
src_template,
"src");
251 gst_pad_set_event_function (self->srcpad,
253 gst_element_add_pad (GST_ELEMENT (
self), self->srcpad);
258 self->send_stream_start =
TRUE;
274 gst_object_unref (self->collect);
275 self->collect = NULL;
278 G_OBJECT_CLASS (parent_class)->finalize (
object);
286 const GValue * value, GParamSpec * pspec)
294 self->lateness = g_value_get_int (value);
297 self->silent = g_value_get_boolean (value);
300 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
310 GValue * value, GParamSpec * pspec)
318 g_value_set_int (value, self->lateness);
321 g_value_set_boolean (value, self->silent);
324 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
332 static GstStateChangeReturn
336 GstStateChangeReturn ret;
340 switch (transition) {
341 case GST_STATE_CHANGE_READY_TO_PAUSED:
342 gst_collect_pads_start (self->collect);
344 case GST_STATE_CHANGE_PAUSED_TO_READY:
345 gst_collect_pads_stop (self->collect);
351 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
353 switch (transition) {
354 case GST_STATE_CHANGE_PAUSED_TO_READY:
370 g_return_val_if_fail (event != NULL,
FALSE);
372 switch (GST_EVENT_TYPE (event)) {
375 gst_event_unref (event);
381 return gst_pad_event_default (pad, parent, event);
389 GstEvent * event, gpointer user_data)
394 g_return_val_if_fail (event != NULL,
FALSE);
398 switch (GST_EVENT_TYPE (event)) {
403 gst_event_parse_caps (event, &caps);
406 gst_event_unref (event);
414 return gst_collect_pads_event_default (pads,
data, event,
FALSE);
423 if (!gst_pad_has_current_caps (self->sinkpad_raw)) {
424 GST_ERROR_OBJECT (
self,
425 "The raw pad of tensor_crop '%s' does not have pad caps.",
426 GST_ELEMENT_NAME (
self));
427 return GST_FLOW_NOT_NEGOTIATED;
430 if (!gst_pad_has_current_caps (self->sinkpad_info)) {
431 GST_ERROR_OBJECT (
self,
432 "The info pad of tensor_crop '%s' does not have pad caps.",
433 GST_ELEMENT_NAME (
self));
434 return GST_FLOW_NOT_NEGOTIATED;
437 if (!gst_pad_has_current_caps (self->srcpad)) {
444 if (self->send_stream_start) {
449 g_autofree gchar *sink_stream_id = gst_pad_get_stream_id (self->sinkpad_raw);
450 g_autofree gchar *element_name = gst_element_get_name (
self);
451 g_autofree gchar *pad_name = gst_pad_get_name (self->srcpad);
452 g_autofree gchar *stream_id = g_strdup_printf (
"%s-%s-nnscrop-%s-%08x",
453 GST_STR_NULL (sink_stream_id), element_name, pad_name, g_random_int ());
455 gst_pad_push_event (self->srcpad, gst_event_new_stream_start (stream_id));
456 self->send_stream_start =
FALSE;
466 walk =
self->collect->data;
477 walk = g_slist_next (walk);
481 gst_pad_set_caps (self->srcpad, caps);
482 gst_caps_unref (caps);
484 gst_segment_init (&segment, GST_FORMAT_TIME);
485 gst_pad_push_event (self->srcpad, gst_event_new_segment (&segment));
499 GstStructure *structure;
502 gboolean ret =
FALSE;
507 caps = gst_pad_get_current_caps (self->sinkpad_raw);
508 structure = gst_caps_get_structure (caps, 0);
511 GST_ERROR_OBJECT (
self,
"Failed to get the config from caps.");
536 gst_caps_unref (caps);
551 gsize hsize, dsize, esize;
553 guint8 *pos, *src, *desc;
554 gboolean ret =
FALSE;
559 GST_WARNING_OBJECT (
self,
560 "Info buffer has %u memories, parse first one.", i);
564 if (!gst_memory_map (mem, &map, GST_MAP_READ)) {
565 GST_ERROR_OBJECT (
self,
"Failed to map the info buffer.");
571 GST_ERROR_OBJECT (
self,
"Failed to get the meta from info buffer.");
579 if (hsize + dsize != map.size) {
580 GST_ERROR_OBJECT (
self,
581 "Invalid meta info, info buffer size is incorrect (received %zd, expected %zd).",
582 map.size, hsize + dsize);
590 g_assert ((dsize % (esize * 4)) == 0);
596 for (i = 0; i < cinfo->
num; i++) {
597 pos = map.data + hsize + (esize * 4 * i);
599 for (j = 0; j < 4; j++) {
600 src = pos + (esize * j);
601 desc = (guint8 *) (&cinfo->
region[i]) +
sizeof (guint) * j;
611 gst_memory_unmap (mem, &map);
612 gst_memory_unref (mem);
631 gsize hsize, esize, dsize;
632 guint8 *cropped, *dpos, *desc, *src;
633 guint i, j, ch, mw, mh, _x, _y, _w, _h;
638 GST_WARNING_OBJECT (
self,
639 "Raw data buffer has %u memories, parse first one.", i);
643 if (!gst_memory_map (mem, &map, GST_MAP_READ)) {
644 GST_ERROR_OBJECT (
self,
"Failed to map the raw buffer.");
650 GST_ERROR_OBJECT (
self,
"Failed to get the output meta.");
656 dpos = map.data + hsize;
657 if ((hsize + dsize) != map.size) {
658 GST_ERROR_OBJECT (
self,
659 "Raw buffer has invalid data size (received %zd, expected %zd).",
664 result = gst_buffer_new ();
673 for (i = 0; i < cinfo->
num; i++) {
679 _w = (_x + cinfo->
region[i].
w - 1 < mw) ? cinfo->
region[i].
w : (mw - _x);
680 _h = (_y + cinfo->
region[i].
h - 1 < mh) ? cinfo->
region[i].
h : (mh - _y);
683 dsize = hsize + (esize * ch * _w * _h);
684 cropped = (guint8 *) g_malloc0 (dsize);
692 for (j = 0; j < _h; j++) {
693 src = dpos + esize * ch * (_x + (j + _y) * mw);
694 desc = cropped + hsize + (esize * ch * _w) * j;
695 memcpy (desc, src, (esize * ch * _w));
701 gst_memory_new_wrapped (0, cropped, dsize, 0, dsize, cropped,
g_free);
708 gst_buffer_copy_into (
result, raw, GST_BUFFER_COPY_METADATA, 0, -1);
712 gst_memory_unmap (mem, &map);
713 gst_memory_unref (mem);
724 GstCollectData * data_raw, GstCollectData * data_info)
727 GstBuffer *buf_raw, *buf_info, *
result;
730 gboolean drop_raw, drop_info;
732 g_return_val_if_fail (data_raw && data_info, GST_FLOW_ERROR);
734 buf_raw = gst_collect_pads_peek (self->collect, data_raw);
735 buf_info = gst_collect_pads_peek (self->collect, data_info);
736 drop_raw = (buf_raw != NULL);
737 drop_info = (buf_info != NULL);
739 if (!buf_raw || !buf_info) {
753 if (self->lateness >= 0) {
754 GstClockTime ts_raw, ts_info, lateness;
756 ts_raw = GST_BUFFER_TIMESTAMP (buf_raw);
757 ts_info = GST_BUFFER_TIMESTAMP (buf_info);
758 lateness =
self->lateness * GST_MSECOND;
760 if (GST_CLOCK_TIME_IS_VALID (ts_raw) && GST_CLOCK_TIME_IS_VALID (ts_info)) {
761 if (((GstClockTime) ABS (GST_CLOCK_DIFF (ts_raw, ts_info))) > lateness) {
762 GST_DEBUG_OBJECT (
self,
"Drop old buffer and wait for next.");
763 GST_DEBUG_OBJECT (
self,
"Raw buffer ts: %" GST_TIME_FORMAT,
764 GST_TIME_ARGS (ts_raw));
765 GST_DEBUG_OBJECT (
self,
"Info buffer ts: %" GST_TIME_FORMAT,
766 GST_TIME_ARGS (ts_info));
769 if (ts_raw > ts_info)
778 GST_WARNING_OBJECT (
self,
779 "Incoming buffer has invalid timestamp, continue cropping data.");
784 ret = GST_FLOW_ERROR;
789 ret = gst_pad_push (self->srcpad,
result);
793 gst_buffer_unref (buf_raw);
795 gst_buffer_unref (buf_info);
799 gst_buffer_unref (gst_collect_pads_pop (self->collect, data_raw));
801 gst_buffer_unref (gst_collect_pads_pop (self->collect, data_info));
813 GstCollectData *data_raw, *data_info;
818 data_raw = data_info = NULL;
821 if (ret != GST_FLOW_OK)
824 for (walk = pads->data; walk; walk = g_slist_next (walk)) {
825 GstCollectData *
data;
827 data = (GstCollectData *) walk->data;
829 if (GST_COLLECT_PADS_STATE_IS_SET (
data, GST_COLLECT_PADS_STATE_EOS)) {
830 gst_pad_push_event (self->srcpad, gst_event_new_eos ());
834 if (
data->pad == self->sinkpad_raw) {
836 }
else if (
data->pad == self->sinkpad_info) {