Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gvaclassify signal #157

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 21 additions & 1 deletion gst/inference_elements/gvaclassify/classification_history.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand All @@ -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<std::mutex> guard(history_mutex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
Expand Down
42 changes: 42 additions & 0 deletions gst/inference_elements/gvaclassify/gstgvaclassify.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@
#include <gst/base/gstbasetransform.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideometa.h>

#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,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can address or otherwise eliminate the apparent overhead, then this property can be eliminated.

The 34 ns I measured is at least 5 orders of magnitude below the typical cost of classification. So, we should be fine to always emit the signal, if it turns out that the "0.4% increase in CPU time" was either a measurement error or a real performance problem we can fix.

};

enum {
SIGNAL_CLASSIFY_ROI,
LAST_SIGNAL
};

#define DEFAULT_OBJECT_CLASS ""
Expand All @@ -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);

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming to something like "should-skip-roi", since that's the effect of a handler returning TRUE.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The accumulator parameter should probably be &g_signal_accumulator_true_handled. We need to actually test that with multiple handlers, as well.

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) {
Expand All @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions gst/inference_elements/gvaclassify/gstgvaclassify.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 8 additions & 3 deletions gst/inference_elements/gvaclassify/pre_processors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down