From 641ece5c0513f34b2e64566605785dc1eec97390 Mon Sep 17 00:00:00 2001 From: William Wright <74670359+WilliamWright-JCI@users.noreply.github.com> Date: Thu, 19 Nov 2020 10:30:50 +0000 Subject: [PATCH 1/5] Raise signal prior to clasifying a tracked object (ROI). The signal subscriber can examine the ROI metadata (included as an arg in the signal) and decide if the ROI does not need to be classified, thereby saving processing resource. --- .../gvaclassify/classification_history.cpp | 22 +++++++++- .../gvaclassify/classification_history.h | 1 + .../gvaclassify/gstgvaclassify.c | 42 +++++++++++++++++++ .../gvaclassify/gstgvaclassify.h | 7 ++++ .../gvaclassify/pre_processors.cpp | 11 +++-- 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/gst/inference_elements/gvaclassify/classification_history.cpp b/gst/inference_elements/gvaclassify/classification_history.cpp index 7f70ca53..32db96b8 100644 --- a/gst/inference_elements/gvaclassify/classification_history.cpp +++ b/gst/inference_elements/gvaclassify/classification_history.cpp @@ -27,8 +27,11 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMe gint id; if (!get_object_id(roi, &id)) // object has not been tracked - return true; + return IsROIClassificationNeededDueToMeta(roi); if (history.count(id) == 0) { // new object + if (!IsROIClassificationNeededDueToMeta(roi)) + return false; + history.put(id); history.get(id).frame_of_last_update = current_num_frame; result = true; @@ -40,6 +43,9 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMe current_interval = (UINT64_MAX - history.get(id).frame_of_last_update) + current_num_frame + 1; if (current_interval >= gva_classify->reclassify_interval) { // new object or reclassify old object + if (!IsROIClassificationNeededDueToMeta(roi)) + return false; + history.get(id).frame_of_last_update = current_num_frame; result = true; } @@ -51,6 +57,20 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMe } } +bool ClassificationHistory::IsROIClassificationNeededDueToMeta(const GstVideoRegionOfInterestMeta *roi) const { + // If the classify signal is not enabled, then a subscriber will not be + // able to decide if classfication should be skipped. + if (!gva_classify->signal_classify_roi) { + return true; + } + + // Ask subsciber if classification of this ROI should be skipped + gboolean skip = FALSE; + g_signal_emit(gva_classify, gva_classify->signal_classify_roi_id, 0, roi, &skip); + + return !skip; +} + void ClassificationHistory::UpdateROIParams(int roi_id, const GstStructure *roi_param) { try { std::lock_guard guard(history_mutex); diff --git a/gst/inference_elements/gvaclassify/classification_history.h b/gst/inference_elements/gvaclassify/classification_history.h index af4d0ce5..91444e2f 100644 --- a/gst/inference_elements/gvaclassify/classification_history.h +++ b/gst/inference_elements/gvaclassify/classification_history.h @@ -49,6 +49,7 @@ struct ClassificationHistory { ClassificationHistory(GstGvaClassify *gva_classify); bool IsROIClassificationNeeded(GstVideoRegionOfInterestMeta *roi, uint64_t current_num_frame); + bool IsROIClassificationNeededDueToMeta(const GstVideoRegionOfInterestMeta *roi) const; void UpdateROIParams(int roi_id, const GstStructure *roi_param); void FillROIParams(GstBuffer *buffer); }; diff --git a/gst/inference_elements/gvaclassify/gstgvaclassify.c b/gst/inference_elements/gvaclassify/gstgvaclassify.c index 9828bd9a..373d80e7 100644 --- a/gst/inference_elements/gvaclassify/gstgvaclassify.c +++ b/gst/inference_elements/gvaclassify/gstgvaclassify.c @@ -17,14 +17,22 @@ #include #include #include +#include #define ELEMENT_LONG_NAME "Object classification (requires GstVideoRegionOfInterestMeta on input)" #define ELEMENT_DESCRIPTION ELEMENT_LONG_NAME +#define DEFAULT_SIGNAL_CLASSIFY_ROI FALSE enum { PROP_0, PROP_OBJECT_CLASS, PROP_RECLASSIFY_INTERVAL, + PROP_SIGNAL_CLASSIFY_ROI, +}; + +enum { + SIGNAL_CLASSIFY_ROI, + LAST_SIGNAL }; #define DEFAULT_OBJECT_CLASS "" @@ -46,6 +54,8 @@ static void gst_gva_classify_finalize(GObject *); static void gst_gva_classify_cleanup(GstGvaClassify *); static void on_base_inference_initialized(GvaBaseInference *base_inference); +static guint gst_classify_signals[LAST_SIGNAL] = { 0 }; + void gst_gva_classify_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { GstGvaClassify *gvaclassify = (GstGvaClassify *)(object); @@ -75,6 +85,10 @@ void gst_gva_classify_set_property(GObject *object, guint property_id, const GVa } break; } + case PROP_SIGNAL_CLASSIFY_ROI: { + gvaclassify->signal_classify_roi = g_value_get_boolean(value); + break; + } default: { G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -94,6 +108,9 @@ void gst_gva_classify_get_property(GObject *object, guint property_id, GValue *v case PROP_RECLASSIFY_INTERVAL: g_value_set_uint(value, gvaclassify->reclassify_interval); break; + case PROP_SIGNAL_CLASSIFY_ROI: + g_value_set_boolean(value, gvaclassify->signal_classify_roi); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -138,6 +155,30 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { "inference interval)", DEFAULT_MIN_RECLASSIFY_INTERVAL, DEFAULT_MAX_RECLASSIFY_INTERVAL, DEFAULT_RECLASSIFY_INTERVAL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + + // Property that determines whether or not the "about-to-classify" signal + // should be raised before classifying a tracked object. + g_object_class_install_property( + gobject_class, PROP_SIGNAL_CLASSIFY_ROI, + g_param_spec_boolean( + "signal-classify-roi", "Signal Classify ROI", + "Send a signal before classifying a tracked object.", + DEFAULT_SIGNAL_CLASSIFY_ROI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + // Signal which indicates to a subscriber that classification of the ROI is + // about to occur and allows the subscriber to request that classification + // be skipped due to some aspect of the ROI's metadata. + // Return value: + // FALSE - classification should be run. + // TRUE - classification should be skipped + // Note: g_signal_emit resets the return value to the default, in this + // case FALSE, when a handler is not connected. + gst_classify_signals[SIGNAL_CLASSIFY_ROI] = + g_signal_new( + "classify-roi", G_TYPE_FROM_CLASS (gvaclassify_class), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstGvaClassifyClass, classify_roi), + NULL, NULL, NULL, G_TYPE_BOOLEAN, 1, + GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE | G_SIGNAL_TYPE_STATIC_SCOPE); } void gst_gva_classify_init(GstGvaClassify *gvaclassify) { @@ -151,6 +192,7 @@ void gst_gva_classify_init(GstGvaClassify *gvaclassify) { gvaclassify->base_inference.is_full_frame = FALSE; gvaclassify->object_class = g_strdup(DEFAULT_OBJECT_CLASS); gvaclassify->reclassify_interval = DEFAULT_RECLASSIFY_INTERVAL; + gvaclassify->signal_classify_roi_id = gst_classify_signals[SIGNAL_CLASSIFY_ROI]; gvaclassify->classification_history = create_classification_history(gvaclassify); if (gvaclassify->classification_history == NULL) return; diff --git a/gst/inference_elements/gvaclassify/gstgvaclassify.h b/gst/inference_elements/gvaclassify/gstgvaclassify.h index 7e478040..b61d79a0 100644 --- a/gst/inference_elements/gvaclassify/gstgvaclassify.h +++ b/gst/inference_elements/gvaclassify/gstgvaclassify.h @@ -23,12 +23,19 @@ typedef struct _GstGvaClassify { // properties: gchar *object_class; guint reclassify_interval; + gboolean signal_classify_roi; + + // Signals + guint signal_classify_roi_id; struct ClassificationHistory *classification_history; } GstGvaClassify; typedef struct _GstGvaClassifyClass { GvaBaseInferenceClass base_class; + + // Declare class handler so that sub-classes have the ability to override it. + gboolean (*classify_roi) (GstElement *element, GstVideoRegionOfInterestMeta *roi); } GstGvaClassifyClass; GType gst_gva_classify_get_type(void); diff --git a/gst/inference_elements/gvaclassify/pre_processors.cpp b/gst/inference_elements/gvaclassify/pre_processors.cpp index 91f37781..9ab7f11b 100644 --- a/gst/inference_elements/gvaclassify/pre_processors.cpp +++ b/gst/inference_elements/gvaclassify/pre_processors.cpp @@ -45,10 +45,15 @@ bool IsROIClassificationNeeded(GvaBaseInference *gva_base_inference, guint64 cur } } - // Check is object recently classified assert(gva_classify->classification_history != NULL); - return (gva_classify->reclassify_interval == 1 || - gva_classify->classification_history->IsROIClassificationNeeded(roi, current_num_frame)); + // If reclassification is possible on every interval, check the metadata to see + // if classification of this ROI should be skipped. + if (gva_classify->reclassify_interval == 1) { + return gva_classify->classification_history->IsROIClassificationNeededDueToMeta(roi); + } + + // Check is object recently classified + return (gva_classify->classification_history->IsROIClassificationNeeded(roi, current_num_frame)); } } // anonymous namespace From 52e60e2d55a7a05de9cb999da2c52c49f5028bbc Mon Sep 17 00:00:00 2001 From: William Wright <74670359+WilliamWright-JCI@users.noreply.github.com> Date: Thu, 19 Nov 2020 10:53:19 +0000 Subject: [PATCH 2/5] Fixed typo in comment --- gst/inference_elements/gvaclassify/gstgvaclassify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/inference_elements/gvaclassify/gstgvaclassify.c b/gst/inference_elements/gvaclassify/gstgvaclassify.c index 373d80e7..7a4e59b4 100644 --- a/gst/inference_elements/gvaclassify/gstgvaclassify.c +++ b/gst/inference_elements/gvaclassify/gstgvaclassify.c @@ -156,7 +156,7 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { DEFAULT_MIN_RECLASSIFY_INTERVAL, DEFAULT_MAX_RECLASSIFY_INTERVAL, DEFAULT_RECLASSIFY_INTERVAL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - // Property that determines whether or not the "about-to-classify" signal + // Property that determines whether or not the "classify-roi" signal // should be raised before classifying a tracked object. g_object_class_install_property( gobject_class, PROP_SIGNAL_CLASSIFY_ROI, From 5352d2b65cd9b69bb2c2b35cda8c3f5484cf463b Mon Sep 17 00:00:00 2001 From: William Wright <74670359+WilliamWright-JCI@users.noreply.github.com> Date: Thu, 3 Dec 2020 13:23:20 +0000 Subject: [PATCH 3/5] Include GstBuffer with signal classify_roi. --- .../gvaclassify/classification_history.cpp | 31 +++++++++---------- .../gvaclassify/classification_history.h | 10 +++--- .../gvaclassify/gstgvaclassify.c | 10 ++++-- .../gvaclassify/gstgvaclassify.h | 2 +- .../gvaclassify/pre_processors.cpp | 8 ++--- 5 files changed, 31 insertions(+), 30 deletions(-) diff --git a/gst/inference_elements/gvaclassify/classification_history.cpp b/gst/inference_elements/gvaclassify/classification_history.cpp index 32db96b8..2bc185bd 100644 --- a/gst/inference_elements/gvaclassify/classification_history.cpp +++ b/gst/inference_elements/gvaclassify/classification_history.cpp @@ -16,7 +16,9 @@ ClassificationHistory::ClassificationHistory(GstGvaClassify *gva_classify) : gva_classify(gva_classify), current_num_frame(0), history(CLASSIFICATION_HISTORY_SIZE) { } -bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMeta *roi, uint64_t current_num_frame) { +bool ClassificationHistory::IsROIClassificationNeeded(GstBuffer *buffer, + GstVideoRegionOfInterestMeta *roi, + unsigned current_num_frame) { try { std::lock_guard guard(history_mutex); this->current_num_frame = current_num_frame; @@ -27,9 +29,9 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMe gint id; if (!get_object_id(roi, &id)) // object has not been tracked - return IsROIClassificationNeededDueToMeta(roi); + return IsROIClassificationNeededDueToMeta(buffer, roi); if (history.count(id) == 0) { // new object - if (!IsROIClassificationNeededDueToMeta(roi)) + if (!IsROIClassificationNeededDueToMeta(buffer, roi)) return false; history.put(id); @@ -37,27 +39,22 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMe result = true; } else if (gva_classify->reclassify_interval == 0) { return false; - } else { - auto current_interval = current_num_frame - history.get(id).frame_of_last_update; - if (current_interval > INT64_MAX && history.get(id).frame_of_last_update > current_num_frame) - current_interval = (UINT64_MAX - history.get(id).frame_of_last_update) + current_num_frame + 1; - if (current_interval >= gva_classify->reclassify_interval) { - // new object or reclassify old object - if (!IsROIClassificationNeededDueToMeta(roi)) - return false; + } else if (current_num_frame - history.get(id).frame_of_last_update >= gva_classify->reclassify_interval) { + // new object or reclassify old object + if (!IsROIClassificationNeededDueToMeta(buffer, roi)) + return false; - history.get(id).frame_of_last_update = current_num_frame; - result = true; - } + history.get(id).frame_of_last_update = current_num_frame; + result = true; } - return result; } catch (const std::exception &e) { std::throw_with_nested(std::runtime_error("Failed to check if detection tensor classification needed")); } } -bool ClassificationHistory::IsROIClassificationNeededDueToMeta(const GstVideoRegionOfInterestMeta *roi) const { +bool ClassificationHistory::IsROIClassificationNeededDueToMeta(GstBuffer *buffer, + const GstVideoRegionOfInterestMeta *roi) const { // If the classify signal is not enabled, then a subscriber will not be // able to decide if classfication should be skipped. if (!gva_classify->signal_classify_roi) { @@ -66,7 +63,7 @@ bool ClassificationHistory::IsROIClassificationNeededDueToMeta(const GstVideoReg // Ask subsciber if classification of this ROI should be skipped gboolean skip = FALSE; - g_signal_emit(gva_classify, gva_classify->signal_classify_roi_id, 0, roi, &skip); + g_signal_emit(gva_classify, gva_classify->signal_classify_roi_id, 0, buffer, roi, &skip); return !skip; } diff --git a/gst/inference_elements/gvaclassify/classification_history.h b/gst/inference_elements/gvaclassify/classification_history.h index 91444e2f..b71c5143 100644 --- a/gst/inference_elements/gvaclassify/classification_history.h +++ b/gst/inference_elements/gvaclassify/classification_history.h @@ -32,24 +32,24 @@ const size_t CLASSIFICATION_HISTORY_SIZE = 100; struct ClassificationHistory { struct ROIClassificationHistory { - uint64_t frame_of_last_update; + unsigned frame_of_last_update; std::map layers_to_roi_params; - ROIClassificationHistory(uint64_t frame_of_last_update = {}, + ROIClassificationHistory(unsigned frame_of_last_update = {}, std::map layers_to_roi_params = {}) : frame_of_last_update(frame_of_last_update), layers_to_roi_params(layers_to_roi_params) { } }; GstGvaClassify *gva_classify; - uint64_t current_num_frame; + unsigned current_num_frame; LRUCache history; std::mutex history_mutex; ClassificationHistory(GstGvaClassify *gva_classify); - bool IsROIClassificationNeeded(GstVideoRegionOfInterestMeta *roi, uint64_t current_num_frame); - bool IsROIClassificationNeededDueToMeta(const GstVideoRegionOfInterestMeta *roi) const; + bool IsROIClassificationNeeded(GstBuffer *buffer, GstVideoRegionOfInterestMeta *roi, unsigned current_num_frame); + bool IsROIClassificationNeededDueToMeta(GstBuffer *buffer, const GstVideoRegionOfInterestMeta *roi) const; void UpdateROIParams(int roi_id, const GstStructure *roi_param); void FillROIParams(GstBuffer *buffer); }; diff --git a/gst/inference_elements/gvaclassify/gstgvaclassify.c b/gst/inference_elements/gvaclassify/gstgvaclassify.c index 7a4e59b4..a468223f 100644 --- a/gst/inference_elements/gvaclassify/gstgvaclassify.c +++ b/gst/inference_elements/gvaclassify/gstgvaclassify.c @@ -19,8 +19,10 @@ #include #include + #define ELEMENT_LONG_NAME "Object classification (requires GstVideoRegionOfInterestMeta on input)" #define ELEMENT_DESCRIPTION ELEMENT_LONG_NAME + #define DEFAULT_SIGNAL_CLASSIFY_ROI FALSE enum { @@ -156,7 +158,7 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { DEFAULT_MIN_RECLASSIFY_INTERVAL, DEFAULT_MAX_RECLASSIFY_INTERVAL, DEFAULT_RECLASSIFY_INTERVAL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - // Property that determines whether or not the "classify-roi" signal + // Property that determines whether or not the "about-to-classify" signal // should be raised before classifying a tracked object. g_object_class_install_property( gobject_class, PROP_SIGNAL_CLASSIFY_ROI, @@ -167,7 +169,8 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { // Signal which indicates to a subscriber that classification of the ROI is // about to occur and allows the subscriber to request that classification - // be skipped due to some aspect of the ROI's metadata. + // be skipped due to some aspect of the ROI's metadata or the frame (buffer) + // that contains the ROI. // Return value: // FALSE - classification should be run. // TRUE - classification should be skipped @@ -177,7 +180,8 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { g_signal_new( "classify-roi", G_TYPE_FROM_CLASS (gvaclassify_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstGvaClassifyClass, classify_roi), - NULL, NULL, NULL, G_TYPE_BOOLEAN, 1, + NULL, NULL, NULL, G_TYPE_BOOLEAN, 2, + GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE | G_SIGNAL_TYPE_STATIC_SCOPE); } diff --git a/gst/inference_elements/gvaclassify/gstgvaclassify.h b/gst/inference_elements/gvaclassify/gstgvaclassify.h index b61d79a0..f92c4a2e 100644 --- a/gst/inference_elements/gvaclassify/gstgvaclassify.h +++ b/gst/inference_elements/gvaclassify/gstgvaclassify.h @@ -35,7 +35,7 @@ typedef struct _GstGvaClassifyClass { GvaBaseInferenceClass base_class; // Declare class handler so that sub-classes have the ability to override it. - gboolean (*classify_roi) (GstElement *element, GstVideoRegionOfInterestMeta *roi); + gboolean (*classify_roi) (GstElement *element, GstBuffer *buf, GstVideoRegionOfInterestMeta *roi); } GstGvaClassifyClass; GType gst_gva_classify_get_type(void); diff --git a/gst/inference_elements/gvaclassify/pre_processors.cpp b/gst/inference_elements/gvaclassify/pre_processors.cpp index 9ab7f11b..5ce0f2e7 100644 --- a/gst/inference_elements/gvaclassify/pre_processors.cpp +++ b/gst/inference_elements/gvaclassify/pre_processors.cpp @@ -24,8 +24,8 @@ namespace { using namespace InferenceBackend; -bool IsROIClassificationNeeded(GvaBaseInference *gva_base_inference, guint64 current_num_frame, - GstBuffer * /* *buffer*/, GstVideoRegionOfInterestMeta *roi) { +bool IsROIClassificationNeeded(GvaBaseInference *gva_base_inference, guint current_num_frame, GstBuffer *buffer, + GstVideoRegionOfInterestMeta *roi) { GstGvaClassify *gva_classify = (GstGvaClassify *)gva_base_inference; // Check is object-class same with roi type @@ -49,11 +49,11 @@ bool IsROIClassificationNeeded(GvaBaseInference *gva_base_inference, guint64 cur // If reclassification is possible on every interval, check the metadata to see // if classification of this ROI should be skipped. if (gva_classify->reclassify_interval == 1) { - return gva_classify->classification_history->IsROIClassificationNeededDueToMeta(roi); + return gva_classify->classification_history->IsROIClassificationNeededDueToMeta(buffer, roi); } // Check is object recently classified - return (gva_classify->classification_history->IsROIClassificationNeeded(roi, current_num_frame)); + return (gva_classify->classification_history->IsROIClassificationNeeded(buffer, roi, current_num_frame)); } } // anonymous namespace From 6cc82fbecb32025f767dcc65c5d7b3a48f8a1460 Mon Sep 17 00:00:00 2001 From: William Wright <74670359+WilliamWright-JCI@users.noreply.github.com> Date: Thu, 3 Dec 2020 14:09:47 +0000 Subject: [PATCH 4/5] Revert "Include GstBuffer with signal classify_roi." The original change was appropriate for the 2020.4 release, but not for master. Will submit a change that is approprite for master shortly. This reverts commit 5352d2b65cd9b69bb2c2b35cda8c3f5484cf463b. --- .../gvaclassify/classification_history.cpp | 31 ++++++++++--------- .../gvaclassify/classification_history.h | 10 +++--- .../gvaclassify/gstgvaclassify.c | 10 ++---- .../gvaclassify/gstgvaclassify.h | 2 +- .../gvaclassify/pre_processors.cpp | 8 ++--- 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/gst/inference_elements/gvaclassify/classification_history.cpp b/gst/inference_elements/gvaclassify/classification_history.cpp index 2bc185bd..32db96b8 100644 --- a/gst/inference_elements/gvaclassify/classification_history.cpp +++ b/gst/inference_elements/gvaclassify/classification_history.cpp @@ -16,9 +16,7 @@ ClassificationHistory::ClassificationHistory(GstGvaClassify *gva_classify) : gva_classify(gva_classify), current_num_frame(0), history(CLASSIFICATION_HISTORY_SIZE) { } -bool ClassificationHistory::IsROIClassificationNeeded(GstBuffer *buffer, - GstVideoRegionOfInterestMeta *roi, - unsigned current_num_frame) { +bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMeta *roi, uint64_t current_num_frame) { try { std::lock_guard guard(history_mutex); this->current_num_frame = current_num_frame; @@ -29,9 +27,9 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstBuffer *buffer, gint id; if (!get_object_id(roi, &id)) // object has not been tracked - return IsROIClassificationNeededDueToMeta(buffer, roi); + return IsROIClassificationNeededDueToMeta(roi); if (history.count(id) == 0) { // new object - if (!IsROIClassificationNeededDueToMeta(buffer, roi)) + if (!IsROIClassificationNeededDueToMeta(roi)) return false; history.put(id); @@ -39,22 +37,27 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstBuffer *buffer, result = true; } else if (gva_classify->reclassify_interval == 0) { return false; - } else if (current_num_frame - history.get(id).frame_of_last_update >= gva_classify->reclassify_interval) { - // new object or reclassify old object - if (!IsROIClassificationNeededDueToMeta(buffer, roi)) - return false; + } else { + auto current_interval = current_num_frame - history.get(id).frame_of_last_update; + if (current_interval > INT64_MAX && history.get(id).frame_of_last_update > current_num_frame) + current_interval = (UINT64_MAX - history.get(id).frame_of_last_update) + current_num_frame + 1; + if (current_interval >= gva_classify->reclassify_interval) { + // new object or reclassify old object + if (!IsROIClassificationNeededDueToMeta(roi)) + return false; - history.get(id).frame_of_last_update = current_num_frame; - result = true; + history.get(id).frame_of_last_update = current_num_frame; + result = true; + } } + return result; } catch (const std::exception &e) { std::throw_with_nested(std::runtime_error("Failed to check if detection tensor classification needed")); } } -bool ClassificationHistory::IsROIClassificationNeededDueToMeta(GstBuffer *buffer, - const GstVideoRegionOfInterestMeta *roi) const { +bool ClassificationHistory::IsROIClassificationNeededDueToMeta(const GstVideoRegionOfInterestMeta *roi) const { // If the classify signal is not enabled, then a subscriber will not be // able to decide if classfication should be skipped. if (!gva_classify->signal_classify_roi) { @@ -63,7 +66,7 @@ bool ClassificationHistory::IsROIClassificationNeededDueToMeta(GstBuffer *buffer // Ask subsciber if classification of this ROI should be skipped gboolean skip = FALSE; - g_signal_emit(gva_classify, gva_classify->signal_classify_roi_id, 0, buffer, roi, &skip); + g_signal_emit(gva_classify, gva_classify->signal_classify_roi_id, 0, roi, &skip); return !skip; } diff --git a/gst/inference_elements/gvaclassify/classification_history.h b/gst/inference_elements/gvaclassify/classification_history.h index b71c5143..91444e2f 100644 --- a/gst/inference_elements/gvaclassify/classification_history.h +++ b/gst/inference_elements/gvaclassify/classification_history.h @@ -32,24 +32,24 @@ const size_t CLASSIFICATION_HISTORY_SIZE = 100; struct ClassificationHistory { struct ROIClassificationHistory { - unsigned frame_of_last_update; + uint64_t frame_of_last_update; std::map layers_to_roi_params; - ROIClassificationHistory(unsigned frame_of_last_update = {}, + ROIClassificationHistory(uint64_t frame_of_last_update = {}, std::map layers_to_roi_params = {}) : frame_of_last_update(frame_of_last_update), layers_to_roi_params(layers_to_roi_params) { } }; GstGvaClassify *gva_classify; - unsigned current_num_frame; + uint64_t current_num_frame; LRUCache history; std::mutex history_mutex; ClassificationHistory(GstGvaClassify *gva_classify); - bool IsROIClassificationNeeded(GstBuffer *buffer, GstVideoRegionOfInterestMeta *roi, unsigned current_num_frame); - bool IsROIClassificationNeededDueToMeta(GstBuffer *buffer, const GstVideoRegionOfInterestMeta *roi) const; + bool IsROIClassificationNeeded(GstVideoRegionOfInterestMeta *roi, uint64_t current_num_frame); + bool IsROIClassificationNeededDueToMeta(const GstVideoRegionOfInterestMeta *roi) const; void UpdateROIParams(int roi_id, const GstStructure *roi_param); void FillROIParams(GstBuffer *buffer); }; diff --git a/gst/inference_elements/gvaclassify/gstgvaclassify.c b/gst/inference_elements/gvaclassify/gstgvaclassify.c index a468223f..7a4e59b4 100644 --- a/gst/inference_elements/gvaclassify/gstgvaclassify.c +++ b/gst/inference_elements/gvaclassify/gstgvaclassify.c @@ -19,10 +19,8 @@ #include #include - #define ELEMENT_LONG_NAME "Object classification (requires GstVideoRegionOfInterestMeta on input)" #define ELEMENT_DESCRIPTION ELEMENT_LONG_NAME - #define DEFAULT_SIGNAL_CLASSIFY_ROI FALSE enum { @@ -158,7 +156,7 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { DEFAULT_MIN_RECLASSIFY_INTERVAL, DEFAULT_MAX_RECLASSIFY_INTERVAL, DEFAULT_RECLASSIFY_INTERVAL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); - // Property that determines whether or not the "about-to-classify" signal + // Property that determines whether or not the "classify-roi" signal // should be raised before classifying a tracked object. g_object_class_install_property( gobject_class, PROP_SIGNAL_CLASSIFY_ROI, @@ -169,8 +167,7 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { // Signal which indicates to a subscriber that classification of the ROI is // about to occur and allows the subscriber to request that classification - // be skipped due to some aspect of the ROI's metadata or the frame (buffer) - // that contains the ROI. + // be skipped due to some aspect of the ROI's metadata. // Return value: // FALSE - classification should be run. // TRUE - classification should be skipped @@ -180,8 +177,7 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { g_signal_new( "classify-roi", G_TYPE_FROM_CLASS (gvaclassify_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstGvaClassifyClass, classify_roi), - NULL, NULL, NULL, G_TYPE_BOOLEAN, 2, - GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, + NULL, NULL, NULL, G_TYPE_BOOLEAN, 1, GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE | G_SIGNAL_TYPE_STATIC_SCOPE); } diff --git a/gst/inference_elements/gvaclassify/gstgvaclassify.h b/gst/inference_elements/gvaclassify/gstgvaclassify.h index f92c4a2e..b61d79a0 100644 --- a/gst/inference_elements/gvaclassify/gstgvaclassify.h +++ b/gst/inference_elements/gvaclassify/gstgvaclassify.h @@ -35,7 +35,7 @@ typedef struct _GstGvaClassifyClass { GvaBaseInferenceClass base_class; // Declare class handler so that sub-classes have the ability to override it. - gboolean (*classify_roi) (GstElement *element, GstBuffer *buf, GstVideoRegionOfInterestMeta *roi); + gboolean (*classify_roi) (GstElement *element, GstVideoRegionOfInterestMeta *roi); } GstGvaClassifyClass; GType gst_gva_classify_get_type(void); diff --git a/gst/inference_elements/gvaclassify/pre_processors.cpp b/gst/inference_elements/gvaclassify/pre_processors.cpp index 5ce0f2e7..9ab7f11b 100644 --- a/gst/inference_elements/gvaclassify/pre_processors.cpp +++ b/gst/inference_elements/gvaclassify/pre_processors.cpp @@ -24,8 +24,8 @@ namespace { using namespace InferenceBackend; -bool IsROIClassificationNeeded(GvaBaseInference *gva_base_inference, guint current_num_frame, GstBuffer *buffer, - GstVideoRegionOfInterestMeta *roi) { +bool IsROIClassificationNeeded(GvaBaseInference *gva_base_inference, guint64 current_num_frame, + GstBuffer * /* *buffer*/, GstVideoRegionOfInterestMeta *roi) { GstGvaClassify *gva_classify = (GstGvaClassify *)gva_base_inference; // Check is object-class same with roi type @@ -49,11 +49,11 @@ bool IsROIClassificationNeeded(GvaBaseInference *gva_base_inference, guint curre // If reclassification is possible on every interval, check the metadata to see // if classification of this ROI should be skipped. if (gva_classify->reclassify_interval == 1) { - return gva_classify->classification_history->IsROIClassificationNeededDueToMeta(buffer, roi); + return gva_classify->classification_history->IsROIClassificationNeededDueToMeta(roi); } // Check is object recently classified - return (gva_classify->classification_history->IsROIClassificationNeeded(buffer, roi, current_num_frame)); + return (gva_classify->classification_history->IsROIClassificationNeeded(roi, current_num_frame)); } } // anonymous namespace From 81a5aae9ed1fa424a9a747e95bd74d1d39f525e2 Mon Sep 17 00:00:00 2001 From: William Wright <74670359+WilliamWright-JCI@users.noreply.github.com> Date: Thu, 3 Dec 2020 15:15:51 +0000 Subject: [PATCH 5/5] Include GstBuffer with signal classify_roi. --- .../gvaclassify/classification_history.cpp | 15 +++++++++------ .../gvaclassify/classification_history.h | 4 ++-- .../gvaclassify/gstgvaclassify.c | 6 ++++-- .../gvaclassify/gstgvaclassify.h | 2 +- .../gvaclassify/pre_processors.cpp | 6 +++--- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/gst/inference_elements/gvaclassify/classification_history.cpp b/gst/inference_elements/gvaclassify/classification_history.cpp index 32db96b8..31279115 100644 --- a/gst/inference_elements/gvaclassify/classification_history.cpp +++ b/gst/inference_elements/gvaclassify/classification_history.cpp @@ -16,7 +16,9 @@ ClassificationHistory::ClassificationHistory(GstGvaClassify *gva_classify) : gva_classify(gva_classify), current_num_frame(0), history(CLASSIFICATION_HISTORY_SIZE) { } -bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMeta *roi, uint64_t current_num_frame) { +bool ClassificationHistory::IsROIClassificationNeeded(GstBuffer *buffer, + GstVideoRegionOfInterestMeta *roi, + uint64_t current_num_frame) { try { std::lock_guard guard(history_mutex); this->current_num_frame = current_num_frame; @@ -27,9 +29,9 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMe gint id; if (!get_object_id(roi, &id)) // object has not been tracked - return IsROIClassificationNeededDueToMeta(roi); + return IsROIClassificationNeededDueToMeta(buffer, roi); if (history.count(id) == 0) { // new object - if (!IsROIClassificationNeededDueToMeta(roi)) + if (!IsROIClassificationNeededDueToMeta(buffer, roi)) return false; history.put(id); @@ -43,7 +45,7 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMe current_interval = (UINT64_MAX - history.get(id).frame_of_last_update) + current_num_frame + 1; if (current_interval >= gva_classify->reclassify_interval) { // new object or reclassify old object - if (!IsROIClassificationNeededDueToMeta(roi)) + if (!IsROIClassificationNeededDueToMeta(buffer, roi)) return false; history.get(id).frame_of_last_update = current_num_frame; @@ -57,7 +59,8 @@ bool ClassificationHistory::IsROIClassificationNeeded(GstVideoRegionOfInterestMe } } -bool ClassificationHistory::IsROIClassificationNeededDueToMeta(const GstVideoRegionOfInterestMeta *roi) const { +bool ClassificationHistory::IsROIClassificationNeededDueToMeta(GstBuffer *buffer, + const GstVideoRegionOfInterestMeta *roi) const { // If the classify signal is not enabled, then a subscriber will not be // able to decide if classfication should be skipped. if (!gva_classify->signal_classify_roi) { @@ -66,7 +69,7 @@ bool ClassificationHistory::IsROIClassificationNeededDueToMeta(const GstVideoReg // Ask subsciber if classification of this ROI should be skipped gboolean skip = FALSE; - g_signal_emit(gva_classify, gva_classify->signal_classify_roi_id, 0, roi, &skip); + g_signal_emit(gva_classify, gva_classify->signal_classify_roi_id, 0, buffer, roi, &skip); return !skip; } diff --git a/gst/inference_elements/gvaclassify/classification_history.h b/gst/inference_elements/gvaclassify/classification_history.h index 91444e2f..d46d22d9 100644 --- a/gst/inference_elements/gvaclassify/classification_history.h +++ b/gst/inference_elements/gvaclassify/classification_history.h @@ -48,8 +48,8 @@ struct ClassificationHistory { ClassificationHistory(GstGvaClassify *gva_classify); - bool IsROIClassificationNeeded(GstVideoRegionOfInterestMeta *roi, uint64_t current_num_frame); - bool IsROIClassificationNeededDueToMeta(const GstVideoRegionOfInterestMeta *roi) const; + bool IsROIClassificationNeeded(GstBuffer *buffer, GstVideoRegionOfInterestMeta *roi, uint64_t current_num_frame); + bool IsROIClassificationNeededDueToMeta(GstBuffer *buffer, const GstVideoRegionOfInterestMeta *roi) const; void UpdateROIParams(int roi_id, const GstStructure *roi_param); void FillROIParams(GstBuffer *buffer); }; diff --git a/gst/inference_elements/gvaclassify/gstgvaclassify.c b/gst/inference_elements/gvaclassify/gstgvaclassify.c index 7a4e59b4..d6e621f7 100644 --- a/gst/inference_elements/gvaclassify/gstgvaclassify.c +++ b/gst/inference_elements/gvaclassify/gstgvaclassify.c @@ -167,7 +167,8 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { // Signal which indicates to a subscriber that classification of the ROI is // about to occur and allows the subscriber to request that classification - // be skipped due to some aspect of the ROI's metadata. + // be skipped due to some aspect of the ROI's metadata or the frame (buffer) + // that contains the ROI. // Return value: // FALSE - classification should be run. // TRUE - classification should be skipped @@ -177,7 +178,8 @@ void gst_gva_classify_class_init(GstGvaClassifyClass *gvaclassify_class) { g_signal_new( "classify-roi", G_TYPE_FROM_CLASS (gvaclassify_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstGvaClassifyClass, classify_roi), - NULL, NULL, NULL, G_TYPE_BOOLEAN, 1, + NULL, NULL, NULL, G_TYPE_BOOLEAN, 2, + GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE | G_SIGNAL_TYPE_STATIC_SCOPE); } diff --git a/gst/inference_elements/gvaclassify/gstgvaclassify.h b/gst/inference_elements/gvaclassify/gstgvaclassify.h index b61d79a0..f92c4a2e 100644 --- a/gst/inference_elements/gvaclassify/gstgvaclassify.h +++ b/gst/inference_elements/gvaclassify/gstgvaclassify.h @@ -35,7 +35,7 @@ typedef struct _GstGvaClassifyClass { GvaBaseInferenceClass base_class; // Declare class handler so that sub-classes have the ability to override it. - gboolean (*classify_roi) (GstElement *element, GstVideoRegionOfInterestMeta *roi); + gboolean (*classify_roi) (GstElement *element, GstBuffer *buf, GstVideoRegionOfInterestMeta *roi); } GstGvaClassifyClass; GType gst_gva_classify_get_type(void); diff --git a/gst/inference_elements/gvaclassify/pre_processors.cpp b/gst/inference_elements/gvaclassify/pre_processors.cpp index 9ab7f11b..bcf8a454 100644 --- a/gst/inference_elements/gvaclassify/pre_processors.cpp +++ b/gst/inference_elements/gvaclassify/pre_processors.cpp @@ -25,7 +25,7 @@ namespace { using namespace InferenceBackend; bool IsROIClassificationNeeded(GvaBaseInference *gva_base_inference, guint64 current_num_frame, - GstBuffer * /* *buffer*/, GstVideoRegionOfInterestMeta *roi) { + GstBuffer *buffer, GstVideoRegionOfInterestMeta *roi) { GstGvaClassify *gva_classify = (GstGvaClassify *)gva_base_inference; // Check is object-class same with roi type @@ -49,11 +49,11 @@ bool IsROIClassificationNeeded(GvaBaseInference *gva_base_inference, guint64 cur // If reclassification is possible on every interval, check the metadata to see // if classification of this ROI should be skipped. if (gva_classify->reclassify_interval == 1) { - return gva_classify->classification_history->IsROIClassificationNeededDueToMeta(roi); + return gva_classify->classification_history->IsROIClassificationNeededDueToMeta(buffer, roi); } // Check is object recently classified - return (gva_classify->classification_history->IsROIClassificationNeeded(roi, current_num_frame)); + return (gva_classify->classification_history->IsROIClassificationNeeded(buffer, roi, current_num_frame)); } } // anonymous namespace