diff --git a/docs/source/elements/gvawatermark.md b/docs/source/elements/gvawatermark.md index a8a14d60..69090622 100644 --- a/docs/source/elements/gvawatermark.md +++ b/docs/source/elements/gvawatermark.md @@ -69,6 +69,11 @@ Element Properties: device : Supported devices are CPU and GPU. Default is CPU on system memory and GPU on video memory flags: readable, writable String. Default: null + disp-avgfps : If true, display the average FPS read from gvafpscounter element on the output video. + The gvafpscounter element must be present in the pipeline. + e.g. ... ! gwatermark disp-avgfps=true ! gvafpscounter ! ... + flags: readable, writable + Boolean. Default: false message-forward : Forwards all children messages flags: readable, writable Boolean. Default: false diff --git a/src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.cpp b/src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.cpp index c1b821a1..169459c2 100644 --- a/src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.cpp +++ b/src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.cpp @@ -30,7 +30,6 @@ #include #include "gva_caps.h" -#include "gva_utils.h" #include "inference_backend/buffer_mapper.h" #include "so_loader.h" #include "utils.h" @@ -115,7 +114,7 @@ InferenceBackend::MemoryType memoryTypeFromCaps(GstCaps *caps) { } // namespace struct Impl { - Impl(GstVideoInfo *info, InferenceBackend::MemoryType mem_type); + Impl(GstVideoInfo *info, InferenceBackend::MemoryType mem_type, GstElement *element, bool disp_avgfps); bool extract_primitives(GstBuffer *buffer); int get_num_primitives() const; bool render(GstBuffer *buffer); @@ -133,7 +132,7 @@ struct Impl { void preparePrimsForKeypointConnections(GstStructure *s, const std::vector &keypoints_data, const std::vector &dims, const std::vector &confidence, const GVA::Rect &rectangle, std::vector &prims) const; - + void find_gvafpscounter_element(); std::unique_ptr createRenderer(std::shared_ptr converter); std::unique_ptr createGPURenderer(dlstreamer::ImageFormat format, @@ -144,6 +143,8 @@ struct Impl { std::unique_ptr createOpenCVRenderer(std::shared_ptr converter); GstVideoInfo *_vinfo; + GstElement *_element; + GstElement *_gvafpscounter_element = nullptr; std::string _backend_type; InferenceBackend::MemoryType _mem_type; @@ -163,9 +164,10 @@ struct Impl { const double scale = 1.0; } _font; const bool _obb = false; + bool _disp_avgfps = false; }; -enum { PROP_0, PROP_DEVICE, PROP_OBB }; +enum { PROP_0, PROP_DEVICE, PROP_OBB, PROP_DISP_AVGFPS }; G_DEFINE_TYPE_WITH_CODE(GstGvaWatermarkImpl, gst_gva_watermark_impl, GST_TYPE_BASE_TRANSFORM, GST_DEBUG_CATEGORY_INIT(gst_gva_watermark_impl_debug_category, "gvawatermarkimpl", 0, @@ -189,6 +191,9 @@ void gst_gva_watermark_impl_set_property(GObject *object, guint prop_id, const G case PROP_OBB: gvawatermark->obb = g_value_get_boolean(value); break; + case PROP_DISP_AVGFPS: + gvawatermark->disp_avgfps = g_value_get_boolean(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -211,6 +216,9 @@ void gst_gva_watermark_impl_get_property(GObject *object, guint prop_id, GValue case PROP_OBB: g_value_set_boolean(value, self->obb); break; + case PROP_DISP_AVGFPS: + g_value_set_boolean(value, self->disp_avgfps); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -326,7 +334,8 @@ static gboolean gst_gva_watermark_impl_set_caps(GstBaseTransform *trans, GstCaps #endif try { - gvawatermark->impl = std::make_shared(&gvawatermark->info, mem_type); + gvawatermark->impl = + std::make_shared(&gvawatermark->info, mem_type, GST_ELEMENT(trans), gvawatermark->disp_avgfps); } catch (const std::exception &e) { GST_ELEMENT_ERROR(gvawatermark, CORE, FAILED, ("Could not initialize"), ("Cannot create watermark instance. %s", Utils::createNestedErrorMsg(e).c_str())); @@ -662,9 +671,17 @@ static void gst_gva_watermark_impl_class_init(GstGvaWatermarkImplClass *klass) { "If true, draw oriented bounding box instead of object mask", false, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + g_object_class_install_property( + gobject_class, PROP_DISP_AVGFPS, + g_param_spec_boolean("disp-avgfps", "Display Average FPS", + "If true, display the average FPS read from gvafpscounter element on the output video." + "The gvafpscounter element must be present in the pipeline." + "e.g. gwatermark ! gvafpscounter ! ...", + false, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); } -Impl::Impl(GstVideoInfo *info, InferenceBackend::MemoryType mem_type) : _vinfo(info), _mem_type(mem_type) { +Impl::Impl(GstVideoInfo *info, InferenceBackend::MemoryType mem_type, GstElement *element, bool disp_avgfps) + : _vinfo(info), _element(element), _mem_type(mem_type), _disp_avgfps(disp_avgfps) { assert(_vinfo); if (GST_VIDEO_INFO_COLORIMETRY(_vinfo).matrix == GstVideoColorMatrix::GST_VIDEO_COLOR_MATRIX_UNKNOWN) throw std::runtime_error("GST_VIDEO_COLOR_MATRIX_UNKNOWN"); @@ -680,6 +697,10 @@ Impl::Impl(GstVideoInfo *info, InferenceBackend::MemoryType mem_type) : _vinfo(i _renderer = createRenderer(std::move(converter)); _renderer_opencv = createOpenCVRenderer(std::move(converterBGR)); + + // Find gvafpscounter element in the pipeline to put avg-fps on output video + if (_disp_avgfps) + find_gvafpscounter_element(); } size_t get_keypoint_index_by_name(const gchar *target_name, GValueArray *names) { @@ -697,6 +718,51 @@ size_t get_keypoint_index_by_name(const gchar *target_name, GValueArray *names) return names->n_values; } +void Impl::find_gvafpscounter_element() { + + if (!_element) + return; + + GstObject *parent = GST_OBJECT_PARENT(GST_ELEMENT(_element)); + GstElement *pipeline = nullptr; + // Traverse up the hierarchy to find the pipeline + while (parent && !GST_IS_PIPELINE(parent)) { + parent = GST_OBJECT_PARENT(parent); + } + if (parent && GST_IS_PIPELINE(parent)) { + pipeline = GST_ELEMENT(parent); + } + if (pipeline) { + GstIterator *it = gst_bin_iterate_elements(GST_BIN(pipeline)); + GValue value = G_VALUE_INIT; + gboolean done = FALSE; + while (!done) { + switch (gst_iterator_next(it, &value)) { + case GST_ITERATOR_OK: { + GstElement *element = GST_ELEMENT(g_value_get_object(&value)); + const gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element)); + if (g_str_has_prefix(factory_name, "gvafpscounter")) { + _gvafpscounter_element = element; + // No need to continue searching + done = TRUE; + } + g_value_reset(&value); + break; + } + case GST_ITERATOR_RESYNC: + gst_iterator_resync(it); + break; + case GST_ITERATOR_ERROR: + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + g_value_unset(&value); + gst_iterator_free(it); + } +} + bool Impl::extract_primitives(GstBuffer *buffer) { ITT_TASK(__FUNCTION__); @@ -783,17 +849,6 @@ void Impl::preparePrimsForRoi(GVA::RegionOfInterest &roi, std::vector rect = {safe_convert(rect_u32.x), safe_convert(rect_u32.y), safe_convert(rect_u32.w), safe_convert(rect_u32.h)}; - // auto rect = roi.normalized_rect(_vinfo->width, _vinfo->height); - // if (rect.w && rect.h) { - // rect.x *= _vinfo->width; - // rect.y *= _vinfo->height; - // rect.w *= _vinfo->width; - // rect.h *= _vinfo->height; - // } else { - // auto rect_u32 = roi.rect(); - // rect = {safe_convert(rect_u32.x), safe_convert(rect_u32.y), safe_convert(rect_u32.w), - // safe_convert(rect_u32.h)}; - // } clip_rect(rect.x, rect.y, rect.w, rect.h, _vinfo); std::ostringstream text; @@ -829,6 +884,20 @@ void Impl::preparePrimsForRoi(GVA::RegionOfInterest &roi, std::vector 0.0f) { + fpstext << "[avg " << std::fixed << std::setprecision(1) << avg_fps << " FPS]"; + if (fpstext.str().size() != 0) { + cv::Point2f pos(_vinfo->width * 0.7, _vinfo->height - 20.f); + prims.emplace_back(render::Text(fpstext.str(), pos, _font.type, _font.scale * 0.7, indexToColor(1))); + } + } + } } void Impl::preparePrimsForTensor(const GVA::Tensor &tensor, GVA::Rect rect, std::vector &prims, diff --git a/src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.h b/src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.h index 8ca4675c..af583ac2 100644 --- a/src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.h +++ b/src/monolithic/gst/elements/gvawatermark/gstgvawatermarkimpl.h @@ -41,6 +41,7 @@ struct _GstGvaWatermarkImpl { GstVideoInfo info; gchar *device; bool obb; + bool disp_avgfps; std::shared_ptr impl; InferenceBackend::MemoryType negotiated_mem_type = InferenceBackend::MemoryType::ANY; diff --git a/src/monolithic/gst/elements/gvawatermark/gvawatermark.cpp b/src/monolithic/gst/elements/gvawatermark/gvawatermark.cpp index d5713ed6..fe7bd969 100644 --- a/src/monolithic/gst/elements/gvawatermark/gvawatermark.cpp +++ b/src/monolithic/gst/elements/gvawatermark/gvawatermark.cpp @@ -21,7 +21,7 @@ GST_DEBUG_CATEGORY_STATIC(gst_gva_watermark_debug_category); #define DEFAULT_DEVICE "CPU" -enum { PROP_0, PROP_DEVICE, PROP_OBB }; +enum { PROP_0, PROP_DEVICE, PROP_OBB, PROP_DISP_AVGFPS }; G_DEFINE_TYPE_WITH_CODE(GstGvaWatermark, gst_gva_watermark, GST_TYPE_BIN, GST_DEBUG_CATEGORY_INIT(gst_gva_watermark_debug_category, "gvawatermark", 0, @@ -97,6 +97,13 @@ static void gst_gva_watermark_class_init(GstGvaWatermarkClass *klass) { "If true, draw oriented bounding box instead of object mask", false, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); + g_object_class_install_property( + gobject_class, PROP_DISP_AVGFPS, + g_param_spec_boolean("disp-avgfps", "Display Average FPS", + "If true, display the average FPS read from gvafpscounter element on the output video.\n" + "\t\t\tThe gvafpscounter element must be present in the pipeline.\n" + "\t\t\te.g. ... ! gwatermark ! gvafpscounter ! ...", + false, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); } static void gst_gva_watermark_init(GstGvaWatermark *self) { @@ -176,6 +183,10 @@ void gst_gva_watermark_set_property(GObject *object, guint property_id, const GV gvawatermark->obb = g_value_get_boolean(value); g_object_set(gvawatermark->watermarkimpl, "obb", gvawatermark->obb, nullptr); break; + case PROP_DISP_AVGFPS: + gvawatermark->disp_avgfps = g_value_get_boolean(value); + g_object_set(gvawatermark->watermarkimpl, "disp-avgfps", gvawatermark->disp_avgfps, nullptr); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -194,6 +205,9 @@ void gst_gva_watermark_get_property(GObject *object, guint property_id, GValue * case PROP_OBB: g_value_set_boolean(value, gvawatermark->obb); break; + case PROP_DISP_AVGFPS: + g_value_set_boolean(value, gvawatermark->disp_avgfps); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; diff --git a/src/monolithic/gst/elements/gvawatermark/gvawatermark.h b/src/monolithic/gst/elements/gvawatermark/gvawatermark.h index 891a8edc..6eb5efb6 100644 --- a/src/monolithic/gst/elements/gvawatermark/gvawatermark.h +++ b/src/monolithic/gst/elements/gvawatermark/gvawatermark.h @@ -30,6 +30,7 @@ struct _GstGvaWatermark { GstPad *srcpad; gchar *device; bool obb; + bool disp_avgfps; bool use_watermarkimpl_only;