From a2fbeec6008f8559d56d3d4cc33809f6b565c241 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 7 Dec 2022 12:49:27 -0600 Subject: [PATCH 001/126] Add process_selector_features function as a static member of the GstPylonFeatureWalker class --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 4 ++-- gst-libs/gst/pylon/gstpylonfeaturewalker.h | 5 ++--- gst-libs/gst/pylon/gstpylonmeta.cpp | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 98fb7ca..057c329 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -109,7 +109,7 @@ static std::vector gst_pylon_get_int_entries( return entry_names; } -std::vector gst_pylon_process_selector_features( +std::vector GstPylonFeatureWalker::process_selector_features( GenApi::INode* node, GenApi::INode** selector_node) { std::vector enum_values; std::string error_msg; @@ -176,7 +176,7 @@ static std::vector gst_pylon_camera_handle_node( g_return_val_if_fail(node, specs_list); std::vector enum_values = - gst_pylon_process_selector_features(node, &selector_node); + GstPylonFeatureWalker::process_selector_features(node, &selector_node); /* If the number of selector values (stored in enum_values) is 1, leave * selector_node NULL, hence treating the feature as a "direct" one. */ diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.h b/gst-libs/gst/pylon/gstpylonfeaturewalker.h index c08c59f..548ea79 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.h +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.h @@ -58,9 +58,8 @@ class GstPylonFeatureWalker { static void install_properties(GObjectClass* oclass, GenApi::INodeMap& nodemap, const gchar* device_fullname); + static std::vector process_selector_features( + GenApi::INode* node, GenApi::INode** selector_node); }; -std::vector gst_pylon_process_selector_features( - GenApi::INode* node, GenApi::INode** selector_node); - #endif diff --git a/gst-libs/gst/pylon/gstpylonmeta.cpp b/gst-libs/gst/pylon/gstpylonmeta.cpp index d204848..6379e97 100644 --- a/gst-libs/gst/pylon/gstpylonmeta.cpp +++ b/gst-libs/gst/pylon/gstpylonmeta.cpp @@ -176,7 +176,8 @@ static void gst_pylon_meta_fill_result_chunks( std::vector enum_values; try { - enum_values = gst_pylon_process_selector_features(node, &selector_node); + enum_values = GstPylonFeatureWalker::process_selector_features( + node, &selector_node); } catch (const Pylon::GenericException &e) { GST_WARNING("Chunk %s not added: %s", node->GetName().c_str(), e.GetDescription()); From 7ebe0af7fb3a5136ff9770d956700fcf9057949c Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 7 Dec 2022 17:17:54 -0600 Subject: [PATCH 002/126] Condense find_limits and query_access into a single function call --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 55 ++++++++++++++------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 11bc198..79c5b11 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -125,6 +125,12 @@ static void gst_pylon_find_limits( GenApi::INode *node, double &minimum_under_all_settings, double &maximum_under_all_settings, std::vector &invalidators_result); +template +static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, + GenApi::INode *node, + GParamFlags &flags, + T &minimum_under_all_settings, + T &maximum_under_all_settings); static gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node); static GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, GenApi::INode *node); @@ -515,6 +521,19 @@ static void gst_pylon_find_limits(GenApi::INode *node, } } +template +static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, + GenApi::INode *node, + GParamFlags &flags, + T &minimum_under_all_settings, + T &maximum_under_all_settings) { + g_return_if_fail(node); + + flags = gst_pylon_query_access(nodemap, node); + gst_pylon_find_limits(node, minimum_under_all_settings, + maximum_under_all_settings); +} + static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, GenApi::INode *node) { g_return_val_if_fail(node, NULL); @@ -522,13 +541,14 @@ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, Pylon::CIntegerParameter param(node); gint64 max_value = 0; gint64 min_value = 0; + GParamFlags flags = G_PARAM_READABLE; - gst_pylon_find_limits(node, min_value, - max_value); + gst_pylon_query_feature_properties( + nodemap, node, flags, min_value, max_value); - return g_param_spec_int64( - node->GetName(), node->GetDisplayName(), node->GetToolTip(), min_value, - max_value, param.GetValue(), gst_pylon_query_access(nodemap, node)); + return g_param_spec_int64(node->GetName(), node->GetDisplayName(), + node->GetToolTip(), min_value, max_value, + param.GetValue(), flags); } static GParamSpec *gst_pylon_make_spec_selector_int64(GenApi::INodeMap &nodemap, @@ -541,14 +561,15 @@ static GParamSpec *gst_pylon_make_spec_selector_int64(GenApi::INodeMap &nodemap, Pylon::CIntegerParameter param(node); gint64 max_value = 0; gint64 min_value = 0; + GParamFlags flags = G_PARAM_READABLE; - gst_pylon_find_limits(node, min_value, - max_value); + gst_pylon_query_feature_properties( + nodemap, node, flags, min_value, max_value); return gst_pylon_param_spec_selector_int64( nodemap, node->GetName(), selector->GetName(), selector_value, node->GetDisplayName(), node->GetToolTip(), min_value, max_value, - param.GetValue(), gst_pylon_query_access(nodemap, node)); + param.GetValue(), flags); } static GParamSpec *gst_pylon_make_spec_bool(GenApi::INodeMap &nodemap, @@ -584,13 +605,14 @@ static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, Pylon::CFloatParameter param(node); gdouble max_value = 0; gdouble min_value = 0; + GParamFlags flags = G_PARAM_READABLE; - gst_pylon_find_limits(node, min_value, - max_value); + gst_pylon_query_feature_properties( + nodemap, node, flags, min_value, max_value); - return g_param_spec_float( - node->GetName(), node->GetDisplayName(), node->GetToolTip(), min_value, - max_value, param.GetValue(), gst_pylon_query_access(nodemap, node)); + return g_param_spec_float(node->GetName(), node->GetDisplayName(), + node->GetToolTip(), min_value, max_value, + param.GetValue(), flags); } static GParamSpec *gst_pylon_make_spec_selector_float(GenApi::INodeMap &nodemap, @@ -603,14 +625,15 @@ static GParamSpec *gst_pylon_make_spec_selector_float(GenApi::INodeMap &nodemap, Pylon::CFloatParameter param(node); gdouble max_value = 0; gdouble min_value = 0; + GParamFlags flags = G_PARAM_READABLE; - gst_pylon_find_limits(node, min_value, - max_value); + gst_pylon_query_feature_properties( + nodemap, node, flags, min_value, max_value); return gst_pylon_param_spec_selector_float( nodemap, node->GetName(), selector->GetName(), selector_value, node->GetDisplayName(), node->GetToolTip(), min_value, max_value, - param.GetValue(), gst_pylon_query_access(nodemap, node)); + param.GetValue(), flags); } static GParamSpec *gst_pylon_make_spec_str(GenApi::INodeMap &nodemap, From ab3928605bf03c11f6b311e3d0eefdcd2b7ed6a6 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 7 Dec 2022 18:32:45 -0600 Subject: [PATCH 003/126] Pass device version string to feature walker --- ext/pylon/gstpylon.cpp | 3 ++- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 8 ++++--- gst-libs/gst/pylon/gstpylonfeaturewalker.h | 3 ++- gst-libs/gst/pylon/gstpylonobject.cpp | 23 ++++++++++++-------- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 845e647..3ad1253 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -831,7 +831,8 @@ static void gst_pylon_append_properties( g_return_if_fail(camera); g_return_if_fail(device_properties); - GType device_type = gst_pylon_object_register(device_full_name, nodemap); + GType device_type = gst_pylon_object_register( + device_full_name, camera->GetDeviceInfo().GetDeviceVersion(), nodemap); GObject *device_obj = G_OBJECT(g_object_new(device_type, NULL)); gchar *device_name = g_strdup_printf( diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 057c329..61597a8 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -226,9 +226,11 @@ static void gst_pylon_camera_install_specs( } } -void GstPylonFeatureWalker::install_properties(GObjectClass* oclass, - GenApi::INodeMap& nodemap, - const gchar* device_fullname) { +static void gst_pylon_check_for_feature_cache(const gchar* device_fullname) {} + +void GstPylonFeatureWalker::install_properties( + GObjectClass* oclass, GenApi::INodeMap& nodemap, + const gchar* device_fullname, const gchar* device_firmware_version) { g_return_if_fail(oclass); gint nprop = 1; diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.h b/gst-libs/gst/pylon/gstpylonfeaturewalker.h index 548ea79..e0b8b9c 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.h +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.h @@ -57,7 +57,8 @@ class GstPylonFeatureWalker { public: static void install_properties(GObjectClass* oclass, GenApi::INodeMap& nodemap, - const gchar* device_fullname); + const gchar* device_fullname, + const gchar* device_firmware_version); static std::vector process_selector_features( GenApi::INode* node, GenApi::INode** selector_node); }; diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 848e1d6..dec0357 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -50,6 +50,7 @@ struct _GstPylonObjectPrivate { typedef struct _GstPylonObjectDeviceMembers GstPylonObjectDeviceMembers; struct _GstPylonObjectDeviceMembers { const gchar* device_name; + const gchar* device_firmware_version; GenApi::INodeMap& nodemap; }; @@ -75,9 +76,11 @@ static inline gpointer gst_pylon_object_get_instance_private( } GType gst_pylon_object_register(const Pylon::String_t& device_name, + const Pylon::String_t& device_firmware_version, GenApi::INodeMap& exemplar) { GstPylonObjectDeviceMembers* device_members = new GstPylonObjectDeviceMembers( - {g_strdup(device_name.c_str()), exemplar}); + {g_strdup(device_name.c_str()), g_strdup(device_firmware_version.c_str()), + exemplar}); GTypeInfo typeinfo = { sizeof(GstPylonObjectClass), @@ -113,9 +116,9 @@ GType gst_pylon_object_register(const Pylon::String_t& device_name, ***********************************************************/ /* prototypes */ -static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, - GenApi::INodeMap& nodemap, - const gchar* device_fullname); +static void gst_pylon_object_install_properties( + GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, + const gchar* device_fullname, const gchar* device_firmware_version); template static void gst_pylon_object_set_pylon_property(GenApi::INodeMap& nodemap, F get_value, @@ -153,14 +156,15 @@ static void gst_pylon_object_get_property(GObject* object, guint property_id, GValue* value, GParamSpec* pspec); static void gst_pylon_object_finalize(GObject* self); -static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, - GenApi::INodeMap& nodemap, - const gchar* device_name) { +static void gst_pylon_object_install_properties( + GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, + const gchar* device_name, const gchar* device_firmware_version) { g_return_if_fail(klass); GObjectClass* oclass = G_OBJECT_CLASS(klass); - GstPylonFeatureWalker::install_properties(oclass, nodemap, device_name); + GstPylonFeatureWalker::install_properties(oclass, nodemap, device_name, + device_firmware_version); } static void gst_pylon_object_class_init( @@ -172,7 +176,8 @@ static void gst_pylon_object_class_init( oclass->finalize = gst_pylon_object_finalize; gst_pylon_object_install_properties(klass, device_members->nodemap, - device_members->device_name); + device_members->device_name, + device_members->device_firmware_version); delete (device_members); } From 8c96fbc5877e411e18e96ae88d4f856049020a45 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 7 Dec 2022 18:47:06 -0600 Subject: [PATCH 004/126] Build cache filename --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 27 +++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 61597a8..190ca1c 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -38,6 +38,8 @@ #include "gstpylonfeaturewalker.h" #include "gstpylonintrospection.h" +#include + #include #include @@ -54,6 +56,8 @@ static std::vector gst_pylon_camera_handle_node( static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); +static gchar* gst_pylon_check_for_feature_cache( + const gchar* device_fullname, const gchar* device_firmware_version); static std::unordered_set propfilter_set = { "Width", @@ -226,13 +230,32 @@ static void gst_pylon_camera_install_specs( } } -static void gst_pylon_check_for_feature_cache(const gchar* device_fullname) {} +static gchar* gst_pylon_check_for_feature_cache( + const gchar* device_fullname, const gchar* device_firmware_version) { + g_return_val_if_fail(device_fullname, NULL); + g_return_val_if_fail(device_firmware_version, NULL); + + gchar* filename = + g_strdup_printf("%s_%s", device_fullname, device_firmware_version); + gchar* filename_hash = g_compute_checksum_for_string( + G_CHECKSUM_SHA256, filename, strlen(filename)); + gchar* filepath = g_strdup_printf("%s/%s/%s", g_get_user_cache_dir(), + "gstpylon", filename_hash); + + g_free(filename_hash); + g_free(filename); + + return filepath; +} void GstPylonFeatureWalker::install_properties( GObjectClass* oclass, GenApi::INodeMap& nodemap, const gchar* device_fullname, const gchar* device_firmware_version) { g_return_if_fail(oclass); + gchar* filepath = gst_pylon_check_for_feature_cache(device_fullname, + device_firmware_version); + gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); auto worklist = std::queue(); @@ -275,4 +298,6 @@ void GstPylonFeatureWalker::install_properties( } } } + + g_free(filepath); } From 5c1e254ac67f36acffe4ec2bcf9174ba8b826b3b Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Thu, 8 Dec 2022 18:32:55 -0600 Subject: [PATCH 005/126] Create gstpylon directory inside cache if non existent --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 190ca1c..ed4ba47 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -239,9 +239,14 @@ static gchar* gst_pylon_check_for_feature_cache( g_strdup_printf("%s_%s", device_fullname, device_firmware_version); gchar* filename_hash = g_compute_checksum_for_string( G_CHECKSUM_SHA256, filename, strlen(filename)); - gchar* filepath = g_strdup_printf("%s/%s/%s", g_get_user_cache_dir(), - "gstpylon", filename_hash); + gchar* dirpath = g_strdup_printf("%s/%s", g_get_user_cache_dir(), "gstpylon"); + gchar* filepath = g_strdup_printf("%s/%s", dirpath, filename_hash); + /* Create gstpylon directory */ + gint dir_permissions = 0775; + g_mkdir_with_parents(dirpath, dir_permissions); + + g_free(dirpath); g_free(filename_hash); g_free(filename); @@ -255,6 +260,7 @@ void GstPylonFeatureWalker::install_properties( gchar* filepath = gst_pylon_check_for_feature_cache(device_fullname, device_firmware_version); + g_free(filepath); gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); @@ -298,6 +304,4 @@ void GstPylonFeatureWalker::install_properties( } } } - - g_free(filepath); } From 4b084965c31ba856203c585dcc4b9c0cfabc9f8f Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Thu, 8 Dec 2022 19:24:36 -0600 Subject: [PATCH 006/126] Add min, max and flags to feature cache GKeyFile object --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 18 +++--- gst-libs/gst/pylon/gstpylonintrospection.cpp | 59 +++++++++++++------- gst-libs/gst/pylon/gstpylonintrospection.h | 3 +- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index ed4ba47..965f947 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -52,7 +52,7 @@ static std::vector gst_pylon_get_int_entries( GenApi::IInteger* int_node); static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const gchar* device_fullname); + const gchar* device_fullname, GKeyFile* feature_cache); static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); @@ -171,7 +171,7 @@ std::vector GstPylonFeatureWalker::process_selector_features( static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const gchar* device_fullname) { + const gchar* device_fullname, GKeyFile* feature_cache) { GenApi::INode* selector_node = NULL; guint64 selector_value = 0; std::vector specs_list; @@ -203,7 +203,8 @@ static std::vector gst_pylon_camera_handle_node( } } specs_list.push_back(GstPylonParamFactory::make_param( - nodemap, node, selector_node, selector_value, device_fullname)); + nodemap, node, selector_node, selector_value, device_fullname, + feature_cache)); } return specs_list; @@ -258,9 +259,8 @@ void GstPylonFeatureWalker::install_properties( const gchar* device_fullname, const gchar* device_firmware_version) { g_return_if_fail(oclass); - gchar* filepath = gst_pylon_check_for_feature_cache(device_fullname, - device_firmware_version); - g_free(filepath); + /* Start KeyFile object to hold property cache */ + GKeyFile* feature_cache = g_key_file_new(); gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); @@ -284,8 +284,8 @@ void GstPylonFeatureWalker::install_properties( GenICam::gcstring attrib; try { - std::vector specs_list = - gst_pylon_camera_handle_node(node, nodemap, device_fullname); + std::vector specs_list = gst_pylon_camera_handle_node( + node, nodemap, device_fullname, feature_cache); gst_pylon_camera_install_specs(specs_list, oclass, nprop); } catch (const Pylon::GenericException& e) { GST_FIXME("Unable to install property \"%s\" on device \"%s\": %s", @@ -304,4 +304,6 @@ void GstPylonFeatureWalker::install_properties( } } } + + g_key_file_free(feature_cache); } diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 79c5b11..c46486d 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -66,11 +66,13 @@ class GstPylonTypeAction : public GstPylonActions { /* prototypes */ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, - GenApi::INode *node); + GenApi::INode *node, + GKeyFile *feature_cache); static GParamSpec *gst_pylon_make_spec_selector_int64(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value); + guint64 selector_value, + GKeyFile *feature_cache); static GParamSpec *gst_pylon_make_spec_bool(GenApi::INodeMap &nodemap, GenApi::INode *node); static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, @@ -78,11 +80,13 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, GenApi::INode *selector, guint64 selector_value); static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, - GenApi::INode *node); + GenApi::INode *node, + GKeyFile *feature_cache); static GParamSpec *gst_pylon_make_spec_selector_float(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value); + guint64 selector_value, + GKeyFile *feature_cache); static GParamSpec *gst_pylon_make_spec_str(GenApi::INodeMap &nodemap, GenApi::INode *node); static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, @@ -130,7 +134,8 @@ static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GenApi::INode *node, GParamFlags &flags, T &minimum_under_all_settings, - T &maximum_under_all_settings); + T &maximum_under_all_settings, + GKeyFile *feature_cache); static gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node); static GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, GenApi::INode *node); @@ -526,16 +531,24 @@ static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GenApi::INode *node, GParamFlags &flags, T &minimum_under_all_settings, - T &maximum_under_all_settings) { + T &maximum_under_all_settings, + GKeyFile *feature_cache) { g_return_if_fail(node); flags = gst_pylon_query_access(nodemap, node); gst_pylon_find_limits(node, minimum_under_all_settings, maximum_under_all_settings); + + std::string limits_and_flags = + std::to_string(minimum_under_all_settings) + " " + + std::to_string(maximum_under_all_settings) + " " + std::to_string(flags); + g_key_file_set_string(feature_cache, "gstpylon", node->GetName().c_str(), + limits_and_flags.c_str()); } static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, - GenApi::INode *node) { + GenApi::INode *node, + GKeyFile *feature_cache) { g_return_val_if_fail(node, NULL); Pylon::CIntegerParameter param(node); @@ -544,7 +557,7 @@ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties( - nodemap, node, flags, min_value, max_value); + nodemap, node, flags, min_value, max_value, feature_cache); return g_param_spec_int64(node->GetName(), node->GetDisplayName(), node->GetToolTip(), min_value, max_value, @@ -554,7 +567,8 @@ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_selector_int64(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value) { + guint64 selector_value, + GKeyFile *feature_cache) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); @@ -564,7 +578,7 @@ static GParamSpec *gst_pylon_make_spec_selector_int64(GenApi::INodeMap &nodemap, GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties( - nodemap, node, flags, min_value, max_value); + nodemap, node, flags, min_value, max_value, feature_cache); return gst_pylon_param_spec_selector_int64( nodemap, node->GetName(), selector->GetName(), selector_value, @@ -599,7 +613,8 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, } static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, - GenApi::INode *node) { + GenApi::INode *node, + GKeyFile *feature_cache) { g_return_val_if_fail(node, NULL); Pylon::CFloatParameter param(node); @@ -608,7 +623,7 @@ static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties( - nodemap, node, flags, min_value, max_value); + nodemap, node, flags, min_value, max_value, feature_cache); return g_param_spec_float(node->GetName(), node->GetDisplayName(), node->GetToolTip(), min_value, max_value, @@ -618,7 +633,8 @@ static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_selector_float(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value) { + guint64 selector_value, + GKeyFile *feature_cache) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); @@ -628,7 +644,7 @@ static GParamSpec *gst_pylon_make_spec_selector_float(GenApi::INodeMap &nodemap, GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties( - nodemap, node, flags, min_value, max_value); + nodemap, node, flags, min_value, max_value, feature_cache); return gst_pylon_param_spec_selector_float( nodemap, node->GetName(), selector->GetName(), selector_value, @@ -743,7 +759,8 @@ GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, - const gchar *device_fullname) { + const gchar *device_fullname, + GKeyFile *feature_cache) { g_return_val_if_fail(node, NULL); GParamSpec *spec = NULL; @@ -752,10 +769,10 @@ GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, switch (iface) { case GenApi::intfIInteger: if (!selector) { - spec = gst_pylon_make_spec_int64(nodemap, node); + spec = gst_pylon_make_spec_int64(nodemap, node, feature_cache); } else { - spec = gst_pylon_make_spec_selector_int64(nodemap, node, selector, - selector_value); + spec = gst_pylon_make_spec_selector_int64( + nodemap, node, selector, selector_value, feature_cache); } break; case GenApi::intfIBoolean: @@ -768,10 +785,10 @@ GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, break; case GenApi::intfIFloat: if (!selector) { - spec = gst_pylon_make_spec_float(nodemap, node); + spec = gst_pylon_make_spec_float(nodemap, node, feature_cache); } else { - spec = gst_pylon_make_spec_selector_float(nodemap, node, selector, - selector_value); + spec = gst_pylon_make_spec_selector_float( + nodemap, node, selector, selector_value, feature_cache); } break; case GenApi::intfIString: diff --git a/gst-libs/gst/pylon/gstpylonintrospection.h b/gst-libs/gst/pylon/gstpylonintrospection.h index dabd9ef..d8debc9 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.h +++ b/gst-libs/gst/pylon/gstpylonintrospection.h @@ -58,7 +58,8 @@ class GstPylonParamFactory { public: static GParamSpec *make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, - const gchar *device_fullname); + const gchar *device_fullname, + GKeyFile *feature_cache); }; #endif From e820d42b6d5f1b68785b1cc922d0fc28f4cec027 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Mon, 12 Dec 2022 15:23:41 -0600 Subject: [PATCH 007/126] Construct unique cache filenames for camera and stream grabber Camera: DeviceModelName + FirmwareVersion + PluginVersion Stream Grabber: ModelName + PylonVersion + PluginVersion --- ext/pylon/gstpylon.cpp | 29 ++++++++++++++------ gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 24 +++++++--------- gst-libs/gst/pylon/gstpylonobject.cpp | 24 ++++++++-------- gst-libs/gst/pylon/gstpylonobject.h | 8 ++++-- 4 files changed, 48 insertions(+), 37 deletions(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 3ad1253..e97f6cc 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -107,8 +107,13 @@ static std::vector gst_pylon_pfnc_list_to_gst( const std::vector &pixel_format_mapping); static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, +<<<<<<< HEAD const Pylon::String_t &device_full_name, const Pylon::String_t &device_type_str, GenApi::INodeMap &nodemap, +======= + Pylon::String_t device_full_name, Pylon::String_t device_type_str, + Pylon::String_t cache_filename, GenApi::INodeMap &nodemap, +>>>>>>> Construct unique cache filenames for camera and stream grabber gchar **device_properties, guint alignment); static void gst_pylon_append_camera_properties( Pylon::CBaslerUniversalInstantCamera *camera, gchar **camera_properties, @@ -825,14 +830,14 @@ gboolean gst_pylon_set_configuration(GstPylon *self, const GstCaps *conf, static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, - const Pylon::String_t &device_full_name, - const Pylon::String_t &device_type_str, GenApi::INodeMap &nodemap, + const Pylon::String_t &device_full_name, const Pylon::String_t &device_type_str, + const Pylon::String_t &cache_filename, GenApi::INodeMap &nodemap, gchar **device_properties, guint alignment) { g_return_if_fail(camera); g_return_if_fail(device_properties); - GType device_type = gst_pylon_object_register( - device_full_name, camera->GetDeviceInfo().GetDeviceVersion(), nodemap); + GType device_type = + gst_pylon_object_register(device_full_name, cache_filename, nodemap); GObject *device_obj = G_OBJECT(g_object_new(device_type, NULL)); gchar *device_name = g_strdup_printf( @@ -864,9 +869,12 @@ static void gst_pylon_append_camera_properties( GenApi::INodeMap &nodemap = camera->GetNodeMap(); Pylon::String_t camera_name = gst_pylon_get_camera_fullname(*camera); Pylon::String_t device_type = "Camera"; + Pylon::String_t cache_filename = camera->DeviceModelName.GetValue() + "_" + + camera->DeviceFirmwareVersion.GetValue() + + "_" + VERSION; - gst_pylon_append_properties(camera, camera_name, device_type, nodemap, - camera_properties, alignment); + gst_pylon_append_properties(camera, camera_name, device_type, cache_filename, + nodemap, camera_properties, alignment); } static void gst_pylon_append_stream_grabber_properties( @@ -876,12 +884,15 @@ static void gst_pylon_append_stream_grabber_properties( g_return_if_fail(sgrabber_properties); GenApi::INodeMap &nodemap = camera->GetStreamGrabberNodeMap(); - ; Pylon::String_t sgrabber_name = gst_pylon_get_sgrabber_name(*camera); Pylon::String_t device_type = "Stream Grabber"; + Pylon::String_t cache_filename = + camera->GetDeviceInfo().GetModelName() + "_" + + Pylon::VersionInfo::getVersionString() + "_" + VERSION; - gst_pylon_append_properties(camera, sgrabber_name, device_type, nodemap, - sgrabber_properties, alignment); + gst_pylon_append_properties(camera, sgrabber_name, device_type, + cache_filename, nodemap, sgrabber_properties, + alignment); } static gchar *gst_pylon_get_string_properties( diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 965f947..697e998 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -56,8 +56,7 @@ static std::vector gst_pylon_camera_handle_node( static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); -static gchar* gst_pylon_check_for_feature_cache( - const gchar* device_fullname, const gchar* device_firmware_version); +static gchar* gst_pylon_check_for_feature_cache(const gchar* cache_filename); static std::unordered_set propfilter_set = { "Width", @@ -231,32 +230,29 @@ static void gst_pylon_camera_install_specs( } } -static gchar* gst_pylon_check_for_feature_cache( - const gchar* device_fullname, const gchar* device_firmware_version) { - g_return_val_if_fail(device_fullname, NULL); - g_return_val_if_fail(device_firmware_version, NULL); +static gchar* gst_pylon_check_for_feature_cache(const gchar* cache_filename) { + g_return_val_if_fail(cache_filename, NULL); - gchar* filename = - g_strdup_printf("%s_%s", device_fullname, device_firmware_version); gchar* filename_hash = g_compute_checksum_for_string( - G_CHECKSUM_SHA256, filename, strlen(filename)); + G_CHECKSUM_SHA256, cache_filename, strlen(cache_filename)); gchar* dirpath = g_strdup_printf("%s/%s", g_get_user_cache_dir(), "gstpylon"); - gchar* filepath = g_strdup_printf("%s/%s", dirpath, filename_hash); /* Create gstpylon directory */ gint dir_permissions = 0775; g_mkdir_with_parents(dirpath, dir_permissions); + gchar* filepath = g_strdup_printf("%s/%s", dirpath, filename_hash); + g_free(dirpath); g_free(filename_hash); - g_free(filename); return filepath; } -void GstPylonFeatureWalker::install_properties( - GObjectClass* oclass, GenApi::INodeMap& nodemap, - const gchar* device_fullname, const gchar* device_firmware_version) { +void GstPylonFeatureWalker::install_properties(GObjectClass* oclass, + GenApi::INodeMap& nodemap, + const gchar* device_fullname, + const gchar* cache_filename) { g_return_if_fail(oclass); /* Start KeyFile object to hold property cache */ diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index dec0357..6bd0b6f 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -50,7 +50,7 @@ struct _GstPylonObjectPrivate { typedef struct _GstPylonObjectDeviceMembers GstPylonObjectDeviceMembers; struct _GstPylonObjectDeviceMembers { const gchar* device_name; - const gchar* device_firmware_version; + const gchar* cache_filename; GenApi::INodeMap& nodemap; }; @@ -76,10 +76,10 @@ static inline gpointer gst_pylon_object_get_instance_private( } GType gst_pylon_object_register(const Pylon::String_t& device_name, - const Pylon::String_t& device_firmware_version, + const Pylon::String_t& cache_filename, GenApi::INodeMap& exemplar) { GstPylonObjectDeviceMembers* device_members = new GstPylonObjectDeviceMembers( - {g_strdup(device_name.c_str()), g_strdup(device_firmware_version.c_str()), + {g_strdup(device_name.c_str()), g_strdup(cache_filename.c_str()), exemplar}); GTypeInfo typeinfo = { @@ -116,9 +116,10 @@ GType gst_pylon_object_register(const Pylon::String_t& device_name, ***********************************************************/ /* prototypes */ -static void gst_pylon_object_install_properties( - GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, - const gchar* device_fullname, const gchar* device_firmware_version); +static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, + GenApi::INodeMap& nodemap, + const gchar* device_fullname, + const gchar* cache_filename); template static void gst_pylon_object_set_pylon_property(GenApi::INodeMap& nodemap, F get_value, @@ -156,15 +157,16 @@ static void gst_pylon_object_get_property(GObject* object, guint property_id, GValue* value, GParamSpec* pspec); static void gst_pylon_object_finalize(GObject* self); -static void gst_pylon_object_install_properties( - GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, - const gchar* device_name, const gchar* device_firmware_version) { +static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, + GenApi::INodeMap& nodemap, + const gchar* device_name, + const gchar* cache_filename) { g_return_if_fail(klass); GObjectClass* oclass = G_OBJECT_CLASS(klass); GstPylonFeatureWalker::install_properties(oclass, nodemap, device_name, - device_firmware_version); + cache_filename); } static void gst_pylon_object_class_init( @@ -177,7 +179,7 @@ static void gst_pylon_object_class_init( gst_pylon_object_install_properties(klass, device_members->nodemap, device_members->device_name, - device_members->device_firmware_version); + device_members->cache_filename); delete (device_members); } diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index 176cd2d..3c17d62 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -56,14 +56,16 @@ G_BEGIN_DECLS -G_DECLARE_DERIVABLE_TYPE (GstPylonObject, gst_pylon_object, - GST, PYLON_OBJECT, GstObject) +G_DECLARE_DERIVABLE_TYPE(GstPylonObject, gst_pylon_object, GST, PYLON_OBJECT, + GstObject) struct _GstPylonObjectClass { GstObjectClass parent_class; }; -EXT_PYLONSRC_API GType gst_pylon_object_register (const Pylon::String_t &device_name, GenApi::INodeMap& nodemap); +EXT_PYLONSRC_API GType gst_pylon_object_register(const Pylon::String_t& device_name, + const Pylon::String_t& cache_filename, + GenApi::INodeMap& nodemap); EXT_PYLONSRC_API GObject* gst_pylon_object_new( std::shared_ptr camera, const Pylon::String_t& device_name, GenApi::INodeMap* nodemap); From 5a2a1f1f8994701c13bc71f557b1663edc9d5644 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Mon, 12 Dec 2022 15:47:37 -0600 Subject: [PATCH 008/126] Add cache file creation function --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 697e998..b958d8f 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -57,6 +57,8 @@ static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); static gchar* gst_pylon_check_for_feature_cache(const gchar* cache_filename); +static void gst_pylon_create_cache_file(GKeyFile* feature_cache, + const gchar* cache_filename); static std::unordered_set propfilter_set = { "Width", @@ -249,6 +251,27 @@ static gchar* gst_pylon_check_for_feature_cache(const gchar* cache_filename) { return filepath; } +static void gst_pylon_create_cache_file(GKeyFile* feature_cache, + const gchar* cache_filename) { + g_return_if_fail(feature_cache); + g_return_if_fail(cache_filename); + + gsize len = 0; + gchar* feature_cache_str = g_key_file_to_data(feature_cache, &len, NULL); + gchar* filepath = gst_pylon_check_for_feature_cache(cache_filename); + + GError* file_err = NULL; + gboolean ret = + g_file_set_contents(filepath, feature_cache_str, len, &file_err); + if (!ret) { + GST_WARNING("Feature cache could not be generated. %s", file_err->message); + g_error_free(file_err); + } + + g_free(feature_cache_str); + g_free(filepath); +} + void GstPylonFeatureWalker::install_properties(GObjectClass* oclass, GenApi::INodeMap& nodemap, const gchar* device_fullname, @@ -301,5 +324,6 @@ void GstPylonFeatureWalker::install_properties(GObjectClass* oclass, } } + gst_pylon_create_cache_file(feature_cache, cache_filename); g_key_file_free(feature_cache); } From 8fff83ea93ba4e6db23266a79752e7a8afefdc81 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Mon, 12 Dec 2022 18:37:44 -0600 Subject: [PATCH 009/126] Use std::string for cache filename and device name instead of gchar* --- ext/pylon/gstpylon.cpp | 43 +++++++++----------- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 33 ++++++++------- gst-libs/gst/pylon/gstpylonfeaturewalker.h | 4 +- gst-libs/gst/pylon/gstpylonintrospection.cpp | 24 +++++------ gst-libs/gst/pylon/gstpylonintrospection.h | 2 +- gst-libs/gst/pylon/gstpylonobject.cpp | 26 ++++++------ gst-libs/gst/pylon/gstpylonobject.h | 6 +-- gst-libs/gst/pylon/gstpylonparamspecs.cpp | 3 +- gst-libs/gst/pylon/gstpylonparamspecs.h | 3 +- 9 files changed, 67 insertions(+), 77 deletions(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index e97f6cc..12a2029 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -77,9 +77,9 @@ typedef struct { static std::string gst_pylon_query_default_set( const Pylon::CBaslerUniversalInstantCamera &camera); static void gst_pylon_apply_set(GstPylon *self, std::string &set); -static Pylon::String_t gst_pylon_get_camera_fullname( +static std::string gst_pylon_get_camera_fullname( Pylon::CBaslerUniversalInstantCamera &camera); -static Pylon::String_t gst_pylon_get_sgrabber_name( +static std::string gst_pylon_get_sgrabber_name( Pylon::CBaslerUniversalInstantCamera &camera); static void free_ptr_grab_result(gpointer data); static void gst_pylon_query_format( @@ -107,13 +107,8 @@ static std::vector gst_pylon_pfnc_list_to_gst( const std::vector &pixel_format_mapping); static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, -<<<<<<< HEAD - const Pylon::String_t &device_full_name, - const Pylon::String_t &device_type_str, GenApi::INodeMap &nodemap, -======= - Pylon::String_t device_full_name, Pylon::String_t device_type_str, - Pylon::String_t cache_filename, GenApi::INodeMap &nodemap, ->>>>>>> Construct unique cache filenames for camera and stream grabber + const std::string &device_full_name, const std::string &device_type_str, + const std::string &cache_filename, GenApi::INodeMap &nodemap, gchar **device_properties, guint alignment); static void gst_pylon_append_camera_properties( Pylon::CBaslerUniversalInstantCamera *camera, gchar **camera_properties, @@ -161,12 +156,12 @@ static const std::vector gst_structure_formats = { void gst_pylon_initialize() { Pylon::PylonInitialize(); } -static Pylon::String_t gst_pylon_get_camera_fullname( +static std::string gst_pylon_get_camera_fullname( Pylon::CBaslerUniversalInstantCamera &camera) { - return camera.GetDeviceInfo().GetFullName(); + return std::string(camera.GetDeviceInfo().GetFullName()); } -static Pylon::String_t gst_pylon_get_sgrabber_name( +static std::string gst_pylon_get_sgrabber_name( Pylon::CBaslerUniversalInstantCamera &camera) { return gst_pylon_get_camera_fullname(camera) + " StreamGrabber"; } @@ -830,8 +825,8 @@ gboolean gst_pylon_set_configuration(GstPylon *self, const GstCaps *conf, static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, - const Pylon::String_t &device_full_name, const Pylon::String_t &device_type_str, - const Pylon::String_t &cache_filename, GenApi::INodeMap &nodemap, + const std::string &device_full_name, const std::string &device_type_str, + const std::string &cache_filename, GenApi::INodeMap &nodemap, gchar **device_properties, guint alignment) { g_return_if_fail(camera); g_return_if_fail(device_properties); @@ -867,11 +862,11 @@ static void gst_pylon_append_camera_properties( g_return_if_fail(camera_properties); GenApi::INodeMap &nodemap = camera->GetNodeMap(); - Pylon::String_t camera_name = gst_pylon_get_camera_fullname(*camera); - Pylon::String_t device_type = "Camera"; - Pylon::String_t cache_filename = camera->DeviceModelName.GetValue() + "_" + - camera->DeviceFirmwareVersion.GetValue() + - "_" + VERSION; + std::string camera_name = gst_pylon_get_camera_fullname(*camera); + std::string device_type = "Camera"; + std::string cache_filename = + std::string(camera->DeviceModelName.GetValue() + "_" + + camera->DeviceFirmwareVersion.GetValue() + "_" + VERSION); gst_pylon_append_properties(camera, camera_name, device_type, cache_filename, nodemap, camera_properties, alignment); @@ -884,11 +879,11 @@ static void gst_pylon_append_stream_grabber_properties( g_return_if_fail(sgrabber_properties); GenApi::INodeMap &nodemap = camera->GetStreamGrabberNodeMap(); - Pylon::String_t sgrabber_name = gst_pylon_get_sgrabber_name(*camera); - Pylon::String_t device_type = "Stream Grabber"; - Pylon::String_t cache_filename = - camera->GetDeviceInfo().GetModelName() + "_" + - Pylon::VersionInfo::getVersionString() + "_" + VERSION; + std::string sgrabber_name = gst_pylon_get_sgrabber_name(*camera); + std::string device_type = "Stream Grabber"; + std::string cache_filename = + std::string(camera->GetDeviceInfo().GetModelName() + "_" + + Pylon::VersionInfo::getVersionString() + "_" + VERSION); gst_pylon_append_properties(camera, sgrabber_name, device_type, cache_filename, nodemap, sgrabber_properties, diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index b958d8f..f27af2d 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -52,13 +52,14 @@ static std::vector gst_pylon_get_int_entries( GenApi::IInteger* int_node); static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const gchar* device_fullname, GKeyFile* feature_cache); + const std::string device_fullname, GKeyFile* feature_cache); static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); -static gchar* gst_pylon_check_for_feature_cache(const gchar* cache_filename); +static gchar* gst_pylon_check_for_feature_cache( + const std::string cache_filename); static void gst_pylon_create_cache_file(GKeyFile* feature_cache, - const gchar* cache_filename); + const std::string cache_filename); static std::unordered_set propfilter_set = { "Width", @@ -172,7 +173,7 @@ std::vector GstPylonFeatureWalker::process_selector_features( static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const gchar* device_fullname, GKeyFile* feature_cache) { + const std::string device_fullname, GKeyFile* feature_cache) { GenApi::INode* selector_node = NULL; guint64 selector_value = 0; std::vector specs_list; @@ -232,11 +233,11 @@ static void gst_pylon_camera_install_specs( } } -static gchar* gst_pylon_check_for_feature_cache(const gchar* cache_filename) { - g_return_val_if_fail(cache_filename, NULL); - - gchar* filename_hash = g_compute_checksum_for_string( - G_CHECKSUM_SHA256, cache_filename, strlen(cache_filename)); +static gchar* gst_pylon_check_for_feature_cache( + const std::string cache_filename) { + gchar* filename_hash = + g_compute_checksum_for_string(G_CHECKSUM_SHA256, cache_filename.c_str(), + strlen(cache_filename.c_str())); gchar* dirpath = g_strdup_printf("%s/%s", g_get_user_cache_dir(), "gstpylon"); /* Create gstpylon directory */ @@ -252,13 +253,12 @@ static gchar* gst_pylon_check_for_feature_cache(const gchar* cache_filename) { } static void gst_pylon_create_cache_file(GKeyFile* feature_cache, - const gchar* cache_filename) { + const std::string cache_filename) { g_return_if_fail(feature_cache); - g_return_if_fail(cache_filename); gsize len = 0; gchar* feature_cache_str = g_key_file_to_data(feature_cache, &len, NULL); - gchar* filepath = gst_pylon_check_for_feature_cache(cache_filename); + gchar* filepath = gst_pylon_check_for_feature_cache(cache_filename.c_str()); GError* file_err = NULL; gboolean ret = @@ -272,10 +272,9 @@ static void gst_pylon_create_cache_file(GKeyFile* feature_cache, g_free(filepath); } -void GstPylonFeatureWalker::install_properties(GObjectClass* oclass, - GenApi::INodeMap& nodemap, - const gchar* device_fullname, - const gchar* cache_filename) { +void GstPylonFeatureWalker::install_properties( + GObjectClass* oclass, GenApi::INodeMap& nodemap, + const std::string device_fullname, const std::string cache_filename) { g_return_if_fail(oclass); /* Start KeyFile object to hold property cache */ @@ -308,7 +307,7 @@ void GstPylonFeatureWalker::install_properties(GObjectClass* oclass, gst_pylon_camera_install_specs(specs_list, oclass, nprop); } catch (const Pylon::GenericException& e) { GST_FIXME("Unable to install property \"%s\" on device \"%s\": %s", - node->GetDisplayName().c_str(), device_fullname, + node->GetDisplayName().c_str(), device_fullname.c_str(), e.GetDescription()); } } diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.h b/gst-libs/gst/pylon/gstpylonfeaturewalker.h index e0b8b9c..834d5b8 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.h +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.h @@ -57,8 +57,8 @@ class GstPylonFeatureWalker { public: static void install_properties(GObjectClass* oclass, GenApi::INodeMap& nodemap, - const gchar* device_fullname, - const gchar* device_firmware_version); + const std::string device_fullname, + std::string cache_filename); static std::vector process_selector_features( GenApi::INode* node, GenApi::INode** selector_node); }; diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index c46486d..9d1ad65 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -95,13 +95,13 @@ static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, guint64 selector_value); static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, GenApi::INode *node, - const gchar *device_fullname); + const std::string device_fullname); static GParamSpec *gst_pylon_make_spec_enum(GenApi::INodeMap &nodemap, GenApi::INode *node, - const gchar *device_fullname); + const std::string device_fullname); static GParamSpec *gst_pylon_make_spec_selector_enum( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, const gchar *device_fullname); + guint64 selector_value, const std::string device_fullname); static GenApi::INode *gst_pylon_find_limit_node(GenApi::INode *feature_node, const GenICam::gcstring &limit); static std::vector gst_pylon_find_parent_features( @@ -680,7 +680,7 @@ static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, GenApi::INode *node, - const gchar *device_fullname) { + const std::string device_fullname) { /* When registering enums to the GType system, their string pointers must remain valid throughout the application lifespan. To achieve this we are saving all found enums into a static hash table @@ -691,8 +691,8 @@ static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, Pylon::CEnumParameter param(node); - gchar *full_name = - g_strdup_printf("%s_%s", device_fullname, node->GetName().c_str()); + gchar *full_name = g_strdup_printf("%s_%s", device_fullname.c_str(), + node->GetName().c_str()); gchar *name = gst_pylon_param_spec_sanitize_name(full_name); g_free(full_name); @@ -729,11 +729,11 @@ static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_enum(GenApi::INodeMap &nodemap, GenApi::INode *node, - const gchar *device_fullname) { + const std::string device_fullname) { g_return_val_if_fail(node, NULL); Pylon::CEnumParameter param(node); - GType type = gst_pylon_make_enum_type(nodemap, node, device_fullname); + GType type = gst_pylon_make_enum_type(nodemap, node, device_fullname.c_str()); return g_param_spec_enum(node->GetName(), node->GetDisplayName(), node->GetToolTip(), type, param.GetIntValue(), @@ -742,24 +742,24 @@ static GParamSpec *gst_pylon_make_spec_enum(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_selector_enum( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, const gchar *device_fullname) { + guint64 selector_value, const std::string device_fullname) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); Pylon::CEnumParameter param(node); - GType type = gst_pylon_make_enum_type(nodemap, node, device_fullname); + GType type = gst_pylon_make_enum_type(nodemap, node, device_fullname.c_str()); return gst_pylon_param_spec_selector_enum( nodemap, node->GetName(), selector->GetName(), selector_value, node->GetDisplayName(), node->GetToolTip(), type, param.GetIntValue(), - gst_pylon_query_access(nodemap, node), device_fullname); + gst_pylon_query_access(nodemap, node)); } GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, - const gchar *device_fullname, + const std::string device_fullname, GKeyFile *feature_cache) { g_return_val_if_fail(node, NULL); diff --git a/gst-libs/gst/pylon/gstpylonintrospection.h b/gst-libs/gst/pylon/gstpylonintrospection.h index d8debc9..214a87f 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.h +++ b/gst-libs/gst/pylon/gstpylonintrospection.h @@ -58,7 +58,7 @@ class GstPylonParamFactory { public: static GParamSpec *make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, - const gchar *device_fullname, + const std::string device_fullname, GKeyFile *feature_cache); }; diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 6bd0b6f..74ac6fe 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -49,8 +49,8 @@ struct _GstPylonObjectPrivate { typedef struct _GstPylonObjectDeviceMembers GstPylonObjectDeviceMembers; struct _GstPylonObjectDeviceMembers { - const gchar* device_name; - const gchar* cache_filename; + const std::string device_name; + const std::string cache_filename; GenApi::INodeMap& nodemap; }; @@ -75,12 +75,11 @@ static inline gpointer gst_pylon_object_get_instance_private( return (G_STRUCT_MEMBER_P(self, GstPylonObject_private_offset)); } -GType gst_pylon_object_register(const Pylon::String_t& device_name, - const Pylon::String_t& cache_filename, +GType gst_pylon_object_register(const std::string& device_name, + const std::string& cache_filename, GenApi::INodeMap& exemplar) { - GstPylonObjectDeviceMembers* device_members = new GstPylonObjectDeviceMembers( - {g_strdup(device_name.c_str()), g_strdup(cache_filename.c_str()), - exemplar}); + GstPylonObjectDeviceMembers* device_members = + new GstPylonObjectDeviceMembers({device_name, cache_filename, exemplar}); GTypeInfo typeinfo = { sizeof(GstPylonObjectClass), @@ -116,10 +115,9 @@ GType gst_pylon_object_register(const Pylon::String_t& device_name, ***********************************************************/ /* prototypes */ -static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, - GenApi::INodeMap& nodemap, - const gchar* device_fullname, - const gchar* cache_filename); +static void gst_pylon_object_install_properties( + GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, + const std::string device_fullname, const std::string cache_filename); template static void gst_pylon_object_set_pylon_property(GenApi::INodeMap& nodemap, F get_value, @@ -159,8 +157,8 @@ static void gst_pylon_object_finalize(GObject* self); static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, - const gchar* device_name, - const gchar* cache_filename) { + std::string device_name, + std::string cache_filename) { g_return_if_fail(klass); GObjectClass* oclass = G_OBJECT_CLASS(klass); @@ -384,7 +382,7 @@ static void gst_pylon_object_get_property(GObject* object, guint property_id, GObject* gst_pylon_object_new( std::shared_ptr camera, - const Pylon::String_t& device_name, GenApi::INodeMap* nodemap) { + const std::string& device_name, GenApi::INodeMap* nodemap) { gchar* type_name = gst_pylon_param_spec_sanitize_name(device_name.c_str()); GType type = g_type_from_name(type_name); diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index 3c17d62..a89c6a8 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -63,12 +63,12 @@ struct _GstPylonObjectClass { GstObjectClass parent_class; }; -EXT_PYLONSRC_API GType gst_pylon_object_register(const Pylon::String_t& device_name, - const Pylon::String_t& cache_filename, +EXT_PYLONSRC_API GType gst_pylon_object_register(const std::string& device_name, + const std::string& cache_filename, GenApi::INodeMap& nodemap); EXT_PYLONSRC_API GObject* gst_pylon_object_new( std::shared_ptr camera, - const Pylon::String_t& device_name, GenApi::INodeMap* nodemap); + const std::string& device_name, GenApi::INodeMap* nodemap); G_END_DECLS diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.cpp b/gst-libs/gst/pylon/gstpylonparamspecs.cpp index 285b383..7456553 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.cpp +++ b/gst-libs/gst/pylon/gstpylonparamspecs.cpp @@ -184,8 +184,7 @@ GParamSpec *gst_pylon_param_spec_selector_string( GParamSpec *gst_pylon_param_spec_selector_enum( GenApi::INodeMap &nodemap, const gchar *feature_name, const gchar *selector_name, guint64 selector_value, const gchar *nick, - const gchar *blurb, GType type, gint64 def, GParamFlags flags, - const gchar *device_fullname) { + const gchar *blurb, GType type, gint64 def, GParamFlags flags) { gchar *name = gst_pylon_param_spec_selector_prolog( nodemap, feature_name, selector_name, selector_value, flags); diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.h b/gst-libs/gst/pylon/gstpylonparamspecs.h index 27c2e21..8de0494 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.h +++ b/gst-libs/gst/pylon/gstpylonparamspecs.h @@ -101,8 +101,7 @@ GParamSpec* gst_pylon_param_spec_selector_string( GParamSpec* gst_pylon_param_spec_selector_enum( GenApi::INodeMap& nodemap, const gchar* feature_name, const gchar* selector_name, guint64 selector_value, const gchar* nick, - const gchar* blurb, GType type, gint64 def, GParamFlags flags, - const gchar* device_fullname) G_GNUC_MALLOC; + const gchar* blurb, GType type, gint64 def, GParamFlags flags) G_GNUC_MALLOC; /* --- Utility prototypes --- */ From e08dfcdff4d850d50167bb7546cb7a7b15e05e6c Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Thu, 15 Dec 2022 16:43:44 -0600 Subject: [PATCH 010/126] Add GstPylonCache class --- ext/pylon/gstpylon.cpp | 16 ++--- gst-libs/gst/pylon/gstpyloncache.cpp | 35 +++++++++++ gst-libs/gst/pylon/gstpyloncache.h | 65 ++++++++++++++++++++ gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 9 ++- gst-libs/gst/pylon/gstpylonfeaturewalker.h | 4 +- gst-libs/gst/pylon/gstpylonobject.cpp | 23 +++---- gst-libs/gst/pylon/gstpylonobject.h | 4 +- gst-libs/gst/pylon/meson.build | 1 + 8 files changed, 132 insertions(+), 25 deletions(-) create mode 100644 gst-libs/gst/pylon/gstpyloncache.cpp create mode 100644 gst-libs/gst/pylon/gstpyloncache.h diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 12a2029..05c5750 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -34,6 +34,7 @@ #include "config.h" #endif +#include "gst/pylon/gstpyloncache.h" #include "gst/pylon/gstpylondebug.h" #include "gst/pylon/gstpylonmetaprivate.h" #include "gst/pylon/gstpylonobject.h" @@ -108,7 +109,7 @@ static std::vector gst_pylon_pfnc_list_to_gst( static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, const std::string &device_full_name, const std::string &device_type_str, - const std::string &cache_filename, GenApi::INodeMap &nodemap, + GstPylonCache &feature_cache, GenApi::INodeMap &nodemap, gchar **device_properties, guint alignment); static void gst_pylon_append_camera_properties( Pylon::CBaslerUniversalInstantCamera *camera, gchar **camera_properties, @@ -826,13 +827,13 @@ gboolean gst_pylon_set_configuration(GstPylon *self, const GstCaps *conf, static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, const std::string &device_full_name, const std::string &device_type_str, - const std::string &cache_filename, GenApi::INodeMap &nodemap, + GstPylonCache &feature_cache, GenApi::INodeMap &nodemap, gchar **device_properties, guint alignment) { g_return_if_fail(camera); g_return_if_fail(device_properties); GType device_type = - gst_pylon_object_register(device_full_name, cache_filename, nodemap); + gst_pylon_object_register(device_full_name, feature_cache, nodemap); GObject *device_obj = G_OBJECT(g_object_new(device_type, NULL)); gchar *device_name = g_strdup_printf( @@ -867,8 +868,9 @@ static void gst_pylon_append_camera_properties( std::string cache_filename = std::string(camera->DeviceModelName.GetValue() + "_" + camera->DeviceFirmwareVersion.GetValue() + "_" + VERSION); + GstPylonCache feature_cache(cache_filename); - gst_pylon_append_properties(camera, camera_name, device_type, cache_filename, + gst_pylon_append_properties(camera, camera_name, device_type, feature_cache, nodemap, camera_properties, alignment); } @@ -884,10 +886,10 @@ static void gst_pylon_append_stream_grabber_properties( std::string cache_filename = std::string(camera->GetDeviceInfo().GetModelName() + "_" + Pylon::VersionInfo::getVersionString() + "_" + VERSION); + GstPylonCache feature_cache(cache_filename); - gst_pylon_append_properties(camera, sgrabber_name, device_type, - cache_filename, nodemap, sgrabber_properties, - alignment); + gst_pylon_append_properties(camera, sgrabber_name, device_type, feature_cache, + nodemap, sgrabber_properties, alignment); } static gchar *gst_pylon_get_string_properties( diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp new file mode 100644 index 0000000..75c5dde --- /dev/null +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -0,0 +1,35 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gstpyloncache.h" + +GstPylonCache::GstPylonCache(const std::string name) : cache_file_name(name) {} diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h new file mode 100644 index 0000000..18c861c --- /dev/null +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -0,0 +1,65 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GST_PYLON_CACHE_H_ +#define _GST_PYLON_CACHE_H_ + +#include + +#ifdef _MSC_VER // MSVC +#pragma warning(push) +#pragma warning(disable : 4265) +#elif __GNUC__ // GCC, CLANG, MinGW +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic ignored "-Woverloaded-virtual" +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +#include + +#ifdef _MSC_VER // MSVC +#pragma warning(pop) +#elif __GNUC__ // GCC, CLANG, MinWG +#pragma GCC diagnostic pop +#endif + +class GstPylonCache { + public: + GstPylonCache(const std::string name); + void CreateCacheFile(); + + private: + const std::string cache_file_name; +}; + +#endif diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index f27af2d..4341571 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -274,11 +274,11 @@ static void gst_pylon_create_cache_file(GKeyFile* feature_cache, void GstPylonFeatureWalker::install_properties( GObjectClass* oclass, GenApi::INodeMap& nodemap, - const std::string device_fullname, const std::string cache_filename) { + const std::string device_fullname, GstPylonCache& feature_cache) { g_return_if_fail(oclass); /* Start KeyFile object to hold property cache */ - GKeyFile* feature_cache = g_key_file_new(); + GKeyFile* feature_cache_dict = g_key_file_new(); gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); @@ -303,7 +303,7 @@ void GstPylonFeatureWalker::install_properties( try { std::vector specs_list = gst_pylon_camera_handle_node( - node, nodemap, device_fullname, feature_cache); + node, nodemap, device_fullname, feature_cache_dict); gst_pylon_camera_install_specs(specs_list, oclass, nprop); } catch (const Pylon::GenericException& e) { GST_FIXME("Unable to install property \"%s\" on device \"%s\": %s", @@ -323,6 +323,5 @@ void GstPylonFeatureWalker::install_properties( } } - gst_pylon_create_cache_file(feature_cache, cache_filename); - g_key_file_free(feature_cache); + g_key_file_free(feature_cache_dict); } diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.h b/gst-libs/gst/pylon/gstpylonfeaturewalker.h index 834d5b8..dc5a771 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.h +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.h @@ -33,6 +33,8 @@ #ifndef _GST_PYLON_FEATURE_WALKER_H_ #define _GST_PYLON_FEATURE_WALKER_H_ +#include "gstpyloncache.h" + #include #ifdef _MSC_VER // MSVC @@ -58,7 +60,7 @@ class GstPylonFeatureWalker { static void install_properties(GObjectClass* oclass, GenApi::INodeMap& nodemap, const std::string device_fullname, - std::string cache_filename); + GstPylonCache& feature_cache); static std::vector process_selector_features( GenApi::INode* node, GenApi::INode** selector_node); }; diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 74ac6fe..3634675 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -49,8 +49,8 @@ struct _GstPylonObjectPrivate { typedef struct _GstPylonObjectDeviceMembers GstPylonObjectDeviceMembers; struct _GstPylonObjectDeviceMembers { - const std::string device_name; - const std::string cache_filename; + const std::string& device_name; + GstPylonCache& feature_cache; GenApi::INodeMap& nodemap; }; @@ -76,10 +76,10 @@ static inline gpointer gst_pylon_object_get_instance_private( } GType gst_pylon_object_register(const std::string& device_name, - const std::string& cache_filename, + GstPylonCache& feature_cache, GenApi::INodeMap& exemplar) { GstPylonObjectDeviceMembers* device_members = - new GstPylonObjectDeviceMembers({device_name, cache_filename, exemplar}); + new GstPylonObjectDeviceMembers({device_name, feature_cache, exemplar}); GTypeInfo typeinfo = { sizeof(GstPylonObjectClass), @@ -115,9 +115,10 @@ GType gst_pylon_object_register(const std::string& device_name, ***********************************************************/ /* prototypes */ -static void gst_pylon_object_install_properties( - GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, - const std::string device_fullname, const std::string cache_filename); +static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, + GenApi::INodeMap& nodemap, + const std::string& device_name, + GstPylonCache& feature_cache); template static void gst_pylon_object_set_pylon_property(GenApi::INodeMap& nodemap, F get_value, @@ -157,14 +158,14 @@ static void gst_pylon_object_finalize(GObject* self); static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, - std::string device_name, - std::string cache_filename) { + const std::string& device_name, + GstPylonCache& feature_cache) { g_return_if_fail(klass); GObjectClass* oclass = G_OBJECT_CLASS(klass); GstPylonFeatureWalker::install_properties(oclass, nodemap, device_name, - cache_filename); + feature_cache); } static void gst_pylon_object_class_init( @@ -177,7 +178,7 @@ static void gst_pylon_object_class_init( gst_pylon_object_install_properties(klass, device_members->nodemap, device_members->device_name, - device_members->cache_filename); + device_members->feature_cache); delete (device_members); } diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index a89c6a8..af701a9 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -33,6 +33,8 @@ #ifndef _GST_PYLON_OBJECT_H_ #define _GST_PYLON_OBJECT_H_ +#include "gstpyloncache.h" + #include #ifdef _MSC_VER // MSVC @@ -64,7 +66,7 @@ struct _GstPylonObjectClass { }; EXT_PYLONSRC_API GType gst_pylon_object_register(const std::string& device_name, - const std::string& cache_filename, + GstPylonCache& feature_cache, GenApi::INodeMap& nodemap); EXT_PYLONSRC_API GObject* gst_pylon_object_new( std::shared_ptr camera, diff --git a/gst-libs/gst/pylon/meson.build b/gst-libs/gst/pylon/meson.build index 44d3838..c365b97 100644 --- a/gst-libs/gst/pylon/meson.build +++ b/gst-libs/gst/pylon/meson.build @@ -34,6 +34,7 @@ gstpylon_sources = [ 'gstpylonmeta.cpp', 'gstpylonobject.cpp', 'gstpylonparamspecs.cpp', + 'gstpyloncache.cpp', ] gstpylon_headers = [ From 152f5640b91640ede3ad9d2718ddca7ab06269a3 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Thu, 15 Dec 2022 17:08:09 -0600 Subject: [PATCH 011/126] Do cache creation operations in GstPylonCache module --- gst-libs/gst/pylon/gstpyloncache.cpp | 49 +++++++++++++++++++- gst-libs/gst/pylon/gstpyloncache.h | 3 ++ gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 49 ++------------------ 3 files changed, 54 insertions(+), 47 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index 75c5dde..caa7f76 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -32,4 +32,51 @@ #include "gstpyloncache.h" -GstPylonCache::GstPylonCache(const std::string name) : cache_file_name(name) {} +/* prototypes */ +static gchar* gst_pylon_check_for_feature_cache( + const std::string cache_filename); + +static gchar* gst_pylon_check_for_feature_cache( + const std::string cache_filename) { + gchar* filename_hash = + g_compute_checksum_for_string(G_CHECKSUM_SHA256, cache_filename.c_str(), + strlen(cache_filename.c_str())); + gchar* dirpath = g_strdup_printf("%s/%s", g_get_user_cache_dir(), "gstpylon"); + + /* Create gstpylon directory */ + gint dir_permissions = 0775; + g_mkdir_with_parents(dirpath, dir_permissions); + + gchar* filepath = g_strdup_printf("%s/%s", dirpath, filename_hash); + + g_free(dirpath); + g_free(filename_hash); + + return filepath; +} + +GstPylonCache::GstPylonCache(const std::string name) + : cache_file_name(name), feature_cache_dict(g_key_file_new()) {} + +GstPylonCache::~GstPylonCache() { g_key_file_free(this->feature_cache_dict); } + +GKeyFile* GstPylonCache::GetCacheDict() { return this->feature_cache_dict; } + +void GstPylonCache::CreateCacheFile() { + gsize len = 0; + gchar* feature_cache_str = + g_key_file_to_data(this->feature_cache_dict, &len, NULL); + gchar* filepath = + gst_pylon_check_for_feature_cache(this->cache_file_name.c_str()); + + GError* file_err = NULL; + gboolean ret = + g_file_set_contents(filepath, feature_cache_str, len, &file_err); + if (!ret) { + GST_WARNING("Feature cache could not be generated. %s", file_err->message); + g_error_free(file_err); + } + + g_free(feature_cache_str); + g_free(filepath); +} \ No newline at end of file diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index 18c861c..91cf269 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -56,10 +56,13 @@ class GstPylonCache { public: GstPylonCache(const std::string name); + ~GstPylonCache(); + GKeyFile* GetCacheDict(); void CreateCacheFile(); private: const std::string cache_file_name; + GKeyFile* feature_cache_dict; }; #endif diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 4341571..70de454 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -56,10 +56,6 @@ static std::vector gst_pylon_camera_handle_node( static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); -static gchar* gst_pylon_check_for_feature_cache( - const std::string cache_filename); -static void gst_pylon_create_cache_file(GKeyFile* feature_cache, - const std::string cache_filename); static std::unordered_set propfilter_set = { "Width", @@ -233,52 +229,13 @@ static void gst_pylon_camera_install_specs( } } -static gchar* gst_pylon_check_for_feature_cache( - const std::string cache_filename) { - gchar* filename_hash = - g_compute_checksum_for_string(G_CHECKSUM_SHA256, cache_filename.c_str(), - strlen(cache_filename.c_str())); - gchar* dirpath = g_strdup_printf("%s/%s", g_get_user_cache_dir(), "gstpylon"); - - /* Create gstpylon directory */ - gint dir_permissions = 0775; - g_mkdir_with_parents(dirpath, dir_permissions); - - gchar* filepath = g_strdup_printf("%s/%s", dirpath, filename_hash); - - g_free(dirpath); - g_free(filename_hash); - - return filepath; -} - -static void gst_pylon_create_cache_file(GKeyFile* feature_cache, - const std::string cache_filename) { - g_return_if_fail(feature_cache); - - gsize len = 0; - gchar* feature_cache_str = g_key_file_to_data(feature_cache, &len, NULL); - gchar* filepath = gst_pylon_check_for_feature_cache(cache_filename.c_str()); - - GError* file_err = NULL; - gboolean ret = - g_file_set_contents(filepath, feature_cache_str, len, &file_err); - if (!ret) { - GST_WARNING("Feature cache could not be generated. %s", file_err->message); - g_error_free(file_err); - } - - g_free(feature_cache_str); - g_free(filepath); -} - void GstPylonFeatureWalker::install_properties( GObjectClass* oclass, GenApi::INodeMap& nodemap, const std::string device_fullname, GstPylonCache& feature_cache) { g_return_if_fail(oclass); - /* Start KeyFile object to hold property cache */ - GKeyFile* feature_cache_dict = g_key_file_new(); + /* Get KeyFile object to hold property cache */ + GKeyFile* feature_cache_dict = feature_cache.GetCacheDict(); gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); @@ -323,5 +280,5 @@ void GstPylonFeatureWalker::install_properties( } } - g_key_file_free(feature_cache_dict); + feature_cache.CreateCacheFile(); } From c6fee3d193d802237ce61258de3cc101d50e21a5 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Thu, 15 Dec 2022 17:34:14 -0600 Subject: [PATCH 012/126] Create a SetCacheValue member to hide GKeyFile logic --- gst-libs/gst/pylon/gstpyloncache.cpp | 5 +- gst-libs/gst/pylon/gstpyloncache.h | 2 +- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 9 ++-- gst-libs/gst/pylon/gstpylonintrospection.cpp | 49 ++++++++------------ gst-libs/gst/pylon/gstpylonintrospection.h | 4 +- 5 files changed, 31 insertions(+), 38 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index caa7f76..295c678 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -60,7 +60,10 @@ GstPylonCache::GstPylonCache(const std::string name) GstPylonCache::~GstPylonCache() { g_key_file_free(this->feature_cache_dict); } -GKeyFile* GstPylonCache::GetCacheDict() { return this->feature_cache_dict; } +void GstPylonCache::SetCacheValue(std::string key, std::string value) { + g_key_file_set_string(this->feature_cache_dict, "gstpylon", key.c_str(), + value.c_str()); +} void GstPylonCache::CreateCacheFile() { gsize len = 0; diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index 91cf269..a725909 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -57,7 +57,7 @@ class GstPylonCache { public: GstPylonCache(const std::string name); ~GstPylonCache(); - GKeyFile* GetCacheDict(); + void SetCacheValue(std::string key, std::string value); void CreateCacheFile(); private: diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 70de454..0d00938 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -52,7 +52,7 @@ static std::vector gst_pylon_get_int_entries( GenApi::IInteger* int_node); static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const std::string device_fullname, GKeyFile* feature_cache); + const std::string device_fullname, GstPylonCache& feature_cache); static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); @@ -169,7 +169,7 @@ std::vector GstPylonFeatureWalker::process_selector_features( static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const std::string device_fullname, GKeyFile* feature_cache) { + const std::string device_fullname, GstPylonCache& feature_cache) { GenApi::INode* selector_node = NULL; guint64 selector_value = 0; std::vector specs_list; @@ -234,9 +234,6 @@ void GstPylonFeatureWalker::install_properties( const std::string device_fullname, GstPylonCache& feature_cache) { g_return_if_fail(oclass); - /* Get KeyFile object to hold property cache */ - GKeyFile* feature_cache_dict = feature_cache.GetCacheDict(); - gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); auto worklist = std::queue(); @@ -260,7 +257,7 @@ void GstPylonFeatureWalker::install_properties( try { std::vector specs_list = gst_pylon_camera_handle_node( - node, nodemap, device_fullname, feature_cache_dict); + node, nodemap, device_fullname, feature_cache); gst_pylon_camera_install_specs(specs_list, oclass, nprop); } catch (const Pylon::GenericException& e) { GST_FIXME("Unable to install property \"%s\" on device \"%s\": %s", diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 9d1ad65..98295ae 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -67,12 +67,10 @@ class GstPylonTypeAction : public GstPylonActions { /* prototypes */ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, GenApi::INode *node, - GKeyFile *feature_cache); -static GParamSpec *gst_pylon_make_spec_selector_int64(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GenApi::INode *selector, - guint64 selector_value, - GKeyFile *feature_cache); + GstPylonCache &feature_cache); +static GParamSpec *gst_pylon_make_spec_selector_int64( + GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, + guint64 selector_value, GstPylonCache &feature_cache); static GParamSpec *gst_pylon_make_spec_bool(GenApi::INodeMap &nodemap, GenApi::INode *node); static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, @@ -81,12 +79,10 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, guint64 selector_value); static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, GenApi::INode *node, - GKeyFile *feature_cache); -static GParamSpec *gst_pylon_make_spec_selector_float(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GenApi::INode *selector, - guint64 selector_value, - GKeyFile *feature_cache); + GstPylonCache &feature_cache); +static GParamSpec *gst_pylon_make_spec_selector_float( + GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, + guint64 selector_value, GstPylonCache &feature_cache); static GParamSpec *gst_pylon_make_spec_str(GenApi::INodeMap &nodemap, GenApi::INode *node); static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, @@ -135,7 +131,7 @@ static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GParamFlags &flags, T &minimum_under_all_settings, T &maximum_under_all_settings, - GKeyFile *feature_cache); + GstPylonCache &feature_cache); static gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node); static GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, GenApi::INode *node); @@ -532,7 +528,7 @@ static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GParamFlags &flags, T &minimum_under_all_settings, T &maximum_under_all_settings, - GKeyFile *feature_cache) { + GstPylonCache &feature_cache) { g_return_if_fail(node); flags = gst_pylon_query_access(nodemap, node); @@ -542,13 +538,12 @@ static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, std::string limits_and_flags = std::to_string(minimum_under_all_settings) + " " + std::to_string(maximum_under_all_settings) + " " + std::to_string(flags); - g_key_file_set_string(feature_cache, "gstpylon", node->GetName().c_str(), - limits_and_flags.c_str()); + feature_cache.SetCacheValue(std::string(node->GetName()), limits_and_flags); } static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, GenApi::INode *node, - GKeyFile *feature_cache) { + GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); Pylon::CIntegerParameter param(node); @@ -564,11 +559,9 @@ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, param.GetValue(), flags); } -static GParamSpec *gst_pylon_make_spec_selector_int64(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GenApi::INode *selector, - guint64 selector_value, - GKeyFile *feature_cache) { +static GParamSpec *gst_pylon_make_spec_selector_int64( + GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, + guint64 selector_value, GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); @@ -614,7 +607,7 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, GenApi::INode *node, - GKeyFile *feature_cache) { + GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); Pylon::CFloatParameter param(node); @@ -630,11 +623,9 @@ static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, param.GetValue(), flags); } -static GParamSpec *gst_pylon_make_spec_selector_float(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GenApi::INode *selector, - guint64 selector_value, - GKeyFile *feature_cache) { +static GParamSpec *gst_pylon_make_spec_selector_float( + GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, + guint64 selector_value, GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); @@ -760,7 +751,7 @@ GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, GenApi::INode *selector, guint64 selector_value, const std::string device_fullname, - GKeyFile *feature_cache) { + GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); GParamSpec *spec = NULL; diff --git a/gst-libs/gst/pylon/gstpylonintrospection.h b/gst-libs/gst/pylon/gstpylonintrospection.h index 214a87f..d1ca0b7 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.h +++ b/gst-libs/gst/pylon/gstpylonintrospection.h @@ -33,6 +33,8 @@ #ifndef _GST_PYLON_INTROSPECTION_H_ #define _GST_PYLON_INTROSPECTION_H_ +#include "gstpyloncache.h" + #include #ifdef _MSC_VER // MSVC @@ -59,7 +61,7 @@ class GstPylonParamFactory { static GParamSpec *make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, const std::string device_fullname, - GKeyFile *feature_cache); + GstPylonCache &feature_cache); }; #endif From 9c08f9ef09cd8e0714554b38e0436287d42d6f6e Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Thu, 15 Dec 2022 17:48:55 -0600 Subject: [PATCH 013/126] Remove unnecessary includes --- gst-libs/gst/pylon/gstpyloncache.h | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index a725909..505e0ca 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -34,24 +34,7 @@ #define _GST_PYLON_CACHE_H_ #include - -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif - -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif +#include class GstPylonCache { public: From bc00c1203e89abe23bb8db635ddd118d94dd1c91 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 20 Dec 2022 17:20:28 -0600 Subject: [PATCH 014/126] Store numeric values as num/den --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 33 ++++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 98295ae..0afc48d 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -125,6 +125,10 @@ static void gst_pylon_find_limits( GenApi::INode *node, double &minimum_under_all_settings, double &maximum_under_all_settings, std::vector &invalidators_result); +template +static std::string gst_pylon_build_cache_value_string( + GParamFlags &flags, T &minimum_under_all_settings, + T &maximum_under_all_settings); template static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GenApi::INode *node, @@ -522,6 +526,29 @@ static void gst_pylon_find_limits(GenApi::INode *node, } } +template +static std::string gst_pylon_build_cache_value_string( + GParamFlags &flags, T &minimum_under_all_settings, + T &maximum_under_all_settings) { + std::string limits_and_flags; + gint numerator = 0; + gint denominator = 0; + + gst_util_double_to_fraction(minimum_under_all_settings, &numerator, + &denominator); + limits_and_flags += + std::to_string(numerator) + "," + std::to_string(denominator); + limits_and_flags += " "; + gst_util_double_to_fraction(maximum_under_all_settings, &numerator, + &denominator); + limits_and_flags += + std::to_string(numerator) + "," + std::to_string(denominator); + limits_and_flags += " "; + limits_and_flags += std::to_string(flags); + + return limits_and_flags; +} + template static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GenApi::INode *node, @@ -535,9 +562,9 @@ static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, gst_pylon_find_limits(node, minimum_under_all_settings, maximum_under_all_settings); - std::string limits_and_flags = - std::to_string(minimum_under_all_settings) + " " + - std::to_string(maximum_under_all_settings) + " " + std::to_string(flags); + std::string limits_and_flags = gst_pylon_build_cache_value_string( + flags, minimum_under_all_settings, maximum_under_all_settings); + feature_cache.SetCacheValue(std::string(node->GetName()), limits_and_flags); } From 58ff5c75c3835d8f238671bff7d16dd6c7f92770 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 20 Dec 2022 18:14:08 -0600 Subject: [PATCH 015/126] React to errors by using Pylon's generic exception --- gst-libs/gst/pylon/gstpyloncache.cpp | 37 ++++++++++++++++---- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 6 +++- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index 295c678..5d48bba 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -32,11 +32,30 @@ #include "gstpyloncache.h" +#include + +#ifdef _MSC_VER // MSVC +#pragma warning(push) +#pragma warning(disable : 4265) +#elif __GNUC__ // GCC, CLANG, MinGW +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif + +#include + +#ifdef _MSC_VER // MSVC +#pragma warning(pop) +#elif __GNUC__ // GCC, CLANG, MinWG +#pragma GCC diagnostic pop +#endif + +#define DIRERR -1 + /* prototypes */ -static gchar* gst_pylon_check_for_feature_cache( - const std::string cache_filename); +static gchar* gst_pylon_cache_create_filepath(const std::string cache_filename); -static gchar* gst_pylon_check_for_feature_cache( +static gchar* gst_pylon_cache_create_filepath( const std::string cache_filename) { gchar* filename_hash = g_compute_checksum_for_string(G_CHECKSUM_SHA256, cache_filename.c_str(), @@ -45,7 +64,12 @@ static gchar* gst_pylon_check_for_feature_cache( /* Create gstpylon directory */ gint dir_permissions = 0775; - g_mkdir_with_parents(dirpath, dir_permissions); + gint ret = g_mkdir_with_parents(dirpath, dir_permissions); + if (DIRERR == ret) { + std::string msg = "Failed to create " + std::string(dirpath) + ": " + + std::string(strerror(errno)); + throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); + } gchar* filepath = g_strdup_printf("%s/%s", dirpath, filename_hash); @@ -70,14 +94,15 @@ void GstPylonCache::CreateCacheFile() { gchar* feature_cache_str = g_key_file_to_data(this->feature_cache_dict, &len, NULL); gchar* filepath = - gst_pylon_check_for_feature_cache(this->cache_file_name.c_str()); + gst_pylon_cache_create_filepath(this->cache_file_name.c_str()); GError* file_err = NULL; gboolean ret = g_file_set_contents(filepath, feature_cache_str, len, &file_err); if (!ret) { - GST_WARNING("Feature cache could not be generated. %s", file_err->message); + std::string file_err_str = std::string(file_err->message); g_error_free(file_err); + throw Pylon::GenericException(file_err_str.c_str(), __FILE__, __LINE__); } g_free(feature_cache_str); diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 0d00938..d6df3e5 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -277,5 +277,9 @@ void GstPylonFeatureWalker::install_properties( } } - feature_cache.CreateCacheFile(); + try { + feature_cache.CreateCacheFile(); + } catch (const Pylon::GenericException& e) { + GST_WARNING("Feature cache could not be generated. %s", e.GetDescription()); + } } From 9d014b062d686b0dd1038ed8123df8c41e17fcb3 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 3 Jan 2023 14:33:22 -0600 Subject: [PATCH 016/126] Use std::string instead of gchars and pass references instead of copies --- gst-libs/gst/pylon/gstpyloncache.cpp | 40 ++++++++++---------- gst-libs/gst/pylon/gstpyloncache.h | 5 ++- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 6 +-- gst-libs/gst/pylon/gstpylonfeaturewalker.h | 2 +- gst-libs/gst/pylon/gstpylonintrospection.cpp | 18 ++++----- gst-libs/gst/pylon/gstpylonintrospection.h | 2 +- 6 files changed, 38 insertions(+), 35 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index 5d48bba..659cdd8 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -53,58 +53,60 @@ #define DIRERR -1 /* prototypes */ -static gchar* gst_pylon_cache_create_filepath(const std::string cache_filename); +static std::string gst_pylon_cache_create_filepath( + const std::string& cache_filename); -static gchar* gst_pylon_cache_create_filepath( - const std::string cache_filename) { +static std::string gst_pylon_cache_create_filepath( + const std::string& cache_filename) { gchar* filename_hash = g_compute_checksum_for_string(G_CHECKSUM_SHA256, cache_filename.c_str(), strlen(cache_filename.c_str())); - gchar* dirpath = g_strdup_printf("%s/%s", g_get_user_cache_dir(), "gstpylon"); + std::string filename_hash_str = std::string(filename_hash); + g_free(filename_hash); + + std::string dirpath = std::string(g_get_user_cache_dir()) + "/" + "gstpylon"; /* Create gstpylon directory */ gint dir_permissions = 0775; - gint ret = g_mkdir_with_parents(dirpath, dir_permissions); + gint ret = g_mkdir_with_parents(dirpath.c_str(), dir_permissions); if (DIRERR == ret) { std::string msg = "Failed to create " + std::string(dirpath) + ": " + std::string(strerror(errno)); throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); } - gchar* filepath = g_strdup_printf("%s/%s", dirpath, filename_hash); - - g_free(dirpath); - g_free(filename_hash); + std::string filepath = dirpath + "/" + filename_hash_str; return filepath; } -GstPylonCache::GstPylonCache(const std::string name) +GstPylonCache::GstPylonCache(const std::string& name) : cache_file_name(name), feature_cache_dict(g_key_file_new()) {} GstPylonCache::~GstPylonCache() { g_key_file_free(this->feature_cache_dict); } -void GstPylonCache::SetCacheValue(std::string key, std::string value) { +void GstPylonCache::SetCacheValue(const std::string& key, + const std::string& value) { g_key_file_set_string(this->feature_cache_dict, "gstpylon", key.c_str(), value.c_str()); } void GstPylonCache::CreateCacheFile() { gsize len = 0; - gchar* feature_cache_str = + gchar* feature_cache = g_key_file_to_data(this->feature_cache_dict, &len, NULL); - gchar* filepath = + std::string feature_cache_str = std::string(feature_cache); + g_free(feature_cache); + + std::string filepath = gst_pylon_cache_create_filepath(this->cache_file_name.c_str()); GError* file_err = NULL; - gboolean ret = - g_file_set_contents(filepath, feature_cache_str, len, &file_err); + gboolean ret = g_file_set_contents(filepath.c_str(), + feature_cache_str.c_str(), len, &file_err); if (!ret) { std::string file_err_str = std::string(file_err->message); g_error_free(file_err); throw Pylon::GenericException(file_err_str.c_str(), __FILE__, __LINE__); } - - g_free(feature_cache_str); - g_free(filepath); -} \ No newline at end of file +} diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index 505e0ca..f16f243 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -34,13 +34,14 @@ #define _GST_PYLON_CACHE_H_ #include + #include class GstPylonCache { public: - GstPylonCache(const std::string name); + GstPylonCache(const std::string& name); ~GstPylonCache(); - void SetCacheValue(std::string key, std::string value); + void SetCacheValue(const std::string& key, const std::string& value); void CreateCacheFile(); private: diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index d6df3e5..89601f3 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -52,7 +52,7 @@ static std::vector gst_pylon_get_int_entries( GenApi::IInteger* int_node); static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const std::string device_fullname, GstPylonCache& feature_cache); + const std::string& device_fullname, GstPylonCache& feature_cache); static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); @@ -169,7 +169,7 @@ std::vector GstPylonFeatureWalker::process_selector_features( static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const std::string device_fullname, GstPylonCache& feature_cache) { + const std::string& device_fullname, GstPylonCache& feature_cache) { GenApi::INode* selector_node = NULL; guint64 selector_value = 0; std::vector specs_list; @@ -231,7 +231,7 @@ static void gst_pylon_camera_install_specs( void GstPylonFeatureWalker::install_properties( GObjectClass* oclass, GenApi::INodeMap& nodemap, - const std::string device_fullname, GstPylonCache& feature_cache) { + const std::string& device_fullname, GstPylonCache& feature_cache) { g_return_if_fail(oclass); gint nprop = 1; diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.h b/gst-libs/gst/pylon/gstpylonfeaturewalker.h index dc5a771..a121fb5 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.h +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.h @@ -59,7 +59,7 @@ class GstPylonFeatureWalker { public: static void install_properties(GObjectClass* oclass, GenApi::INodeMap& nodemap, - const std::string device_fullname, + const std::string& device_fullname, GstPylonCache& feature_cache); static std::vector process_selector_features( GenApi::INode* node, GenApi::INode** selector_node); diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 0afc48d..19178b3 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -91,13 +91,13 @@ static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, guint64 selector_value); static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, GenApi::INode *node, - const std::string device_fullname); + const std::string &device_fullname); static GParamSpec *gst_pylon_make_spec_enum(GenApi::INodeMap &nodemap, GenApi::INode *node, - const std::string device_fullname); + const std::string &device_fullname); static GParamSpec *gst_pylon_make_spec_selector_enum( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, const std::string device_fullname); + guint64 selector_value, const std::string &device_fullname); static GenApi::INode *gst_pylon_find_limit_node(GenApi::INode *feature_node, const GenICam::gcstring &limit); static std::vector gst_pylon_find_parent_features( @@ -698,7 +698,7 @@ static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, GenApi::INode *node, - const std::string device_fullname) { + const std::string &device_fullname) { /* When registering enums to the GType system, their string pointers must remain valid throughout the application lifespan. To achieve this we are saving all found enums into a static hash table @@ -745,9 +745,9 @@ static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, return type; } -static GParamSpec *gst_pylon_make_spec_enum(GenApi::INodeMap &nodemap, - GenApi::INode *node, - const std::string device_fullname) { +static GParamSpec *gst_pylon_make_spec_enum( + GenApi::INodeMap &nodemap, GenApi::INode *node, + const std::string &device_fullname) { g_return_val_if_fail(node, NULL); Pylon::CEnumParameter param(node); @@ -760,7 +760,7 @@ static GParamSpec *gst_pylon_make_spec_enum(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_selector_enum( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, const std::string device_fullname) { + guint64 selector_value, const std::string &device_fullname) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); @@ -777,7 +777,7 @@ GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, - const std::string device_fullname, + const std::string &device_fullname, GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); diff --git a/gst-libs/gst/pylon/gstpylonintrospection.h b/gst-libs/gst/pylon/gstpylonintrospection.h index d1ca0b7..638f9a2 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.h +++ b/gst-libs/gst/pylon/gstpylonintrospection.h @@ -60,7 +60,7 @@ class GstPylonParamFactory { public: static GParamSpec *make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, - const std::string device_fullname, + const std::string &device_fullname, GstPylonCache &feature_cache); }; From c831fa4abf01cc0ee1a4cba382e605649bbbdf00 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 3 Jan 2023 14:57:00 -0600 Subject: [PATCH 017/126] Use '.' instead of ',' for nom/den values and don't pass min,max,flags as references when they're not outputs --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 19178b3..2c0494b 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -127,8 +127,8 @@ static void gst_pylon_find_limits( std::vector &invalidators_result); template static std::string gst_pylon_build_cache_value_string( - GParamFlags &flags, T &minimum_under_all_settings, - T &maximum_under_all_settings); + GParamFlags flags, T minimum_under_all_settings, + T maximum_under_all_settings); template static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GenApi::INode *node, @@ -528,21 +528,23 @@ static void gst_pylon_find_limits(GenApi::INode *node, template static std::string gst_pylon_build_cache_value_string( - GParamFlags &flags, T &minimum_under_all_settings, - T &maximum_under_all_settings) { + GParamFlags flags, T minimum_under_all_settings, + T maximum_under_all_settings) { std::string limits_and_flags; gint numerator = 0; gint denominator = 0; + /* Values are stored as nominator.denominator so that a cache file with double + * values can be read and be valid independent of locale */ gst_util_double_to_fraction(minimum_under_all_settings, &numerator, &denominator); limits_and_flags += - std::to_string(numerator) + "," + std::to_string(denominator); + std::to_string(numerator) + "." + std::to_string(denominator); limits_and_flags += " "; gst_util_double_to_fraction(maximum_under_all_settings, &numerator, &denominator); limits_and_flags += - std::to_string(numerator) + "," + std::to_string(denominator); + std::to_string(numerator) + "." + std::to_string(denominator); limits_and_flags += " "; limits_and_flags += std::to_string(flags); From 5c71b3c154ecdbb06ff7fdf36e4077c391874f84 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 3 Jan 2023 15:10:27 -0600 Subject: [PATCH 018/126] Include installed headers instead of local ones --- gst-libs/gst/pylon/gstpylonfeaturewalker.h | 3 +-- gst-libs/gst/pylon/gstpylonintrospection.h | 3 +-- gst-libs/gst/pylon/gstpylonobject.h | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.h b/gst-libs/gst/pylon/gstpylonfeaturewalker.h index a121fb5..d40048e 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.h +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.h @@ -33,9 +33,8 @@ #ifndef _GST_PYLON_FEATURE_WALKER_H_ #define _GST_PYLON_FEATURE_WALKER_H_ -#include "gstpyloncache.h" - #include +#include #ifdef _MSC_VER // MSVC #pragma warning(push) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.h b/gst-libs/gst/pylon/gstpylonintrospection.h index 638f9a2..cf12934 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.h +++ b/gst-libs/gst/pylon/gstpylonintrospection.h @@ -33,9 +33,8 @@ #ifndef _GST_PYLON_INTROSPECTION_H_ #define _GST_PYLON_INTROSPECTION_H_ -#include "gstpyloncache.h" - #include +#include #ifdef _MSC_VER // MSVC #pragma warning(push) diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index af701a9..a78a8e2 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -33,9 +33,8 @@ #ifndef _GST_PYLON_OBJECT_H_ #define _GST_PYLON_OBJECT_H_ -#include "gstpyloncache.h" - #include +#include #ifdef _MSC_VER // MSVC #pragma warning(push) From 5f6870ec7ede7a3c8ddf95e82225efee0ff0d908 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 3 Jan 2023 15:15:45 -0600 Subject: [PATCH 019/126] Install all pylon headers --- gst-libs/gst/pylon/meson.build | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/meson.build b/gst-libs/gst/pylon/meson.build index c365b97..67a734b 100644 --- a/gst-libs/gst/pylon/meson.build +++ b/gst-libs/gst/pylon/meson.build @@ -38,8 +38,15 @@ gstpylon_sources = [ ] gstpylon_headers = [ + 'gstpylon-prelude.h', 'gstpylonmeta.h', - 'gstpylon-prelude.h' + 'gstpylondebug.h', + 'gstpylonfeaturewalker.h', + 'gstpylonintrospection.h', + 'gstpylonmetaprivate.h', + 'gstpylonobject.h', + 'gstpylonparamspecs.h', + 'gstpyloncache.h' ] install_headers(gstpylon_headers, subdir : 'gstreamer-1.0/gst/pylon/') From a6575a40f6e7b863443a2db2e31f8c89d51d9ecf Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 3 Jan 2023 17:13:04 -0600 Subject: [PATCH 020/126] Avoid explicit string wrap when possible --- gst-libs/gst/pylon/gstpyloncache.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index 659cdd8..c3e9776 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -61,7 +61,7 @@ static std::string gst_pylon_cache_create_filepath( gchar* filename_hash = g_compute_checksum_for_string(G_CHECKSUM_SHA256, cache_filename.c_str(), strlen(cache_filename.c_str())); - std::string filename_hash_str = std::string(filename_hash); + std::string filename_hash_str = filename_hash; g_free(filename_hash); std::string dirpath = std::string(g_get_user_cache_dir()) + "/" + "gstpylon"; @@ -70,8 +70,8 @@ static std::string gst_pylon_cache_create_filepath( gint dir_permissions = 0775; gint ret = g_mkdir_with_parents(dirpath.c_str(), dir_permissions); if (DIRERR == ret) { - std::string msg = "Failed to create " + std::string(dirpath) + ": " + - std::string(strerror(errno)); + std::string msg = + "Failed to create " + dirpath + ": " + std::string(strerror(errno)); throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); } @@ -95,7 +95,7 @@ void GstPylonCache::CreateCacheFile() { gsize len = 0; gchar* feature_cache = g_key_file_to_data(this->feature_cache_dict, &len, NULL); - std::string feature_cache_str = std::string(feature_cache); + std::string feature_cache_str = feature_cache; g_free(feature_cache); std::string filepath = @@ -105,7 +105,7 @@ void GstPylonCache::CreateCacheFile() { gboolean ret = g_file_set_contents(filepath.c_str(), feature_cache_str.c_str(), len, &file_err); if (!ret) { - std::string file_err_str = std::string(file_err->message); + std::string file_err_str = file_err->message; g_error_free(file_err); throw Pylon::GenericException(file_err_str.c_str(), __FILE__, __LINE__); } From 88c2c3d42cf85fe0ae1c7c2302d85afb9560c2f0 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 3 Jan 2023 17:21:06 -0600 Subject: [PATCH 021/126] Sort sources in alphabetical order in meson file --- gst-libs/gst/pylon/meson.build | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gst-libs/gst/pylon/meson.build b/gst-libs/gst/pylon/meson.build index 67a734b..1d5ba31 100644 --- a/gst-libs/gst/pylon/meson.build +++ b/gst-libs/gst/pylon/meson.build @@ -28,25 +28,25 @@ else endif gstpylon_sources = [ + 'gstpyloncache.cpp', 'gstpylondebug.c', - 'gstpylonintrospection.cpp', 'gstpylonfeaturewalker.cpp', + 'gstpylonintrospection.cpp', 'gstpylonmeta.cpp', 'gstpylonobject.cpp', - 'gstpylonparamspecs.cpp', - 'gstpyloncache.cpp', + 'gstpylonparamspecs.cpp' ] gstpylon_headers = [ 'gstpylon-prelude.h', - 'gstpylonmeta.h', + 'gstpyloncache.h', 'gstpylondebug.h', 'gstpylonfeaturewalker.h', 'gstpylonintrospection.h', + 'gstpylonmeta.h', 'gstpylonmetaprivate.h', 'gstpylonobject.h', - 'gstpylonparamspecs.h', - 'gstpyloncache.h' + 'gstpylonparamspecs.h' ] install_headers(gstpylon_headers, subdir : 'gstreamer-1.0/gst/pylon/') From 5ef236efd8e5ae977238580553b63099a4d0fe35 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 21 Dec 2022 10:35:15 -0600 Subject: [PATCH 022/126] Add .config extension to cache files --- gst-libs/gst/pylon/gstpyloncache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index c3e9776..fd1b000 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -75,7 +75,7 @@ static std::string gst_pylon_cache_create_filepath( throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); } - std::string filepath = dirpath + "/" + filename_hash_str; + std::string filepath = dirpath + "/" + filename_hash_str + ".config"; return filepath; } From f840669e67919749a1d1f1ab303a78f59b1f2b4b Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 21 Dec 2022 13:18:41 -0600 Subject: [PATCH 023/126] Add check to verify if cache is valid --- gst-libs/gst/pylon/gstpyloncache.cpp | 60 +++++++++++++------- gst-libs/gst/pylon/gstpyloncache.h | 6 +- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 13 +++-- 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index fd1b000..3f8d016 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -69,41 +69,63 @@ static std::string gst_pylon_cache_create_filepath( /* Create gstpylon directory */ gint dir_permissions = 0775; gint ret = g_mkdir_with_parents(dirpath.c_str(), dir_permissions); + std::string filepath = dirpath + "/" + filename_hash_str + ".config"; if (DIRERR == ret) { std::string msg = "Failed to create " + dirpath + ": " + std::string(strerror(errno)); - throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); + GST_WARNING("%s", msg.c_str()); } - std::string filepath = dirpath + "/" + filename_hash_str + ".config"; - return filepath; } GstPylonCache::GstPylonCache(const std::string& name) - : cache_file_name(name), feature_cache_dict(g_key_file_new()) {} + : filepath(gst_pylon_cache_create_filepath(name)), + feature_cache_dict(g_key_file_new()), + keyfile_groupname("gstpylon") {} + +GstPylonCache::~GstPylonCache() { + g_key_file_free(this->feature_cache_dict); + free(this->filepath); +} -GstPylonCache::~GstPylonCache() { g_key_file_free(this->feature_cache_dict); } +gboolean GstPylonCache::IsCacheValid() { + gboolean ret = TRUE; -void GstPylonCache::SetCacheValue(const std::string& key, - const std::string& value) { - g_key_file_set_string(this->feature_cache_dict, "gstpylon", key.c_str(), + /* Check if file exists */ + ret = g_file_test(this->filepath, G_FILE_TEST_EXISTS); + if (!ret) { + return FALSE; + } + + /* Check if file contents are valid, this also sets the content of the + * GKeyFile object if valid */ + ret = g_key_file_load_from_file(this->feature_cache_dict, this->filepath, + G_KEY_FILE_NONE, NULL); + if (!ret) { + return FALSE; + } + + /* Check if the 'GstPylonCacheIsNew' flag is in the file */ + if (!g_key_file_get_string(this->feature_cache_dict, + this->keyfile_groupname.c_str(), + "GstPylonCacheIsNew", NULL)) { + return FALSE; + } + + return TRUE; +} + +void GstPylonCache::SetCacheValue(std::string& key, std::string& value) { + g_key_file_set_string(this->feature_cache_dict, + this->keyfile_groupname.c_str(), key.c_str(), value.c_str()); } void GstPylonCache::CreateCacheFile() { - gsize len = 0; - gchar* feature_cache = - g_key_file_to_data(this->feature_cache_dict, &len, NULL); - std::string feature_cache_str = feature_cache; - g_free(feature_cache); - - std::string filepath = - gst_pylon_cache_create_filepath(this->cache_file_name.c_str()); - GError* file_err = NULL; - gboolean ret = g_file_set_contents(filepath.c_str(), - feature_cache_str.c_str(), len, &file_err); + gboolean ret = g_key_file_save_to_file(this->feature_cache_dict, + this->filepath, &file_err); if (!ret) { std::string file_err_str = file_err->message; g_error_free(file_err); diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index f16f243..727dffa 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -41,12 +41,14 @@ class GstPylonCache { public: GstPylonCache(const std::string& name); ~GstPylonCache(); - void SetCacheValue(const std::string& key, const std::string& value); + gboolean IsCacheValid(); + void SetCacheValue(std::string& key, std::string& value); void CreateCacheFile(); private: - const std::string cache_file_name; + gchar* filepath; GKeyFile* feature_cache_dict; + std::string keyfile_groupname; }; #endif diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 89601f3..0baf4e4 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -277,9 +277,14 @@ void GstPylonFeatureWalker::install_properties( } } - try { - feature_cache.CreateCacheFile(); - } catch (const Pylon::GenericException& e) { - GST_WARNING("Feature cache could not be generated. %s", e.GetDescription()); + if (feature_cache.IsCacheValid()) { + std::cout << "Cache is valid" << std::endl; + } else { + try { + feature_cache.CreateCacheFile(); + } catch (const Pylon::GenericException& e) { + GST_WARNING("Feature cache could not be generated. %s", + e.GetDescription()); + } } } From a717a394e27b577de4da5eb5ebb409c3d39cbfd8 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 21 Dec 2022 21:06:15 -0600 Subject: [PATCH 024/126] Use cache values if cache exists and is valid --- gst-libs/gst/pylon/gstpyloncache.cpp | 14 +++--- gst-libs/gst/pylon/gstpyloncache.h | 50 ++++++++++++++++++-- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 6 +-- gst-libs/gst/pylon/gstpylonintrospection.cpp | 18 ++++--- 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index 3f8d016..a513af3 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -82,11 +82,12 @@ static std::string gst_pylon_cache_create_filepath( GstPylonCache::GstPylonCache(const std::string& name) : filepath(gst_pylon_cache_create_filepath(name)), feature_cache_dict(g_key_file_new()), - keyfile_groupname("gstpylon") {} + keyfile_groupname("gstpylon"), + is_cache_new(TRUE) {} GstPylonCache::~GstPylonCache() { g_key_file_free(this->feature_cache_dict); - free(this->filepath); + g_free(this->filepath); } gboolean GstPylonCache::IsCacheValid() { @@ -106,16 +107,13 @@ gboolean GstPylonCache::IsCacheValid() { return FALSE; } - /* Check if the 'GstPylonCacheIsNew' flag is in the file */ - if (!g_key_file_get_string(this->feature_cache_dict, - this->keyfile_groupname.c_str(), - "GstPylonCacheIsNew", NULL)) { - return FALSE; - } + this->is_cache_new = FALSE; return TRUE; } +gboolean GstPylonCache::IsCacheNew() { return this->is_cache_new; } + void GstPylonCache::SetCacheValue(std::string& key, std::string& value) { g_key_file_set_string(this->feature_cache_dict, this->keyfile_groupname.c_str(), key.c_str(), diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index 727dffa..ca7d708 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -37,18 +37,60 @@ #include +#define MIN_VALUE_INDEX 0 +#define MAX_VALUE_INDEX 1 +#define FLAGS_VALUE_INDEX 2 +#define NUMERATOR_INDEX 0 +#define DENOMINATOR_INDEX 1 + class GstPylonCache { public: - GstPylonCache(const std::string& name); + GstPylonCache(const std::string &name); ~GstPylonCache(); gboolean IsCacheValid(); - void SetCacheValue(std::string& key, std::string& value); + gboolean IsCacheNew(); + void SetCacheValue(std::string &key, std::string &value); void CreateCacheFile(); + template + void GetKeyValues(std::string key, T &min, T &max, GParamFlags &flags); + private: - gchar* filepath; - GKeyFile* feature_cache_dict; + gchar *filepath; + GKeyFile *feature_cache_dict; std::string keyfile_groupname; + gboolean is_cache_new; }; +template +void GstPylonCache::GetKeyValues(std::string key, T &min, T &max, + GParamFlags &flags) { + GError *err; + + gchar *values_str = + g_key_file_get_string(this->feature_cache_dict, + this->keyfile_groupname.c_str(), key.c_str(), &err); + if (!values_str) { + GST_ERROR("Could not read values for feature %s from file %s: %s", + key.c_str(), this->filepath, err->message); + g_error_free(err); + return; + } + + gchar **values_list = g_strsplit(values_str, " ", -1); + gchar **min_limit = g_strsplit(values_list[MIN_VALUE_INDEX], ",", -1); + gchar **max_limit = g_strsplit(values_list[MAX_VALUE_INDEX], ",", -1); + + min = (std::stod(min_limit[NUMERATOR_INDEX]) / + std::stod(min_limit[DENOMINATOR_INDEX])); + max = (std::stod(max_limit[NUMERATOR_INDEX]) / + std::stod(max_limit[DENOMINATOR_INDEX])); + flags = static_cast(std::stoi(values_list[FLAGS_VALUE_INDEX])); + + g_strfreev(min_limit); + g_strfreev(max_limit); + g_strfreev(values_list); + g_free(values_str); +} + #endif diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 0baf4e4..a1420a4 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -234,6 +234,8 @@ void GstPylonFeatureWalker::install_properties( const std::string& device_fullname, GstPylonCache& feature_cache) { g_return_if_fail(oclass); + gboolean is_cache_valid = feature_cache.IsCacheValid(); + gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); auto worklist = std::queue(); @@ -277,9 +279,7 @@ void GstPylonFeatureWalker::install_properties( } } - if (feature_cache.IsCacheValid()) { - std::cout << "Cache is valid" << std::endl; - } else { + if (!is_cache_valid) { try { feature_cache.CreateCacheFile(); } catch (const Pylon::GenericException& e) { diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 2c0494b..ad99718 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -560,14 +560,20 @@ static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GstPylonCache &feature_cache) { g_return_if_fail(node); - flags = gst_pylon_query_access(nodemap, node); - gst_pylon_find_limits(node, minimum_under_all_settings, - maximum_under_all_settings); + if (feature_cache.IsCacheNew()) { + flags = gst_pylon_query_access(nodemap, node); + gst_pylon_find_limits(node, minimum_under_all_settings, + maximum_under_all_settings); - std::string limits_and_flags = gst_pylon_build_cache_value_string( - flags, minimum_under_all_settings, maximum_under_all_settings); + std::string limits_and_flags = gst_pylon_build_cache_value_string( + flags, minimum_under_all_settings, maximum_under_all_settings); - feature_cache.SetCacheValue(std::string(node->GetName()), limits_and_flags); + feature_cache.SetCacheValue(std::string(node->GetName()), limits_and_flags); + } else { + feature_cache.GetKeyValues(std::string(node->GetName()), + minimum_under_all_settings, + maximum_under_all_settings, flags); + } } static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, From 19d0e67e3cbcfc6e9d11bf6f351a510dbfb0eef4 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 21 Dec 2022 21:11:50 -0600 Subject: [PATCH 025/126] Group output parameters together --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index ad99718..5b38bf2 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -132,10 +132,10 @@ static std::string gst_pylon_build_cache_value_string( template static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GenApi::INode *node, + GstPylonCache &feature_cache, GParamFlags &flags, T &minimum_under_all_settings, - T &maximum_under_all_settings, - GstPylonCache &feature_cache); + T &maximum_under_all_settings); static gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node); static GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, GenApi::INode *node); @@ -554,10 +554,10 @@ static std::string gst_pylon_build_cache_value_string( template static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, GenApi::INode *node, + GstPylonCache &feature_cache, GParamFlags &flags, T &minimum_under_all_settings, - T &maximum_under_all_settings, - GstPylonCache &feature_cache) { + T &maximum_under_all_settings) { g_return_if_fail(node); if (feature_cache.IsCacheNew()) { @@ -587,7 +587,7 @@ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties( - nodemap, node, flags, min_value, max_value, feature_cache); + nodemap, node, feature_cache, flags, min_value, max_value); return g_param_spec_int64(node->GetName(), node->GetDisplayName(), node->GetToolTip(), min_value, max_value, @@ -606,7 +606,7 @@ static GParamSpec *gst_pylon_make_spec_selector_int64( GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties( - nodemap, node, flags, min_value, max_value, feature_cache); + nodemap, node, feature_cache, flags, min_value, max_value); return gst_pylon_param_spec_selector_int64( nodemap, node->GetName(), selector->GetName(), selector_value, @@ -651,7 +651,7 @@ static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties( - nodemap, node, flags, min_value, max_value, feature_cache); + nodemap, node, feature_cache, flags, min_value, max_value); return g_param_spec_float(node->GetName(), node->GetDisplayName(), node->GetToolTip(), min_value, max_value, @@ -670,7 +670,7 @@ static GParamSpec *gst_pylon_make_spec_selector_float( GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties( - nodemap, node, flags, min_value, max_value, feature_cache); + nodemap, node, feature_cache, flags, min_value, max_value); return gst_pylon_param_spec_selector_float( nodemap, node->GetName(), selector->GetName(), selector_value, From cbda4e58cfe5e75749679c54a931cc706bb64b45 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 3 Jan 2023 17:00:35 -0600 Subject: [PATCH 026/126] Use string wrapper for filepath and make key and value const parameters --- gst-libs/gst/pylon/gstpyloncache.cpp | 16 +++++++--------- gst-libs/gst/pylon/gstpyloncache.h | 6 +++--- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index a513af3..74f4ba3 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -85,24 +85,21 @@ GstPylonCache::GstPylonCache(const std::string& name) keyfile_groupname("gstpylon"), is_cache_new(TRUE) {} -GstPylonCache::~GstPylonCache() { - g_key_file_free(this->feature_cache_dict); - g_free(this->filepath); -} +GstPylonCache::~GstPylonCache() { g_key_file_free(this->feature_cache_dict); } gboolean GstPylonCache::IsCacheValid() { gboolean ret = TRUE; /* Check if file exists */ - ret = g_file_test(this->filepath, G_FILE_TEST_EXISTS); + ret = g_file_test(this->filepath.c_str(), G_FILE_TEST_EXISTS); if (!ret) { return FALSE; } /* Check if file contents are valid, this also sets the content of the * GKeyFile object if valid */ - ret = g_key_file_load_from_file(this->feature_cache_dict, this->filepath, - G_KEY_FILE_NONE, NULL); + ret = g_key_file_load_from_file( + this->feature_cache_dict, this->filepath.c_str(), G_KEY_FILE_NONE, NULL); if (!ret) { return FALSE; } @@ -114,7 +111,8 @@ gboolean GstPylonCache::IsCacheValid() { gboolean GstPylonCache::IsCacheNew() { return this->is_cache_new; } -void GstPylonCache::SetCacheValue(std::string& key, std::string& value) { +void GstPylonCache::SetCacheValue(const std::string& key, + const std::string& value) { g_key_file_set_string(this->feature_cache_dict, this->keyfile_groupname.c_str(), key.c_str(), value.c_str()); @@ -123,7 +121,7 @@ void GstPylonCache::SetCacheValue(std::string& key, std::string& value) { void GstPylonCache::CreateCacheFile() { GError* file_err = NULL; gboolean ret = g_key_file_save_to_file(this->feature_cache_dict, - this->filepath, &file_err); + this->filepath.c_str(), &file_err); if (!ret) { std::string file_err_str = file_err->message; g_error_free(file_err); diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index ca7d708..e85f894 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -49,14 +49,14 @@ class GstPylonCache { ~GstPylonCache(); gboolean IsCacheValid(); gboolean IsCacheNew(); - void SetCacheValue(std::string &key, std::string &value); + void SetCacheValue(const std::string &key, const std::string &value); void CreateCacheFile(); template void GetKeyValues(std::string key, T &min, T &max, GParamFlags &flags); private: - gchar *filepath; + std::string filepath; GKeyFile *feature_cache_dict; std::string keyfile_groupname; gboolean is_cache_new; @@ -72,7 +72,7 @@ void GstPylonCache::GetKeyValues(std::string key, T &min, T &max, this->keyfile_groupname.c_str(), key.c_str(), &err); if (!values_str) { GST_ERROR("Could not read values for feature %s from file %s: %s", - key.c_str(), this->filepath, err->message); + key.c_str(), this->filepath.c_str(), err->message); g_error_free(err); return; } From 72258b3723750c653dfea753997b43f39cbe2f3f Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 3 Jan 2023 17:27:50 -0600 Subject: [PATCH 027/126] Use '.' instead of ',' as read separators --- gst-libs/gst/pylon/gstpyloncache.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index e85f894..cfa457d 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -78,8 +78,8 @@ void GstPylonCache::GetKeyValues(std::string key, T &min, T &max, } gchar **values_list = g_strsplit(values_str, " ", -1); - gchar **min_limit = g_strsplit(values_list[MIN_VALUE_INDEX], ",", -1); - gchar **max_limit = g_strsplit(values_list[MAX_VALUE_INDEX], ",", -1); + gchar **min_limit = g_strsplit(values_list[MIN_VALUE_INDEX], ".", -1); + gchar **max_limit = g_strsplit(values_list[MAX_VALUE_INDEX], ".", -1); min = (std::stod(min_limit[NUMERATOR_INDEX]) / std::stod(min_limit[DENOMINATOR_INDEX])); From 52dcc46122ecfd2dafbb1e94c3e0fcccfebdd1fa Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Wed, 4 Jan 2023 11:49:04 +0100 Subject: [PATCH 028/126] check all implemented featues. avoid skipping temp unavail --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 2 +- gst-libs/gst/pylon/gstpylonintrospection.cpp | 2 +- gst-libs/gst/pylon/gstpylonmeta.cpp | 2 +- tests/prototypes/dynamic_limits.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index a1420a4..2d1d8fb 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -250,7 +250,7 @@ void GstPylonFeatureWalker::install_properties( * selectors and are available */ auto sel_node = dynamic_cast(node); if (node->IsFeature() && (node->GetVisibility() != GenApi::Invisible) && - sel_node && GenApi::IsAvailable(node) && !sel_node->IsSelector() && + sel_node && GenApi::IsImplemented(node) && !sel_node->IsSelector() && propfilter_set.find(std::string(node->GetName())) == propfilter_set.end() && node->GetPrincipalInterfaceType() != GenApi::intfICategory) { diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 5b38bf2..0a3144e 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -266,7 +266,7 @@ static std::vector gst_pylon_get_available_features( const std::set &feature_list) { std::vector available_features; for (const auto &feature : feature_list) { - if (GenApi::IsAvailable(feature)) { + if (GenApi::IsImplemented(feature)) { available_features.push_back(feature); } } diff --git a/gst-libs/gst/pylon/gstpylonmeta.cpp b/gst-libs/gst/pylon/gstpylonmeta.cpp index 6379e97..5968047 100644 --- a/gst-libs/gst/pylon/gstpylonmeta.cpp +++ b/gst-libs/gst/pylon/gstpylonmeta.cpp @@ -169,7 +169,7 @@ static void gst_pylon_meta_fill_result_chunks( /* Only take into account valid Chunk nodes */ auto sel_node = dynamic_cast(node); - if (!GenApi::IsAvailable(node) || !node->IsFeature() || + if (!GenApi::IsImplemented(node) || !node->IsFeature() || (node->GetName() == "Root") || !sel_node || sel_node->IsSelector()) { continue; } diff --git a/tests/prototypes/dynamic_limits.cpp b/tests/prototypes/dynamic_limits.cpp index 45893ad..83dcff3 100644 --- a/tests/prototypes/dynamic_limits.cpp +++ b/tests/prototypes/dynamic_limits.cpp @@ -115,7 +115,7 @@ static vector get_available_features( const vector& feature_list) { vector available_features; for (const auto& feature : feature_list) { - if (GenApi::IsAvailable(feature)) { + if (GenApi::IsImplemented(feature)) { available_features.push_back(feature); } } @@ -354,7 +354,7 @@ static vector walk_nodes(Pylon::CInstantCamera& camera) { auto node = worklist.front(); worklist.pop(); - if (GenApi::IsAvailable(node)) { + if (GenApi::IsImplemented(node)) { if (has_ranges(node)) { node_list.push_back(node); } From 127d5a310654215c51808243430457a05ed22816 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Wed, 4 Jan 2023 11:49:28 +0100 Subject: [PATCH 029/126] skip bayer and mono packed features in limits introspection --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 0a3144e..df2e1ce 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -38,6 +38,8 @@ #include "gstpylonintrospection.h" #include "gstpylonparamspecs.h" +#include + #include #include #include @@ -370,6 +372,13 @@ gst_pylon_create_set_value_actions( GenApi::StringList_t settable_values; param.GetSettableValues(settable_values); for (const auto &value : settable_values) { + /* skip unsupported packed mono and bayer formats */ + if (node->GetName() == "PixelFormat" && + (Pylon::IsMonoPacked(static_cast( + param.GetEntryByName(value)->GetValue())) || + Pylon::IsBayerPacked(static_cast( + param.GetEntryByName(value)->GetValue())))) + continue; values.push_back( new GstPylonTypeAction( param, value)); From a62cdd99368cafd371f7dc777fae1f5449077e62 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 11:31:51 +0100 Subject: [PATCH 030/126] New cache format * introduce new cache format [featurename] min=xx max=xx flags=xx This allows to use the serdes code in glib * If a feature is not or only partially found in the cache, or the cache is not existing the properties are newly introspected and written to cache --- gst-libs/gst/pylon/gstpyloncache.cpp | 110 ++++++++++++++++--- gst-libs/gst/pylon/gstpyloncache.h | 56 +++------- gst-libs/gst/pylon/gstpylonintrospection.cpp | 106 +++++++++--------- 3 files changed, 161 insertions(+), 111 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index 74f4ba3..b8e0dc0 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -54,11 +54,11 @@ /* prototypes */ static std::string gst_pylon_cache_create_filepath( - const std::string& cache_filename); + const std::string &cache_filename); static std::string gst_pylon_cache_create_filepath( - const std::string& cache_filename) { - gchar* filename_hash = + const std::string &cache_filename) { + gchar *filename_hash = g_compute_checksum_for_string(G_CHECKSUM_SHA256, cache_filename.c_str(), strlen(cache_filename.c_str())); std::string filename_hash_str = filename_hash; @@ -79,11 +79,10 @@ static std::string gst_pylon_cache_create_filepath( return filepath; } -GstPylonCache::GstPylonCache(const std::string& name) +GstPylonCache::GstPylonCache(const std::string &name) : filepath(gst_pylon_cache_create_filepath(name)), feature_cache_dict(g_key_file_new()), - keyfile_groupname("gstpylon"), - is_cache_new(TRUE) {} + is_empty(TRUE) {} GstPylonCache::~GstPylonCache() { g_key_file_free(this->feature_cache_dict); } @@ -104,22 +103,15 @@ gboolean GstPylonCache::IsCacheValid() { return FALSE; } - this->is_cache_new = FALSE; + this->is_empty = FALSE; return TRUE; } -gboolean GstPylonCache::IsCacheNew() { return this->is_cache_new; } - -void GstPylonCache::SetCacheValue(const std::string& key, - const std::string& value) { - g_key_file_set_string(this->feature_cache_dict, - this->keyfile_groupname.c_str(), key.c_str(), - value.c_str()); -} +gboolean GstPylonCache::IsEmpty() { return this->is_empty; } void GstPylonCache::CreateCacheFile() { - GError* file_err = NULL; + GError *file_err = NULL; gboolean ret = g_key_file_save_to_file(this->feature_cache_dict, this->filepath.c_str(), &file_err); if (!ret) { @@ -128,3 +120,89 @@ void GstPylonCache::CreateCacheFile() { throw Pylon::GenericException(file_err_str.c_str(), __FILE__, __LINE__); } } + +void GstPylonCache::SetIntegerAttribute(const char *feature, + const char *attribute, + const gint64 val) { + g_key_file_set_int64(this->feature_cache_dict, feature, attribute, val); +} + +void GstPylonCache::SetDoubleAttribute(const char *feature, + const char *attribute, + const gdouble val) { + g_key_file_set_double(this->feature_cache_dict, feature, attribute, val); +} + +bool GstPylonCache::GetIntegerAttribute(const char *feature, + const char *attribute, gint64 &val) { + GError *err = NULL; + + gint64 value = + g_key_file_get_int64(this->feature_cache_dict, feature, attribute, &err); + if (err) { + GST_WARNING("Could not read values for feature %s from file %s: %s", + feature, this->filepath.c_str(), err->message); + g_error_free(err); + return false; + } + val = value; + return true; +} + +bool GstPylonCache::GetDoubleAttribute(const char *feature, + const char *attribute, gdouble &val) { + GError *err = NULL; + + gdouble value = + g_key_file_get_double(this->feature_cache_dict, feature, attribute, &err); + if (err) { + GST_WARNING("Could not read values for feature %s from file %s: %s", + feature, this->filepath.c_str(), err->message); + g_error_free(err); + return false; + } + val = value; + return true; +} + +void GstPylonCache::SetIntProps(const std::string &key, const gint64 min, + const gint64 max, const GParamFlags flags) { + const char *feature_name = key.c_str(); + SetIntegerAttribute(feature_name, "min", min); + SetIntegerAttribute(feature_name, "max", max); + SetIntegerAttribute(feature_name, "flags", static_cast(flags)); +} +void GstPylonCache::SetDoubleProps(const std::string &key, const gdouble min, + const gdouble max, const GParamFlags flags) { + const char *feature_name = key.c_str(); + SetDoubleAttribute(feature_name, "min", min); + SetDoubleAttribute(feature_name, "max", max); + SetIntegerAttribute(feature_name, "flags", static_cast(flags)); +} + +bool GstPylonCache::GetIntProps(const std::string &key, gint64 &min, + gint64 &max, GParamFlags &flags) { + const char *feature_name = key.c_str(); + if (!GetIntegerAttribute(feature_name, "min", min)) return false; + if (!GetIntegerAttribute(feature_name, "max", max)) return false; + gint64 flag_val = 0; + if (!GetIntegerAttribute(feature_name, "flags", flag_val)) return false; + + flags = static_cast(flag_val); + + return true; +} + +bool GstPylonCache::GetDoubleProps(const std::string &key, gdouble &min, + gdouble &max, GParamFlags &flags) { + const char *feature_name = key.c_str(); + if (!GetDoubleAttribute(feature_name, "min", min)) return false; + if (!GetDoubleAttribute(feature_name, "max", max)) return false; + + gint64 flag_val = 0; + if (!GetIntegerAttribute(feature_name, "flags", flag_val)) return false; + + flags = static_cast(flag_val); + + return true; +} diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index cfa457d..e6be222 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -40,57 +40,35 @@ #define MIN_VALUE_INDEX 0 #define MAX_VALUE_INDEX 1 #define FLAGS_VALUE_INDEX 2 -#define NUMERATOR_INDEX 0 -#define DENOMINATOR_INDEX 1 class GstPylonCache { public: GstPylonCache(const std::string &name); ~GstPylonCache(); gboolean IsCacheValid(); - gboolean IsCacheNew(); - void SetCacheValue(const std::string &key, const std::string &value); - void CreateCacheFile(); + gboolean IsEmpty(); - template - void GetKeyValues(std::string key, T &min, T &max, GParamFlags &flags); + void SetIntProps(const std::string &key, const gint64 min,const gint64 max,const GParamFlags flags); + void SetDoubleProps(const std::string &key, const gdouble min,const gdouble max,const GParamFlags flags); - private: - std::string filepath; - GKeyFile *feature_cache_dict; - std::string keyfile_groupname; - gboolean is_cache_new; -}; + bool GetIntProps(const std::string &key, gint64 &min,gint64 &max,GParamFlags &flags); + bool GetDoubleProps(const std::string &key, gdouble &min,gdouble &max,GParamFlags &flags); -template -void GstPylonCache::GetKeyValues(std::string key, T &min, T &max, - GParamFlags &flags) { - GError *err; + /* persist cache to filesystem */ + void CreateCacheFile(); - gchar *values_str = - g_key_file_get_string(this->feature_cache_dict, - this->keyfile_groupname.c_str(), key.c_str(), &err); - if (!values_str) { - GST_ERROR("Could not read values for feature %s from file %s: %s", - key.c_str(), this->filepath.c_str(), err->message); - g_error_free(err); - return; - } + private: + + void SetIntegerAttribute(const char *feature, const char* attribute, const gint64 val); + void SetDoubleAttribute(const char *feature, const char* attribute, gdouble val); - gchar **values_list = g_strsplit(values_str, " ", -1); - gchar **min_limit = g_strsplit(values_list[MIN_VALUE_INDEX], ".", -1); - gchar **max_limit = g_strsplit(values_list[MAX_VALUE_INDEX], ".", -1); + bool GetIntegerAttribute(const char *feature, const char* attribute, gint64 &val); + bool GetDoubleAttribute(const char *feature, const char* attribute, gdouble &val); - min = (std::stod(min_limit[NUMERATOR_INDEX]) / - std::stod(min_limit[DENOMINATOR_INDEX])); - max = (std::stod(max_limit[NUMERATOR_INDEX]) / - std::stod(max_limit[DENOMINATOR_INDEX])); - flags = static_cast(std::stoi(values_list[FLAGS_VALUE_INDEX])); - g_strfreev(min_limit); - g_strfreev(max_limit); - g_strfreev(values_list); - g_free(values_str); -} + std::string filepath; + GKeyFile *feature_cache_dict; + gboolean is_empty; +}; #endif diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index df2e1ce..06c80e2 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -131,13 +131,17 @@ template static std::string gst_pylon_build_cache_value_string( GParamFlags flags, T minimum_under_all_settings, T maximum_under_all_settings); -template -static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GstPylonCache &feature_cache, - GParamFlags &flags, - T &minimum_under_all_settings, - T &maximum_under_all_settings); + +static void gst_pylon_query_feature_properties_float( + GenApi::INodeMap &nodemap, GenApi::INode *node, + GstPylonCache &feature_cache, GParamFlags &flags, + gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings); + +static void gst_pylon_query_feature_properties_integer( + GenApi::INodeMap &nodemap, GenApi::INode *node, + GstPylonCache &feature_cache, GParamFlags &flags, + gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings); + static gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node); static GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, GenApi::INode *node); @@ -535,53 +539,43 @@ static void gst_pylon_find_limits(GenApi::INode *node, } } -template -static std::string gst_pylon_build_cache_value_string( - GParamFlags flags, T minimum_under_all_settings, - T maximum_under_all_settings) { - std::string limits_and_flags; - gint numerator = 0; - gint denominator = 0; - - /* Values are stored as nominator.denominator so that a cache file with double - * values can be read and be valid independent of locale */ - gst_util_double_to_fraction(minimum_under_all_settings, &numerator, - &denominator); - limits_and_flags += - std::to_string(numerator) + "." + std::to_string(denominator); - limits_and_flags += " "; - gst_util_double_to_fraction(maximum_under_all_settings, &numerator, - &denominator); - limits_and_flags += - std::to_string(numerator) + "." + std::to_string(denominator); - limits_and_flags += " "; - limits_and_flags += std::to_string(flags); - - return limits_and_flags; +void gst_pylon_query_feature_properties_float( + GenApi::INodeMap &nodemap, GenApi::INode *node, + GstPylonCache &feature_cache, GParamFlags &flags, + gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings) { + g_return_if_fail(node); + + /* if access to a feature cache entry fails, create new props dynamically */ + if (!feature_cache.GetDoubleProps(std::string(node->GetName()), + minimum_under_all_settings, + maximum_under_all_settings, flags)) { + flags = gst_pylon_query_access(nodemap, node); + gst_pylon_find_limits( + node, minimum_under_all_settings, maximum_under_all_settings); + + feature_cache.SetDoubleProps(std::string(node->GetName()), + minimum_under_all_settings, + maximum_under_all_settings, flags); + } } -template -static void gst_pylon_query_feature_properties(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GstPylonCache &feature_cache, - GParamFlags &flags, - T &minimum_under_all_settings, - T &maximum_under_all_settings) { +void gst_pylon_query_feature_properties_integer( + GenApi::INodeMap &nodemap, GenApi::INode *node, + GstPylonCache &feature_cache, GParamFlags &flags, + gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings) { g_return_if_fail(node); - if (feature_cache.IsCacheNew()) { + /* if access to a feature cache entry fails, create new props dynamically */ + if (!feature_cache.GetIntProps(std::string(node->GetName()), + minimum_under_all_settings, + maximum_under_all_settings, flags)) { flags = gst_pylon_query_access(nodemap, node); - gst_pylon_find_limits(node, minimum_under_all_settings, - maximum_under_all_settings); + gst_pylon_find_limits( + node, minimum_under_all_settings, maximum_under_all_settings); - std::string limits_and_flags = gst_pylon_build_cache_value_string( - flags, minimum_under_all_settings, maximum_under_all_settings); - - feature_cache.SetCacheValue(std::string(node->GetName()), limits_and_flags); - } else { - feature_cache.GetKeyValues(std::string(node->GetName()), - minimum_under_all_settings, - maximum_under_all_settings, flags); + feature_cache.SetIntProps(std::string(node->GetName()), + minimum_under_all_settings, + maximum_under_all_settings, flags); } } @@ -595,8 +589,8 @@ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, gint64 min_value = 0; GParamFlags flags = G_PARAM_READABLE; - gst_pylon_query_feature_properties( - nodemap, node, feature_cache, flags, min_value, max_value); + gst_pylon_query_feature_properties_integer(nodemap, node, feature_cache, + flags, min_value, max_value); return g_param_spec_int64(node->GetName(), node->GetDisplayName(), node->GetToolTip(), min_value, max_value, @@ -614,8 +608,8 @@ static GParamSpec *gst_pylon_make_spec_selector_int64( gint64 min_value = 0; GParamFlags flags = G_PARAM_READABLE; - gst_pylon_query_feature_properties( - nodemap, node, feature_cache, flags, min_value, max_value); + gst_pylon_query_feature_properties_integer(nodemap, node, feature_cache, + flags, min_value, max_value); return gst_pylon_param_spec_selector_int64( nodemap, node->GetName(), selector->GetName(), selector_value, @@ -659,8 +653,8 @@ static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, gdouble min_value = 0; GParamFlags flags = G_PARAM_READABLE; - gst_pylon_query_feature_properties( - nodemap, node, feature_cache, flags, min_value, max_value); + gst_pylon_query_feature_properties_float(nodemap, node, feature_cache, flags, + min_value, max_value); return g_param_spec_float(node->GetName(), node->GetDisplayName(), node->GetToolTip(), min_value, max_value, @@ -678,8 +672,8 @@ static GParamSpec *gst_pylon_make_spec_selector_float( gdouble min_value = 0; GParamFlags flags = G_PARAM_READABLE; - gst_pylon_query_feature_properties( - nodemap, node, feature_cache, flags, min_value, max_value); + gst_pylon_query_feature_properties_float(nodemap, node, feature_cache, flags, + min_value, max_value); return gst_pylon_param_spec_selector_float( nodemap, node->GetName(), selector->GetName(), selector_value, From 6e1db2a53ac4590856e16be82f91519a6fb7c8cd Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 11:32:25 +0100 Subject: [PATCH 031/126] use correct double datatype to represent genicam floatingpoint features --- gst-libs/gst/pylon/gstpylonparamspecs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.cpp b/gst-libs/gst/pylon/gstpylonparamspecs.cpp index 7456553..1d97a69 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.cpp +++ b/gst-libs/gst/pylon/gstpylonparamspecs.cpp @@ -156,7 +156,7 @@ GParamSpec *gst_pylon_param_spec_selector_float( nodemap, feature_name, selector_name, selector_value, flags); GParamSpec *spec = - g_param_spec_float(name, nick, blurb, min, max, def, flags); + g_param_spec_double(name, nick, blurb, min, max, def, flags); g_free(name); gst_pylon_param_spec_selector_epilog(spec, feature_name, selector_name, From d69fca88850e2e8636eb4065bc6c3c7130c233db Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 11:32:42 +0100 Subject: [PATCH 032/126] modernize: range-for --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 2d1d8fb..b44e52b 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -186,16 +186,15 @@ static std::vector gst_pylon_camera_handle_node( selector_node = NULL; } - for (guint i = 0; i < enum_values.size(); i++) { + for (auto& enum_value : enum_values) { if (NULL != selector_node) { switch (selector_node->GetPrincipalInterfaceType()) { case GenApi::intfIEnumeration: param.Attach(selector_node); - selector_value = - param.GetEntryByName(enum_values[i].c_str())->GetValue(); + selector_value = param.GetEntryByName(enum_value.c_str())->GetValue(); break; case GenApi::intfIInteger: - selector_value = std::stoi(enum_values[i]); + selector_value = std::stoi(enum_value); break; default:; /* do nothing */ } @@ -260,7 +259,9 @@ void GstPylonFeatureWalker::install_properties( try { std::vector specs_list = gst_pylon_camera_handle_node( node, nodemap, device_fullname, feature_cache); + gst_pylon_camera_install_specs(specs_list, oclass, nprop); + } catch (const Pylon::GenericException& e) { GST_FIXME("Unable to install property \"%s\" on device \"%s\": %s", node->GetDisplayName().c_str(), device_fullname.c_str(), From 1294c15de3bffac7440c5ca7f988398a940f937a Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 13:13:38 +0100 Subject: [PATCH 033/126] restructure set pylon feature --- gst-libs/gst/pylon/gstpylonobject.cpp | 131 ++++++++++++-------------- 1 file changed, 61 insertions(+), 70 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 3634675..5cf4195 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -119,36 +119,41 @@ static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, const std::string& device_name, GstPylonCache& feature_cache); + +/* set a pylon feature from a gstreamer gst property */ template -static void gst_pylon_object_set_pylon_property(GenApi::INodeMap& nodemap, - F get_value, - const GValue* value, - const gchar* name); -static void gst_pylon_object_set_enum_property(GenApi::INodeMap& nodemap, - const GValue* value, +static void gst_pylon_object_set_pylon_feature(GenApi::INodeMap& nodemap, + F get_value, const GValue* value, const gchar* name); -static void gst_pylon_object_classify_selector(GenApi::INodeMap& nodemap, - const gchar* selector_name, - guint64& selector_value); + +static void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, + const gchar* selector_name, + guint64& selector_value); + template -static void gst_pylon_object_set_pylon_selector( +static void gst_pylon_object_set_pylon_selected_feature( GenApi::INodeMap& nodemap, F get_value, const GValue* value, const gchar* feature, const gchar* selector, guint64& selector_value); -static void gst_pylon_object_set_enum_selector(GenApi::INodeMap& nodemap, - const GValue* value, - const gchar* feature_name, - const gchar* selector_name, - guint64& selector_value); + template static T gst_pylon_object_get_pylon_property(GenApi::INodeMap& nodemap, const gchar* name); + static gint gst_pylon_object_get_enum_property(GenApi::INodeMap& nodemap, const gchar* name); + template -static void gst_pylon_object_classify_feature( +static void gst_pylon_object_feature_set_value( GParamSpec* pspec, GstPylonObjectPrivate* priv, GstPylonParamSpecSelectorData* selector_data, F get_value, const GValue* value); + +template +static void gst_pylon_object_feature_get_value( + GParamSpec* pspec, GstPylonObjectPrivate* priv, + GstPylonParamSpecSelectorData* selector_data, F get_value, + const GValue* value); + static void gst_pylon_object_set_property(GObject* object, guint property_id, const GValue* value, GParamSpec* pspec); @@ -156,6 +161,15 @@ static void gst_pylon_object_get_property(GObject* object, guint property_id, GValue* value, GParamSpec* pspec); static void gst_pylon_object_finalize(GObject* self); +/* gst value get fptr */ +typedef gint64 (*GGetInt64)(const GValue*); +typedef gboolean (*GGetBool)(const GValue*); +typedef gfloat (*GGetFloat)(const GValue*); +typedef const gchar* (*GGetString)(const GValue*); +typedef gint (*GGetEnum)(const GValue*); + +/* implementations */ + static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, const std::string& device_name, @@ -185,25 +199,25 @@ static void gst_pylon_object_class_init( static void gst_pylon_object_init(GstPylonObject* self) {} -template -static void gst_pylon_object_set_pylon_property(GenApi::INodeMap& nodemap, - F get_value, - const GValue* value, - const gchar* name) { +template +static void gst_pylon_object_set_pylon_feature(GenApi::INodeMap& nodemap, + F get_value, const GValue* value, + const gchar* name) { P param(nodemap, name); param.SetValue(get_value(value)); } -static void gst_pylon_object_set_enum_property(GenApi::INodeMap& nodemap, - const GValue* value, - const gchar* name) { +template <> +void gst_pylon_object_set_pylon_feature( + GenApi::INodeMap& nodemap, GGetEnum get_value, const GValue* value, + const gchar* name) { Pylon::CEnumParameter param(nodemap, name); - param.SetIntValue(g_value_get_enum(value)); + param.SetIntValue(get_value(value)); } -static void gst_pylon_object_classify_selector(GenApi::INodeMap& nodemap, - const gchar* selector_name, - guint64& selector_value) { +static void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, + const gchar* selector_name, + guint64& selector_value) { gint selector_type = nodemap.GetNode(selector_name)->GetPrincipalInterfaceType(); switch (selector_type) { @@ -223,26 +237,14 @@ static void gst_pylon_object_classify_selector(GenApi::INodeMap& nodemap, } template -static void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, - F get_value, - const GValue* value, - const gchar* feature_name, - const gchar* selector_name, - guint64& selector_value) { - gst_pylon_object_classify_selector(nodemap, selector_name, selector_value); - - gst_pylon_object_set_pylon_property(nodemap, get_value, value, - feature_name); -} - -static void gst_pylon_object_set_enum_selector(GenApi::INodeMap& nodemap, - const GValue* value, - const gchar* feature_name, - const gchar* selector_name, - guint64& selector_value) { - gst_pylon_object_classify_selector(nodemap, selector_name, selector_value); +static void gst_pylon_object_set_pylon_selected_feature( + GenApi::INodeMap& nodemap, F get_value, const GValue* value, + const gchar* feature_name, const gchar* selector_name, + guint64& selector_value) { + gst_pylon_object_set_pylon_selector(nodemap, selector_name, selector_value); - gst_pylon_object_set_enum_property(nodemap, value, feature_name); + gst_pylon_object_set_pylon_feature(nodemap, get_value, value, + feature_name); } template @@ -259,20 +261,18 @@ static gint gst_pylon_object_get_enum_property(GenApi::INodeMap& nodemap, } template -static void gst_pylon_object_classify_feature( +static void gst_pylon_object_feature_set_value( GParamSpec* pspec, GstPylonObjectPrivate* priv, GstPylonParamSpecSelectorData* selector_data, F get_value, const GValue* value) { /* The value accepted by the pspec can be a direct feature or a feature that * has a selector. */ if (GST_PYLON_PARAM_FLAG_IS_SET(pspec, GST_PYLON_PARAM_IS_SELECTOR)) { - gst_pylon_object_set_pylon_selector( - *priv->nodemap, get_value, value, selector_data->feature, - selector_data->selector, selector_data->selector_value); - } else { - gst_pylon_object_set_pylon_property(*priv->nodemap, get_value, value, - pspec->name); + gst_pylon_object_set_pylon_selector(*priv->nodemap, selector_data->selector, + selector_data->selector_value); } + gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, + pspec->name); } static void gst_pylon_object_set_property(GObject* object, guint property_id, @@ -291,35 +291,26 @@ static void gst_pylon_object_set_property(GObject* object, guint property_id, try { switch (value_type) { case G_TYPE_INT64: - typedef gint64 (*GGetInt64)(const GValue*); - gst_pylon_object_classify_feature( + gst_pylon_object_feature_set_value( pspec, priv, selector_data, g_value_get_int64, value); break; case G_TYPE_BOOLEAN: - typedef gboolean (*GGetBool)(const GValue*); - gst_pylon_object_classify_feature( + gst_pylon_object_feature_set_value( pspec, priv, selector_data, g_value_get_boolean, value); break; case G_TYPE_FLOAT: - typedef gfloat (*GGetFloat)(const GValue*); - gst_pylon_object_classify_feature( + gst_pylon_object_feature_set_value( pspec, priv, selector_data, g_value_get_float, value); break; case G_TYPE_STRING: - typedef const gchar* (*GGetString)(const GValue*); - gst_pylon_object_classify_feature( + gst_pylon_object_feature_set_value( pspec, priv, selector_data, g_value_get_string, value); break; case G_TYPE_ENUM: - if (GST_PYLON_PARAM_FLAG_IS_SET(pspec, GST_PYLON_PARAM_IS_SELECTOR)) { - gst_pylon_object_set_enum_selector( - *priv->nodemap, value, selector_data->feature, - selector_data->selector, selector_data->selector_value); - } else { - gst_pylon_object_set_enum_property(*priv->nodemap, value, - pspec->name); - } + gst_pylon_object_feature_set_value( + pspec, priv, selector_data, g_value_get_enum, value); break; + default: g_warning("Unsupported GType: %s", g_type_name(pspec->value_type)); std::string msg = From ae3f8cdb004c0a686b6b6e3631c7ed37f051d326 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 13:45:03 +0100 Subject: [PATCH 034/126] selector is gint64 --- gst-libs/gst/pylon/gstpylonobject.cpp | 4 ++-- gst-libs/gst/pylon/gstpylonparamspecs.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 5cf4195..e37a98c 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -128,7 +128,7 @@ static void gst_pylon_object_set_pylon_feature(GenApi::INodeMap& nodemap, static void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, const gchar* selector_name, - guint64& selector_value); + gint64& selector_value); template static void gst_pylon_object_set_pylon_selected_feature( @@ -217,7 +217,7 @@ void gst_pylon_object_set_pylon_feature( static void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, const gchar* selector_name, - guint64& selector_value) { + gint64& selector_value) { gint selector_type = nodemap.GetNode(selector_name)->GetPrincipalInterfaceType(); switch (selector_type) { diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.h b/gst-libs/gst/pylon/gstpylonparamspecs.h index 8de0494..e9dd79f 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.h +++ b/gst-libs/gst/pylon/gstpylonparamspecs.h @@ -75,7 +75,7 @@ typedef struct _GstPylonParamSpecSelectorData GstPylonParamSpecSelectorData; struct _GstPylonParamSpecSelectorData { gchar* feature; gchar* selector; - guint64 selector_value; + gint64 selector_value; }; /* --- GParamSpec prototypes --- */ From 3fc79a93d32eba63add5053f5297da912e36e52f Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 13:48:50 +0100 Subject: [PATCH 035/126] refactor to make get/set symmetric --- gst-libs/gst/pylon/gstpylonobject.cpp | 99 +++++++++++++++++---------- 1 file changed, 62 insertions(+), 37 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index e37a98c..6f33b52 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -139,9 +139,6 @@ template static T gst_pylon_object_get_pylon_property(GenApi::INodeMap& nodemap, const gchar* name); -static gint gst_pylon_object_get_enum_property(GenApi::INodeMap& nodemap, - const gchar* name); - template static void gst_pylon_object_feature_set_value( GParamSpec* pspec, GstPylonObjectPrivate* priv, @@ -168,6 +165,13 @@ typedef gfloat (*GGetFloat)(const GValue*); typedef const gchar* (*GGetString)(const GValue*); typedef gint (*GGetEnum)(const GValue*); +/* gst value set fptr */ +typedef void (*GSetInt64)(GValue*, gint64); +typedef void (*GSetBool)(GValue*, gboolean); +typedef void (*GSetFloat)(GValue*, gfloat); +typedef void (*GSetString)(GValue*, const gchar*); +typedef void (*GSetEnum)(GValue*, gint); + /* implementations */ static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, @@ -199,6 +203,7 @@ static void gst_pylon_object_class_init( static void gst_pylon_object_init(GstPylonObject* self) {} +/* set pylon feature from gst property */ template static void gst_pylon_object_set_pylon_feature(GenApi::INodeMap& nodemap, F get_value, const GValue* value, @@ -215,6 +220,31 @@ void gst_pylon_object_set_pylon_feature( param.SetIntValue(get_value(value)); } +/* get gst property from pylon feature */ +template +static void gst_pylon_object_get_pylon_feature(GenApi::INodeMap& nodemap, + F set_value, GValue* value, + const gchar* name) { + P param(nodemap, name); + set_value(value, param.GetValue()); +} + +template <> +void gst_pylon_object_get_pylon_feature( + GenApi::INodeMap& nodemap, GSetEnum set_value, GValue* value, + const gchar* name) { + Pylon::CEnumParameter param(nodemap, name); + set_value(value, param.GetIntValue()); +} + +template <> +void gst_pylon_object_get_pylon_feature( + GenApi::INodeMap& nodemap, GSetString set_value, GValue* value, + const gchar* name) { + Pylon::CStringParameter param(nodemap, name); + set_value(value, param.GetValue().c_str()); +} + static void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, const gchar* selector_name, gint64& selector_value) { @@ -236,17 +266,6 @@ static void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, } } -template -static void gst_pylon_object_set_pylon_selected_feature( - GenApi::INodeMap& nodemap, F get_value, const GValue* value, - const gchar* feature_name, const gchar* selector_name, - guint64& selector_value) { - gst_pylon_object_set_pylon_selector(nodemap, selector_name, selector_value); - - gst_pylon_object_set_pylon_feature(nodemap, get_value, value, - feature_name); -} - template static T gst_pylon_object_get_pylon_property(GenApi::INodeMap& nodemap, const gchar* name) { @@ -254,12 +273,6 @@ static T gst_pylon_object_get_pylon_property(GenApi::INodeMap& nodemap, return param.GetValue(); } -static gint gst_pylon_object_get_enum_property(GenApi::INodeMap& nodemap, - const gchar* name) { - Pylon::CEnumParameter param(nodemap, name); - return param.GetIntValue(); -} - template static void gst_pylon_object_feature_set_value( GParamSpec* pspec, GstPylonObjectPrivate* priv, @@ -275,6 +288,20 @@ static void gst_pylon_object_feature_set_value( pspec->name); } +template +static void gst_pylon_object_feature_get_value( + GParamSpec* pspec, GstPylonObjectPrivate* priv, + GstPylonParamSpecSelectorData* selector_data, F set_value, GValue* value) { + /* The value accepted by the pspec can be a direct feature or a feature that + * has a selector. */ + if (GST_PYLON_PARAM_FLAG_IS_SET(pspec, GST_PYLON_PARAM_IS_SELECTOR)) { + gst_pylon_object_set_pylon_selector(*priv->nodemap, selector_data->selector, + selector_data->selector_value); + } + gst_pylon_object_get_pylon_feature(*priv->nodemap, set_value, value, + pspec->name); +} + static void gst_pylon_object_set_property(GObject* object, guint property_id, const GValue* value, GParamSpec* pspec) { @@ -329,35 +356,33 @@ static void gst_pylon_object_get_property(GObject* object, guint property_id, GstPylonObject* self = (GstPylonObject*)object; GstPylonObjectPrivate* priv = (GstPylonObjectPrivate*)gst_pylon_object_get_instance_private(self); + GstPylonParamSpecSelectorData* selector_data = NULL; + + if (GST_PYLON_PARAM_FLAG_IS_SET(pspec, GST_PYLON_PARAM_IS_SELECTOR)) { + selector_data = gst_pylon_param_spec_selector_get_data(pspec); + } try { switch (g_type_fundamental(pspec->value_type)) { case G_TYPE_INT64: - g_value_set_int64(value, gst_pylon_object_get_pylon_property< - gint64, Pylon::CIntegerParameter>( - *priv->nodemap, pspec->name)); + gst_pylon_object_feature_get_value( + pspec, priv, selector_data, g_value_set_int64, value); break; case G_TYPE_BOOLEAN: - g_value_set_boolean(value, gst_pylon_object_get_pylon_property< - gboolean, Pylon::CBooleanParameter>( - *priv->nodemap, pspec->name)); + gst_pylon_object_feature_get_value( + pspec, priv, selector_data, g_value_set_boolean, value); break; case G_TYPE_FLOAT: - g_value_set_float( - value, - gst_pylon_object_get_pylon_property( - *priv->nodemap, pspec->name)); + gst_pylon_object_feature_get_value( + pspec, priv, selector_data, g_value_set_float, value); break; case G_TYPE_STRING: - g_value_set_string( - value, gst_pylon_object_get_pylon_property( - *priv->nodemap, pspec->name) - .c_str()); + gst_pylon_object_feature_get_value( + pspec, priv, selector_data, g_value_set_string, value); break; case G_TYPE_ENUM: - g_value_set_enum(value, gst_pylon_object_get_enum_property( - *priv->nodemap, pspec->name)); + gst_pylon_object_feature_get_value( + pspec, priv, selector_data, g_value_set_enum, value); break; default: g_warning("Unsupported GType: %s", g_type_name(pspec->value_type)); From a4f2a3be6e7e755da55a9da29fb1d4e7ed1464d1 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 14:49:04 +0100 Subject: [PATCH 036/126] pylon floats are double --- ext/pylon/gstchildinspector.cpp | 22 +++++------ gst-libs/gst/pylon/gstpylonintrospection.cpp | 40 ++++++++++---------- gst-libs/gst/pylon/gstpylonobject.cpp | 16 ++++---- gst-libs/gst/pylon/gstpylonparamspecs.cpp | 2 +- gst-libs/gst/pylon/gstpylonparamspecs.h | 2 +- tests/examples/pylon/list_properties.c | 12 +++--- tests/examples/pylon/show_meta.c | 6 +-- 7 files changed, 50 insertions(+), 50 deletions(-) diff --git a/ext/pylon/gstchildinspector.cpp b/ext/pylon/gstchildinspector.cpp index c91f3b4..6dfd2fb 100644 --- a/ext/pylon/gstchildinspector.cpp +++ b/ext/pylon/gstchildinspector.cpp @@ -53,9 +53,9 @@ static gchar *gst_child_inspector_type_int64_to_string(GParamSpec *pspec, static gchar *gst_child_inspector_type_bool_to_string(GParamSpec *pspec, GValue *value, gint alignment); -static gchar *gst_child_inspector_type_float_to_string(GParamSpec *pspec, - GValue *value, - gint alignment); +static gchar *gst_child_inspector_type_double_to_string(GParamSpec *pspec, + GValue *value, + gint alignment); static gchar *gst_child_inspector_type_string_to_string(GParamSpec *pspec, GValue *value, gint alignment); @@ -84,7 +84,7 @@ static GstChildInspectorFlag flags[] = { static GstChildInspectorType types[] = { {G_TYPE_INT64, gst_child_inspector_type_int64_to_string}, {G_TYPE_BOOLEAN, gst_child_inspector_type_bool_to_string}, - {G_TYPE_FLOAT, gst_child_inspector_type_float_to_string}, + {G_TYPE_DOUBLE, gst_child_inspector_type_double_to_string}, {G_TYPE_STRING, gst_child_inspector_type_string_to_string}, {G_TYPE_ENUM, gst_child_inspector_type_enum_to_string}, {0, NULL}}; @@ -140,17 +140,17 @@ static gchar *gst_child_inspector_type_int64_to_string(GParamSpec *pspec, g_value_get_int64(value)); } -static gchar *gst_child_inspector_type_float_to_string(GParamSpec *pspec, - GValue *value, - gint alignment) { +static gchar *gst_child_inspector_type_double_to_string(GParamSpec *pspec, + GValue *value, + gint alignment) { g_return_val_if_fail(pspec, NULL); g_return_val_if_fail(value, NULL); - GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT(pspec); + GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE(pspec); - return g_strdup_printf("Float. Range: %.2f - %.2f Default: %.2f", - pfloat->minimum, pfloat->maximum, - g_value_get_float(value)); + return g_strdup_printf("Double. Range: %.2f - %.2f Default: %.2f", + pdouble->minimum, pdouble->maximum, + g_value_get_double(value)); } static gchar *gst_child_inspector_type_bool_to_string(GParamSpec *pspec, diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 06c80e2..55fdd2f 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -79,10 +79,10 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value); -static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GstPylonCache &feature_cache); -static GParamSpec *gst_pylon_make_spec_selector_float( +static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, + GenApi::INode *node, + GstPylonCache &feature_cache); +static GParamSpec *gst_pylon_make_spec_selector_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, GstPylonCache &feature_cache); static GParamSpec *gst_pylon_make_spec_str(GenApi::INodeMap &nodemap, @@ -132,7 +132,7 @@ static std::string gst_pylon_build_cache_value_string( GParamFlags flags, T minimum_under_all_settings, T maximum_under_all_settings); -static void gst_pylon_query_feature_properties_float( +static void gst_pylon_query_feature_properties_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GstPylonCache &feature_cache, GParamFlags &flags, gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings); @@ -539,7 +539,7 @@ static void gst_pylon_find_limits(GenApi::INode *node, } } -void gst_pylon_query_feature_properties_float( +void gst_pylon_query_feature_properties_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GstPylonCache &feature_cache, GParamFlags &flags, gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings) { @@ -643,9 +643,9 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, gst_pylon_query_access(nodemap, node)); } -static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GstPylonCache &feature_cache) { +static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, + GenApi::INode *node, + GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); Pylon::CFloatParameter param(node); @@ -653,15 +653,15 @@ static GParamSpec *gst_pylon_make_spec_float(GenApi::INodeMap &nodemap, gdouble min_value = 0; GParamFlags flags = G_PARAM_READABLE; - gst_pylon_query_feature_properties_float(nodemap, node, feature_cache, flags, - min_value, max_value); + gst_pylon_query_feature_properties_double(nodemap, node, feature_cache, flags, + min_value, max_value); - return g_param_spec_float(node->GetName(), node->GetDisplayName(), - node->GetToolTip(), min_value, max_value, - param.GetValue(), flags); + return g_param_spec_double(node->GetName(), node->GetDisplayName(), + node->GetToolTip(), min_value, max_value, + param.GetValue(), flags); } -static GParamSpec *gst_pylon_make_spec_selector_float( +static GParamSpec *gst_pylon_make_spec_selector_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); @@ -672,10 +672,10 @@ static GParamSpec *gst_pylon_make_spec_selector_float( gdouble min_value = 0; GParamFlags flags = G_PARAM_READABLE; - gst_pylon_query_feature_properties_float(nodemap, node, feature_cache, flags, - min_value, max_value); + gst_pylon_query_feature_properties_double(nodemap, node, feature_cache, flags, + min_value, max_value); - return gst_pylon_param_spec_selector_float( + return gst_pylon_param_spec_selector_double( nodemap, node->GetName(), selector->GetName(), selector_value, node->GetDisplayName(), node->GetToolTip(), min_value, max_value, param.GetValue(), flags); @@ -814,9 +814,9 @@ GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, break; case GenApi::intfIFloat: if (!selector) { - spec = gst_pylon_make_spec_float(nodemap, node, feature_cache); + spec = gst_pylon_make_spec_double(nodemap, node, feature_cache); } else { - spec = gst_pylon_make_spec_selector_float( + spec = gst_pylon_make_spec_selector_double( nodemap, node, selector, selector_value, feature_cache); } break; diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 6f33b52..25c5872 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -161,14 +161,14 @@ static void gst_pylon_object_finalize(GObject* self); /* gst value get fptr */ typedef gint64 (*GGetInt64)(const GValue*); typedef gboolean (*GGetBool)(const GValue*); -typedef gfloat (*GGetFloat)(const GValue*); +typedef gdouble (*GGetDouble)(const GValue*); typedef const gchar* (*GGetString)(const GValue*); typedef gint (*GGetEnum)(const GValue*); /* gst value set fptr */ typedef void (*GSetInt64)(GValue*, gint64); typedef void (*GSetBool)(GValue*, gboolean); -typedef void (*GSetFloat)(GValue*, gfloat); +typedef void (*GSetDouble)(GValue*, gdouble); typedef void (*GSetString)(GValue*, const gchar*); typedef void (*GSetEnum)(GValue*, gint); @@ -325,9 +325,9 @@ static void gst_pylon_object_set_property(GObject* object, guint property_id, gst_pylon_object_feature_set_value( pspec, priv, selector_data, g_value_get_boolean, value); break; - case G_TYPE_FLOAT: - gst_pylon_object_feature_set_value( - pspec, priv, selector_data, g_value_get_float, value); + case G_TYPE_DOUBLE: + gst_pylon_object_feature_set_value( + pspec, priv, selector_data, g_value_get_double, value); break; case G_TYPE_STRING: gst_pylon_object_feature_set_value( @@ -372,9 +372,9 @@ static void gst_pylon_object_get_property(GObject* object, guint property_id, gst_pylon_object_feature_get_value( pspec, priv, selector_data, g_value_set_boolean, value); break; - case G_TYPE_FLOAT: - gst_pylon_object_feature_get_value( - pspec, priv, selector_data, g_value_set_float, value); + case G_TYPE_DOUBLE: + gst_pylon_object_feature_get_value( + pspec, priv, selector_data, g_value_set_double, value); break; case G_TYPE_STRING: gst_pylon_object_feature_get_value( diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.cpp b/gst-libs/gst/pylon/gstpylonparamspecs.cpp index 1d97a69..d1ab3d6 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.cpp +++ b/gst-libs/gst/pylon/gstpylonparamspecs.cpp @@ -145,7 +145,7 @@ GParamSpec *gst_pylon_param_spec_selector_boolean( return spec; } -GParamSpec *gst_pylon_param_spec_selector_float( +GParamSpec *gst_pylon_param_spec_selector_double( GenApi::INodeMap &nodemap, const gchar *feature_name, const gchar *selector_name, guint64 selector_value, const gchar *nick, const gchar *blurb, gdouble min, gdouble max, gdouble def, diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.h b/gst-libs/gst/pylon/gstpylonparamspecs.h index e9dd79f..f280a89 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.h +++ b/gst-libs/gst/pylon/gstpylonparamspecs.h @@ -89,7 +89,7 @@ GParamSpec* gst_pylon_param_spec_selector_boolean( GenApi::INodeMap& nodemap, const gchar* selector_name, const gchar* feature_name, guint64 selector_value, const gchar* nick, const gchar* blurb, gboolean def, GParamFlags flags) G_GNUC_MALLOC; -GParamSpec* gst_pylon_param_spec_selector_float( +GParamSpec* gst_pylon_param_spec_selector_double( GenApi::INodeMap& nodemap, const gchar* feature_name, const gchar* selector_name, guint64 selector_value, const gchar* nick, const gchar* blurb, gdouble min, gdouble max, gdouble def, diff --git a/tests/examples/pylon/list_properties.c b/tests/examples/pylon/list_properties.c index 7ee2ab4..ffd66f0 100644 --- a/tests/examples/pylon/list_properties.c +++ b/tests/examples/pylon/list_properties.c @@ -89,12 +89,12 @@ int64_to_string (GParamSpec * spec) } static gchar * -float_to_string (GParamSpec * spec) +double_to_string (GParamSpec * spec) { - GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (spec); + GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (spec); - return g_strdup_printf ("Float. Range: %.2f - %.2f Default: %.2f", - pfloat->minimum, pfloat->maximum, pfloat->default_value); + return g_strdup_printf ("Double. Range: %.2f - %.2f Default: %.2f", + pdouble->minimum, pdouble->maximum, pdouble->default_value); } static gchar * @@ -146,8 +146,8 @@ property_to_string (GParamSpec * spec) case G_TYPE_STRING: details = string_to_string (spec); break; - case G_TYPE_FLOAT: - details = float_to_string (spec); + case G_TYPE_DOUBLE: + details = double_to_string (spec); break; case G_TYPE_ENUM: details = enum_to_string (spec); diff --git a/tests/examples/pylon/show_meta.c b/tests/examples/pylon/show_meta.c index 7363404..0b4af69 100644 --- a/tests/examples/pylon/show_meta.c +++ b/tests/examples/pylon/show_meta.c @@ -178,7 +178,7 @@ cb_have_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) gchar *meta_str = NULL; gchar *tmp_str = NULL; gint64 int_chunk; - gdouble float_chunk; + gdouble double_chunk; g_return_val_if_fail (ctx, GST_PAD_PROBE_DROP); @@ -205,9 +205,9 @@ cb_have_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) meta_str = tmp_str; break; case G_TYPE_DOUBLE: - gst_structure_get_double (meta->chunks, chunk_name, &float_chunk); + gst_structure_get_double (meta->chunks, chunk_name, &double_chunk); tmp_str = - g_strdup_printf ("%s%s_%.2f ", meta_str, chunk_name, float_chunk); + g_strdup_printf ("%s%s_%.2f ", meta_str, chunk_name, double_chunk); g_free (meta_str); meta_str = tmp_str; break; From 9b769a57330ac4c59b7b1f8c5141927931708d8a Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 14:49:58 +0100 Subject: [PATCH 037/126] fix access selected features --- gst-libs/gst/pylon/gstpylonobject.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 25c5872..9a1db91 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -280,12 +280,20 @@ static void gst_pylon_object_feature_set_value( const GValue* value) { /* The value accepted by the pspec can be a direct feature or a feature that * has a selector. */ + if (GST_PYLON_PARAM_FLAG_IS_SET(pspec, GST_PYLON_PARAM_IS_SELECTOR)) { gst_pylon_object_set_pylon_selector(*priv->nodemap, selector_data->selector, selector_data->selector_value); + /* strip off selector */ + gchar** featurename_split_list = NULL; + featurename_split_list = g_strsplit(pspec->name, "-", -1); + gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, + featurename_split_list[0]); + g_strfreev(featurename_split_list); + } else { + gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, + pspec->name); } - gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, - pspec->name); } template @@ -297,9 +305,16 @@ static void gst_pylon_object_feature_get_value( if (GST_PYLON_PARAM_FLAG_IS_SET(pspec, GST_PYLON_PARAM_IS_SELECTOR)) { gst_pylon_object_set_pylon_selector(*priv->nodemap, selector_data->selector, selector_data->selector_value); + /* strip off selector */ + gchar** featurename_split_list = NULL; + featurename_split_list = g_strsplit(pspec->name, "-", -1); + gst_pylon_object_get_pylon_feature(*priv->nodemap, set_value, value, + featurename_split_list[0]); + g_strfreev(featurename_split_list); + } else { + gst_pylon_object_get_pylon_feature(*priv->nodemap, set_value, value, + pspec->name); } - gst_pylon_object_get_pylon_feature(*priv->nodemap, set_value, value, - pspec->name); } static void gst_pylon_object_set_property(GObject* object, guint property_id, From 00bb21eff95ec60b73b3104c46290a121ab003aa Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 17:45:05 +0100 Subject: [PATCH 038/126] use gchar for feature names --- gst-libs/gst/pylon/gstpyloncache.cpp | 12 ++++-------- gst-libs/gst/pylon/gstpyloncache.h | 14 +++++++------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index b8e0dc0..d5f25dc 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -165,24 +165,21 @@ bool GstPylonCache::GetDoubleAttribute(const char *feature, return true; } -void GstPylonCache::SetIntProps(const std::string &key, const gint64 min, +void GstPylonCache::SetIntProps(const gchar *feature_name, const gint64 min, const gint64 max, const GParamFlags flags) { - const char *feature_name = key.c_str(); SetIntegerAttribute(feature_name, "min", min); SetIntegerAttribute(feature_name, "max", max); SetIntegerAttribute(feature_name, "flags", static_cast(flags)); } -void GstPylonCache::SetDoubleProps(const std::string &key, const gdouble min, +void GstPylonCache::SetDoubleProps(const gchar *feature_name, const gdouble min, const gdouble max, const GParamFlags flags) { - const char *feature_name = key.c_str(); SetDoubleAttribute(feature_name, "min", min); SetDoubleAttribute(feature_name, "max", max); SetIntegerAttribute(feature_name, "flags", static_cast(flags)); } -bool GstPylonCache::GetIntProps(const std::string &key, gint64 &min, +bool GstPylonCache::GetIntProps(const gchar *feature_name, gint64 &min, gint64 &max, GParamFlags &flags) { - const char *feature_name = key.c_str(); if (!GetIntegerAttribute(feature_name, "min", min)) return false; if (!GetIntegerAttribute(feature_name, "max", max)) return false; gint64 flag_val = 0; @@ -193,9 +190,8 @@ bool GstPylonCache::GetIntProps(const std::string &key, gint64 &min, return true; } -bool GstPylonCache::GetDoubleProps(const std::string &key, gdouble &min, +bool GstPylonCache::GetDoubleProps(const char *feature_name, gdouble &min, gdouble &max, GParamFlags &flags) { - const char *feature_name = key.c_str(); if (!GetDoubleAttribute(feature_name, "min", min)) return false; if (!GetDoubleAttribute(feature_name, "max", max)) return false; diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index e6be222..5644bc8 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -37,9 +37,7 @@ #include -#define MIN_VALUE_INDEX 0 -#define MAX_VALUE_INDEX 1 -#define FLAGS_VALUE_INDEX 2 +G_BEGIN_DECLS class GstPylonCache { public: @@ -48,11 +46,11 @@ class GstPylonCache { gboolean IsCacheValid(); gboolean IsEmpty(); - void SetIntProps(const std::string &key, const gint64 min,const gint64 max,const GParamFlags flags); - void SetDoubleProps(const std::string &key, const gdouble min,const gdouble max,const GParamFlags flags); + void SetIntProps(const gchar *feature_name, const gint64 min,const gint64 max,const GParamFlags flags); + void SetDoubleProps(const gchar *feature_name, const gdouble min,const gdouble max,const GParamFlags flags); - bool GetIntProps(const std::string &key, gint64 &min,gint64 &max,GParamFlags &flags); - bool GetDoubleProps(const std::string &key, gdouble &min,gdouble &max,GParamFlags &flags); + bool GetIntProps(const gchar *feature_name, gint64 &min,gint64 &max,GParamFlags &flags); + bool GetDoubleProps(const gchar *feature_name, gdouble &min,gdouble &max,GParamFlags &flags); /* persist cache to filesystem */ void CreateCacheFile(); @@ -71,4 +69,6 @@ class GstPylonCache { gboolean is_empty; }; +G_END_DECLS + #endif From 67479e456511087e5e0c6715ecc4127650d8a40e Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 17:55:59 +0100 Subject: [PATCH 039/126] store selected features into cache --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 53 ++++++++++++++++---- gst-libs/gst/pylon/gstpylonobject.cpp | 10 ++-- gst-libs/gst/pylon/gstpylonobject.h | 4 ++ gst-libs/gst/pylon/gstpylonparamspecs.cpp | 23 +++++++-- gst-libs/gst/pylon/gstpylonparamspecs.h | 5 ++ 5 files changed, 74 insertions(+), 21 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 55fdd2f..91a8bd0 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -36,6 +36,7 @@ #include "gstpylondebug.h" #include "gstpylonintrospection.h" +#include "gstpylonobject.h" #include "gstpylonparamspecs.h" #include @@ -135,12 +136,14 @@ static std::string gst_pylon_build_cache_value_string( static void gst_pylon_query_feature_properties_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GstPylonCache &feature_cache, GParamFlags &flags, - gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings); + gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings, + GenApi::INode *selector = NULL, gint64 selector_value = 0); static void gst_pylon_query_feature_properties_integer( GenApi::INodeMap &nodemap, GenApi::INode *node, GstPylonCache &feature_cache, GParamFlags &flags, - gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings); + gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings, + GenApi::INode *selector = NULL, gint64 selector_value = 0); static gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node); static GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, @@ -542,41 +545,73 @@ static void gst_pylon_find_limits(GenApi::INode *node, void gst_pylon_query_feature_properties_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GstPylonCache &feature_cache, GParamFlags &flags, - gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings) { + gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings, + GenApi::INode *selector, gint64 selector_value) { g_return_if_fail(node); + gchar *feature_cache_name = NULL; + if (selector) { + /* set selector value value */ + gst_pylon_object_set_pylon_selector(nodemap, selector->GetName().c_str(), + selector_value); + + feature_cache_name = gst_pylon_create_selected_name( + nodemap, node->GetName().c_str(), selector->GetName().c_str(), + selector_value); + } else { + feature_cache_name = g_strdup(node->GetName().c_str()); + } + /* if access to a feature cache entry fails, create new props dynamically */ - if (!feature_cache.GetDoubleProps(std::string(node->GetName()), + if (!feature_cache.GetDoubleProps(feature_cache_name, minimum_under_all_settings, maximum_under_all_settings, flags)) { flags = gst_pylon_query_access(nodemap, node); gst_pylon_find_limits( node, minimum_under_all_settings, maximum_under_all_settings); - feature_cache.SetDoubleProps(std::string(node->GetName()), - minimum_under_all_settings, + feature_cache.SetDoubleProps(feature_cache_name, minimum_under_all_settings, maximum_under_all_settings, flags); } + + g_free(feature_cache_name); } void gst_pylon_query_feature_properties_integer( GenApi::INodeMap &nodemap, GenApi::INode *node, GstPylonCache &feature_cache, GParamFlags &flags, - gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings) { + gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings, + GenApi::INode *selector, gint64 selector_value) { g_return_if_fail(node); + gchar *feature_cache_name = NULL; + if (selector) { + /* set selector value value */ + gst_pylon_object_set_pylon_selector(nodemap, selector->GetName().c_str(), + selector_value); + + feature_cache_name = gst_pylon_create_selected_name( + nodemap, node->GetName().c_str(), selector->GetName().c_str(), + selector_value); + + } else { + feature_cache_name = g_strdup(node->GetName().c_str()); + } + /* if access to a feature cache entry fails, create new props dynamically */ - if (!feature_cache.GetIntProps(std::string(node->GetName()), + if (!feature_cache.GetIntProps(node->GetName().c_str(), minimum_under_all_settings, maximum_under_all_settings, flags)) { flags = gst_pylon_query_access(nodemap, node); gst_pylon_find_limits( node, minimum_under_all_settings, maximum_under_all_settings); - feature_cache.SetIntProps(std::string(node->GetName()), + feature_cache.SetIntProps(node->GetName().c_str(), minimum_under_all_settings, maximum_under_all_settings, flags); } + + g_free(feature_cache_name); } static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 9a1db91..a11db81 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -126,10 +126,6 @@ static void gst_pylon_object_set_pylon_feature(GenApi::INodeMap& nodemap, F get_value, const GValue* value, const gchar* name); -static void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, - const gchar* selector_name, - gint64& selector_value); - template static void gst_pylon_object_set_pylon_selected_feature( GenApi::INodeMap& nodemap, F get_value, const GValue* value, @@ -245,9 +241,9 @@ void gst_pylon_object_get_pylon_feature( set_value(value, param.GetValue().c_str()); } -static void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, - const gchar* selector_name, - gint64& selector_value) { +void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, + const gchar* selector_name, + gint64& selector_value) { gint selector_type = nodemap.GetNode(selector_name)->GetPrincipalInterfaceType(); switch (selector_type) { diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index a78a8e2..705ccbc 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -71,6 +71,10 @@ EXT_PYLONSRC_API GObject* gst_pylon_object_new( std::shared_ptr camera, const std::string& device_name, GenApi::INodeMap* nodemap); +void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, + const gchar* selector_name, + gint64& selector_value); + G_END_DECLS #endif diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.cpp b/gst-libs/gst/pylon/gstpylonparamspecs.cpp index d1ab3d6..565fd50 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.cpp +++ b/gst-libs/gst/pylon/gstpylonparamspecs.cpp @@ -46,11 +46,10 @@ gchar *gst_pylon_param_spec_sanitize_name(const gchar *name) { return g_strcanon(g_strdup_printf("_%s", name), VALID_CHARS, '_'); } -static gchar *gst_pylon_param_spec_selector_prolog(GenApi::INodeMap &nodemap, - const gchar *feature_name, - const gchar *selector_name, - guint64 selector_value, - GParamFlags &flags) { +gchar *gst_pylon_create_selected_name(GenApi::INodeMap &nodemap, + const gchar *feature_name, + const gchar *selector_name, + guint64 selector_value) { g_return_val_if_fail(feature_name, NULL); g_return_val_if_fail(selector_name, NULL); @@ -73,6 +72,20 @@ static gchar *gst_pylon_param_spec_selector_prolog(GenApi::INodeMap &nodemap, gchar *name = g_strdup_printf("%s-%s", feature_name, selector_value_str.c_str()); + return name; +} + +static gchar *gst_pylon_param_spec_selector_prolog(GenApi::INodeMap &nodemap, + const gchar *feature_name, + const gchar *selector_name, + guint64 selector_value, + GParamFlags &flags) { + g_return_val_if_fail(feature_name, NULL); + g_return_val_if_fail(selector_name, NULL); + + gchar *name = gst_pylon_create_selected_name(nodemap, feature_name, + selector_name, selector_value); + gint int_flags = flags & ~G_PARAM_STATIC_NAME; int_flags |= GST_PYLON_PARAM_IS_SELECTOR; diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.h b/gst-libs/gst/pylon/gstpylonparamspecs.h index f280a89..521b4ad 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.h +++ b/gst-libs/gst/pylon/gstpylonparamspecs.h @@ -107,6 +107,11 @@ GParamSpec* gst_pylon_param_spec_selector_enum( gchar* gst_pylon_param_spec_sanitize_name(const gchar* name); GstPylonParamSpecSelectorData* gst_pylon_param_spec_selector_get_data(GParamSpec* spec); +gchar *gst_pylon_create_selected_name(GenApi::INodeMap &nodemap, + const gchar *feature_name, + const gchar *selector_name, + guint64 selector_value); + G_END_DECLS From d7382a72caf714b1d91318f35a96b18480a2a435 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 18:29:39 +0100 Subject: [PATCH 040/126] compact output for double limits --- ext/pylon/gstchildinspector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/pylon/gstchildinspector.cpp b/ext/pylon/gstchildinspector.cpp index 6dfd2fb..93d3d30 100644 --- a/ext/pylon/gstchildinspector.cpp +++ b/ext/pylon/gstchildinspector.cpp @@ -148,7 +148,7 @@ static gchar *gst_child_inspector_type_double_to_string(GParamSpec *pspec, GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE(pspec); - return g_strdup_printf("Double. Range: %.2f - %.2f Default: %.2f", + return g_strdup_printf("Double. Range: %.2g - %.2g Default: %.2g", pdouble->minimum, pdouble->maximum, g_value_get_double(value)); } From 0dce5759635a28604726efa0405935667d400ac4 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 5 Jan 2023 18:30:59 +0100 Subject: [PATCH 041/126] handle selectors and only partially available features --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 33 ++++++++++++-------- gst-libs/gst/pylon/gstpylonintrospection.cpp | 6 ++-- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index b44e52b..4dc549a 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -187,21 +187,28 @@ static std::vector gst_pylon_camera_handle_node( } for (auto& enum_value : enum_values) { - if (NULL != selector_node) { - switch (selector_node->GetPrincipalInterfaceType()) { - case GenApi::intfIEnumeration: - param.Attach(selector_node); - selector_value = param.GetEntryByName(enum_value.c_str())->GetValue(); - break; - case GenApi::intfIInteger: - selector_value = std::stoi(enum_value); - break; - default:; /* do nothing */ + try { + if (NULL != selector_node) { + switch (selector_node->GetPrincipalInterfaceType()) { + case GenApi::intfIEnumeration: + param.Attach(selector_node); + selector_value = + param.GetEntryByName(enum_value.c_str())->GetValue(); + break; + case GenApi::intfIInteger: + selector_value = std::stoi(enum_value); + break; + default:; /* do nothing */ + } } + specs_list.push_back(GstPylonParamFactory::make_param( + nodemap, node, selector_node, selector_value, device_fullname, + feature_cache)); + } catch (const Pylon::GenericException& e) { + GST_FIXME("Unable to fully install property \"%s\" on device \"%s\": %s", + node->GetDisplayName().c_str(), device_fullname.c_str(), + e.GetDescription()); } - specs_list.push_back(GstPylonParamFactory::make_param( - nodemap, node, selector_node, selector_value, device_fullname, - feature_cache)); } return specs_list; diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 91a8bd0..99af69e 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -644,7 +644,8 @@ static GParamSpec *gst_pylon_make_spec_selector_int64( GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties_integer(nodemap, node, feature_cache, - flags, min_value, max_value); + flags, min_value, max_value, + selector, selector_value); return gst_pylon_param_spec_selector_int64( nodemap, node->GetName(), selector->GetName(), selector_value, @@ -708,7 +709,8 @@ static GParamSpec *gst_pylon_make_spec_selector_double( GParamFlags flags = G_PARAM_READABLE; gst_pylon_query_feature_properties_double(nodemap, node, feature_cache, flags, - min_value, max_value); + min_value, max_value, selector, + selector_value); return gst_pylon_param_spec_selector_double( nodemap, node->GetName(), selector->GetName(), selector_value, From 9e4a339bed4501a2034d04f31503c8dce636d03a Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Fri, 6 Jan 2023 13:24:00 +0100 Subject: [PATCH 042/126] fix feature name access in selected case --- gst-libs/gst/pylon/gstpylonobject.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index a11db81..828a822 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -280,12 +280,8 @@ static void gst_pylon_object_feature_set_value( if (GST_PYLON_PARAM_FLAG_IS_SET(pspec, GST_PYLON_PARAM_IS_SELECTOR)) { gst_pylon_object_set_pylon_selector(*priv->nodemap, selector_data->selector, selector_data->selector_value); - /* strip off selector */ - gchar** featurename_split_list = NULL; - featurename_split_list = g_strsplit(pspec->name, "-", -1); gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, - featurename_split_list[0]); - g_strfreev(featurename_split_list); + selector_data->feature); } else { gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, pspec->name); @@ -301,12 +297,8 @@ static void gst_pylon_object_feature_get_value( if (GST_PYLON_PARAM_FLAG_IS_SET(pspec, GST_PYLON_PARAM_IS_SELECTOR)) { gst_pylon_object_set_pylon_selector(*priv->nodemap, selector_data->selector, selector_data->selector_value); - /* strip off selector */ - gchar** featurename_split_list = NULL; - featurename_split_list = g_strsplit(pspec->name, "-", -1); gst_pylon_object_get_pylon_feature(*priv->nodemap, set_value, value, - featurename_split_list[0]); - g_strfreev(featurename_split_list); + selector_data->feature); } else { gst_pylon_object_get_pylon_feature(*priv->nodemap, set_value, value, pspec->name); From a3f88de6ffc0d7f748d51dbcf105d30fecac9d27 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Fri, 6 Jan 2023 13:34:18 +0100 Subject: [PATCH 043/126] handle gst name mangling Only a few the pylon names contain a "_" --- gst-libs/gst/pylon/gstpylonobject.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 828a822..a3ab31d 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -283,8 +283,13 @@ static void gst_pylon_object_feature_set_value( gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, selector_data->feature); } else { + /* decanonicalize gst to pylon name */ + gchar** split = g_strsplit(pspec->name, "-", -1); + gchar* name_pylon = g_strjoinv("_", split); + g_strfreev(split); gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, - pspec->name); + name_pylon); + g_free(name_pylon); } } @@ -300,8 +305,13 @@ static void gst_pylon_object_feature_get_value( gst_pylon_object_get_pylon_feature(*priv->nodemap, set_value, value, selector_data->feature); } else { + /* decanonicalize gst to pylon name */ + gchar** split = g_strsplit(pspec->name, "-", -1); + gchar* name_pylon = g_strjoinv("_", split); + g_strfreev(split); gst_pylon_object_get_pylon_feature(*priv->nodemap, set_value, value, - pspec->name); + name_pylon); + g_free(name_pylon); } } From 6843f724a300602d37593a5ef35444453960df09 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Fri, 6 Jan 2023 16:17:56 +0100 Subject: [PATCH 044/126] skip ChunkData features --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 4dc549a..d01dd1b 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -63,7 +63,8 @@ static std::unordered_set propfilter_set = { "PixelFormat", "AcquisitionFrameRateEnable", "AcquisitionFrameRate", - "AcquisitionFrameRateAbs"}; + "AcquisitionFrameRateAbs", + "ChunkData"}; static std::vector gst_pylon_get_enum_entries( GenApi::IEnumeration* enum_node) { From ff64d527128a5b3de7dccf7388b11c51b6ddbe46 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 9 Jan 2023 15:47:02 +0100 Subject: [PATCH 045/126] fix windows linkage --- gst-libs/gst/pylon/gstpyloncache.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index 5644bc8..6afd6e4 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -37,9 +37,7 @@ #include -G_BEGIN_DECLS - -class GstPylonCache { +class GST_PLUGIN_EXPORT GstPylonCache { public: GstPylonCache(const std::string &name); ~GstPylonCache(); @@ -69,6 +67,4 @@ class GstPylonCache { gboolean is_empty; }; -G_END_DECLS - #endif From 174cf7c34c14ca1ab1d487861868831fd575a9c4 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Tue, 17 Jan 2023 15:52:28 +0100 Subject: [PATCH 046/126] check if a chunk is currently available --- gst-libs/gst/pylon/gstpylonmeta.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpylonmeta.cpp b/gst-libs/gst/pylon/gstpylonmeta.cpp index 5968047..6379e97 100644 --- a/gst-libs/gst/pylon/gstpylonmeta.cpp +++ b/gst-libs/gst/pylon/gstpylonmeta.cpp @@ -169,7 +169,7 @@ static void gst_pylon_meta_fill_result_chunks( /* Only take into account valid Chunk nodes */ auto sel_node = dynamic_cast(node); - if (!GenApi::IsImplemented(node) || !node->IsFeature() || + if (!GenApi::IsAvailable(node) || !node->IsFeature() || (node->GetName() == "Root") || !sel_node || sel_node->IsSelector()) { continue; } From b6a27107a7f7d06d34369cd173e13282adf6af0b Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Wed, 18 Jan 2023 17:07:35 +0100 Subject: [PATCH 047/126] ensure consistency of writing of cache content active in GLIB >= 2.66 --- gst-libs/gst/pylon/gstpyloncache.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index d5f25dc..a6779a0 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -33,6 +33,7 @@ #include "gstpyloncache.h" #include +#include #ifdef _MSC_VER // MSVC #pragma warning(push) @@ -112,8 +113,25 @@ gboolean GstPylonCache::IsEmpty() { return this->is_empty; } void GstPylonCache::CreateCacheFile() { GError *file_err = NULL; + +#if defined(GLIB_VERSION_2_66) && GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_66 + gchar *contents = NULL; + gsize length = 0; + + contents = g_key_file_to_data(this->feature_cache_dict, &length, NULL); + g_assert(contents != NULL); + + gboolean ret = g_file_set_contents_full( + this->filepath.c_str(), contents, length, + static_cast(G_FILE_SET_CONTENTS_CONSISTENT), 0666, + &file_err); + + g_free(contents); +#else gboolean ret = g_key_file_save_to_file(this->feature_cache_dict, this->filepath.c_str(), &file_err); +#endif + if (!ret) { std::string file_err_str = file_err->message; g_error_free(file_err); From c6959ff9af9fd8569832ba9d7fe26d7068d517c4 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 24 Jan 2023 17:33:00 -0600 Subject: [PATCH 048/126] Ensure consistent code format --- gst-libs/gst/pylon/gstpyloncache.h | 28 ++++++++++++-------- gst-libs/gst/pylon/gstpylonintrospection.cpp | 10 +++---- gst-libs/gst/pylon/gstpylonobject.cpp | 14 +++++----- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index 6afd6e4..0fa7f0a 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -44,23 +44,29 @@ class GST_PLUGIN_EXPORT GstPylonCache { gboolean IsCacheValid(); gboolean IsEmpty(); - void SetIntProps(const gchar *feature_name, const gint64 min,const gint64 max,const GParamFlags flags); - void SetDoubleProps(const gchar *feature_name, const gdouble min,const gdouble max,const GParamFlags flags); + void SetIntProps(const gchar *feature_name, const gint64 min, + const gint64 max, const GParamFlags flags); + void SetDoubleProps(const gchar *feature_name, const gdouble min, + const gdouble max, const GParamFlags flags); - bool GetIntProps(const gchar *feature_name, gint64 &min,gint64 &max,GParamFlags &flags); - bool GetDoubleProps(const gchar *feature_name, gdouble &min,gdouble &max,GParamFlags &flags); + bool GetIntProps(const gchar *feature_name, gint64 &min, gint64 &max, + GParamFlags &flags); + bool GetDoubleProps(const gchar *feature_name, gdouble &min, gdouble &max, + GParamFlags &flags); - /* persist cache to filesystem */ + /* Persist cache to filesystem */ void CreateCacheFile(); private: + void SetIntegerAttribute(const char *feature, const char *attribute, + const gint64 val); + void SetDoubleAttribute(const char *feature, const char *attribute, + gdouble val); - void SetIntegerAttribute(const char *feature, const char* attribute, const gint64 val); - void SetDoubleAttribute(const char *feature, const char* attribute, gdouble val); - - bool GetIntegerAttribute(const char *feature, const char* attribute, gint64 &val); - bool GetDoubleAttribute(const char *feature, const char* attribute, gdouble &val); - + bool GetIntegerAttribute(const char *feature, const char *attribute, + gint64 &val); + bool GetDoubleAttribute(const char *feature, const char *attribute, + gdouble &val); std::string filepath; GKeyFile *feature_cache_dict; diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 99af69e..6547ea1 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -379,7 +379,7 @@ gst_pylon_create_set_value_actions( GenApi::StringList_t settable_values; param.GetSettableValues(settable_values); for (const auto &value : settable_values) { - /* skip unsupported packed mono and bayer formats */ + /* Skip unsupported packed mono and bayer formats */ if (node->GetName() == "PixelFormat" && (Pylon::IsMonoPacked(static_cast( param.GetEntryByName(value)->GetValue())) || @@ -551,7 +551,7 @@ void gst_pylon_query_feature_properties_double( gchar *feature_cache_name = NULL; if (selector) { - /* set selector value value */ + /* Set selector value value */ gst_pylon_object_set_pylon_selector(nodemap, selector->GetName().c_str(), selector_value); @@ -562,7 +562,7 @@ void gst_pylon_query_feature_properties_double( feature_cache_name = g_strdup(node->GetName().c_str()); } - /* if access to a feature cache entry fails, create new props dynamically */ + /* If access to a feature cache entry fails, create new props dynamically */ if (!feature_cache.GetDoubleProps(feature_cache_name, minimum_under_all_settings, maximum_under_all_settings, flags)) { @@ -586,7 +586,7 @@ void gst_pylon_query_feature_properties_integer( gchar *feature_cache_name = NULL; if (selector) { - /* set selector value value */ + /* Set selector value value */ gst_pylon_object_set_pylon_selector(nodemap, selector->GetName().c_str(), selector_value); @@ -598,7 +598,7 @@ void gst_pylon_query_feature_properties_integer( feature_cache_name = g_strdup(node->GetName().c_str()); } - /* if access to a feature cache entry fails, create new props dynamically */ + /* If access to a feature cache entry fails, create new props dynamically */ if (!feature_cache.GetIntProps(node->GetName().c_str(), minimum_under_all_settings, maximum_under_all_settings, flags)) { diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index a3ab31d..bae86f3 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -120,7 +120,7 @@ static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, const std::string& device_name, GstPylonCache& feature_cache); -/* set a pylon feature from a gstreamer gst property */ +/* Set a pylon feature from a gstreamer gst property */ template static void gst_pylon_object_set_pylon_feature(GenApi::INodeMap& nodemap, F get_value, const GValue* value, @@ -154,14 +154,14 @@ static void gst_pylon_object_get_property(GObject* object, guint property_id, GValue* value, GParamSpec* pspec); static void gst_pylon_object_finalize(GObject* self); -/* gst value get fptr */ +/* GValue get fptr */ typedef gint64 (*GGetInt64)(const GValue*); typedef gboolean (*GGetBool)(const GValue*); typedef gdouble (*GGetDouble)(const GValue*); typedef const gchar* (*GGetString)(const GValue*); typedef gint (*GGetEnum)(const GValue*); -/* gst value set fptr */ +/* GValue set fptr */ typedef void (*GSetInt64)(GValue*, gint64); typedef void (*GSetBool)(GValue*, gboolean); typedef void (*GSetDouble)(GValue*, gdouble); @@ -199,7 +199,7 @@ static void gst_pylon_object_class_init( static void gst_pylon_object_init(GstPylonObject* self) {} -/* set pylon feature from gst property */ +/* Set pylon feature from gst property */ template static void gst_pylon_object_set_pylon_feature(GenApi::INodeMap& nodemap, F get_value, const GValue* value, @@ -216,7 +216,7 @@ void gst_pylon_object_set_pylon_feature( param.SetIntValue(get_value(value)); } -/* get gst property from pylon feature */ +/* Get gst property from pylon feature */ template static void gst_pylon_object_get_pylon_feature(GenApi::INodeMap& nodemap, F set_value, GValue* value, @@ -283,7 +283,7 @@ static void gst_pylon_object_feature_set_value( gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, selector_data->feature); } else { - /* decanonicalize gst to pylon name */ + /* Decanonicalize gst to pylon name */ gchar** split = g_strsplit(pspec->name, "-", -1); gchar* name_pylon = g_strjoinv("_", split); g_strfreev(split); @@ -305,7 +305,7 @@ static void gst_pylon_object_feature_get_value( gst_pylon_object_get_pylon_feature(*priv->nodemap, set_value, value, selector_data->feature); } else { - /* decanonicalize gst to pylon name */ + /* Decanonicalize gst to pylon name */ gchar** split = g_strsplit(pspec->name, "-", -1); gchar* name_pylon = g_strjoinv("_", split); g_strfreev(split); From f620a61f7f1665f1730f59b9ce8ac1d45de6571d Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 4 Jan 2023 16:42:23 -0600 Subject: [PATCH 049/126] Make sanitize_name function return an std::string instead of an allocated gchar --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 8 +++----- gst-libs/gst/pylon/gstpylonobject.cpp | 17 ++++++++--------- gst-libs/gst/pylon/gstpylonparamspecs.cpp | 8 ++++++-- gst-libs/gst/pylon/gstpylonparamspecs.h | 9 +++++---- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 6547ea1..eabad50 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -759,10 +759,10 @@ static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, gchar *full_name = g_strdup_printf("%s_%s", device_fullname.c_str(), node->GetName().c_str()); - gchar *name = gst_pylon_param_spec_sanitize_name(full_name); + std::string name = gst_pylon_param_spec_sanitize_name(full_name); g_free(full_name); - GType type = g_type_from_name(name); + GType type = g_type_from_name(name.c_str()); if (!type) { std::vector enumvalues; @@ -784,12 +784,10 @@ static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, GEnumValue sentinel = {0}; enumvalues.push_back(sentinel); - type = g_enum_register_static(name, enumvalues.data()); + type = g_enum_register_static(name.c_str(), enumvalues.data()); persistent_values.insert({type, std::move(enumvalues)}); } - g_free(name); - return type; } diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index bae86f3..d3839fa 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -94,16 +94,15 @@ GType gst_pylon_object_register(const std::string& device_name, }; /* Convert camera name to a valid string */ - gchar* type_name = gst_pylon_param_spec_sanitize_name(device_name.c_str()); + std::string type_name = + gst_pylon_param_spec_sanitize_name(device_name.c_str()); - GType type = g_type_from_name(type_name); + GType type = g_type_from_name(type_name.c_str()); if (!type) { - type = g_type_register_static(GST_TYPE_OBJECT, type_name, &typeinfo, + type = g_type_register_static(GST_TYPE_OBJECT, type_name.c_str(), &typeinfo, static_cast(0)); } - g_free(type_name); - GstPylonObject_private_offset = g_type_add_instance_private(type, sizeof(GstPylonObjectPrivate)); @@ -413,14 +412,14 @@ static void gst_pylon_object_get_property(GObject* object, guint property_id, GObject* gst_pylon_object_new( std::shared_ptr camera, const std::string& device_name, GenApi::INodeMap* nodemap) { - gchar* type_name = gst_pylon_param_spec_sanitize_name(device_name.c_str()); + std::string type_name = + gst_pylon_param_spec_sanitize_name(device_name.c_str()); - GType type = g_type_from_name(type_name); - GObject* obj = G_OBJECT(g_object_new(type, "name", type_name, NULL)); + GType type = g_type_from_name(type_name.c_str()); + GObject* obj = G_OBJECT(g_object_new(type, "name", type_name.c_str(), NULL)); GstPylonObject* self = (GstPylonObject*)obj; GstPylonObjectPrivate* priv = (GstPylonObjectPrivate*)gst_pylon_object_get_instance_private(self); - g_free(type_name); priv->camera = std::move(camera); priv->nodemap = nodemap; diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.cpp b/gst-libs/gst/pylon/gstpylonparamspecs.cpp index 565fd50..b412f48 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.cpp +++ b/gst-libs/gst/pylon/gstpylonparamspecs.cpp @@ -40,10 +40,14 @@ #define QSTRING "GstPylonParamSpecSelector" #define VALID_CHARS G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS -gchar *gst_pylon_param_spec_sanitize_name(const gchar *name) { +std::string gst_pylon_param_spec_sanitize_name(const gchar *name) { g_return_val_if_fail(name, NULL); + gchar *sanitzed_name = + g_strcanon(g_strdup_printf("_%s", name), VALID_CHARS, '_'); + std::string sanitzed_name_str = sanitzed_name; + g_free(sanitzed_name); - return g_strcanon(g_strdup_printf("_%s", name), VALID_CHARS, '_'); + return sanitzed_name_str; } gchar *gst_pylon_create_selected_name(GenApi::INodeMap &nodemap, diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.h b/gst-libs/gst/pylon/gstpylonparamspecs.h index 521b4ad..041f5ce 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.h +++ b/gst-libs/gst/pylon/gstpylonparamspecs.h @@ -59,7 +59,6 @@ G_BEGIN_DECLS #define GST_PYLON_PARAM_IS_SELECTOR (1 << (G_PARAM_USER_SHIFT + 1)) #define GST_PYLON_PARAM_FLAG_IS_SET(pspec, flag) ((pspec)->flags & (flag)) - /* --- typedefs & structures --- */ typedef struct _GstPylonParamSpecSelectorData GstPylonParamSpecSelectorData; @@ -101,12 +100,14 @@ GParamSpec* gst_pylon_param_spec_selector_string( GParamSpec* gst_pylon_param_spec_selector_enum( GenApi::INodeMap& nodemap, const gchar* feature_name, const gchar* selector_name, guint64 selector_value, const gchar* nick, - const gchar* blurb, GType type, gint64 def, GParamFlags flags) G_GNUC_MALLOC; + const gchar* blurb, GType type, gint64 def, + GParamFlags flags) G_GNUC_MALLOC; /* --- Utility prototypes --- */ -gchar* gst_pylon_param_spec_sanitize_name(const gchar* name); -GstPylonParamSpecSelectorData* gst_pylon_param_spec_selector_get_data(GParamSpec* spec); +std::string gst_pylon_param_spec_sanitize_name(const gchar* name); +GstPylonParamSpecSelectorData* gst_pylon_param_spec_selector_get_data( + GParamSpec* spec); gchar *gst_pylon_create_selected_name(GenApi::INodeMap &nodemap, const gchar *feature_name, const gchar *selector_name, From 064f8308caed0ca85ef2b3de995dc0259db6b9fa Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 4 Jan 2023 17:16:27 -0600 Subject: [PATCH 050/126] Fail correctly when a camera does not get registered and it is later required --- gst-libs/gst/pylon/gstpylonobject.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index d3839fa..5389224 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -416,6 +416,12 @@ GObject* gst_pylon_object_new( gst_pylon_param_spec_sanitize_name(device_name.c_str()); GType type = g_type_from_name(type_name.c_str()); + + if (!type) { + std::string msg = "Camera " + type_name + " is not available"; + throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); + } + GObject* obj = G_OBJECT(g_object_new(type, "name", type_name.c_str(), NULL)); GstPylonObject* self = (GstPylonObject*)obj; GstPylonObjectPrivate* priv = From 705e9ff5e8fdebac8e230410bfc5ba421579a782 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 4 Jan 2023 17:22:05 -0600 Subject: [PATCH 051/126] Register event handlers after requesting device instances Pylon will raise an internal exception if the event handlers get destroyed before unregistering them. By requesting the device instances first we ensure that if creating the instances fail, the registration of the event handlers never occurs. --- ext/pylon/gstpylon.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 05c5750..47c1156 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -281,14 +281,6 @@ GstPylon *gst_pylon_new(GstElement *gstpylonsrc, const gchar *device_user_name, device_info = device_list.at(device_index); self->camera->Attach(factory.CreateDevice(device_info)); - - self->camera->RegisterImageEventHandler(&self->image_handler, - Pylon::RegistrationMode_Append, - Pylon::Cleanup_None); - self->disconnect_handler.SetData(self->gstpylonsrc, &self->image_handler); - self->camera->RegisterConfiguration(&self->disconnect_handler, - Pylon::RegistrationMode_Append, - Pylon::Cleanup_None); self->camera->Open(); /* Set the camera to a valid state */ @@ -308,6 +300,16 @@ GstPylon *gst_pylon_new(GstElement *gstpylonsrc, const gchar *device_user_name, self->camera, gst_pylon_get_sgrabber_name(*self->camera), &sgrabber_nodemap); + /* Register event handlers after device instances are requested so they do + * not get registered if creating the device instances fails */ + self->camera->RegisterImageEventHandler(&self->image_handler, + Pylon::RegistrationMode_Append, + Pylon::Cleanup_None); + self->disconnect_handler.SetData(self->gstpylonsrc, &self->image_handler); + self->camera->RegisterConfiguration(&self->disconnect_handler, + Pylon::RegistrationMode_Append, + Pylon::Cleanup_None); + } catch (const Pylon::GenericException &e) { g_set_error(err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, "%s", e.GetDescription()); From 65633aa50447d26649f2493ffc987f0ad976fa1a Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Wed, 4 Jan 2023 17:35:04 -0600 Subject: [PATCH 052/126] Use friendly device name for error --- gst-libs/gst/pylon/gstpylonobject.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 5389224..edc7b68 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -418,7 +418,9 @@ GObject* gst_pylon_object_new( GType type = g_type_from_name(type_name.c_str()); if (!type) { - std::string msg = "Camera " + type_name + " is not available"; + std::string msg = "Camera \'" + + std::string(camera->GetDeviceInfo().GetFriendlyName()) + + "\' is not available."; throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); } From db84fedf7c87d764217ace8baaa7ba17055fc8e9 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Wed, 18 Jan 2023 17:48:56 +0100 Subject: [PATCH 053/126] add pybind11 dependency --- .gitignore | 1 - subprojects/pybind11.wrap | 12 ++++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 subprojects/pybind11.wrap diff --git a/.gitignore b/.gitignore index b40d524..e7f1191 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ Build # Meson /build /_build -/subprojects # vscode .vscode/ diff --git a/subprojects/pybind11.wrap b/subprojects/pybind11.wrap new file mode 100644 index 0000000..82ac176 --- /dev/null +++ b/subprojects/pybind11.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = pybind11-2.10.0 +source_url = https://github.com/pybind/pybind11/archive/refs/tags/v2.10.0.tar.gz +source_filename = pybind11-2.10.0.tar.gz +source_hash = eacf582fa8f696227988d08cfc46121770823839fe9e301a20fbce67e7cd70ec +patch_filename = pybind11_2.10.0-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/pybind11_2.10.0-1/get_patch +patch_hash = ebb87b55ef4a32cc8627b90f091df2c9f39899f7bc5447a4657b662340497c27 +wrapdb_version = 2.10.0-1 + +[provide] +pybind11 = pybind11_dep From 5af4381a33d3e4e9a8ec7bada89452739b1fc5c1 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Wed, 18 Jan 2023 15:54:09 +0100 Subject: [PATCH 054/126] python bindings to access pylonsrc metadata --- bindings/include/bindaccessfunctions.h | 43 ++++++++++ bindings/include/bindpylonmeta.h | 44 +++++++++++ bindings/include/pygstpylon.h | 47 +++++++++++ bindings/meson.build | 36 +++++++++ bindings/packaging/setup.py | 12 +++ bindings/src/bindaccessfunctions.cpp | 53 +++++++++++++ bindings/src/bindpylonmeta.cpp | 76 ++++++++++++++++++ bindings/src/pygstpylon.cpp | 53 +++++++++++++ gst-libs/gst/pylon/gstpylonmeta.cpp | 6 ++ gst-libs/gst/pylon/gstpylonmeta.h | 2 + meson.build | 1 + tests/examples/pylon/show_meta.c | 10 +-- tests/examples/python/snapshot_gpio.py | 105 +++++++++++++++++++++++++ 13 files changed, 479 insertions(+), 9 deletions(-) create mode 100644 bindings/include/bindaccessfunctions.h create mode 100644 bindings/include/bindpylonmeta.h create mode 100644 bindings/include/pygstpylon.h create mode 100644 bindings/meson.build create mode 100644 bindings/packaging/setup.py create mode 100644 bindings/src/bindaccessfunctions.cpp create mode 100644 bindings/src/bindpylonmeta.cpp create mode 100644 bindings/src/pygstpylon.cpp create mode 100755 tests/examples/python/snapshot_gpio.py diff --git a/bindings/include/bindaccessfunctions.h b/bindings/include/bindaccessfunctions.h new file mode 100644 index 0000000..708b93c --- /dev/null +++ b/bindings/include/bindaccessfunctions.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "pybind11/pybind11.h" +#include "pygstpylon.h" + +namespace py = pybind11; + +using namespace std; + +namespace pygstpylon { + void bindaccessfunctions(py::module &m); +} diff --git a/bindings/include/bindpylonmeta.h b/bindings/include/bindpylonmeta.h new file mode 100644 index 0000000..9b50b19 --- /dev/null +++ b/bindings/include/bindpylonmeta.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BINDPYLONMETA_H +#define BINDPYLONMETA_H + +#include "pygstpylon.h" + +namespace py = pybind11; + +namespace pygstpylon { + void bindpylonmeta(py::module &m); +} + +#endif diff --git a/bindings/include/pygstpylon.h b/bindings/include/pygstpylon.h new file mode 100644 index 0000000..764dde2 --- /dev/null +++ b/bindings/include/pygstpylon.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PYGSTPYLON_H +#define PYGSTPYLON_H + +#include +#include +#include +#include + + +namespace py = pybind11; + +namespace pygstpylon { +} + +#endif /* PYGSTPYLON_H */ diff --git a/bindings/meson.build b/bindings/meson.build new file mode 100644 index 0000000..25a07f3 --- /dev/null +++ b/bindings/meson.build @@ -0,0 +1,36 @@ +py_mod = import('python') +py3 = py_mod.find_installation('python3') +py3_dep = py3.dependency() +message(py3.path()) +message(py3.get_install_dir()) + +pygstpylon_sources = [ + 'src/pygstpylon.cpp', + 'src/bindpylonmeta.cpp', + 'src/bindaccessfunctions.cpp' +] + +pybind11_dep = dependency('pybind11', fallback : ['pybind11', 'pybind11_dep']) +gstpylon_dep = dependency('gstpylon') + +pygstpylon_deps = [ + py3_dep, + pybind11_dep, + gstvideo_dep, + gst_dep, + gstpylon_dep +] + +destdir = get_option('libdir') / 'python' + py3_dep.version() / 'site-packages/pygstpylon' +incdir = include_directories('include') + +pymeta = py3.extension_module('pygstpylon', + pygstpylon_sources, + install : true, + cpp_args: ['-DHAVE_CONFIG_H=1'], + include_directories : [configinc, incdir], + dependencies : pygstpylon_deps, + ) + + + diff --git a/bindings/packaging/setup.py b/bindings/packaging/setup.py new file mode 100644 index 0000000..1ec2351 --- /dev/null +++ b/bindings/packaging/setup.py @@ -0,0 +1,12 @@ +import setuptools + +setuptools.setup( + name="pygstpylon", + version="0.6.0", + author="Basler AG", + description="python bindings to gstpylon", + url="baslerweb.com", + packages=[''], + package_data={'': ['pygstpylon.so']}, + install_requires=["pgi", "PyGObject"] +) diff --git a/bindings/src/bindaccessfunctions.cpp b/bindings/src/bindaccessfunctions.cpp new file mode 100644 index 0000000..a5e2182 --- /dev/null +++ b/bindings/src/bindaccessfunctions.cpp @@ -0,0 +1,53 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bindaccessfunctions.h" + +#include + +namespace py = pybind11; +using namespace pybind11::literals; +using namespace std; + +namespace pygstpylon { + +void bindaccessfunctions(py::module &m) { + m.def( + "gst_buffer_get_pylon_meta", + [](size_t gst_buffer) { + auto *buffer = reinterpret_cast(gst_buffer); + return gst_buffer_get_pylon_meta(buffer); + }, + "buffer"_a, py::return_value_policy::reference); +} + +} // namespace pygstpylon diff --git a/bindings/src/bindpylonmeta.cpp b/bindings/src/bindpylonmeta.cpp new file mode 100644 index 0000000..12edaa0 --- /dev/null +++ b/bindings/src/bindpylonmeta.cpp @@ -0,0 +1,76 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bindpylonmeta.h" + +#include + +namespace py = pybind11; +namespace pygstpylon { + +void bindpylonmeta(py::module &m) { + py::class_(m, "GstPylonMeta") + .def(py::init<>()) + .def_readonly("block_id", &GstPylonMeta::block_id) + .def_readonly("image_number", &GstPylonMeta::image_number) + .def_readonly("skipped_images", &GstPylonMeta::skipped_images) + .def_readonly("timestamp", &GstPylonMeta::timestamp) + .def_readonly("stride", &GstPylonMeta::stride) + .def_property_readonly("chunks", [](const GstPylonMeta &self) { + py::dict dict; + gint64 int_chunk; + gdouble double_chunk; + /* export chunks embedded in the stream to dict*/ + for (int idx = 0; idx < gst_structure_n_fields(self.chunks); idx++) { + const gchar *chunk_name = + gst_structure_nth_field_name(self.chunks, idx); + GType chunk_type = + gst_structure_get_field_type(self.chunks, chunk_name); + /* display double and int types */ + switch (chunk_type) { + case G_TYPE_INT64: + gst_structure_get_int64(self.chunks, chunk_name, &int_chunk); + dict[py::str{std::string(chunk_name)}] = int_chunk; + break; + case G_TYPE_DOUBLE: + gst_structure_get_double(self.chunks, chunk_name, &double_chunk); + dict[py::str{std::string(chunk_name)}] = double_chunk; + break; + default: + g_print("Skip chunk %s\n", chunk_name); + } + } + return dict; + }); +} + +} // namespace pygstpylon diff --git a/bindings/src/pygstpylon.cpp b/bindings/src/pygstpylon.cpp new file mode 100644 index 0000000..f1f9c32 --- /dev/null +++ b/bindings/src/pygstpylon.cpp @@ -0,0 +1,53 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "bindaccessfunctions.h" +#include "bindpylonmeta.h" +#include "pygstpylon.h" + +using namespace std; +namespace py = pybind11; + +namespace pygstpylon { + +PYBIND11_MODULE(pygstpylon, m) { + m.doc() = "Basler gstreamer pylonsrc access package"; + m.attr("__version__") = PACKAGE_VERSION; + + bindaccessfunctions(m); + bindpylonmeta(m); +} +} // namespace pygstpylon diff --git a/gst-libs/gst/pylon/gstpylonmeta.cpp b/gst-libs/gst/pylon/gstpylonmeta.cpp index 6379e97..6cabf68 100644 --- a/gst-libs/gst/pylon/gstpylonmeta.cpp +++ b/gst-libs/gst/pylon/gstpylonmeta.cpp @@ -239,3 +239,9 @@ static void gst_pylon_meta_free(GstMeta *meta, GstBuffer *buffer) { gst_structure_free(pylon_meta->chunks); } + +GstPylonMeta * gst_buffer_get_pylon_meta (GstBuffer * buffer) +{ + return reinterpret_cast(gst_buffer_get_meta (buffer, GST_PYLON_META_API_TYPE)); +} + diff --git a/gst-libs/gst/pylon/gstpylonmeta.h b/gst-libs/gst/pylon/gstpylonmeta.h index 5afbd8f..06ac682 100644 --- a/gst-libs/gst/pylon/gstpylonmeta.h +++ b/gst-libs/gst/pylon/gstpylonmeta.h @@ -64,6 +64,8 @@ struct _GstPylonMeta EXT_PYLONSRC_API GType gst_pylon_meta_api_get_type (void); EXT_PYLONSRC_API const GstMetaInfo *gst_pylon_meta_get_info (void); +EXT_PYLONSRC_API GstPylonMeta * gst_buffer_get_pylon_meta (GstBuffer * buffer); + G_END_DECLS #endif diff --git a/meson.build b/meson.build index af180d0..3bb4763 100644 --- a/meson.build +++ b/meson.build @@ -244,6 +244,7 @@ subdir('gst-libs') subdir('ext') subdir('tests') subdir('docs') +subdir('bindings') configure_file(output : 'config.h', configuration : cdata) diff --git a/tests/examples/pylon/show_meta.c b/tests/examples/pylon/show_meta.c index 0b4af69..a9335ff 100644 --- a/tests/examples/pylon/show_meta.c +++ b/tests/examples/pylon/show_meta.c @@ -161,14 +161,6 @@ try_enable_all_chunks (Context * ctx) } -static GstPylonMeta * -gst_buffer_get_pylon_meta (GstBuffer * buffer) -{ - GstPylonMeta *meta = - (GstPylonMeta *) gst_buffer_get_meta (buffer, GST_PYLON_META_API_TYPE); - return meta; -} - static GstPadProbeReturn cb_have_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) { @@ -183,7 +175,7 @@ cb_have_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) g_return_val_if_fail (ctx, GST_PAD_PROBE_DROP); buffer = GST_PAD_PROBE_INFO_BUFFER (info); - meta = (GstPylonMeta *) gst_buffer_get_pylon_meta (buffer); + meta = (GstPylonMeta *) gst_buffer_get_meta (buffer, GST_PYLON_META_API_TYPE); meta_str = g_strdup_printf diff --git a/tests/examples/python/snapshot_gpio.py b/tests/examples/python/snapshot_gpio.py new file mode 100755 index 0000000..b7ce414 --- /dev/null +++ b/tests/examples/python/snapshot_gpio.py @@ -0,0 +1,105 @@ +#! /usr/bin/python3.10 + +import gi +import pygstpylon + + + +gi.require_version("Gst", "1.0") +gi.require_version("GstBase", "1.0") +gi.require_version("GstVideo", "1.0") +gi.require_version("GObject", "2.0") +gi.require_version("GLib", "2.0") + + +def test_meta(value, userdata): + print(value, userdata) + + +from gi.repository import Gst, GObject, GstBase, GstVideo, GLib + +Gst.init(None) +FIXED_CAPS = Gst.Caps.from_string( + "video/x-raw,format=GRAY8,width=[1,2147483647],height=[1,2147483647]" +) + + +class PylonGPIOSnapshot(GstBase.BaseTransform): + __gstmetadata__ = ( + "PylonGPIOSnapshot", + "Filter/Effect/Video", + "filter that will pass a snapshot on edge of gpio ", + "thies.moeller@baslerweb.com", + ) + + __gproperties__ = { + "trigger-source": ( + int, + "gpio line for trigger", + "GPIO line on the camera to use for the trigger of snapshot", + 0, + 4, + 0, + GObject.ParamFlags.READWRITE, + ), + "rising-edge": ( + bool, + "use rising edge as trigger condition", + "create snapshot on rising edge of input signal", + True, + GObject.ParamFlags.READWRITE, + ), + } + + __gsttemplates__ = ( + Gst.PadTemplate.new( + "src", Gst.PadDirection.SRC, Gst.PadPresence.ALWAYS, FIXED_CAPS + ), + Gst.PadTemplate.new( + "sink", Gst.PadDirection.SINK, Gst.PadPresence.ALWAYS, FIXED_CAPS + ), + ) + + def __init__(self): + super(PylonGPIOSnapshot, self).__init__() + + # Initialize properties before Base Class initialization + self.trigger_source = 0 + self.rising_edge = True + self.last_state = None + + + self.set_passthrough(True) + + + def do_get_property(self, prop): + if prop.name == "trigger-source": + return self.trigger_source + elif prop.name == "rising_edge": + return self.rising_edge + else: + raise AttributeError("unknown property %s" % prop.name) + + def do_set_property(self, prop, value): + if prop.name == "trigger-source": + self.trigger_source = value + elif prop.name == "rising-edge": + self.rising_edge = value + else: + raise AttributeError("unknown property %s" % prop.name) + + def do_transform_ip(self, buf): + Gst.info("timestamp(buffer):%d" % buf.pts) + + meta = pygstpylon.gst_buffer_get_pylon_meta(hash(buf)) + print(meta.block_id, meta, meta.chunks) + + if (True): + Gst.info(" snapshot") + return Gst.FlowReturn.OK + else: + return Gst.FlowReturn.CUSTOM_SUCCESS + + +GObject.type_register(PylonGPIOSnapshot) +__gstelementfactory__ = ("pylongpiosnapshot_py", Gst.Rank.NONE, PylonGPIOSnapshot) From 072fdf6b153d3630c987eda8ead678224dce5fbf Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Wed, 18 Jan 2023 17:18:23 +0100 Subject: [PATCH 055/126] add programming sample for pygstpylon python bindings --- tests/examples/python/snapshot_gpio.py | 44 ++++++++++++++++++-------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/tests/examples/python/snapshot_gpio.py b/tests/examples/python/snapshot_gpio.py index b7ce414..ead1c26 100755 --- a/tests/examples/python/snapshot_gpio.py +++ b/tests/examples/python/snapshot_gpio.py @@ -4,7 +4,6 @@ import pygstpylon - gi.require_version("Gst", "1.0") gi.require_version("GstBase", "1.0") gi.require_version("GstVideo", "1.0") @@ -19,9 +18,6 @@ def test_meta(value, userdata): from gi.repository import Gst, GObject, GstBase, GstVideo, GLib Gst.init(None) -FIXED_CAPS = Gst.Caps.from_string( - "video/x-raw,format=GRAY8,width=[1,2147483647],height=[1,2147483647]" -) class PylonGPIOSnapshot(GstBase.BaseTransform): @@ -37,9 +33,9 @@ class PylonGPIOSnapshot(GstBase.BaseTransform): int, "gpio line for trigger", "GPIO line on the camera to use for the trigger of snapshot", - 0, + 1, 4, - 0, + 1, GObject.ParamFlags.READWRITE, ), "rising-edge": ( @@ -53,10 +49,10 @@ class PylonGPIOSnapshot(GstBase.BaseTransform): __gsttemplates__ = ( Gst.PadTemplate.new( - "src", Gst.PadDirection.SRC, Gst.PadPresence.ALWAYS, FIXED_CAPS + "src", Gst.PadDirection.SRC, Gst.PadPresence.ALWAYS, Gst.Caps.new_any() ), Gst.PadTemplate.new( - "sink", Gst.PadDirection.SINK, Gst.PadPresence.ALWAYS, FIXED_CAPS + "sink", Gst.PadDirection.SINK, Gst.PadPresence.ALWAYS, Gst.Caps.new_any() ), ) @@ -64,14 +60,12 @@ def __init__(self): super(PylonGPIOSnapshot, self).__init__() # Initialize properties before Base Class initialization - self.trigger_source = 0 + self.trigger_source = 1 self.rising_edge = True self.last_state = None - self.set_passthrough(True) - def do_get_property(self, prop): if prop.name == "trigger-source": return self.trigger_source @@ -92,12 +86,34 @@ def do_transform_ip(self, buf): Gst.info("timestamp(buffer):%d" % buf.pts) meta = pygstpylon.gst_buffer_get_pylon_meta(hash(buf)) - print(meta.block_id, meta, meta.chunks) - - if (True): + line_state = meta.chunks["ChunkLineStatusAll"] + + gpio_state = line_state & (1 << (self.trigger_source - 1)) + + trigger = False + + if not self.last_state is None: + if self.rising_edge: + if self.last_state == False and gpio_state == True: + trigger = True + else: + trigger = False + else: + if self.last_state == True and gpio_state == False: + trigger = True + else: + trigger = False + + self.last_state = gpio_state + if trigger: Gst.info(" snapshot") return Gst.FlowReturn.OK else: + ts = buf.pts + # check that the timestamp is valid + if ts != -1: + duration = buf.duration + self.srcpad.push_event(Gst.Event.new_gap(ts, duration)) return Gst.FlowReturn.CUSTOM_SUCCESS From a0bb8105f10cd4a2619ddb4e3894c3948ce62bbe Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Sun, 22 Jan 2023 23:06:58 +0100 Subject: [PATCH 056/126] add documentation for python bindings --- README.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 556aac7..0b2768a 100644 --- a/README.md +++ b/README.md @@ -267,7 +267,27 @@ gst-launch-1.0 pylonsrc cam::ChunkModeActive=True cam::ChunkEnable-Timestamp=Tru The plugin meta data is defined in [gstpylonmeta.h](gst-libs/gst/pylon/gstpylonmeta.h). -A programming sample using these defintions to decode the data is in [show_meta](tests/examples/pylon/show_meta.c) +A programming sample using these defintions to decode the data is in [show_meta](tests/examples/pylon/show_meta.c) + +**Access to GstMetaPylon from python ** + +To access the metadata a Python support library is available. The `pygstpylon` provides the required access helper to decode the metadata from plugins and probes. + +One usage example to access camera chunk and metadata from a python plugin is in [snapshot_gpio.py](tests/examples/python/snapshot_gpio.py) + +This sample plugin will check the LineStatusAll chunk to detect an edge on one of the inputs to output a single image while per default all images get dropped. + +The below usage example will show live video and store a snapshot if the gpio edge is detected on Line4 of the camera. + +```bash +# the plugin path for python code has to point to a directory with a 'python' subdirectory +export GST_PLUGIN_PATH=/tests/examples +gst-launch-1.0 pylonsrc cam::ChunkModeActive=True cam::ChunkEnable-LineStatusAll=True \ + ! tee name=t \ + t. ! queue ! pylongpiosnapshot_py line-source=4 rising-edge=true ! videoconvert ! pngenc ! multifilesink location=image%05d.png async=false\ + t. ! queue ! videoconvert ! autovideosink +``` + # Building @@ -304,6 +324,9 @@ sudo -H python3 -m pip install meson ninja --upgrade # GStreamer sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev cmake +# if you want to use the sample python plugin +sudo apt install gstreamer1.0-python3-plugin-loader + ``` The build process relies on `PYLON_ROOT` pointing to the Basler pylon install directory. From 119983654b9beac06cc9127fbb0772a8f593a710 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 19 Jan 2023 18:42:31 +0100 Subject: [PATCH 057/126] introduce negative list for selectors fixes issues with DeviceLinkSelector --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 45 ++++++++++++++++---- gst-libs/gst/pylon/gstpylonintrospection.cpp | 6 +-- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index d01dd1b..cd0944f 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -57,6 +57,7 @@ static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); +/* filter for features and categories */ static std::unordered_set propfilter_set = { "Width", "Height", @@ -64,7 +65,20 @@ static std::unordered_set propfilter_set = { "AcquisitionFrameRateEnable", "AcquisitionFrameRate", "AcquisitionFrameRateAbs", - "ChunkData"}; + "ChunkData", + "AcquisitionStart", + "AcquisitionStop", + "UserSetLoad", + "UserSetSave", + "TriggerSoftware", + "DeviceReset", + "DeviceRegistersStreamingStart", + "DeviceRegistersStreamingEnd"}; + +/* filter for selector nodes */ +static std::unordered_set selectorfilter_set = { + "DeviceLinkSelector", +}; static std::vector gst_pylon_get_enum_entries( GenApi::IEnumeration* enum_node) { @@ -126,14 +140,10 @@ std::vector GstPylonFeatureWalker::process_selector_features( throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); } - /* If the feature has no selectors then it is a "direct" feature, it does not - * depend on any other selector */ GenApi::FeatureList_t selectors; + bool is_direct_feature = false; + sel_node->GetSelectingFeatures(selectors); - if (selectors.empty()) { - enum_values.push_back("direct-feature"); - return enum_values; - } /* At the time being features with multiple selectors are not supported */ guint max_selectors = 1; @@ -144,6 +154,25 @@ std::vector GstPylonFeatureWalker::process_selector_features( throw Pylon::GenericException(error_msg.c_str(), __FILE__, __LINE__); } + /* If the feature has no selectors then it is a "direct" feature, it does not + * depend on any other selector + */ + if (selectors.empty()) { + is_direct_feature = true; + } else { + /* If the selecrtor is in negative list it is a "direct" feature and + * selector is ignored */ + auto selector = selectors.at(0); + is_direct_feature |= + selectorfilter_set.find(std::string(selector->GetNode()->GetName())) != + selectorfilter_set.end(); + } + + if (is_direct_feature) { + enum_values.push_back("direct-feature"); + return enum_values; + } + auto selector = selectors.at(0); *selector_node = selector->GetNode(); @@ -207,7 +236,7 @@ static std::vector gst_pylon_camera_handle_node( feature_cache)); } catch (const Pylon::GenericException& e) { GST_FIXME("Unable to fully install property \"%s\" on device \"%s\": %s", - node->GetDisplayName().c_str(), device_fullname.c_str(), + node->GetName().c_str(), device_fullname.c_str(), e.GetDescription()); } } diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index eabad50..5a00c6d 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -872,9 +872,9 @@ GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, } break; default: - std::string msg = "Unsupported node of type " + - std::to_string(node->GetPrincipalInterfaceType()); - throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); + Pylon::String_t msg = + "Unsupported node of type " + GenApi::GetInterfaceName(node); + throw Pylon::GenericException(msg, __FILE__, __LINE__); } return spec; From 7d084099c0b06a305271ca9a0491808dfaa9ebfc Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Wed, 25 Jan 2023 17:59:48 +0100 Subject: [PATCH 058/126] more finegrained lists for not mapped features --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 61 +++++++++++++++----- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index cd0944f..b872f63 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -57,8 +57,7 @@ static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); -/* filter for features and categories */ -static std::unordered_set propfilter_set = { +static const std::unordered_set propfilter_set = { "Width", "Height", "PixelFormat", @@ -72,14 +71,43 @@ static std::unordered_set propfilter_set = { "UserSetSave", "TriggerSoftware", "DeviceReset", + "FileAccessControl", "DeviceRegistersStreamingStart", - "DeviceRegistersStreamingEnd"}; + "DeviceRegistersStreamingEnd", + "FileAccessControl" /* has to be implemented in access library */ + "EventControl", /* disable full event section until mapped to gst + events/msgs */ + "SequencerControl" /* sequencer control relies on cmd feature */ +}; + +static const std::unordered_set categoryfilter_set = { + "ChunkData", + "FileAccessControl" /* has to be implemented in access library */ + "EventControl", /* disable full event section until mapped to gst + events/msgs */ + "SequencerControl" /* sequencer control relies on cmd feature */ +}; + +/* filter for features that are not supported */ +static bool is_unsupported_feature(const std::string& feature_name) { + return propfilter_set.find(feature_name) != propfilter_set.end(); +} + +/* filter for categories that are not supported */ +static bool is_unsupported_category(const std::string& category_name) { + return categoryfilter_set.find(category_name) != categoryfilter_set.end(); +} /* filter for selector nodes */ static std::unordered_set selectorfilter_set = { "DeviceLinkSelector", }; +/* filter for selectors and categories that are supported */ +static bool is_unsupported_selector(const std::string& feature_name) { + return selectorfilter_set.find(feature_name) != selectorfilter_set.end(); +} + static std::vector gst_pylon_get_enum_entries( GenApi::IEnumeration* enum_node) { GenApi::NodeList_t enum_entries; @@ -160,12 +188,11 @@ std::vector GstPylonFeatureWalker::process_selector_features( if (selectors.empty()) { is_direct_feature = true; } else { - /* If the selecrtor is in negative list it is a "direct" feature and + /* If the selector is in negative list it is a "direct" feature and * selector is ignored */ auto selector = selectors.at(0); is_direct_feature |= - selectorfilter_set.find(std::string(selector->GetNode()->GetName())) != - selectorfilter_set.end(); + is_unsupported_selector(std::string(selector->GetNode()->GetName())); } if (is_direct_feature) { @@ -201,7 +228,7 @@ static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, const std::string& device_fullname, GstPylonCache& feature_cache) { GenApi::INode* selector_node = NULL; - guint64 selector_value = 0; + gint64 selector_value = 0; std::vector specs_list; Pylon::CEnumParameter param; @@ -231,13 +258,14 @@ static std::vector gst_pylon_camera_handle_node( default:; /* do nothing */ } } + specs_list.push_back(GstPylonParamFactory::make_param( nodemap, node, selector_node, selector_value, device_fullname, feature_cache)); } catch (const Pylon::GenericException& e) { - GST_FIXME("Unable to fully install property \"%s\" on device \"%s\": %s", - node->GetName().c_str(), device_fullname.c_str(), - e.GetDescription()); + GST_FIXME("Unable to fully install property '%s-%s' on device \"%s\": %s", + node->GetName().c_str(), enum_value.c_str(), + device_fullname.c_str(), e.GetDescription()); } } @@ -286,10 +314,10 @@ void GstPylonFeatureWalker::install_properties( * selectors and are available */ auto sel_node = dynamic_cast(node); if (node->IsFeature() && (node->GetVisibility() != GenApi::Invisible) && - sel_node && GenApi::IsImplemented(node) && !sel_node->IsSelector() && - propfilter_set.find(std::string(node->GetName())) == - propfilter_set.end() && - node->GetPrincipalInterfaceType() != GenApi::intfICategory) { + GenApi::IsImplemented(node) && + !is_unsupported_feature(std::string(node->GetName())) && + node->GetPrincipalInterfaceType() != GenApi::intfICategory && + sel_node && !sel_node->IsSelector()) { GenICam::gcstring value; GenICam::gcstring attrib; @@ -301,14 +329,15 @@ void GstPylonFeatureWalker::install_properties( } catch (const Pylon::GenericException& e) { GST_FIXME("Unable to install property \"%s\" on device \"%s\": %s", - node->GetDisplayName().c_str(), device_fullname.c_str(), + node->GetName().c_str(), device_fullname.c_str(), e.GetDescription()); } } /* Walk down all categories */ auto category_node = dynamic_cast(node); - if (category_node) { + if (category_node && + !is_unsupported_category(std::string(node->GetName()))) { GenApi::FeatureList_t features; category_node->GetFeatures(features); for (auto const& f : features) { From 2b9ab28e70e71ef2d23a498ac37ce84facbeac05 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 26 Jan 2023 13:06:22 +0100 Subject: [PATCH 059/126] cleanup bindings --- bindings/include/bindaccessfunctions.h | 10 +++++----- bindings/include/bindpylonmeta.h | 2 +- bindings/include/pygstpylon.h | 9 ++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/bindings/include/bindaccessfunctions.h b/bindings/include/bindaccessfunctions.h index 708b93c..9e2c0bf 100644 --- a/bindings/include/bindaccessfunctions.h +++ b/bindings/include/bindaccessfunctions.h @@ -29,15 +29,15 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef BINDACCESSFUNCTIONS_H +#define BINDACCESSFUNCTIONS_H -#include #include "pybind11/pybind11.h" #include "pygstpylon.h" namespace py = pybind11; - -using namespace std; - namespace pygstpylon { - void bindaccessfunctions(py::module &m); +void bindaccessfunctions(py::module &m); } + +#endif diff --git a/bindings/include/bindpylonmeta.h b/bindings/include/bindpylonmeta.h index 9b50b19..47e585e 100644 --- a/bindings/include/bindpylonmeta.h +++ b/bindings/include/bindpylonmeta.h @@ -38,7 +38,7 @@ namespace py = pybind11; namespace pygstpylon { - void bindpylonmeta(py::module &m); +void bindpylonmeta(py::module &m); } #endif diff --git a/bindings/include/pygstpylon.h b/bindings/include/pygstpylon.h index 764dde2..040b79c 100644 --- a/bindings/include/pygstpylon.h +++ b/bindings/include/pygstpylon.h @@ -33,15 +33,14 @@ #ifndef PYGSTPYLON_H #define PYGSTPYLON_H -#include -#include -#include #include +#include +#include +#include namespace py = pybind11; -namespace pygstpylon { -} +namespace pygstpylon {} #endif /* PYGSTPYLON_H */ From 753b8b5accdfe19e7ee48a5ed2bdf436a3af5c67 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 26 Jan 2023 13:06:36 +0100 Subject: [PATCH 060/126] add missing offset_xy to bindings --- bindings/src/bindpylonmeta.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bindings/src/bindpylonmeta.cpp b/bindings/src/bindpylonmeta.cpp index 12edaa0..b92bcb4 100644 --- a/bindings/src/bindpylonmeta.cpp +++ b/bindings/src/bindpylonmeta.cpp @@ -45,6 +45,12 @@ void bindpylonmeta(py::module &m) { .def_readonly("skipped_images", &GstPylonMeta::skipped_images) .def_readonly("timestamp", &GstPylonMeta::timestamp) .def_readonly("stride", &GstPylonMeta::stride) + .def_property_readonly( + "offset_x", + [](const GstPylonMeta &self) { return self.offset.offset_x; }) + .def_property_readonly( + "offset_y", + [](const GstPylonMeta &self) { return self.offset.offset_y; }) .def_property_readonly("chunks", [](const GstPylonMeta &self) { py::dict dict; gint64 int_chunk; From 09c61edb880b1f2b05bdcee24062a6cfb2e921c7 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Fri, 27 Jan 2023 13:17:03 +0100 Subject: [PATCH 061/126] silence pybind11 redundant declaration warning --- bindings/include/bindaccessfunctions.h | 12 ++++++++++-- bindings/include/bindpylonmeta.h | 11 ++++++++++- bindings/include/pygstpylon.h | 11 ++++++++--- bindings/src/pygstpylon.cpp | 1 - 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/bindings/include/bindaccessfunctions.h b/bindings/include/bindaccessfunctions.h index 9e2c0bf..243c8a1 100644 --- a/bindings/include/bindaccessfunctions.h +++ b/bindings/include/bindaccessfunctions.h @@ -32,8 +32,16 @@ #ifndef BINDACCESSFUNCTIONS_H #define BINDACCESSFUNCTIONS_H -#include "pybind11/pybind11.h" -#include "pygstpylon.h" +#if __GNUC__ // GCC, CLANG, MinGW +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + +#include + +#if __GNUC__ // GCC, CLANG, MinWG +#pragma GCC diagnostic pop +#endif namespace py = pybind11; namespace pygstpylon { diff --git a/bindings/include/bindpylonmeta.h b/bindings/include/bindpylonmeta.h index 47e585e..97b13e7 100644 --- a/bindings/include/bindpylonmeta.h +++ b/bindings/include/bindpylonmeta.h @@ -33,7 +33,16 @@ #ifndef BINDPYLONMETA_H #define BINDPYLONMETA_H -#include "pygstpylon.h" +#if __GNUC__ // GCC, CLANG, MinGW +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + +#include + +#if __GNUC__ // GCC, CLANG, MinWG +#pragma GCC diagnostic pop +#endif namespace py = pybind11; diff --git a/bindings/include/pygstpylon.h b/bindings/include/pygstpylon.h index 040b79c..e628d5d 100644 --- a/bindings/include/pygstpylon.h +++ b/bindings/include/pygstpylon.h @@ -33,11 +33,16 @@ #ifndef PYGSTPYLON_H #define PYGSTPYLON_H -#include +#if __GNUC__ // GCC, CLANG, MinGW +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + #include -#include -#include +#if __GNUC__ // GCC, CLANG, MinWG +#pragma GCC diagnostic pop +#endif namespace py = pybind11; diff --git a/bindings/src/pygstpylon.cpp b/bindings/src/pygstpylon.cpp index f1f9c32..55acfdc 100644 --- a/bindings/src/pygstpylon.cpp +++ b/bindings/src/pygstpylon.cpp @@ -39,7 +39,6 @@ #include "pygstpylon.h" using namespace std; -namespace py = pybind11; namespace pygstpylon { From 54598c91afa3f250f3833a90d7199df812dfb6ea Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Fri, 27 Jan 2023 13:30:00 +0100 Subject: [PATCH 062/126] centralize include of pylon api --- ext/pylon/gstpylon.cpp | 18 +-------------- ext/pylon/gstpylondisconnecthandler.h | 18 +-------------- ext/pylon/gstpylonimagehandler.h | 21 ++--------------- gst-libs/gst/pylon/gstpyloncache.cpp | 17 +------------- gst-libs/gst/pylon/gstpylonfeaturewalker.h | 19 +--------------- gst-libs/gst/pylon/gstpylonincludes.h | 26 ++++++++++++++++++++++ gst-libs/gst/pylon/gstpylonintrospection.h | 20 +---------------- gst-libs/gst/pylon/gstpylonmeta.cpp | 25 ++++----------------- gst-libs/gst/pylon/gstpylonmetaprivate.h | 20 +---------------- gst-libs/gst/pylon/gstpylonobject.h | 24 +++----------------- gst-libs/gst/pylon/gstpylonparamspecs.h | 19 ++-------------- 11 files changed, 43 insertions(+), 184 deletions(-) create mode 100644 gst-libs/gst/pylon/gstpylonincludes.h diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 47c1156..48f9c4b 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -36,6 +36,7 @@ #include "gst/pylon/gstpyloncache.h" #include "gst/pylon/gstpylondebug.h" +#include "gst/pylon/gstpylonincludes.h" #include "gst/pylon/gstpylonmetaprivate.h" #include "gst/pylon/gstpylonobject.h" #include "gstchildinspector.h" @@ -45,23 +46,6 @@ #include -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#endif - -#include -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif - /* Pixel format definitions */ typedef struct { std::string pfnc_name; diff --git a/ext/pylon/gstpylondisconnecthandler.h b/ext/pylon/gstpylondisconnecthandler.h index eb1e899..9edd553 100644 --- a/ext/pylon/gstpylondisconnecthandler.h +++ b/ext/pylon/gstpylondisconnecthandler.h @@ -36,27 +36,11 @@ #include "gstpylonimagehandler.h" #include +#include #include #include -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#endif - -#include -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif - class GstPylonDisconnectHandler : public Pylon::CBaslerUniversalConfigurationEventHandler { public: diff --git a/ext/pylon/gstpylonimagehandler.h b/ext/pylon/gstpylonimagehandler.h index 9278a42..fa40012 100644 --- a/ext/pylon/gstpylonimagehandler.h +++ b/ext/pylon/gstpylonimagehandler.h @@ -33,28 +33,11 @@ #ifndef _GST_PYLON_IMAGE_HANDLER_H_ #define _GST_PYLON_IMAGE_HANDLER_H_ +#include + #include #include -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif - -#include -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif - class GstPylonImageHandler : public Pylon::CBaslerUniversalImageEventHandler { public: GstPylonImageHandler(); diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index a6779a0..7db2cf9 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -34,22 +34,7 @@ #include #include - -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#endif - -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif +#include #define DIRERR -1 diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.h b/gst-libs/gst/pylon/gstpylonfeaturewalker.h index d40048e..36fd007 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.h +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.h @@ -35,24 +35,7 @@ #include #include - -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif - -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif +#include class GstPylonFeatureWalker { public: diff --git a/gst-libs/gst/pylon/gstpylonincludes.h b/gst-libs/gst/pylon/gstpylonincludes.h new file mode 100644 index 0000000..364b4c3 --- /dev/null +++ b/gst-libs/gst/pylon/gstpylonincludes.h @@ -0,0 +1,26 @@ +#ifndef GST_PYLON_INCLUDES_H +#define GST_PYLON_INCLUDES_H + +#ifdef _MSC_VER // MSVC +#pragma warning(push) +#pragma warning(disable : 4265) +#elif __GNUC__ // GCC, CLANG, MinGW +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic ignored "-Woverloaded-virtual" +#pragma GCC diagnostic ignored "-Wunused-variable" +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#endif +#endif + +#include +#include + +#ifdef _MSC_VER // MSVC +#pragma warning(pop) +#elif __GNUC__ // GCC, CLANG, MinWG +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/gst-libs/gst/pylon/gstpylonintrospection.h b/gst-libs/gst/pylon/gstpylonintrospection.h index cf12934..5cc01a9 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.h +++ b/gst-libs/gst/pylon/gstpylonintrospection.h @@ -35,25 +35,7 @@ #include #include - -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif - -#include -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif +#include class GstPylonParamFactory { public: diff --git a/gst-libs/gst/pylon/gstpylonmeta.cpp b/gst-libs/gst/pylon/gstpylonmeta.cpp index 6cabf68..0bc8906 100644 --- a/gst-libs/gst/pylon/gstpylonmeta.cpp +++ b/gst-libs/gst/pylon/gstpylonmeta.cpp @@ -39,25 +39,9 @@ #include "gstpylonmeta.h" #include "gstpylonmetaprivate.h" +#include #include -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#endif - -#include -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif - /* prototypes */ static gboolean gst_pylon_meta_init(GstMeta *meta, gpointer params, GstBuffer *buffer); @@ -240,8 +224,7 @@ static void gst_pylon_meta_free(GstMeta *meta, GstBuffer *buffer) { gst_structure_free(pylon_meta->chunks); } -GstPylonMeta * gst_buffer_get_pylon_meta (GstBuffer * buffer) -{ - return reinterpret_cast(gst_buffer_get_meta (buffer, GST_PYLON_META_API_TYPE)); +GstPylonMeta *gst_buffer_get_pylon_meta(GstBuffer *buffer) { + return reinterpret_cast( + gst_buffer_get_meta(buffer, GST_PYLON_META_API_TYPE)); } - diff --git a/gst-libs/gst/pylon/gstpylonmetaprivate.h b/gst-libs/gst/pylon/gstpylonmetaprivate.h index 20a38a0..4523c06 100644 --- a/gst-libs/gst/pylon/gstpylonmetaprivate.h +++ b/gst-libs/gst/pylon/gstpylonmetaprivate.h @@ -35,27 +35,9 @@ #include #include +#include #include - - -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#endif - -#include -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif - G_BEGIN_DECLS EXT_PYLONSRC_API void gst_buffer_add_pylon_meta( diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index 705ccbc..3dba979 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -35,25 +35,7 @@ #include #include - -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif - -#include -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif +#include G_BEGIN_DECLS @@ -72,8 +54,8 @@ EXT_PYLONSRC_API GObject* gst_pylon_object_new( const std::string& device_name, GenApi::INodeMap* nodemap); void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, - const gchar* selector_name, - gint64& selector_value); + const gchar* selector_name, + gint64& selector_value); G_END_DECLS diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.h b/gst-libs/gst/pylon/gstpylonparamspecs.h index 041f5ce..37a1f7a 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.h +++ b/gst-libs/gst/pylon/gstpylonparamspecs.h @@ -35,23 +35,8 @@ #include -#ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) -#elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif - -#include - -#ifdef _MSC_VER // MSVC -#pragma warning(pop) -#elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif +#include "gst/pylon/gstpylonincludes.h" + G_BEGIN_DECLS From 2eb1acf2739949b5eb75aaf67023e38eb0a1ad11 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Fri, 27 Jan 2023 13:28:57 +0100 Subject: [PATCH 063/126] ignore warning in pylon API --- tests/prototypes/dynamic_limits.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/prototypes/dynamic_limits.cpp b/tests/prototypes/dynamic_limits.cpp index 83dcff3..371ab54 100644 --- a/tests/prototypes/dynamic_limits.cpp +++ b/tests/prototypes/dynamic_limits.cpp @@ -38,8 +38,12 @@ #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" #pragma GCC diagnostic ignored "-Woverloaded-virtual" #pragma GCC diagnostic ignored "-Wunused-variable" +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#endif #endif +#include #include #ifdef _MSC_VER // MSVC From 5366c77110ca9f8e5e9fc3a7274327aa862cbba2 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 6 Feb 2023 13:04:49 +0100 Subject: [PATCH 064/126] disable MultipleROI until fixed in feature walker --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index b872f63..b0e5c3b 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -85,7 +85,9 @@ static const std::unordered_set categoryfilter_set = { "FileAccessControl" /* has to be implemented in access library */ "EventControl", /* disable full event section until mapped to gst events/msgs */ - "SequencerControl" /* sequencer control relies on cmd feature */ + "SequencerControl", /* sequencer control relies on cmd feature */ + "MultipleROI" /* workaround skip to avoid issues with ace2/dart2 + FIXME: this has to be fixed in feature walker */ }; /* filter for features that are not supported */ From 7fea9ae05501c6ad045d8ea7734dba6b98a0104d Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Fri, 10 Feb 2023 14:21:47 -0600 Subject: [PATCH 065/126] Add option to enable or disable python bindings --- meson.build | 10 +++++++++- meson_options.txt | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3bb4763..b788f38 100644 --- a/meson.build +++ b/meson.build @@ -91,6 +91,7 @@ if glib_checks.disabled() or (glib_checks.auto() and not gst_version_is_dev) add_project_arguments('-DG_DISABLE_CHECKS', language: 'c') endif + cdata = configuration_data() check_headers = [ @@ -244,7 +245,14 @@ subdir('gst-libs') subdir('ext') subdir('tests') subdir('docs') -subdir('bindings') + +meta_python_bindings = get_option('meta-python-bindings') +if meta_python_bindings.enabled() + message('Meta python bindings enabled') + subdir('bindings') +else + message('Meta python bindings disabled') +endif configure_file(output : 'config.h', configuration : cdata) diff --git a/meson_options.txt b/meson_options.txt index 09b755d..dfc356a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,6 +8,8 @@ option('glib-asserts', type : 'feature', value : 'enabled', yield : true, description: 'Enable GLib assertion (auto = enabled for development, disabled for stable releases)') option('glib-checks', type : 'feature', value : 'enabled', yield : true, description: 'Enable GLib checks such as API guards (auto = enabled for development, disabled for stable releases)') +option('meta-python-bindings', type : 'feature', value : 'disabled', yield : true, + description: 'Enable meta python bindings') # Common options option('package-name', type : 'string', yield : true, From f0c27c4c2dc98b93e328031ab4e72223d5cbb889 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 13 Feb 2023 07:08:50 -0600 Subject: [PATCH 066/126] Change python bindings option name --- meson.build | 2 +- meson_options.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index b788f38..0c6b309 100644 --- a/meson.build +++ b/meson.build @@ -246,7 +246,7 @@ subdir('ext') subdir('tests') subdir('docs') -meta_python_bindings = get_option('meta-python-bindings') +meta_python_bindings = get_option('python-bindings') if meta_python_bindings.enabled() message('Meta python bindings enabled') subdir('bindings') diff --git a/meson_options.txt b/meson_options.txt index dfc356a..c8285e2 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,8 +8,8 @@ option('glib-asserts', type : 'feature', value : 'enabled', yield : true, description: 'Enable GLib assertion (auto = enabled for development, disabled for stable releases)') option('glib-checks', type : 'feature', value : 'enabled', yield : true, description: 'Enable GLib checks such as API guards (auto = enabled for development, disabled for stable releases)') -option('meta-python-bindings', type : 'feature', value : 'disabled', yield : true, - description: 'Enable meta python bindings') +option('python-bindings', type : 'feature', value : 'disabled', yield : true, + description: 'Enable meta Python bindings') # Common options option('package-name', type : 'string', yield : true, From b9d0233288ee0e42400206a4d8521626d81ecdf2 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 13 Feb 2023 07:37:53 -0600 Subject: [PATCH 067/126] Fix copyright headers --- bindings/include/bindaccessfunctions.h | 11 +------- bindings/include/bindpylonmeta.h | 7 +----- bindings/include/pygstpylon.h | 7 +----- bindings/src/pygstpylon.cpp | 2 +- meson.build | 1 - tests/examples/python/snapshot_gpio.py | 35 +++++++++++++++++++++++++- 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/bindings/include/bindaccessfunctions.h b/bindings/include/bindaccessfunctions.h index 243c8a1..53fee7c 100644 --- a/bindings/include/bindaccessfunctions.h +++ b/bindings/include/bindaccessfunctions.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Basler AG +/* Copyright (C) 2023 Basler AG * * * Redistribution and use in source and binary forms, with or without @@ -32,17 +32,8 @@ #ifndef BINDACCESSFUNCTIONS_H #define BINDACCESSFUNCTIONS_H -#if __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wredundant-decls" -#endif - #include -#if __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop -#endif - namespace py = pybind11; namespace pygstpylon { void bindaccessfunctions(py::module &m); diff --git a/bindings/include/bindpylonmeta.h b/bindings/include/bindpylonmeta.h index 97b13e7..084ea73 100644 --- a/bindings/include/bindpylonmeta.h +++ b/bindings/include/bindpylonmeta.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Basler AG +/* Copyright (C) 2023 Basler AG * * * Redistribution and use in source and binary forms, with or without @@ -33,11 +33,6 @@ #ifndef BINDPYLONMETA_H #define BINDPYLONMETA_H -#if __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wredundant-decls" -#endif - #include #if __GNUC__ // GCC, CLANG, MinWG diff --git a/bindings/include/pygstpylon.h b/bindings/include/pygstpylon.h index e628d5d..0ec9410 100644 --- a/bindings/include/pygstpylon.h +++ b/bindings/include/pygstpylon.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Basler AG +/* Copyright (C) 2023 Basler AG * * * Redistribution and use in source and binary forms, with or without @@ -33,11 +33,6 @@ #ifndef PYGSTPYLON_H #define PYGSTPYLON_H -#if __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wredundant-decls" -#endif - #include #if __GNUC__ // GCC, CLANG, MinWG diff --git a/bindings/src/pygstpylon.cpp b/bindings/src/pygstpylon.cpp index 55acfdc..681beb0 100644 --- a/bindings/src/pygstpylon.cpp +++ b/bindings/src/pygstpylon.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Basler AG +/* Copyright (C) 2023 Basler AG * * * Redistribution and use in source and binary forms, with or without diff --git a/meson.build b/meson.build index 0c6b309..d64168e 100644 --- a/meson.build +++ b/meson.build @@ -91,7 +91,6 @@ if glib_checks.disabled() or (glib_checks.auto() and not gst_version_is_dev) add_project_arguments('-DG_DISABLE_CHECKS', language: 'c') endif - cdata = configuration_data() check_headers = [ diff --git a/tests/examples/python/snapshot_gpio.py b/tests/examples/python/snapshot_gpio.py index ead1c26..d1cc089 100755 --- a/tests/examples/python/snapshot_gpio.py +++ b/tests/examples/python/snapshot_gpio.py @@ -1,5 +1,38 @@ #! /usr/bin/python3.10 +""" + Copyright (C) 2023 Basler AG + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + 3. Neither the name of the copyright holder nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +""" + + import gi import pygstpylon @@ -83,7 +116,7 @@ def do_set_property(self, prop, value): raise AttributeError("unknown property %s" % prop.name) def do_transform_ip(self, buf): - Gst.info("timestamp(buffer):%d" % buf.pts) + Gst.info("timestamp(buffer):%ld" % buf.pts) meta = pygstpylon.gst_buffer_get_pylon_meta(hash(buf)) line_state = meta.chunks["ChunkLineStatusAll"] From 2608d9c954f60da03e37b07ccc9485455578937b Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 13 Feb 2023 08:00:16 -0600 Subject: [PATCH 068/126] Add instructions on how to enable python bindings --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 0b2768a..72a98c7 100644 --- a/README.md +++ b/README.md @@ -346,6 +346,12 @@ cd gst-plugin-pylon meson setup builddir --prefix /usr/ ``` +If you want to enable Python bindings, run the following command instead when setting up the meson project, since the bindings are disabled by default: + +```bash +meson setup builddir --prefix /usr/ -Dpython-bindings=enabled +``` + Build, test and install the project: ```bash From df9c0d4be72ebb5284e6e0ffb19b28c30733020b Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 13 Feb 2023 08:10:00 -0600 Subject: [PATCH 069/126] Fix copyright year in bindpylonmeta.cpp file --- bindings/src/bindpylonmeta.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/src/bindpylonmeta.cpp b/bindings/src/bindpylonmeta.cpp index b92bcb4..6e4e74e 100644 --- a/bindings/src/bindpylonmeta.cpp +++ b/bindings/src/bindpylonmeta.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Basler AG +/* Copyright (C) 2023 Basler AG * * * Redistribution and use in source and binary forms, with or without From f24eb339e299a24c92ff1213a71f9a2214452911 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 13 Feb 2023 09:38:57 -0600 Subject: [PATCH 070/126] Fix copyright year in bindaccessfunctions.cpp --- bindings/src/bindaccessfunctions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/src/bindaccessfunctions.cpp b/bindings/src/bindaccessfunctions.cpp index a5e2182..e6ba5c2 100644 --- a/bindings/src/bindaccessfunctions.cpp +++ b/bindings/src/bindaccessfunctions.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Basler AG +/* Copyright (C) 2023 Basler AG * * * Redistribution and use in source and binary forms, with or without From 08e8f0e990102718963819cccd7400e3973a5f68 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 13 Feb 2023 11:35:49 -0600 Subject: [PATCH 071/126] Add disclaimer about bindings being disabled by default --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 72a98c7..744ba9c 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,8 @@ A programming sample using these defintions to decode the data is in [show_meta] To access the metadata a Python support library is available. The `pygstpylon` provides the required access helper to decode the metadata from plugins and probes. +Note that Python bindings are disabled by default, refer to the build section for instructions on how to enable them. + One usage example to access camera chunk and metadata from a python plugin is in [snapshot_gpio.py](tests/examples/python/snapshot_gpio.py) This sample plugin will check the LineStatusAll chunk to detect an edge on one of the inputs to output a single image while per default all images get dropped. From 701f4cf2e9b6ca78687d431fd64a3ed79d58c0ef Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 13 Feb 2023 14:38:06 -0600 Subject: [PATCH 072/126] Remove Python specific version from Python bindings example --- tests/examples/python/snapshot_gpio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/examples/python/snapshot_gpio.py b/tests/examples/python/snapshot_gpio.py index d1cc089..fac975f 100755 --- a/tests/examples/python/snapshot_gpio.py +++ b/tests/examples/python/snapshot_gpio.py @@ -1,4 +1,4 @@ -#! /usr/bin/python3.10 +#! /usr/bin/python3 """ Copyright (C) 2023 Basler AG From 708f084fd624ce92b74549d9dde941960874a83b Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Tue, 14 Feb 2023 08:00:42 -0600 Subject: [PATCH 073/126] Fix Python bindings example pipeline --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 744ba9c..804f262 100644 --- a/README.md +++ b/README.md @@ -286,7 +286,7 @@ The below usage example will show live video and store a snapshot if the gpio ed export GST_PLUGIN_PATH=/tests/examples gst-launch-1.0 pylonsrc cam::ChunkModeActive=True cam::ChunkEnable-LineStatusAll=True \ ! tee name=t \ - t. ! queue ! pylongpiosnapshot_py line-source=4 rising-edge=true ! videoconvert ! pngenc ! multifilesink location=image%05d.png async=false\ + t. ! queue ! pylongpiosnapshot_py trigger-source=4 rising-edge=true ! videoconvert ! pngenc ! multifilesink location=image%05d.png async=false\ t. ! queue ! videoconvert ! autovideosink ``` From 1d259b656491478ffab95f125bf1353e16805251 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Tue, 14 Feb 2023 10:45:47 +0100 Subject: [PATCH 074/126] add more temp files to .gitignore --- .gitignore | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.gitignore b/.gitignore index e7f1191..c2dd13e 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,14 @@ Build # qtcreator .qtc_clangd/ + +# vs code +.devcontainer + +# temp files +.ipynb_checkpoints +__pycache__ + +# subprojects +subprojects/packagecache +subprojects/pybind11-2.10.3 From 2cff0e8c45b16c4f23985fb95465681b10b71576 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Tue, 14 Feb 2023 11:19:13 +0100 Subject: [PATCH 075/126] convert project to c++ codebase ( except examples ) --- .../{gstpylonplugin.c => gstpylonplugin.cpp} | 23 +- ext/pylon/gstpylonsrc.c | 965 ------------------ ext/pylon/gstpylonsrc.cpp | 953 +++++++++++++++++ ext/pylon/meson.build | 4 +- hooks/cpp-format | 1 + hooks/gst-indent | 59 -- hooks/pre-commit.hook | 20 +- 7 files changed, 971 insertions(+), 1054 deletions(-) rename ext/pylon/{gstpylonplugin.c => gstpylonplugin.cpp} (74%) delete mode 100644 ext/pylon/gstpylonsrc.c create mode 100644 ext/pylon/gstpylonsrc.cpp delete mode 100755 hooks/gst-indent diff --git a/ext/pylon/gstpylonplugin.c b/ext/pylon/gstpylonplugin.cpp similarity index 74% rename from ext/pylon/gstpylonplugin.c rename to ext/pylon/gstpylonplugin.cpp index ae5faa8..f7090c0 100644 --- a/ext/pylon/gstpylonplugin.c +++ b/ext/pylon/gstpylonplugin.cpp @@ -31,22 +31,21 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gstpylonsrc.h" + #include -static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "pylonsrc", GST_RANK_NONE, - GST_TYPE_PYLON_SRC); +static gboolean plugin_init(GstPlugin* plugin) { + return gst_element_register(plugin, "pylonsrc", GST_RANK_NONE, + GST_TYPE_PYLON_SRC); } -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - pylon, - "Basler/Pylon plugin for pylon SDK " PYLON_VERSIONSTRING_MAJOR "." - PYLON_VERSIONSTRING_MINOR "." PYLON_VERSIONSTRING_SUBMINOR "(" - PYLON_VERSIONSTRING_BUILD ")", plugin_init, VERSION, GST_PACKAGE_LICENSE, - GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) +GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, pylon, + "Basler/Pylon plugin for pylon SDK " PYLON_VERSIONSTRING_MAJOR + "." PYLON_VERSIONSTRING_MINOR "." PYLON_VERSIONSTRING_SUBMINOR + "(" PYLON_VERSIONSTRING_BUILD ")", + plugin_init, VERSION, GST_PACKAGE_LICENSE, GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN) diff --git a/ext/pylon/gstpylonsrc.c b/ext/pylon/gstpylonsrc.c deleted file mode 100644 index e8992dd..0000000 --- a/ext/pylon/gstpylonsrc.c +++ /dev/null @@ -1,965 +0,0 @@ -/* Copyright (C) 2022 Basler AG - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * SECTION:element-gstpylonsrc - * - * The pylonsrc element captures images from Basler cameras. - * - * - * Example launch line - * |[ - * gst-launch-1.0 -v pylonsrc ! videoconvert ! autovideosink - * ]| - * Capture images from a Basler camera and display them. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstpylonsrc.h" - -#include "gstpylon.h" -#include "gst/pylon/gstpylonmeta.h" -#include "gst/pylon/gstpylondebug.h" - -#include - -struct _GstPylonSrc -{ - GstPushSrc base_pylonsrc; - GstPylon *pylon; - GstClockTime duration; - GstVideoInfo video_info; - - gchar *device_user_name; - gchar *device_serial_number; - gint device_index; - gchar *user_set; - gchar *pfs_location; - GstPylonCaptureErrorEnum capture_error; - GObject *cam; - GObject *stream; -}; - -/* prototypes */ - -static void -gst_pylon_src_set_property (GObject * object, - guint property_id, const GValue * value, GParamSpec * pspec); -static void gst_pylon_src_get_property (GObject * object, - guint property_id, GValue * value, GParamSpec * pspec); -static void gst_pylon_src_finalize (GObject * object); - -static GstCaps *gst_pylon_src_get_caps (GstBaseSrc * src, GstCaps * filter); -static gboolean gst_pylon_src_is_bayer (GstStructure * st); -static GstCaps *gst_pylon_src_fixate (GstBaseSrc * src, GstCaps * caps); -static gboolean gst_pylon_src_set_caps (GstBaseSrc * src, GstCaps * caps); -static gboolean gst_pylon_src_decide_allocation (GstBaseSrc * src, - GstQuery * query); -static gboolean gst_pylon_src_start (GstBaseSrc * src); -static gboolean gst_pylon_src_stop (GstBaseSrc * src); -static gboolean gst_pylon_src_unlock (GstBaseSrc * src); -static gboolean gst_pylon_src_query (GstBaseSrc * src, GstQuery * query); -static void gst_plyon_src_add_metadata (GstPylonSrc * self, GstBuffer * buf); -static GstFlowReturn gst_pylon_src_create (GstPushSrc * src, GstBuffer ** buf); - -static void gst_pylon_src_child_proxy_init (GstChildProxyInterface * iface); - -enum -{ - PROP_0, - PROP_DEVICE_USER_NAME, - PROP_DEVICE_SERIAL_NUMBER, - PROP_DEVICE_INDEX, - PROP_USER_SET, - PROP_PFS_LOCATION, - PROP_CAPTURE_ERROR, - PROP_CAM, - PROP_STREAM -}; - -#define PROP_DEVICE_USER_NAME_DEFAULT NULL -#define PROP_DEVICE_SERIAL_NUMBER_DEFAULT NULL -#define PROP_DEVICE_INDEX_DEFAULT -1 -#define PROP_DEVICE_INDEX_MIN -1 -#define PROP_DEVICE_INDEX_MAX G_MAXINT32 -#define PROP_USER_SET_DEFAULT NULL -#define PROP_PFS_LOCATION_DEFAULT NULL -#define PROP_CAM_DEFAULT NULL -#define PROP_STREAM_DEFAULT NULL -#define PROP_CAPTURE_ERROR_DEFAULT ENUM_ABORT - -/* Enum for cature_error */ -#define GST_TYPE_CAPTURE_ERROR_ENUM (gst_pylon_capture_error_enum_get_type ()) - -/* Child proxy interface names */ -static const gchar *gst_pylon_src_child_proxy_names[] = { - "cam", - "stream" -}; - -static GType -gst_pylon_capture_error_enum_get_type (void) -{ - static gsize gtype = 0; - static const GEnumValue values[] = { - {ENUM_KEEP, "keep", "Use partial or corrupt buffers"}, - {ENUM_SKIP, "skip", - "Skip partial or corrupt buffers. A maximum of 100 buffers can be skipped before the pipeline aborts."}, - {ENUM_ABORT, "abort", "Stop pipeline in case of any capture error"}, - {0, NULL, NULL} - }; - - if (g_once_init_enter (>ype)) { - GType tmp = g_enum_register_static ("GstPylonCaptureErrorEnum", values); - g_once_init_leave (>ype, tmp); - } - - return (GType) gtype; -} - -/* pad templates */ - -static GstStaticPadTemplate gst_pylon_src_src_template = - GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (" {GRAY8, RGB, BGR, YUY2, UYVY} ") ";" - "video/x-bayer,format={rggb,bggr,gbgr,grgb},width=" GST_VIDEO_SIZE_RANGE - ",height=" GST_VIDEO_SIZE_RANGE ",framerate=" GST_VIDEO_FPS_RANGE)); - - -/* class initialization */ -G_DEFINE_TYPE_WITH_CODE (GstPylonSrc, gst_pylon_src, GST_TYPE_PUSH_SRC, - gst_pylon_debug_init (); - G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY, gst_pylon_src_child_proxy_init) - ); - -static void -gst_pylon_src_class_init (GstPylonSrcClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS (klass); - GstPushSrcClass *push_src_class = GST_PUSH_SRC_CLASS (klass); - gchar *cam_params = NULL; - gchar *cam_blurb = NULL; - gchar *stream_params = NULL; - gchar *stream_blurb = NULL; - const gchar *cam_prolog = NULL; - const gchar *stream_prolog = NULL; - - gst_pylon_initialize (); - - /* Setting up pads and setting metadata should be moved to - base_class_init if you intend to subclass this class. */ - gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass), - &gst_pylon_src_src_template); - - gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass), - "Basler/Pylon source element", "Source/Video/Hardware", - "Source element for Basler cameras", - "Basler AG "); - - gobject_class->set_property = gst_pylon_src_set_property; - gobject_class->get_property = gst_pylon_src_get_property; - gobject_class->finalize = gst_pylon_src_finalize; - - g_object_class_install_property (gobject_class, PROP_DEVICE_USER_NAME, - g_param_spec_string ("device-user-name", "Device user defined name", - "The user-defined name of the device to use. May be combined" - "with other device selection properties to reduce the search.", - PROP_DEVICE_USER_NAME_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_DEVICE_SERIAL_NUMBER, - g_param_spec_string ("device-serial-number", "Device serial number", - "The serial number of the device to use. May be combined with " - "other device selection properties to reduce the search.", - PROP_DEVICE_SERIAL_NUMBER_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_DEVICE_INDEX, - g_param_spec_int ("device-index", "Device index", - "The index of the device to use.This index applies to the " - "resulting device list after applying the other device selection " - "properties. The index is mandatory if multiple devices match " - "the given search criteria.", PROP_DEVICE_INDEX_MIN, - PROP_DEVICE_INDEX_MAX, PROP_DEVICE_INDEX_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_USER_SET, - g_param_spec_string ("user-set", "Device user configuration set", - "The user-defined configuration set to use. Leaving this property " - "unset, or using 'Auto' result in selecting the " - "power-on default camera configuration.", - PROP_USER_SET_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_PFS_LOCATION, - g_param_spec_string ("pfs-location", "PFS file location", - "The filepath to the PFS file from which to load the device configuration. " - "Setting this property will override the user set property if also set.", - PROP_PFS_LOCATION_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_CAPTURE_ERROR, - g_param_spec_enum ("capture-error", - "Capture error strategy", - "The strategy to use in case of a camera capture error.", - GST_TYPE_CAPTURE_ERROR_ENUM, PROP_CAPTURE_ERROR_DEFAULT, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - cam_params = gst_pylon_camera_get_string_properties (); - stream_params = gst_pylon_stream_grabber_get_string_properties (); - - if (NULL == cam_params) { - cam_prolog = "No valid cameras where found connected to the system."; - stream_prolog = cam_prolog; - cam_params = g_strdup (""); - stream_params = g_strdup (""); - } else { - cam_prolog = "The following list details the properties for each camera.\n"; - stream_prolog = - "The following list details the properties for each stream grabber.\n"; - } - - cam_blurb = g_strdup_printf ("The camera to use.\n" - "\t\t\tAccording to the selected camera " - "different properties will be available.\n " - "\t\t\tThese properties can be accessed using the " - "\"cam::\" syntax.\n" "\t\t\t%s%s", cam_prolog, cam_params); - - g_object_class_install_property (gobject_class, PROP_CAM, - g_param_spec_object ("cam", "Camera", cam_blurb, G_TYPE_OBJECT, - G_PARAM_READABLE)); - - stream_blurb = g_strdup_printf ("The stream grabber to use.\n" - "\t\t\tAccording to the selected stream grabber " - "different properties will be available.\n " - "\t\t\tThese properties can be accessed using the " - "\"stream::\" syntax.\n" "\t\t\t%s%s", stream_prolog, - stream_params); - - g_object_class_install_property (gobject_class, PROP_STREAM, - g_param_spec_object ("stream", "Stream Grabber", stream_blurb, - G_TYPE_OBJECT, G_PARAM_READABLE)); - - g_free (cam_params); - g_free (stream_params); - - base_src_class->get_caps = GST_DEBUG_FUNCPTR (gst_pylon_src_get_caps); - base_src_class->fixate = GST_DEBUG_FUNCPTR (gst_pylon_src_fixate); - base_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_pylon_src_set_caps); - base_src_class->decide_allocation = - GST_DEBUG_FUNCPTR (gst_pylon_src_decide_allocation); - base_src_class->start = GST_DEBUG_FUNCPTR (gst_pylon_src_start); - base_src_class->stop = GST_DEBUG_FUNCPTR (gst_pylon_src_stop); - base_src_class->unlock = GST_DEBUG_FUNCPTR (gst_pylon_src_unlock); - base_src_class->query = GST_DEBUG_FUNCPTR (gst_pylon_src_query); - - push_src_class->create = GST_DEBUG_FUNCPTR (gst_pylon_src_create); -} - -static void -gst_pylon_src_init (GstPylonSrc * self) -{ - GstBaseSrc *base = GST_BASE_SRC (self); - - self->pylon = NULL; - self->duration = GST_CLOCK_TIME_NONE; - self->device_user_name = PROP_DEVICE_USER_NAME_DEFAULT; - self->device_serial_number = PROP_DEVICE_SERIAL_NUMBER_DEFAULT; - self->device_index = PROP_DEVICE_INDEX_DEFAULT; - self->user_set = PROP_USER_SET_DEFAULT; - self->pfs_location = PROP_PFS_LOCATION_DEFAULT; - self->capture_error = PROP_CAPTURE_ERROR_DEFAULT; - self->cam = PROP_CAM_DEFAULT; - self->stream = PROP_STREAM_DEFAULT; - gst_video_info_init (&self->video_info); - - gst_base_src_set_live (base, TRUE); - gst_base_src_set_format (base, GST_FORMAT_TIME); -} - -static void -gst_pylon_src_set_property (GObject * object, guint property_id, - const GValue * value, GParamSpec * pspec) -{ - GstPylonSrc *self = GST_PYLON_SRC (object); - - GST_LOG_OBJECT (self, "set_property"); - - GST_OBJECT_LOCK (self); - - switch (property_id) { - case PROP_DEVICE_USER_NAME: - g_free (self->device_user_name); - self->device_user_name = g_value_dup_string (value); - break; - case PROP_DEVICE_SERIAL_NUMBER: - g_free (self->device_serial_number); - self->device_serial_number = g_value_dup_string (value); - break; - case PROP_DEVICE_INDEX: - self->device_index = g_value_get_int (value); - break; - case PROP_USER_SET: - g_free (self->user_set); - self->user_set = g_value_dup_string (value); - break; - case PROP_PFS_LOCATION: - g_free (self->pfs_location); - self->pfs_location = g_value_dup_string (value); - break; - case PROP_CAPTURE_ERROR: - self->capture_error = g_value_get_enum (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } - - GST_OBJECT_UNLOCK (self); -} - -static void -gst_pylon_src_get_property (GObject * object, guint property_id, - GValue * value, GParamSpec * pspec) -{ - GstPylonSrc *self = GST_PYLON_SRC (object); - - GST_LOG_OBJECT (self, "get_property"); - - GST_OBJECT_LOCK (self); - - switch (property_id) { - case PROP_DEVICE_USER_NAME: - g_value_set_string (value, self->device_user_name); - break; - case PROP_DEVICE_SERIAL_NUMBER: - g_value_set_string (value, self->device_serial_number); - break; - case PROP_DEVICE_INDEX: - g_value_set_int (value, self->device_index); - break; - case PROP_USER_SET: - g_value_set_string (value, self->user_set); - break; - case PROP_PFS_LOCATION: - g_value_set_string (value, self->pfs_location); - break; - case PROP_CAPTURE_ERROR: - g_value_set_enum (value, self->capture_error); - break; - case PROP_CAM: - g_value_set_object (value, self->cam); - break; - case PROP_STREAM: - g_value_set_object (value, self->stream); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } - - GST_OBJECT_UNLOCK (self); -} - -static void -gst_pylon_src_finalize (GObject * object) -{ - GstPylonSrc *self = GST_PYLON_SRC (object); - - GST_LOG_OBJECT (self, "finalize"); - - g_free (self->device_user_name); - self->device_user_name = NULL; - - g_free (self->device_serial_number); - self->device_serial_number = NULL; - - g_free (self->user_set); - self->user_set = NULL; - - if (self->cam) { - g_object_unref (self->cam); - self->cam = NULL; - } - - if (self->stream) { - g_object_unref (self->stream); - self->stream = NULL; - } - - G_OBJECT_CLASS (gst_pylon_src_parent_class)->finalize (object); -} - -/* get caps from subclass */ -static GstCaps * -gst_pylon_src_get_caps (GstBaseSrc * src, GstCaps * filter) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GstCaps *outcaps = NULL; - GError *error = NULL; - - if (!self->pylon) { - outcaps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (self)); - GST_INFO_OBJECT (self, - "Camera not open yet, returning src template caps %" GST_PTR_FORMAT, - outcaps); - goto out; - } - - outcaps = gst_pylon_query_configuration (self->pylon, &error); - - if (outcaps == NULL && error) { - goto log_gst_error; - } - - GST_DEBUG_OBJECT (self, "Camera returned caps %" GST_PTR_FORMAT, outcaps); - - if (filter) { - GstCaps *tmp = outcaps; - - GST_DEBUG_OBJECT (self, "Filtering with %" GST_PTR_FORMAT, filter); - - outcaps = gst_caps_intersect (outcaps, filter); - gst_caps_unref (tmp); - } - - GST_INFO_OBJECT (self, "Returning caps %" GST_PTR_FORMAT, outcaps); - - goto out; - -log_gst_error: - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to get caps."), ("%s", error->message)); - g_error_free (error); - -out: - return outcaps; -} - -static gboolean -gst_pylon_src_is_bayer (GstStructure * st) -{ - gboolean is_bayer = FALSE; - - g_return_val_if_fail (st, FALSE); - - if (0 == g_strcmp0 (gst_structure_get_name (st), "video/x-bayer")) { - is_bayer = TRUE; - } - return is_bayer; -} - -/* called if, in negotiation, caps need fixating */ -static GstCaps * -gst_pylon_src_fixate (GstBaseSrc * src, GstCaps * caps) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GstCaps *outcaps = NULL; - GstStructure *st = NULL; - const GValue *width_field = NULL; - static const gint width_1080p = 1920; - static const gint height_1080p = 1080; - static const gint preferred_framerate_num = 30; - static const gint preferred_framerate_den = 1; - gint preferred_width_adjusted = 0; - - /* get the configured width/height after applying userset and pfs */ - gint preferred_width = width_1080p; - gint preferred_height = height_1080p; - gst_pylon_get_startup_geometry (self->pylon, &preferred_width, - &preferred_height); - - GST_DEBUG_OBJECT (self, "Fixating caps %" GST_PTR_FORMAT, caps); - - if (gst_caps_is_fixed (caps)) { - GST_DEBUG_OBJECT (self, "Caps are already fixed"); - return caps; - } - - outcaps = gst_caps_new_empty (); - st = gst_structure_copy (gst_caps_get_structure (caps, 0)); - width_field = gst_structure_get_value (st, "width"); - gst_caps_unref (caps); - - if (gst_pylon_src_is_bayer (st) && GST_VALUE_HOLDS_INT_RANGE (width_field)) { - preferred_width_adjusted = - GST_ROUND_DOWN_4 (gst_value_get_int_range_max (width_field)); - } else { - preferred_width_adjusted = preferred_width; - } - - gst_structure_fixate_field_nearest_int (st, "width", - preferred_width_adjusted); - gst_structure_fixate_field_nearest_int (st, "height", preferred_height); - gst_structure_fixate_field_nearest_fraction (st, "framerate", - preferred_framerate_num, preferred_framerate_den); - - gst_caps_append_structure (outcaps, st); - - /* fixate the remainder of the fields */ - outcaps = gst_caps_fixate (outcaps); - - GST_INFO_OBJECT (self, "Fixated caps to %" GST_PTR_FORMAT, outcaps); - - return outcaps; -} - -/* notify the subclass of new caps */ -static gboolean -gst_pylon_src_set_caps (GstBaseSrc * src, GstCaps * caps) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GstStructure *st = NULL; - gint numerator = 0; - gint denominator = 0; - gint width = 0; - static const gint byte_alignment = 4; - gchar *error_msg = NULL; - GError *error = NULL; - gboolean ret = FALSE; - const gchar *action = NULL; - - GST_INFO_OBJECT (self, "Setting new caps: %" GST_PTR_FORMAT, caps); - - st = gst_caps_get_structure (caps, 0); - gst_structure_get_int (st, "width", &width); - - if (gst_pylon_src_is_bayer (st) && 0 != width % byte_alignment) { - action = "configure"; - error_msg = - g_strdup - ("Bayer formats require the width to be word aligned (4 bytes)."); - goto error; - } - - gst_structure_get_fraction (st, "framerate", &numerator, &denominator); - - GST_OBJECT_LOCK (self); - if (numerator != 0) { - self->duration = gst_util_uint64_scale (GST_SECOND, denominator, numerator); - } else { - self->duration = GST_CLOCK_TIME_NONE; - } - GST_OBJECT_UNLOCK (self); - - ret = gst_pylon_stop (self->pylon, &error); - if (FALSE == ret && error) { - action = "stop"; - goto log_error; - } - - ret = gst_pylon_set_configuration (self->pylon, caps, &error); - if (FALSE == ret && error) { - action = "configure"; - goto log_error; - } - - ret = gst_pylon_start (self->pylon, &error); - if (FALSE == ret && error) { - action = "start"; - goto log_error; - } - - ret = gst_video_info_from_caps (&self->video_info, caps); - - goto out; - -log_error: - error_msg = g_strdup (error->message); - g_error_free (error); - -error: - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to %s camera.", action), ("%s", error_msg)); - g_free (error_msg); - -out: - return ret; -} - -/* setup allocation query */ -static gboolean -gst_pylon_src_decide_allocation (GstBaseSrc * src, GstQuery * query) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - - GST_LOG_OBJECT (self, "decide_allocation"); - - return TRUE; -} - -/* start and stop processing, ideal for opening/closing the resource */ -static gboolean -gst_pylon_src_start (GstBaseSrc * src) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GError *error = NULL; - gboolean ret = TRUE; - gboolean using_pfs = FALSE; - gboolean same_device = TRUE; - - GST_OBJECT_LOCK (self); - same_device = self->pylon - && gst_pylon_is_same_device (self->pylon, self->device_index, - self->device_user_name, self->device_serial_number); - GST_OBJECT_UNLOCK (self); - - if (same_device) { - goto out; - } - - if (self->pylon) { - gst_pylon_stop (self->pylon, &error); - gst_pylon_free (self->pylon); - self->pylon = NULL; - - if (error) { - ret = FALSE; - goto log_gst_error; - } - } - - GST_OBJECT_LOCK (self); - GST_INFO_OBJECT (self, - "Attempting to create camera device with the following configuration:" - "\n\tname: %s\n\tserial number: %s\n\tindex: %d\n\tuser set: %s \n\tPFS filepath: %s. " - "If defined, the PFS file will override the user set configuration.", - self->device_user_name, self->device_serial_number, self->device_index, - self->user_set, self->pfs_location); - - self->pylon = - gst_pylon_new (GST_ELEMENT_CAST (self), self->device_user_name, - self->device_serial_number, self->device_index, &error); - GST_OBJECT_UNLOCK (self); - - if (error) { - ret = FALSE; - goto log_gst_error; - } - - GST_OBJECT_LOCK (self); - ret = gst_pylon_set_user_config (self->pylon, self->user_set, &error); - GST_OBJECT_UNLOCK (self); - - if (ret == FALSE && error) { - goto log_gst_error; - } - - GST_OBJECT_LOCK (self); - if (self->pfs_location) { - using_pfs = TRUE; - ret = gst_pylon_set_pfs_config (self->pylon, self->pfs_location, &error); - } - GST_OBJECT_UNLOCK (self); - - if (using_pfs && ret == FALSE && error) { - goto log_gst_error; - } - - self->duration = GST_CLOCK_TIME_NONE; - - goto out; - -log_gst_error: - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to start camera."), ("%s", error->message)); - g_error_free (error); - -out: - return ret; -} - -static gboolean -gst_pylon_src_stop (GstBaseSrc * src) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GError *error = NULL; - gboolean ret = TRUE; - - GST_INFO_OBJECT (self, "Stopping camera device"); - - ret = gst_pylon_stop (self->pylon, &error); - - if (ret == FALSE && error) { - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to close camera."), ("%s", error->message)); - g_error_free (error); - } - - gst_pylon_free (self->pylon); - self->pylon = NULL; - - return ret; -} - -/* unlock any pending access to the resource. subclasses should unlock - * any function ASAP. */ -static gboolean -gst_pylon_src_unlock (GstBaseSrc * src) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - - GST_LOG_OBJECT (self, "unlock"); - - gst_pylon_interrupt_capture (self->pylon); - - return TRUE; -} - -/* notify subclasses of a query */ -static gboolean -gst_pylon_src_query (GstBaseSrc * src, GstQuery * query) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - gboolean res = FALSE; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY:{ - GstClockTime min_latency = GST_CLOCK_TIME_NONE; - GstClockTime max_latency = GST_CLOCK_TIME_NONE; - - if (GST_CLOCK_TIME_NONE == self->duration) { - GST_WARNING_OBJECT (src, - "Can't report latency since framerate is not fixated yet"); - goto done; - } - - /* FIXME: we are assuming we cannot hold more than one - buffer. Eventually we want to have Pylon::StartGrabbing's - MaxNumImages extend the max_latency. - */ - max_latency = min_latency = self->duration; - - GST_DEBUG_OBJECT (self, - "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); - - gst_query_set_latency (query, TRUE, min_latency, max_latency); - - res = TRUE; - break; - } - default: - res = GST_BASE_SRC_CLASS (gst_pylon_src_parent_class)->query (src, query); - break; - } - -done: - return res; -} - -/* add time metadata to buffer */ -static void -gst_plyon_src_add_metadata (GstPylonSrc * self, GstBuffer * buf) -{ - GstClock *clock = NULL; - GstClockTime abs_time = GST_CLOCK_TIME_NONE; - GstClockTime base_time = GST_CLOCK_TIME_NONE; - GstClockTime timestamp = GST_CLOCK_TIME_NONE; - GstCaps *ref = NULL; - guint64 offset = G_GUINT64_CONSTANT (0); - GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; - GstPylonMeta *pylon_meta = NULL; - guint width = 0; - guint height = 0; - guint n_planes = 0; - gint stride[GST_VIDEO_MAX_PLANES] = { 0 }; - - g_return_if_fail (self); - g_return_if_fail (buf); - - pylon_meta = - (GstPylonMeta *) gst_buffer_get_meta (buf, GST_PYLON_META_API_TYPE); - - GST_OBJECT_LOCK (self); - /* set duration */ - GST_BUFFER_DURATION (buf) = self->duration; - - if ((clock = GST_ELEMENT_CLOCK (self))) { - /* we have a clock, get base time and ref clock */ - base_time = GST_ELEMENT (self)->base_time; - gst_object_ref (clock); - } else { - /* no clock, can't set timestamps */ - base_time = GST_CLOCK_TIME_NONE; - } - GST_OBJECT_UNLOCK (self); - - /* sample pipeline clock */ - if (clock) { - abs_time = gst_clock_get_time (clock); - gst_object_unref (clock); - } else { - abs_time = GST_CLOCK_TIME_NONE; - } - - timestamp = abs_time - base_time; - offset = pylon_meta->block_id; - - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_OFFSET (buf) = offset; - GST_BUFFER_OFFSET_END (buf) = offset + 1; - - /* add pylon timestamp as reference timestamp meta */ - ref = gst_caps_from_string ("timestamp/x-pylon"); - gst_buffer_add_reference_timestamp_meta (buf, ref, pylon_meta->timestamp, - GST_CLOCK_TIME_NONE); - gst_caps_unref (ref); - - /* add video meta data */ - format = GST_VIDEO_INFO_FORMAT (&self->video_info); - width = GST_VIDEO_INFO_WIDTH (&self->video_info); - height = GST_VIDEO_INFO_HEIGHT (&self->video_info); - n_planes = GST_VIDEO_INFO_N_PLANES (&self->video_info); - - /* assuming pylon formats come in a single plane */ - for (gint p = 0; p < n_planes; p++) { - stride[p] = pylon_meta->stride; - } - - gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, format, width, - height, n_planes, self->video_info.offset, stride); -} - -/* ask the subclass to create a buffer with offset and size, the default - * implementation will call alloc and fill. */ -static GstFlowReturn -gst_pylon_src_create (GstPushSrc * src, GstBuffer ** buf) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GError *error = NULL; - gboolean pylon_ret = TRUE; - GstFlowReturn ret = GST_FLOW_OK; - gint capture_error = -1; - - GST_OBJECT_LOCK (self); - capture_error = self->capture_error; - GST_OBJECT_UNLOCK (self); - - pylon_ret = gst_pylon_capture (self->pylon, buf, capture_error, &error); - - if (pylon_ret == FALSE) { - if (error) { - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to create buffer."), ("%s", error->message)); - g_error_free (error); - ret = GST_FLOW_ERROR; - } else { - GST_DEBUG_OBJECT (self, - "Buffer not created, user requested EOS or device connection was lost"); - ret = GST_FLOW_EOS; - } - goto done; - } - - gst_plyon_src_add_metadata (self, *buf); - - GST_LOG_OBJECT (self, "Created buffer %" GST_PTR_FORMAT, *buf); - -done: - return ret; -} - -static guint -gst_pylon_src_child_proxy_get_children_count (GstChildProxy * child_proxy) -{ - return sizeof (gst_pylon_src_child_proxy_names) / sizeof (gchar *); -} - -static GObject * -gst_pylon_src_child_proxy_get_child_by_name (GstChildProxy * - child_proxy, const gchar * name) -{ - GstPylonSrc *self = GST_PYLON_SRC (child_proxy); - GObject *obj = NULL; - - GST_DEBUG_OBJECT (self, "Looking for child \"%s\"", name); - - if (!gst_pylon_src_start (GST_BASE_SRC (self))) { - GST_ERROR_OBJECT (self, - "Please specify a camera before attempting to set Pylon device properties"); - return NULL; - } - - if (!g_strcmp0 (name, "cam")) { - GST_OBJECT_LOCK (self); - obj = gst_pylon_get_camera (self->pylon); - GST_OBJECT_UNLOCK (self); - } else if (!g_strcmp0 (name, "stream")) { - GST_OBJECT_LOCK (self); - obj = gst_pylon_get_stream_grabber (self->pylon); - GST_OBJECT_UNLOCK (self); - } else { - GST_ERROR_OBJECT (self, - "No child named \"%s\". Use \"cam\" or \"stream\" instead.", name); - } - - return obj; -} - -static GObject * -gst_pylon_src_child_proxy_get_child_by_index (GstChildProxy * child_proxy, - guint index) -{ - GstPylonSrc *self = GST_PYLON_SRC (child_proxy); - GObject *obj = NULL; - - GST_DEBUG_OBJECT (self, "Looking for child at index \"%d\"", index); - - if (index >= gst_pylon_src_child_proxy_get_children_count (child_proxy)) { - GST_ERROR_OBJECT (self, - "No child at index \"%d\". Use a valid child index instead.", index); - goto done; - } - - obj = - gst_pylon_src_child_proxy_get_child_by_name (child_proxy, - gst_pylon_src_child_proxy_names[index]); - -done: - return obj; -} - -static void -gst_pylon_src_child_proxy_init (GstChildProxyInterface * iface) -{ - iface->get_child_by_name = gst_pylon_src_child_proxy_get_child_by_name; - iface->get_child_by_index = gst_pylon_src_child_proxy_get_child_by_index; - iface->get_children_count = gst_pylon_src_child_proxy_get_children_count; -} diff --git a/ext/pylon/gstpylonsrc.cpp b/ext/pylon/gstpylonsrc.cpp new file mode 100644 index 0000000..8b0147c --- /dev/null +++ b/ext/pylon/gstpylonsrc.cpp @@ -0,0 +1,953 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * SECTION:element-gstpylonsrc + * + * The pylonsrc element captures images from Basler cameras. + * + * + * Example launch line + * |[ + * gst-launch-1.0 -v pylonsrc ! videoconvert ! autovideosink + * ]| + * Capture images from a Basler camera and display them. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gst/pylon/gstpylondebug.h" +#include "gst/pylon/gstpylonmeta.h" +#include "gstpylon.h" +#include "gstpylonsrc.h" + +#include + +struct _GstPylonSrc { + GstPushSrc base_pylonsrc; + GstPylon *pylon; + GstClockTime duration; + GstVideoInfo video_info; + + gchar *device_user_name; + gchar *device_serial_number; + gint device_index; + gchar *user_set; + gchar *pfs_location; + GstPylonCaptureErrorEnum capture_error; + GObject *cam; + GObject *stream; +}; + +/* prototypes */ + +static void gst_pylon_src_set_property(GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec); +static void gst_pylon_src_get_property(GObject *object, guint property_id, + GValue *value, GParamSpec *pspec); +static void gst_pylon_src_finalize(GObject *object); + +static GstCaps *gst_pylon_src_get_caps(GstBaseSrc *src, GstCaps *filter); +static gboolean gst_pylon_src_is_bayer(GstStructure *st); +static GstCaps *gst_pylon_src_fixate(GstBaseSrc *src, GstCaps *caps); +static gboolean gst_pylon_src_set_caps(GstBaseSrc *src, GstCaps *caps); +static gboolean gst_pylon_src_decide_allocation(GstBaseSrc *src, + GstQuery *query); +static gboolean gst_pylon_src_start(GstBaseSrc *src); +static gboolean gst_pylon_src_stop(GstBaseSrc *src); +static gboolean gst_pylon_src_unlock(GstBaseSrc *src); +static gboolean gst_pylon_src_query(GstBaseSrc *src, GstQuery *query); +static void gst_plyon_src_add_metadata(GstPylonSrc *self, GstBuffer *buf); +static GstFlowReturn gst_pylon_src_create(GstPushSrc *src, GstBuffer **buf); + +static void gst_pylon_src_child_proxy_init(GstChildProxyInterface *iface); + +enum { + PROP_0, + PROP_DEVICE_USER_NAME, + PROP_DEVICE_SERIAL_NUMBER, + PROP_DEVICE_INDEX, + PROP_USER_SET, + PROP_PFS_LOCATION, + PROP_CAPTURE_ERROR, + PROP_CAM, + PROP_STREAM +}; + +#define PROP_DEVICE_USER_NAME_DEFAULT NULL +#define PROP_DEVICE_SERIAL_NUMBER_DEFAULT NULL +#define PROP_DEVICE_INDEX_DEFAULT -1 +#define PROP_DEVICE_INDEX_MIN -1 +#define PROP_DEVICE_INDEX_MAX G_MAXINT32 +#define PROP_USER_SET_DEFAULT NULL +#define PROP_PFS_LOCATION_DEFAULT NULL +#define PROP_CAM_DEFAULT NULL +#define PROP_STREAM_DEFAULT NULL +#define PROP_CAPTURE_ERROR_DEFAULT ENUM_ABORT + +/* Enum for cature_error */ +#define GST_TYPE_CAPTURE_ERROR_ENUM (gst_pylon_capture_error_enum_get_type()) + +/* Child proxy interface names */ +static const gchar *gst_pylon_src_child_proxy_names[] = {"cam", "stream"}; + +static GType gst_pylon_capture_error_enum_get_type(void) { + static gsize gtype = 0; + static const GEnumValue values[] = { + {ENUM_KEEP, "keep", "Use partial or corrupt buffers"}, + {ENUM_SKIP, "skip", + "Skip partial or corrupt buffers. A maximum of 100 buffers can be " + "skipped before the pipeline aborts."}, + {ENUM_ABORT, "abort", "Stop pipeline in case of any capture error"}, + {0, NULL, NULL}}; + + if (g_once_init_enter(>ype)) { + GType tmp = g_enum_register_static("GstPylonCaptureErrorEnum", values); + g_once_init_leave(>ype, tmp); + } + + return (GType)gtype; +} + +/* pad templates */ + +static GstStaticPadTemplate gst_pylon_src_src_template = + GST_STATIC_PAD_TEMPLATE( + "src", GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS(GST_VIDEO_CAPS_MAKE( + " {GRAY8, RGB, BGR, YUY2, UYVY} ") ";" + "video/" + "x-bayer,format={rggb,bggr,gbgr," + "grgb}," + "width=" GST_VIDEO_SIZE_RANGE + ",height=" GST_VIDEO_SIZE_RANGE + ",framerate" + "=" GST_VIDEO_FPS_RANGE)); + +/* class initialization */ +G_DEFINE_TYPE_WITH_CODE(GstPylonSrc, gst_pylon_src, GST_TYPE_PUSH_SRC, + gst_pylon_debug_init(); + G_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY, + gst_pylon_src_child_proxy_init)); + +static void gst_pylon_src_class_init(GstPylonSrcClass *klass) { + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS(klass); + GstPushSrcClass *push_src_class = GST_PUSH_SRC_CLASS(klass); + gchar *cam_params = NULL; + gchar *cam_blurb = NULL; + gchar *stream_params = NULL; + gchar *stream_blurb = NULL; + const gchar *cam_prolog = NULL; + const gchar *stream_prolog = NULL; + + gst_pylon_initialize(); + + /* Setting up pads and setting metadata should be moved to + base_class_init if you intend to subclass this class. */ + gst_element_class_add_static_pad_template(GST_ELEMENT_CLASS(klass), + &gst_pylon_src_src_template); + + gst_element_class_set_static_metadata( + GST_ELEMENT_CLASS(klass), "Basler/Pylon source element", + "Source/Video/Hardware", "Source element for Basler cameras", + "Basler AG "); + + gobject_class->set_property = gst_pylon_src_set_property; + gobject_class->get_property = gst_pylon_src_get_property; + gobject_class->finalize = gst_pylon_src_finalize; + + g_object_class_install_property( + gobject_class, PROP_DEVICE_USER_NAME, + g_param_spec_string( + "device-user-name", "Device user defined name", + "The user-defined name of the device to use. May be combined" + "with other device selection properties to reduce the search.", + PROP_DEVICE_USER_NAME_DEFAULT, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + g_object_class_install_property( + gobject_class, PROP_DEVICE_SERIAL_NUMBER, + g_param_spec_string( + "device-serial-number", "Device serial number", + "The serial number of the device to use. May be combined with " + "other device selection properties to reduce the search.", + PROP_DEVICE_SERIAL_NUMBER_DEFAULT, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + g_object_class_install_property( + gobject_class, PROP_DEVICE_INDEX, + g_param_spec_int( + "device-index", "Device index", + "The index of the device to use.This index applies to the " + "resulting device list after applying the other device selection " + "properties. The index is mandatory if multiple devices match " + "the given search criteria.", + PROP_DEVICE_INDEX_MIN, PROP_DEVICE_INDEX_MAX, + PROP_DEVICE_INDEX_DEFAULT, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + g_object_class_install_property( + gobject_class, PROP_USER_SET, + g_param_spec_string( + "user-set", "Device user configuration set", + "The user-defined configuration set to use. Leaving this property " + "unset, or using 'Auto' result in selecting the " + "power-on default camera configuration.", + PROP_USER_SET_DEFAULT, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + g_object_class_install_property( + gobject_class, PROP_PFS_LOCATION, + g_param_spec_string( + "pfs-location", "PFS file location", + "The filepath to the PFS file from which to load the device " + "configuration. " + "Setting this property will override the user set property if also " + "set.", + PROP_PFS_LOCATION_DEFAULT, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + g_object_class_install_property( + gobject_class, PROP_CAPTURE_ERROR, + g_param_spec_enum( + "capture-error", "Capture error strategy", + "The strategy to use in case of a camera capture error.", + GST_TYPE_CAPTURE_ERROR_ENUM, PROP_CAPTURE_ERROR_DEFAULT, + static_cast(G_PARAM_READWRITE | + GST_PARAM_CONTROLLABLE))); + + cam_params = gst_pylon_camera_get_string_properties(); + stream_params = gst_pylon_stream_grabber_get_string_properties(); + + if (NULL == cam_params) { + cam_prolog = "No valid cameras where found connected to the system."; + stream_prolog = cam_prolog; + cam_params = g_strdup(""); + stream_params = g_strdup(""); + } else { + cam_prolog = "The following list details the properties for each camera.\n"; + stream_prolog = + "The following list details the properties for each stream grabber.\n"; + } + + cam_blurb = g_strdup_printf( + "The camera to use.\n" + "\t\t\tAccording to the selected camera " + "different properties will be available.\n " + "\t\t\tThese properties can be accessed using the " + "\"cam::\" syntax.\n" + "\t\t\t%s%s", + cam_prolog, cam_params); + + g_object_class_install_property( + gobject_class, PROP_CAM, + g_param_spec_object("cam", "Camera", cam_blurb, G_TYPE_OBJECT, + G_PARAM_READABLE)); + + stream_blurb = g_strdup_printf( + "The stream grabber to use.\n" + "\t\t\tAccording to the selected stream grabber " + "different properties will be available.\n " + "\t\t\tThese properties can be accessed using the " + "\"stream::\" syntax.\n" + "\t\t\t%s%s", + stream_prolog, stream_params); + + g_object_class_install_property( + gobject_class, PROP_STREAM, + g_param_spec_object("stream", "Stream Grabber", stream_blurb, + G_TYPE_OBJECT, G_PARAM_READABLE)); + + g_free(cam_params); + g_free(stream_params); + + base_src_class->get_caps = GST_DEBUG_FUNCPTR(gst_pylon_src_get_caps); + base_src_class->fixate = GST_DEBUG_FUNCPTR(gst_pylon_src_fixate); + base_src_class->set_caps = GST_DEBUG_FUNCPTR(gst_pylon_src_set_caps); + base_src_class->decide_allocation = + GST_DEBUG_FUNCPTR(gst_pylon_src_decide_allocation); + base_src_class->start = GST_DEBUG_FUNCPTR(gst_pylon_src_start); + base_src_class->stop = GST_DEBUG_FUNCPTR(gst_pylon_src_stop); + base_src_class->unlock = GST_DEBUG_FUNCPTR(gst_pylon_src_unlock); + base_src_class->query = GST_DEBUG_FUNCPTR(gst_pylon_src_query); + + push_src_class->create = GST_DEBUG_FUNCPTR(gst_pylon_src_create); +} + +static void gst_pylon_src_init(GstPylonSrc *self) { + GstBaseSrc *base = GST_BASE_SRC(self); + + self->pylon = NULL; + self->duration = GST_CLOCK_TIME_NONE; + self->device_user_name = PROP_DEVICE_USER_NAME_DEFAULT; + self->device_serial_number = PROP_DEVICE_SERIAL_NUMBER_DEFAULT; + self->device_index = PROP_DEVICE_INDEX_DEFAULT; + self->user_set = PROP_USER_SET_DEFAULT; + self->pfs_location = PROP_PFS_LOCATION_DEFAULT; + self->capture_error = PROP_CAPTURE_ERROR_DEFAULT; + self->cam = PROP_CAM_DEFAULT; + self->stream = PROP_STREAM_DEFAULT; + gst_video_info_init(&self->video_info); + + gst_base_src_set_live(base, TRUE); + gst_base_src_set_format(base, GST_FORMAT_TIME); +} + +static void gst_pylon_src_set_property(GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) { + GstPylonSrc *self = GST_PYLON_SRC(object); + + GST_LOG_OBJECT(self, "set_property"); + + GST_OBJECT_LOCK(self); + + switch (property_id) { + case PROP_DEVICE_USER_NAME: + g_free(self->device_user_name); + self->device_user_name = g_value_dup_string(value); + break; + case PROP_DEVICE_SERIAL_NUMBER: + g_free(self->device_serial_number); + self->device_serial_number = g_value_dup_string(value); + break; + case PROP_DEVICE_INDEX: + self->device_index = g_value_get_int(value); + break; + case PROP_USER_SET: + g_free(self->user_set); + self->user_set = g_value_dup_string(value); + break; + case PROP_PFS_LOCATION: + g_free(self->pfs_location); + self->pfs_location = g_value_dup_string(value); + break; + case PROP_CAPTURE_ERROR: + self->capture_error = + static_cast(g_value_get_enum(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } + + GST_OBJECT_UNLOCK(self); +} + +static void gst_pylon_src_get_property(GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) { + GstPylonSrc *self = GST_PYLON_SRC(object); + + GST_LOG_OBJECT(self, "get_property"); + + GST_OBJECT_LOCK(self); + + switch (property_id) { + case PROP_DEVICE_USER_NAME: + g_value_set_string(value, self->device_user_name); + break; + case PROP_DEVICE_SERIAL_NUMBER: + g_value_set_string(value, self->device_serial_number); + break; + case PROP_DEVICE_INDEX: + g_value_set_int(value, self->device_index); + break; + case PROP_USER_SET: + g_value_set_string(value, self->user_set); + break; + case PROP_PFS_LOCATION: + g_value_set_string(value, self->pfs_location); + break; + case PROP_CAPTURE_ERROR: + g_value_set_enum(value, self->capture_error); + break; + case PROP_CAM: + g_value_set_object(value, self->cam); + break; + case PROP_STREAM: + g_value_set_object(value, self->stream); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } + + GST_OBJECT_UNLOCK(self); +} + +static void gst_pylon_src_finalize(GObject *object) { + GstPylonSrc *self = GST_PYLON_SRC(object); + + GST_LOG_OBJECT(self, "finalize"); + + g_free(self->device_user_name); + self->device_user_name = NULL; + + g_free(self->device_serial_number); + self->device_serial_number = NULL; + + g_free(self->user_set); + self->user_set = NULL; + + if (self->cam) { + g_object_unref(self->cam); + self->cam = NULL; + } + + if (self->stream) { + g_object_unref(self->stream); + self->stream = NULL; + } + + G_OBJECT_CLASS(gst_pylon_src_parent_class)->finalize(object); +} + +/* get caps from subclass */ +static GstCaps *gst_pylon_src_get_caps(GstBaseSrc *src, GstCaps *filter) { + GstPylonSrc *self = GST_PYLON_SRC(src); + GstCaps *outcaps = NULL; + GError *error = NULL; + + if (!self->pylon) { + outcaps = gst_pad_get_pad_template_caps(GST_BASE_SRC_PAD(self)); + GST_INFO_OBJECT( + self, + "Camera not open yet, returning src template caps %" GST_PTR_FORMAT, + outcaps); + goto out; + } + + outcaps = gst_pylon_query_configuration(self->pylon, &error); + + if (outcaps == NULL && error) { + goto log_gst_error; + } + + GST_DEBUG_OBJECT(self, "Camera returned caps %" GST_PTR_FORMAT, outcaps); + + if (filter) { + GstCaps *tmp = outcaps; + + GST_DEBUG_OBJECT(self, "Filtering with %" GST_PTR_FORMAT, filter); + + outcaps = gst_caps_intersect(outcaps, filter); + gst_caps_unref(tmp); + } + + GST_INFO_OBJECT(self, "Returning caps %" GST_PTR_FORMAT, outcaps); + + goto out; + +log_gst_error: + GST_ELEMENT_ERROR(self, LIBRARY, FAILED, ("Failed to get caps."), + ("%s", error->message)); + g_error_free(error); + +out: + return outcaps; +} + +static gboolean gst_pylon_src_is_bayer(GstStructure *st) { + gboolean is_bayer = FALSE; + + g_return_val_if_fail(st, FALSE); + + if (0 == g_strcmp0(gst_structure_get_name(st), "video/x-bayer")) { + is_bayer = TRUE; + } + return is_bayer; +} + +/* called if, in negotiation, caps need fixating */ +static GstCaps *gst_pylon_src_fixate(GstBaseSrc *src, GstCaps *caps) { + GstPylonSrc *self = GST_PYLON_SRC(src); + GstCaps *outcaps = NULL; + GstStructure *st = NULL; + const GValue *width_field = NULL; + static const gint width_1080p = 1920; + static const gint height_1080p = 1080; + static const gint preferred_framerate_num = 30; + static const gint preferred_framerate_den = 1; + gint preferred_width_adjusted = 0; + + /* get the configured width/height after applying userset and pfs */ + gint preferred_width = width_1080p; + gint preferred_height = height_1080p; + gst_pylon_get_startup_geometry(self->pylon, &preferred_width, + &preferred_height); + + GST_DEBUG_OBJECT(self, "Fixating caps %" GST_PTR_FORMAT, caps); + + if (gst_caps_is_fixed(caps)) { + GST_DEBUG_OBJECT(self, "Caps are already fixed"); + return caps; + } + + outcaps = gst_caps_new_empty(); + st = gst_structure_copy(gst_caps_get_structure(caps, 0)); + width_field = gst_structure_get_value(st, "width"); + gst_caps_unref(caps); + + if (gst_pylon_src_is_bayer(st) && GST_VALUE_HOLDS_INT_RANGE(width_field)) { + preferred_width_adjusted = + GST_ROUND_DOWN_4(gst_value_get_int_range_max(width_field)); + } else { + preferred_width_adjusted = preferred_width; + } + + gst_structure_fixate_field_nearest_int(st, "width", preferred_width_adjusted); + gst_structure_fixate_field_nearest_int(st, "height", preferred_height); + gst_structure_fixate_field_nearest_fraction( + st, "framerate", preferred_framerate_num, preferred_framerate_den); + + gst_caps_append_structure(outcaps, st); + + /* fixate the remainder of the fields */ + outcaps = gst_caps_fixate(outcaps); + + GST_INFO_OBJECT(self, "Fixated caps to %" GST_PTR_FORMAT, outcaps); + + return outcaps; +} + +/* notify the subclass of new caps */ +static gboolean gst_pylon_src_set_caps(GstBaseSrc *src, GstCaps *caps) { + GstPylonSrc *self = GST_PYLON_SRC(src); + GstStructure *st = NULL; + gint numerator = 0; + gint denominator = 0; + gint width = 0; + static const gint byte_alignment = 4; + gchar *error_msg = NULL; + GError *error = NULL; + gboolean ret = FALSE; + const gchar *action = NULL; + + GST_INFO_OBJECT(self, "Setting new caps: %" GST_PTR_FORMAT, caps); + + st = gst_caps_get_structure(caps, 0); + gst_structure_get_int(st, "width", &width); + + if (gst_pylon_src_is_bayer(st) && 0 != width % byte_alignment) { + action = "configure"; + error_msg = g_strdup( + "Bayer formats require the width to be word aligned (4 bytes)."); + goto error; + } + + gst_structure_get_fraction(st, "framerate", &numerator, &denominator); + + GST_OBJECT_LOCK(self); + if (numerator != 0) { + self->duration = gst_util_uint64_scale(GST_SECOND, denominator, numerator); + } else { + self->duration = GST_CLOCK_TIME_NONE; + } + GST_OBJECT_UNLOCK(self); + + ret = gst_pylon_stop(self->pylon, &error); + if (FALSE == ret && error) { + action = "stop"; + goto log_error; + } + + ret = gst_pylon_set_configuration(self->pylon, caps, &error); + if (FALSE == ret && error) { + action = "configure"; + goto log_error; + } + + ret = gst_pylon_start(self->pylon, &error); + if (FALSE == ret && error) { + action = "start"; + goto log_error; + } + + ret = gst_video_info_from_caps(&self->video_info, caps); + + goto out; + +log_error: + error_msg = g_strdup(error->message); + g_error_free(error); + +error: + GST_ELEMENT_ERROR(self, LIBRARY, FAILED, ("Failed to %s camera.", action), + ("%s", error_msg)); + g_free(error_msg); + +out: + return ret; +} + +/* setup allocation query */ +static gboolean gst_pylon_src_decide_allocation(GstBaseSrc *src, + GstQuery *query) { + GstPylonSrc *self = GST_PYLON_SRC(src); + + GST_LOG_OBJECT(self, "decide_allocation"); + + return TRUE; +} + +/* start and stop processing, ideal for opening/closing the resource */ +static gboolean gst_pylon_src_start(GstBaseSrc *src) { + GstPylonSrc *self = GST_PYLON_SRC(src); + GError *error = NULL; + gboolean ret = TRUE; + gboolean using_pfs = FALSE; + gboolean same_device = TRUE; + + GST_OBJECT_LOCK(self); + same_device = + self->pylon && gst_pylon_is_same_device(self->pylon, self->device_index, + self->device_user_name, + self->device_serial_number); + GST_OBJECT_UNLOCK(self); + + if (same_device) { + goto out; + } + + if (self->pylon) { + gst_pylon_stop(self->pylon, &error); + gst_pylon_free(self->pylon); + self->pylon = NULL; + + if (error) { + ret = FALSE; + goto log_gst_error; + } + } + + GST_OBJECT_LOCK(self); + GST_INFO_OBJECT( + self, + "Attempting to create camera device with the following configuration:" + "\n\tname: %s\n\tserial number: %s\n\tindex: %d\n\tuser set: %s \n\tPFS " + "filepath: %s. " + "If defined, the PFS file will override the user set configuration.", + self->device_user_name, self->device_serial_number, self->device_index, + self->user_set, self->pfs_location); + + self->pylon = + gst_pylon_new(GST_ELEMENT_CAST(self), self->device_user_name, + self->device_serial_number, self->device_index, &error); + GST_OBJECT_UNLOCK(self); + + if (error) { + ret = FALSE; + goto log_gst_error; + } + + GST_OBJECT_LOCK(self); + ret = gst_pylon_set_user_config(self->pylon, self->user_set, &error); + GST_OBJECT_UNLOCK(self); + + if (ret == FALSE && error) { + goto log_gst_error; + } + + GST_OBJECT_LOCK(self); + if (self->pfs_location) { + using_pfs = TRUE; + ret = gst_pylon_set_pfs_config(self->pylon, self->pfs_location, &error); + } + GST_OBJECT_UNLOCK(self); + + if (using_pfs && ret == FALSE && error) { + goto log_gst_error; + } + + self->duration = GST_CLOCK_TIME_NONE; + + goto out; + +log_gst_error: + GST_ELEMENT_ERROR(self, LIBRARY, FAILED, ("Failed to start camera."), + ("%s", error->message)); + g_error_free(error); + +out: + return ret; +} + +static gboolean gst_pylon_src_stop(GstBaseSrc *src) { + GstPylonSrc *self = GST_PYLON_SRC(src); + GError *error = NULL; + gboolean ret = TRUE; + + GST_INFO_OBJECT(self, "Stopping camera device"); + + ret = gst_pylon_stop(self->pylon, &error); + + if (ret == FALSE && error) { + GST_ELEMENT_ERROR(self, LIBRARY, FAILED, ("Failed to close camera."), + ("%s", error->message)); + g_error_free(error); + } + + gst_pylon_free(self->pylon); + self->pylon = NULL; + + return ret; +} + +/* unlock any pending access to the resource. subclasses should unlock + * any function ASAP. */ +static gboolean gst_pylon_src_unlock(GstBaseSrc *src) { + GstPylonSrc *self = GST_PYLON_SRC(src); + + GST_LOG_OBJECT(self, "unlock"); + + gst_pylon_interrupt_capture(self->pylon); + + return TRUE; +} + +/* notify subclasses of a query */ +static gboolean gst_pylon_src_query(GstBaseSrc *src, GstQuery *query) { + GstPylonSrc *self = GST_PYLON_SRC(src); + gboolean res = FALSE; + + switch (GST_QUERY_TYPE(query)) { + case GST_QUERY_LATENCY: { + GstClockTime min_latency = GST_CLOCK_TIME_NONE; + GstClockTime max_latency = GST_CLOCK_TIME_NONE; + + if (GST_CLOCK_TIME_NONE == self->duration) { + GST_WARNING_OBJECT( + src, "Can't report latency since framerate is not fixated yet"); + goto done; + } + + /* FIXME: we are assuming we cannot hold more than one + buffer. Eventually we want to have Pylon::StartGrabbing's + MaxNumImages extend the max_latency. + */ + max_latency = min_latency = self->duration; + + GST_DEBUG_OBJECT( + self, "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, + GST_TIME_ARGS(min_latency), GST_TIME_ARGS(max_latency)); + + gst_query_set_latency(query, TRUE, min_latency, max_latency); + + res = TRUE; + break; + } + default: + res = GST_BASE_SRC_CLASS(gst_pylon_src_parent_class)->query(src, query); + break; + } + +done: + return res; +} + +/* add time metadata to buffer */ +static void gst_plyon_src_add_metadata(GstPylonSrc *self, GstBuffer *buf) { + GstClock *clock = NULL; + GstClockTime abs_time = GST_CLOCK_TIME_NONE; + GstClockTime base_time = GST_CLOCK_TIME_NONE; + GstClockTime timestamp = GST_CLOCK_TIME_NONE; + GstCaps *ref = NULL; + guint64 offset = G_GUINT64_CONSTANT(0); + GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; + GstPylonMeta *pylon_meta = NULL; + guint width = 0; + guint height = 0; + guint n_planes = 0; + gint stride[GST_VIDEO_MAX_PLANES] = {0}; + + g_return_if_fail(self); + g_return_if_fail(buf); + + pylon_meta = + (GstPylonMeta *)gst_buffer_get_meta(buf, GST_PYLON_META_API_TYPE); + + GST_OBJECT_LOCK(self); + /* set duration */ + GST_BUFFER_DURATION(buf) = self->duration; + + if ((clock = GST_ELEMENT_CLOCK(self))) { + /* we have a clock, get base time and ref clock */ + base_time = GST_ELEMENT(self)->base_time; + gst_object_ref(clock); + } else { + /* no clock, can't set timestamps */ + base_time = GST_CLOCK_TIME_NONE; + } + GST_OBJECT_UNLOCK(self); + + /* sample pipeline clock */ + if (clock) { + abs_time = gst_clock_get_time(clock); + gst_object_unref(clock); + } else { + abs_time = GST_CLOCK_TIME_NONE; + } + + timestamp = abs_time - base_time; + offset = pylon_meta->block_id; + + GST_BUFFER_TIMESTAMP(buf) = timestamp; + GST_BUFFER_OFFSET(buf) = offset; + GST_BUFFER_OFFSET_END(buf) = offset + 1; + + /* add pylon timestamp as reference timestamp meta */ + ref = gst_caps_from_string("timestamp/x-pylon"); + gst_buffer_add_reference_timestamp_meta(buf, ref, pylon_meta->timestamp, + GST_CLOCK_TIME_NONE); + gst_caps_unref(ref); + + /* add video meta data */ + format = GST_VIDEO_INFO_FORMAT(&self->video_info); + width = GST_VIDEO_INFO_WIDTH(&self->video_info); + height = GST_VIDEO_INFO_HEIGHT(&self->video_info); + n_planes = GST_VIDEO_INFO_N_PLANES(&self->video_info); + + /* assuming pylon formats come in a single plane */ + for (guint p = 0; p < n_planes; p++) { + stride[p] = pylon_meta->stride; + } + + gst_buffer_add_video_meta_full(buf, GST_VIDEO_FRAME_FLAG_NONE, format, width, + height, n_planes, self->video_info.offset, + stride); +} + +/* ask the subclass to create a buffer with offset and size, the default + * implementation will call alloc and fill. */ +static GstFlowReturn gst_pylon_src_create(GstPushSrc *src, GstBuffer **buf) { + GstPylonSrc *self = GST_PYLON_SRC(src); + GError *error = NULL; + gboolean pylon_ret = TRUE; + GstFlowReturn ret = GST_FLOW_OK; + gint capture_error = -1; + + GST_OBJECT_LOCK(self); + capture_error = self->capture_error; + GST_OBJECT_UNLOCK(self); + + pylon_ret = gst_pylon_capture( + self->pylon, buf, static_cast(capture_error), + &error); + + if (pylon_ret == FALSE) { + if (error) { + GST_ELEMENT_ERROR(self, LIBRARY, FAILED, ("Failed to create buffer."), + ("%s", error->message)); + g_error_free(error); + ret = GST_FLOW_ERROR; + } else { + GST_DEBUG_OBJECT(self, + "Buffer not created, user requested EOS or device " + "connection was lost"); + ret = GST_FLOW_EOS; + } + goto done; + } + + gst_plyon_src_add_metadata(self, *buf); + + GST_LOG_OBJECT(self, "Created buffer %" GST_PTR_FORMAT, *buf); + +done: + return ret; +} + +static guint gst_pylon_src_child_proxy_get_children_count( + GstChildProxy *child_proxy) { + return sizeof(gst_pylon_src_child_proxy_names) / sizeof(gchar *); +} + +static GObject *gst_pylon_src_child_proxy_get_child_by_name( + GstChildProxy *child_proxy, const gchar *name) { + GstPylonSrc *self = GST_PYLON_SRC(child_proxy); + GObject *obj = NULL; + + GST_DEBUG_OBJECT(self, "Looking for child \"%s\"", name); + + if (!gst_pylon_src_start(GST_BASE_SRC(self))) { + GST_ERROR_OBJECT(self, + "Please specify a camera before attempting to set Pylon " + "device properties"); + return NULL; + } + + if (!g_strcmp0(name, "cam")) { + GST_OBJECT_LOCK(self); + obj = gst_pylon_get_camera(self->pylon); + GST_OBJECT_UNLOCK(self); + } else if (!g_strcmp0(name, "stream")) { + GST_OBJECT_LOCK(self); + obj = gst_pylon_get_stream_grabber(self->pylon); + GST_OBJECT_UNLOCK(self); + } else { + GST_ERROR_OBJECT( + self, "No child named \"%s\". Use \"cam\" or \"stream\" instead.", + name); + } + + return obj; +} + +static GObject *gst_pylon_src_child_proxy_get_child_by_index( + GstChildProxy *child_proxy, guint index) { + GstPylonSrc *self = GST_PYLON_SRC(child_proxy); + GObject *obj = NULL; + + GST_DEBUG_OBJECT(self, "Looking for child at index \"%d\"", index); + + if (index >= gst_pylon_src_child_proxy_get_children_count(child_proxy)) { + GST_ERROR_OBJECT( + self, "No child at index \"%d\". Use a valid child index instead.", + index); + goto done; + } + + obj = gst_pylon_src_child_proxy_get_child_by_name( + child_proxy, gst_pylon_src_child_proxy_names[index]); + +done: + return obj; +} + +static void gst_pylon_src_child_proxy_init(GstChildProxyInterface *iface) { + iface->get_child_by_name = gst_pylon_src_child_proxy_get_child_by_name; + iface->get_child_by_index = gst_pylon_src_child_proxy_get_child_by_index; + iface->get_children_count = gst_pylon_src_child_proxy_get_children_count; +} diff --git a/ext/pylon/meson.build b/ext/pylon/meson.build index c4df305..014824e 100644 --- a/ext/pylon/meson.build +++ b/ext/pylon/meson.build @@ -1,7 +1,7 @@ pylon_sources = [ - 'gstpylonsrc.c', - 'gstpylonplugin.c', + 'gstpylonsrc.cpp', + 'gstpylonplugin.cpp', 'gstchildinspector.cpp', 'gstpylon.cpp', 'gstpylonimagehandler.cpp', diff --git a/hooks/cpp-format b/hooks/cpp-format index 10832f9..57740e4 100755 --- a/hooks/cpp-format +++ b/hooks/cpp-format @@ -22,6 +22,7 @@ fi CLANG_INDENT_STYLE="{ BasedOnStyle: Google, IncludeBlocks: Regroup, + IndentPPDirectives: AfterHash, IncludeCategories: [ { Regex: '^', diff --git a/hooks/gst-indent b/hooks/gst-indent deleted file mode 100755 index d4ef9b6..0000000 --- a/hooks/gst-indent +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -# -# Format code with a consistent code style -# - -file=$1 - -if [ "$file" = "" ]; then - echo "Please specify the file to indent, run as:" - echo " gst-indent " - exit 1 -fi - -version=`gnuindent --version 2>/dev/null` -if test "x$version" = "x"; then - version=`gindent --version 2>/dev/null` - if test "x$version" = "x"; then - version=`indent --version 2>/dev/null` - if test "x$version" = "x"; then - echo "GStreamer git pre-commit hook:" - echo "Did not find GNU indent, please install it before continuing." - exit 1 - else - GNU_INDENT=indent - fi - else - GNU_INDENT=gindent - fi -else - GNU_INDENT=gnuindent -fi - -case `$GNU_INDENT --version` in - GNU*) - ;; - default) - echo "GStreamer git pre-commit hook:" - echo "Did not find GNU indent, please install it before continuing." - echo "(Found $GNU_INDENT, but it doesn't seem to be GNU indent)" - exit 1 - ;; -esac - -GNU_INDENT_PARAMETERS="--braces-on-if-line \ - --case-brace-indentation0 \ - --case-indentation2 \ - --braces-after-struct-decl-line \ - --line-length80 \ - --no-tabs \ - --cuddle-else \ - --dont-line-up-parentheses \ - --continuation-indentation4 \ - --honour-newlines \ - --tab-size8 \ - --indent-level2 \ - --leave-preprocessor-space" - -echo "--Formatting ${file}--" -eval ${GNU_INDENT} ${GNU_INDENT_PARAMETERS} ${file} \ No newline at end of file diff --git a/hooks/pre-commit.hook b/hooks/pre-commit.hook index f1e7629..724b47c 100755 --- a/hooks/pre-commit.hook +++ b/hooks/pre-commit.hook @@ -8,7 +8,7 @@ # so check for that first. echo "--Checking style--" -for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep -e "\.c$" -e "\.cpp$"` ; do +for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep -e "\.h$" -e "\.cpp$"` ; do # nf is the temporary checkout. This makes sure we check against the # revision in the index (and not the checked out version). nf=`git checkout-index --temp ${file} | cut -f 1` @@ -16,17 +16,9 @@ for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep - touch "/tmp/$newfile_name" || exit 1 newfile="/tmp/$newfile_name" - #Check if file is a .cpp file - echo $file | grep -e "\.cpp$" - found_cpp=$? - cp "${nf}" "${newfile}" - if [ $found_cpp = 0 ] ; then - INDENT="hooks/cpp-format" - else - INDENT="hooks/gst-indent" - fi + INDENT="hooks/cpp-format" eval ${INDENT} $newfile 2>> /dev/null @@ -39,13 +31,9 @@ echo "========================================================================== echo " Code style error in: $file " echo " " echo " Please fix before committing. Don't forget to run git add before trying to commit again. " -echo " If the whole file is to be committed, run as (scripts may be found in hooks/): " -echo " " -echo " gst-indent $file; git add $file; git commit" -echo " " -echo " If the file is a .cpp file: " +echo " If the whole file is to be committed, run as : " echo " " -echo " cpp-format $file; git add $file; git commit" +echo " hooks/cpp-format $file; git add $file; git commit" echo " " echo "=================================================================================================" exit 1 From 4669c91a5c9bd041394d4ab5d9386d866617d1aa Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Tue, 14 Feb 2023 12:42:53 +0100 Subject: [PATCH 076/126] limit symbol visibility on c++ libs --- bindings/include/bindaccessfunctions.h | 9 +++++++++ bindings/include/bindpylonmeta.h | 7 ++++++- bindings/include/pygstpylon.h | 7 ++++++- bindings/meson.build | 1 + ext/pylon/gstchildinspector.h | 13 +++++-------- ext/pylon/gstpylon.h | 4 ---- ext/pylon/meson.build | 1 + gst-libs/gst/pylon/gstpylonmetaprivate.h | 4 ---- gst-libs/gst/pylon/gstpylonobject.h | 4 ---- gst-libs/gst/pylon/gstpylonparamspecs.h | 16 +++++----------- gst-libs/gst/pylon/meson.build | 1 + meson.build | 2 +- 12 files changed, 35 insertions(+), 34 deletions(-) diff --git a/bindings/include/bindaccessfunctions.h b/bindings/include/bindaccessfunctions.h index 53fee7c..1b23b77 100644 --- a/bindings/include/bindaccessfunctions.h +++ b/bindings/include/bindaccessfunctions.h @@ -32,8 +32,17 @@ #ifndef BINDACCESSFUNCTIONS_H #define BINDACCESSFUNCTIONS_H +#if __GNUC__ // GCC, CLANG, MinGW +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + #include +#if __GNUC__ // GCC, CLANG, MinWG +# pragma GCC diagnostic pop +#endif + namespace py = pybind11; namespace pygstpylon { void bindaccessfunctions(py::module &m); diff --git a/bindings/include/bindpylonmeta.h b/bindings/include/bindpylonmeta.h index 084ea73..2f3c662 100644 --- a/bindings/include/bindpylonmeta.h +++ b/bindings/include/bindpylonmeta.h @@ -33,10 +33,15 @@ #ifndef BINDPYLONMETA_H #define BINDPYLONMETA_H +#if __GNUC__ // GCC, CLANG, MinGW +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + #include #if __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif namespace py = pybind11; diff --git a/bindings/include/pygstpylon.h b/bindings/include/pygstpylon.h index 0ec9410..c2b5716 100644 --- a/bindings/include/pygstpylon.h +++ b/bindings/include/pygstpylon.h @@ -33,10 +33,15 @@ #ifndef PYGSTPYLON_H #define PYGSTPYLON_H +#if __GNUC__ // GCC, CLANG, MinGW +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + #include #if __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif namespace py = pybind11; diff --git a/bindings/meson.build b/bindings/meson.build index 25a07f3..6418182 100644 --- a/bindings/meson.build +++ b/bindings/meson.build @@ -29,6 +29,7 @@ pymeta = py3.extension_module('pygstpylon', install : true, cpp_args: ['-DHAVE_CONFIG_H=1'], include_directories : [configinc, incdir], + gnu_symbol_visibility: 'inlineshidden', dependencies : pygstpylon_deps, ) diff --git a/ext/pylon/gstchildinspector.h b/ext/pylon/gstchildinspector.h index e8522b9..c01d3d4 100644 --- a/ext/pylon/gstchildinspector.h +++ b/ext/pylon/gstchildinspector.h @@ -35,13 +35,10 @@ #include -G_BEGIN_DECLS - -gchar *gst_child_inspector_property_to_string (GObject * object, - GParamSpec * param, guint alignment); -gchar *gst_child_inspector_properties_to_string (GObject * object, - guint alignment, gchar * title); - -G_END_DECLS +gchar *gst_child_inspector_property_to_string(GObject *object, + GParamSpec *param, + guint alignment); +gchar *gst_child_inspector_properties_to_string(GObject *object, + guint alignment, gchar *title); #endif /* __GST_CHILD_INSPECTOR_H__ */ diff --git a/ext/pylon/gstpylon.h b/ext/pylon/gstpylon.h index 97afba5..efcd810 100644 --- a/ext/pylon/gstpylon.h +++ b/ext/pylon/gstpylon.h @@ -36,8 +36,6 @@ #include #include -G_BEGIN_DECLS - typedef struct _GstPylon GstPylon; typedef enum { @@ -78,6 +76,4 @@ gboolean gst_pylon_is_same_device(GstPylon *self, const gint device_index, const gchar *device_user_name, const gchar *device_serial_number); -G_END_DECLS - #endif diff --git a/ext/pylon/meson.build b/ext/pylon/meson.build index 014824e..5944f53 100644 --- a/ext/pylon/meson.build +++ b/ext/pylon/meson.build @@ -14,6 +14,7 @@ gstpylon_plugin = library('gstpylon', cpp_args : gst_plugin_pylon_args, link_args : [noseh_link_args], include_directories : [configinc], + gnu_symbol_visibility: 'inlineshidden', dependencies : [gstpylon_dep], install : true, install_dir : plugins_install_dir diff --git a/gst-libs/gst/pylon/gstpylonmetaprivate.h b/gst-libs/gst/pylon/gstpylonmetaprivate.h index 4523c06..45c28ee 100644 --- a/gst-libs/gst/pylon/gstpylonmetaprivate.h +++ b/gst-libs/gst/pylon/gstpylonmetaprivate.h @@ -38,12 +38,8 @@ #include #include -G_BEGIN_DECLS - EXT_PYLONSRC_API void gst_buffer_add_pylon_meta( GstBuffer *buffer, const Pylon::CBaslerUniversalGrabResultPtr &grab_result_ptr); -G_END_DECLS - #endif diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index 3dba979..540dcdd 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -37,8 +37,6 @@ #include #include -G_BEGIN_DECLS - G_DECLARE_DERIVABLE_TYPE(GstPylonObject, gst_pylon_object, GST, PYLON_OBJECT, GstObject) @@ -57,6 +55,4 @@ void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, const gchar* selector_name, gint64& selector_value); -G_END_DECLS - #endif diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.h b/gst-libs/gst/pylon/gstpylonparamspecs.h index 37a1f7a..31de9a9 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.h +++ b/gst-libs/gst/pylon/gstpylonparamspecs.h @@ -33,12 +33,9 @@ #ifndef __GST_PYLON_PARAM_SPECS_H__ #define __GST_PYLON_PARAM_SPECS_H__ -#include - #include "gst/pylon/gstpylonincludes.h" - -G_BEGIN_DECLS +#include /* Set flag for features with selectors */ #define GST_PYLON_PARAM_IS_SELECTOR (1 << (G_PARAM_USER_SHIFT + 1)) @@ -93,12 +90,9 @@ GParamSpec* gst_pylon_param_spec_selector_enum( std::string gst_pylon_param_spec_sanitize_name(const gchar* name); GstPylonParamSpecSelectorData* gst_pylon_param_spec_selector_get_data( GParamSpec* spec); -gchar *gst_pylon_create_selected_name(GenApi::INodeMap &nodemap, - const gchar *feature_name, - const gchar *selector_name, - guint64 selector_value); - - -G_END_DECLS +gchar* gst_pylon_create_selected_name(GenApi::INodeMap& nodemap, + const gchar* feature_name, + const gchar* selector_name, + guint64 selector_value); #endif /* __GST_PYLON_PARAM_SPECS_H__ */ diff --git a/gst-libs/gst/pylon/meson.build b/gst-libs/gst/pylon/meson.build index 1d5ba31..a944bbc 100644 --- a/gst-libs/gst/pylon/meson.build +++ b/gst-libs/gst/pylon/meson.build @@ -56,6 +56,7 @@ gstpylon = library('gstpylon-' + api_version, c_args : gst_plugin_pylon_args + '-DBUILDING_EXT_PYLONSRC', cpp_args : gst_plugin_pylon_args + '-DBUILDING_EXT_PYLONSRC', link_args : [noseh_link_args, pylon_link_args], + gnu_symbol_visibility: 'inlineshidden', include_directories : [configinc], dependencies : [gstbase_dep, gstvideo_dep, pylon_dep], install : true, diff --git a/meson.build b/meson.build index d64168e..6cef2e7 100644 --- a/meson.build +++ b/meson.build @@ -136,7 +136,7 @@ cdata.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('local if cc.get_id() == 'msvc' export_define = '__declspec(dllexport) extern' elif cc.has_argument('-fvisibility=hidden') - add_project_arguments('-fvisibility=hidden', language: 'c') + add_project_arguments('-fvisibility=hidden', language: 'cpp') export_define = 'extern __attribute__ ((visibility ("default")))' else export_define = 'extern' From dcf85082b0675c5ce887a3186ca0f672434c7e0f Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Tue, 14 Feb 2023 14:39:43 +0100 Subject: [PATCH 077/126] reformatting with cpp-format --- ext/pylon/gstchildinspector.cpp | 2 +- ext/pylon/gstpylon.cpp | 2 +- ext/pylon/gstpylondisconnecthandler.cpp | 2 +- ext/pylon/gstpylonsrc.h | 5 ++--- gst-libs/gst/pylon/gstpylon-prelude.h | 23 +++++++++----------- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 2 +- gst-libs/gst/pylon/gstpylonincludes.h | 22 +++++++++---------- gst-libs/gst/pylon/gstpylonintrospection.cpp | 2 +- gst-libs/gst/pylon/gstpylonmeta.cpp | 2 +- gst-libs/gst/pylon/gstpylonmeta.h | 13 +++++------ gst-libs/gst/pylon/gstpylonobject.cpp | 2 +- gst-libs/gst/pylon/gstpylonparamspecs.cpp | 2 +- 12 files changed, 36 insertions(+), 43 deletions(-) diff --git a/ext/pylon/gstchildinspector.cpp b/ext/pylon/gstchildinspector.cpp index 93d3d30..201a0a0 100644 --- a/ext/pylon/gstchildinspector.cpp +++ b/ext/pylon/gstchildinspector.cpp @@ -31,7 +31,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gst/pylon/gstpylondebug.h" diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 48f9c4b..61630a3 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -31,7 +31,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gst/pylon/gstpyloncache.h" diff --git a/ext/pylon/gstpylondisconnecthandler.cpp b/ext/pylon/gstpylondisconnecthandler.cpp index 43695a4..f061e09 100644 --- a/ext/pylon/gstpylondisconnecthandler.cpp +++ b/ext/pylon/gstpylondisconnecthandler.cpp @@ -31,7 +31,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gst/pylon/gstpylondebug.h" diff --git a/ext/pylon/gstpylonsrc.h b/ext/pylon/gstpylonsrc.h index 8b24b5d..b949bbf 100644 --- a/ext/pylon/gstpylonsrc.h +++ b/ext/pylon/gstpylonsrc.h @@ -37,9 +37,8 @@ G_BEGIN_DECLS -#define GST_TYPE_PYLON_SRC gst_pylon_src_get_type () -G_DECLARE_FINAL_TYPE (GstPylonSrc, gst_pylon_src, - GST, PYLON_SRC, GstPushSrc) +#define GST_TYPE_PYLON_SRC gst_pylon_src_get_type() +G_DECLARE_FINAL_TYPE(GstPylonSrc, gst_pylon_src, GST, PYLON_SRC, GstPushSrc) G_END_DECLS diff --git a/gst-libs/gst/pylon/gstpylon-prelude.h b/gst-libs/gst/pylon/gstpylon-prelude.h index 51a2359..8f14674 100644 --- a/gst-libs/gst/pylon/gstpylon-prelude.h +++ b/gst-libs/gst/pylon/gstpylon-prelude.h @@ -37,22 +37,19 @@ /* backport definition to support ubuntu 18.04 */ #ifndef GST_API_IMPORT -# if defined(_MSC_VER) && !defined(GST_STATIC_COMPILATION) -# define GST_API_IMPORT __declspec(dllimport) extern -# else -# define GST_API_IMPORT extern -# endif +# if defined(_MSC_VER) && !defined(GST_STATIC_COMPILATION) +# define GST_API_IMPORT __declspec(dllimport) extern +# else +# define GST_API_IMPORT extern +# endif #endif - - - #ifndef EXT_PYLONSRC_API -# ifdef BUILDING_EXT_PYLONSRC -# define EXT_PYLONSRC_API GST_API_EXPORT /* from config.h */ -# else -# define EXT_PYLONSRC_API GST_API_IMPORT -# endif +# ifdef BUILDING_EXT_PYLONSRC +# define EXT_PYLONSRC_API GST_API_EXPORT /* from config.h */ +# else +# define EXT_PYLONSRC_API GST_API_IMPORT +# endif #endif #endif /* __GST_PYLON_PRELUDE_H__ */ diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index b0e5c3b..a7e0a6f 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -31,7 +31,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gstpylondebug.h" diff --git a/gst-libs/gst/pylon/gstpylonincludes.h b/gst-libs/gst/pylon/gstpylonincludes.h index 364b4c3..d0e09ee 100644 --- a/gst-libs/gst/pylon/gstpylonincludes.h +++ b/gst-libs/gst/pylon/gstpylonincludes.h @@ -2,25 +2,25 @@ #define GST_PYLON_INCLUDES_H #ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) +# pragma warning(push) +# pragma warning(disable : 4265) #elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#pragma GCC diagnostic ignored "-Wunused-variable" -#ifdef __clang__ -#pragma GCC diagnostic ignored "-Wunknown-warning-option" -#endif +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +# pragma GCC diagnostic ignored "-Woverloaded-virtual" +# pragma GCC diagnostic ignored "-Wunused-variable" +# ifdef __clang__ +# pragma GCC diagnostic ignored "-Wunknown-warning-option" +# endif #endif #include #include #ifdef _MSC_VER // MSVC -#pragma warning(pop) +# pragma warning(pop) #elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif #endif diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 5a00c6d..4e96e46 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -31,7 +31,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gstpylondebug.h" diff --git a/gst-libs/gst/pylon/gstpylonmeta.cpp b/gst-libs/gst/pylon/gstpylonmeta.cpp index 0bc8906..d0ede81 100644 --- a/gst-libs/gst/pylon/gstpylonmeta.cpp +++ b/gst-libs/gst/pylon/gstpylonmeta.cpp @@ -31,7 +31,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gstpylondebug.h" diff --git a/gst-libs/gst/pylon/gstpylonmeta.h b/gst-libs/gst/pylon/gstpylonmeta.h index 06ac682..063a7b4 100644 --- a/gst-libs/gst/pylon/gstpylonmeta.h +++ b/gst-libs/gst/pylon/gstpylonmeta.h @@ -43,14 +43,12 @@ G_BEGIN_DECLS typedef struct _GstPylonOffset GstPylonOffset; typedef struct _GstPylonMeta GstPylonMeta; -struct _GstPylonOffset -{ +struct _GstPylonOffset { guint64 offset_x; guint64 offset_y; }; -struct _GstPylonMeta -{ +struct _GstPylonMeta { GstMeta meta; GstStructure *chunks; @@ -62,10 +60,9 @@ struct _GstPylonMeta gsize stride; }; -EXT_PYLONSRC_API GType gst_pylon_meta_api_get_type (void); -EXT_PYLONSRC_API const GstMetaInfo *gst_pylon_meta_get_info (void); -EXT_PYLONSRC_API GstPylonMeta * gst_buffer_get_pylon_meta (GstBuffer * buffer); - +EXT_PYLONSRC_API GType gst_pylon_meta_api_get_type(void); +EXT_PYLONSRC_API const GstMetaInfo *gst_pylon_meta_get_info(void); +EXT_PYLONSRC_API GstPylonMeta *gst_buffer_get_pylon_meta(GstBuffer *buffer); G_END_DECLS #endif diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index edc7b68..756b4f6 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -31,7 +31,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gstpylondebug.h" diff --git a/gst-libs/gst/pylon/gstpylonparamspecs.cpp b/gst-libs/gst/pylon/gstpylonparamspecs.cpp index b412f48..0bd9707 100644 --- a/gst-libs/gst/pylon/gstpylonparamspecs.cpp +++ b/gst-libs/gst/pylon/gstpylonparamspecs.cpp @@ -31,7 +31,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gstpylondebug.h" From 3f4cf686b8c005dc348a54a1bb842e9bfbfca573 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Tue, 14 Feb 2023 14:40:21 +0100 Subject: [PATCH 078/126] Reformatting of remaining c files with cpp-format even if the clang-format definitions are targeting c++ this will limit the project to one formatting tool --- tests/examples/pylon/list_properties.c | 184 +++++++++----------- tests/examples/pylon/pylonsrc.c | 141 +++++++-------- tests/examples/pylon/show_meta.c | 229 ++++++++++++------------- 3 files changed, 257 insertions(+), 297 deletions(-) diff --git a/tests/examples/pylon/list_properties.c b/tests/examples/pylon/list_properties.c index ffd66f0..6a60c2a 100644 --- a/tests/examples/pylon/list_properties.c +++ b/tests/examples/pylon/list_properties.c @@ -37,162 +37,145 @@ #include #include -static gchar * -flags_to_string (GParamSpec * spec) -{ - GString *flags = g_string_new (NULL); +static gchar *flags_to_string(GParamSpec *spec) { + GString *flags = g_string_new(NULL); - g_return_val_if_fail (spec, NULL); + g_return_val_if_fail(spec, NULL); if (spec->flags & G_PARAM_READABLE) { - g_string_append_printf (flags, "readable,"); + g_string_append_printf(flags, "readable,"); } if (spec->flags & G_PARAM_WRITABLE) { - g_string_append_printf (flags, "writable,"); + g_string_append_printf(flags, "writable,"); } if (spec->flags & GST_PARAM_MUTABLE_READY) { - g_string_append_printf (flags, "changeable only in NULL or READY state"); + g_string_append_printf(flags, "changeable only in NULL or READY state"); } if (spec->flags & GST_PARAM_MUTABLE_PLAYING) { - g_string_append_printf (flags, - "changeable only in NULL, READY, PAUSED or PLAYING state"); + g_string_append_printf( + flags, "changeable only in NULL, READY, PAUSED or PLAYING state"); } - return g_string_free (flags, FALSE); + return g_string_free(flags, FALSE); } -static gchar * -string_to_string (GParamSpec * spec) -{ - GParamSpecString *pstring = G_PARAM_SPEC_STRING (spec); +static gchar *string_to_string(GParamSpec *spec) { + GParamSpecString *pstring = G_PARAM_SPEC_STRING(spec); - return g_strdup_printf ("String. Default: \"%s\"", pstring->default_value); + return g_strdup_printf("String. Default: \"%s\"", pstring->default_value); } -static gchar * -boolean_to_string (GParamSpec * spec) -{ - GParamSpecBoolean *pboolean = G_PARAM_SPEC_BOOLEAN (spec); +static gchar *boolean_to_string(GParamSpec *spec) { + GParamSpecBoolean *pboolean = G_PARAM_SPEC_BOOLEAN(spec); const gchar *value = pboolean->default_value ? "true" : "false"; - return g_strdup_printf ("Boolean. Default: %s", value); + return g_strdup_printf("Boolean. Default: %s", value); } -static gchar * -int64_to_string (GParamSpec * spec) -{ - GParamSpecInt64 *pint = G_PARAM_SPEC_INT64 (spec); +static gchar *int64_to_string(GParamSpec *spec) { + GParamSpecInt64 *pint = G_PARAM_SPEC_INT64(spec); - return g_strdup_printf ("Integer64. Range: %" G_GINT64_FORMAT - " - %" G_GINT64_FORMAT " Default: %" G_GINT64_FORMAT, - pint->minimum, pint->maximum, pint->default_value); + return g_strdup_printf("Integer64. Range: %" G_GINT64_FORMAT + " - %" G_GINT64_FORMAT " Default: %" G_GINT64_FORMAT, + pint->minimum, pint->maximum, pint->default_value); } -static gchar * -double_to_string (GParamSpec * spec) -{ - GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE (spec); +static gchar *double_to_string(GParamSpec *spec) { + GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE(spec); - return g_strdup_printf ("Double. Range: %.2f - %.2f Default: %.2f", - pdouble->minimum, pdouble->maximum, pdouble->default_value); + return g_strdup_printf("Double. Range: %.2f - %.2f Default: %.2f", + pdouble->minimum, pdouble->maximum, + pdouble->default_value); } -static gchar * -enum_to_string (GParamSpec * spec) -{ - GParamSpecEnum *penum = G_PARAM_SPEC_ENUM (spec); - GString *desc = g_string_new (NULL); - GType type = G_TYPE_FROM_CLASS (penum->enum_class); - gchar *def = g_enum_to_string (type, penum->default_value); - const gchar *type_name = g_type_name (type); +static gchar *enum_to_string(GParamSpec *spec) { + GParamSpecEnum *penum = G_PARAM_SPEC_ENUM(spec); + GString *desc = g_string_new(NULL); + GType type = G_TYPE_FROM_CLASS(penum->enum_class); + gchar *def = g_enum_to_string(type, penum->default_value); + const gchar *type_name = g_type_name(type); GEnumValue *iter = NULL; - g_string_append_printf (desc, "Enum \"%s\" Default: %d, \"%s\"", - type_name, penum->default_value, def); - g_free (def); + g_string_append_printf(desc, "Enum \"%s\" Default: %d, \"%s\"", type_name, + penum->default_value, def); + g_free(def); for (iter = penum->enum_class->values; iter->value_name; iter++) { if (iter->value_nick[0] == '\0') { - g_string_append_printf (desc, "\n\t(%d): %s", iter->value, - iter->value_name); + g_string_append_printf(desc, "\n\t(%d): %s", iter->value, + iter->value_name); } else { - g_string_append_printf (desc, "\n\t(%d): %s - %s", iter->value, - iter->value_name, iter->value_nick); + g_string_append_printf(desc, "\n\t(%d): %s - %s", iter->value, + iter->value_name, iter->value_nick); } } - return g_string_free (desc, FALSE); + return g_string_free(desc, FALSE); } -static gchar * -property_to_string (GParamSpec * spec) -{ +static gchar *property_to_string(GParamSpec *spec) { const gchar *name = NULL; const gchar *blurb = NULL; gchar *flags = NULL; gchar *details = NULL; gchar *prop = NULL; - g_return_val_if_fail (spec, NULL); + g_return_val_if_fail(spec, NULL); - name = g_param_spec_get_name (spec); - blurb = g_param_spec_get_blurb (spec); - flags = flags_to_string (spec); + name = g_param_spec_get_name(spec); + blurb = g_param_spec_get_blurb(spec); + flags = flags_to_string(spec); - switch (G_TYPE_FUNDAMENTAL (spec->value_type)) { + switch (G_TYPE_FUNDAMENTAL(spec->value_type)) { case G_TYPE_INT64: - details = int64_to_string (spec); + details = int64_to_string(spec); break; case G_TYPE_STRING: - details = string_to_string (spec); + details = string_to_string(spec); break; case G_TYPE_DOUBLE: - details = double_to_string (spec); + details = double_to_string(spec); break; case G_TYPE_ENUM: - details = enum_to_string (spec); + details = enum_to_string(spec); break; case G_TYPE_BOOLEAN: - details = boolean_to_string (spec); + details = boolean_to_string(spec); break; default: - details = g_strdup ("unknown type"); + details = g_strdup("unknown type"); break; } - prop = g_strdup_printf ("Name: %s\nBlurb: %s\nFlags: %s\nDetails: %s\n", - name, blurb, flags, details); + prop = g_strdup_printf("Name: %s\nBlurb: %s\nFlags: %s\nDetails: %s\n", name, + blurb, flags, details); - g_free (flags); - g_free (details); + g_free(flags); + g_free(details); return prop; } -static void -print_device_properties (GObject * object) -{ +static void print_device_properties(GObject *object) { GParamSpec **property_specs = NULL; guint num_properties = 0, i = 0; - g_return_if_fail (object); + g_return_if_fail(object); - property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), - &num_properties); + property_specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(object), + &num_properties); for (i = 0; i < num_properties; i++) { - gchar *property = property_to_string (property_specs[i]); + gchar *property = property_to_string(property_specs[i]); - g_print ("%s", property); - g_print ("-----------\n"); + g_print("%s", property); + g_print("-----------\n"); - g_free (property); + g_free(property); } } -int -main (int argc, char **argv) -{ +int main(int argc, char **argv) { GstElement *element = NULL; GstChildProxy *child_proxy = NULL; gint device = 0; @@ -200,30 +183,32 @@ main (int argc, char **argv) gint ret = EXIT_FAILURE; /* Make sure we have at least an emulator running */ - g_setenv ("PYLON_CAMEMU", "1", FALSE); + g_setenv("PYLON_CAMEMU", "1", FALSE); - gst_init (&argc, &argv); + gst_init(&argc, &argv); - element = gst_element_factory_make ("pylonsrc", NULL); + element = gst_element_factory_make("pylonsrc", NULL); if (NULL == element) { - g_printerr - ("Unable to create a pylon camera, activate GST_DEBUG=2 to find the cause\n"); + g_printerr( + "Unable to create a pylon camera, activate GST_DEBUG=2 to find the " + "cause\n"); goto out; } - child_proxy = GST_CHILD_PROXY (element); + child_proxy = GST_CHILD_PROXY(element); - /* After selecting each device, a number of child subdevices may be accessed */ - num_subdevices = gst_child_proxy_get_children_count (child_proxy); + /* After selecting each device, a number of child subdevices may be accessed + */ + num_subdevices = gst_child_proxy_get_children_count(child_proxy); for (device = 0;; device++) { gint i = 0; GObject *subdevice = NULL; - g_object_set (element, "device-index", device, NULL); + g_object_set(element, "device-index", device, NULL); for (i = 0; i < num_subdevices; ++i) { - subdevice = gst_child_proxy_get_child_by_index (child_proxy, i); + subdevice = gst_child_proxy_get_child_by_index(child_proxy, i); if (NULL == subdevice) { /* No more devices */ @@ -232,24 +217,25 @@ main (int argc, char **argv) /* Only print main title if there is a subdevice available */ if (0 == i) { - g_print - ("**************************\nDevice Index: %d\n**************************\n", + g_print( + "**************************\nDevice Index: " + "%d\n**************************\n", device); } - g_print ("\n%s:\n==========================\n", - GST_OBJECT_NAME (subdevice)); - print_device_properties (subdevice); + g_print("\n%s:\n==========================\n", + GST_OBJECT_NAME(subdevice)); + print_device_properties(subdevice); - gst_object_unref (subdevice); + gst_object_unref(subdevice); } } no_more_devices: - gst_object_unref (element); + gst_object_unref(element); out: - gst_deinit (); + gst_deinit(); return ret; } diff --git a/tests/examples/pylon/pylonsrc.c b/tests/examples/pylon/pylonsrc.c index d8a8a76..701017b 100644 --- a/tests/examples/pylon/pylonsrc.c +++ b/tests/examples/pylon/pylonsrc.c @@ -36,7 +36,7 @@ #include #ifdef G_OS_UNIX -#include +# include #endif #include @@ -44,86 +44,78 @@ #define OVERLAY_NAME "overlay" typedef struct _Context Context; -struct _Context -{ +struct _Context { GMainLoop *loop; GstElement *pylonsrc; GstElement *overlay; }; #ifdef G_OS_UNIX -static gboolean -sig_handler (Context * ctx) -{ - g_return_val_if_fail (ctx, FALSE); - g_return_val_if_fail (ctx->loop, FALSE); +static gboolean sig_handler(Context *ctx) { + g_return_val_if_fail(ctx, FALSE); + g_return_val_if_fail(ctx->loop, FALSE); - g_print ("Interrupt caught, exiting..."); - g_main_loop_quit (ctx->loop); + g_print("Interrupt caught, exiting..."); + g_main_loop_quit(ctx->loop); return TRUE; } #endif -static gboolean -toggle_pattern (Context * ctx) -{ +static gboolean toggle_pattern(Context *ctx) { gint pattern = 0; - const gchar *name_list[] = { "Off", "Testimage1", "Testimage2" }; + const gchar *name_list[] = {"Off", "Testimage1", "Testimage2"}; const gchar *name = NULL; GstChildProxy *cp = NULL; - g_return_val_if_fail (ctx, FALSE); - g_return_val_if_fail (ctx->pylonsrc, FALSE); - g_return_val_if_fail (ctx->overlay, FALSE); + g_return_val_if_fail(ctx, FALSE); + g_return_val_if_fail(ctx->pylonsrc, FALSE); + g_return_val_if_fail(ctx->overlay, FALSE); - cp = GST_CHILD_PROXY (ctx->pylonsrc); + cp = GST_CHILD_PROXY(ctx->pylonsrc); - gst_child_proxy_get (cp, "cam::TestImageSelector", &pattern, NULL); + gst_child_proxy_get(cp, "cam::TestImageSelector", &pattern, NULL); /* Toggle test image pattern */ pattern = (pattern + 1) % 3; name = name_list[pattern]; - gst_child_proxy_set (cp, "cam::TestImageSelector", pattern, NULL); - g_object_set (ctx->overlay, "text", name, NULL); + gst_child_proxy_set(cp, "cam::TestImageSelector", pattern, NULL); + g_object_set(ctx->overlay, "text", name, NULL); return TRUE; } -static void -print_error (GstMessage * msg, GError * error, gchar * dbg, const gchar * tag) -{ - g_return_if_fail (msg); - g_return_if_fail (error); - g_return_if_fail (tag); - - g_printerr ("%s from element %s: %s\n", tag, GST_OBJECT_NAME (msg->src), - error->message); - g_printerr ("Debugging info: %s\n", (dbg) ? dbg : "none"); - g_error_free (error); - g_free (dbg); +static void print_error(GstMessage *msg, GError *error, gchar *dbg, + const gchar *tag) { + g_return_if_fail(msg); + g_return_if_fail(error); + g_return_if_fail(tag); + + g_printerr("%s from element %s: %s\n", tag, GST_OBJECT_NAME(msg->src), + error->message); + g_printerr("Debugging info: %s\n", (dbg) ? dbg : "none"); + g_error_free(error); + g_free(dbg); } -static gboolean -bus_callback (GstBus * bus, GstMessage * msg, Context * ctx) -{ +static gboolean bus_callback(GstBus *bus, GstMessage *msg, Context *ctx) { GError *err = NULL; gchar *dbg_info = NULL; - g_return_val_if_fail (ctx, FALSE); - g_return_val_if_fail (ctx->loop, FALSE); + g_return_val_if_fail(ctx, FALSE); + g_return_val_if_fail(ctx->loop, FALSE); - switch (GST_MESSAGE_TYPE (msg)) { + switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_ERROR: - gst_message_parse_error (msg, &err, &dbg_info); - print_error (msg, err, dbg_info, "ERROR"); + gst_message_parse_error(msg, &err, &dbg_info); + print_error(msg, err, dbg_info, "ERROR"); /* Treat errors as fatal and tear down the app */ - g_main_loop_quit (ctx->loop); + g_main_loop_quit(ctx->loop); break; case GST_MESSAGE_WARNING: - gst_message_parse_warning (msg, &err, &dbg_info); - print_error (msg, err, dbg_info, "WARNING"); + gst_message_parse_warning(msg, &err, &dbg_info); + print_error(msg, err, dbg_info, "WARNING"); break; default: break; @@ -132,10 +124,8 @@ bus_callback (GstBus * bus, GstMessage * msg, Context * ctx) return TRUE; } -int -main (int argc, char **argv) -{ - Context ctx = { 0 }; +int main(int argc, char **argv) { + Context ctx = {0}; GstElement *pipe = NULL; GstBus *bus = NULL; guint bus_watch = 0; @@ -147,73 +137,72 @@ main (int argc, char **argv) " ! queue ! videoconvert ! autovideosink"; /* Make sure we have an emulator running */ - g_setenv ("PYLON_CAMEMU", "1", TRUE); + g_setenv("PYLON_CAMEMU", "1", TRUE); - gst_init (&argc, &argv); + gst_init(&argc, &argv); - pipe = - gst_parse_launch_full (desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error); + pipe = gst_parse_launch_full(desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error); if (!pipe) { - g_printerr ("Unable to create pipeline: %s\n", error->message); - g_error_free (error); + g_printerr("Unable to create pipeline: %s\n", error->message); + g_error_free(error); goto out; } - ctx.pylonsrc = gst_bin_get_by_name (GST_BIN (pipe), PYLONSRC_NAME); + ctx.pylonsrc = gst_bin_get_by_name(GST_BIN(pipe), PYLONSRC_NAME); if (!ctx.pylonsrc) { - g_printerr ("No pylonsrc element found\n"); + g_printerr("No pylonsrc element found\n"); goto free_pipe; } - ctx.overlay = gst_bin_get_by_name (GST_BIN (pipe), OVERLAY_NAME); + ctx.overlay = gst_bin_get_by_name(GST_BIN(pipe), OVERLAY_NAME); if (!ctx.overlay) { - g_printerr ("No textoverlay element found\n"); + g_printerr("No textoverlay element found\n"); goto free_pylonsrc; } - ctx.loop = g_main_loop_new (NULL, FALSE); + ctx.loop = g_main_loop_new(NULL, FALSE); #ifdef G_OS_UNIX - g_unix_signal_add (SIGINT, (GSourceFunc) sig_handler, &ctx); + g_unix_signal_add(SIGINT, (GSourceFunc)sig_handler, &ctx); #endif /* Add a bus listener to receive errors, warnings and other notifications * from the pipeline */ - bus = gst_pipeline_get_bus (GST_PIPELINE (pipe)); - bus_watch = gst_bus_add_watch (bus, (GstBusFunc) bus_callback, &ctx); - gst_object_unref (bus); + bus = gst_pipeline_get_bus(GST_PIPELINE(pipe)); + bus_watch = gst_bus_add_watch(bus, (GstBusFunc)bus_callback, &ctx); + gst_object_unref(bus); - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (pipe, - GST_STATE_PLAYING)) { - g_printerr ("Unable to play pipeline\n"); + if (GST_STATE_CHANGE_FAILURE == + gst_element_set_state(pipe, GST_STATE_PLAYING)) { + g_printerr("Unable to play pipeline\n"); goto free_overlay; } /* Add a periodic callback to change a camera property */ - g_timeout_add_seconds (1, (GSourceFunc) toggle_pattern, &ctx); + g_timeout_add_seconds(1, (GSourceFunc)toggle_pattern, &ctx); /* Run until an interrupt is received */ - g_main_loop_run (ctx.loop); + g_main_loop_run(ctx.loop); - gst_element_set_state (pipe, GST_STATE_NULL); + gst_element_set_state(pipe, GST_STATE_NULL); - g_main_loop_unref (ctx.loop); + g_main_loop_unref(ctx.loop); ret = EXIT_SUCCESS; - g_print ("bye!\n"); + g_print("bye!\n"); free_overlay: - gst_object_unref (ctx.overlay); + gst_object_unref(ctx.overlay); free_pylonsrc: - gst_object_unref (ctx.pylonsrc); + gst_object_unref(ctx.pylonsrc); free_pipe: - g_source_remove (bus_watch); - gst_object_unref (pipe); + g_source_remove(bus_watch); + gst_object_unref(pipe); out: - gst_deinit (); + gst_deinit(); return ret; } diff --git a/tests/examples/pylon/show_meta.c b/tests/examples/pylon/show_meta.c index a9335ff..3047826 100644 --- a/tests/examples/pylon/show_meta.c +++ b/tests/examples/pylon/show_meta.c @@ -38,77 +38,70 @@ #include #ifdef G_OS_UNIX -#include +# include #endif -#include -#include - #include +#include +#include #define PYLONSRC_NAME "src" #define OVERLAY_NAME "text" #define SINK_NAME "sink" typedef struct _Context Context; -struct _Context -{ +struct _Context { GMainLoop *loop; GstElement *pylonsrc; GstElement *overlay; }; #ifdef G_OS_UNIX -static gboolean -sig_handler (Context * ctx) -{ - g_return_val_if_fail (ctx, FALSE); - g_return_val_if_fail (ctx->loop, FALSE); +static gboolean sig_handler(Context *ctx) { + g_return_val_if_fail(ctx, FALSE); + g_return_val_if_fail(ctx->loop, FALSE); - g_print ("Interrupt caught, exiting..."); - g_main_loop_quit (ctx->loop); + g_print("Interrupt caught, exiting..."); + g_main_loop_quit(ctx->loop); return TRUE; } #endif -static void -print_error (GstMessage * msg, GError * error, gchar * dbg, const gchar * tag) -{ - g_return_if_fail (msg); - g_return_if_fail (error); - g_return_if_fail (tag); - - g_printerr ("%s from element %s: %s\n", tag, GST_OBJECT_NAME (msg->src), - error->message); - g_printerr ("Debugging info: %s\n", (dbg) ? dbg : "none"); - g_error_free (error); - g_free (dbg); +static void print_error(GstMessage *msg, GError *error, gchar *dbg, + const gchar *tag) { + g_return_if_fail(msg); + g_return_if_fail(error); + g_return_if_fail(tag); + + g_printerr("%s from element %s: %s\n", tag, GST_OBJECT_NAME(msg->src), + error->message); + g_printerr("Debugging info: %s\n", (dbg) ? dbg : "none"); + g_error_free(error); + g_free(dbg); } -static gboolean -bus_callback (GstBus * bus, GstMessage * msg, Context * ctx) -{ +static gboolean bus_callback(GstBus *bus, GstMessage *msg, Context *ctx) { GError *err = NULL; gchar *dbg_info = NULL; - g_return_val_if_fail (ctx, FALSE); - g_return_val_if_fail (ctx->loop, FALSE); + g_return_val_if_fail(ctx, FALSE); + g_return_val_if_fail(ctx->loop, FALSE); - switch (GST_MESSAGE_TYPE (msg)) { + switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_ERROR: - gst_message_parse_error (msg, &err, &dbg_info); - print_error (msg, err, dbg_info, "ERROR"); + gst_message_parse_error(msg, &err, &dbg_info); + print_error(msg, err, dbg_info, "ERROR"); /* Treat errors as fatal and tear down the app */ - g_main_loop_quit (ctx->loop); + g_main_loop_quit(ctx->loop); break; case GST_MESSAGE_WARNING: - gst_message_parse_warning (msg, &err, &dbg_info); - print_error (msg, err, dbg_info, "WARNING"); + gst_message_parse_warning(msg, &err, &dbg_info); + print_error(msg, err, dbg_info, "WARNING"); break; case GST_MESSAGE_EOS: /* end-of-stream */ - printf ("end of stream\n"); - g_main_loop_quit (ctx->loop); + printf("end of stream\n"); + g_main_loop_quit(ctx->loop); break; default: break; @@ -117,110 +110,102 @@ bus_callback (GstBus * bus, GstMessage * msg, Context * ctx) return TRUE; } -static void -try_enable_all_chunks (Context * ctx) -{ +static void try_enable_all_chunks(Context *ctx) { GParamSpec **property_specs = NULL; GObject *cam = NULL; guint num_properties = 0; GstChildProxy *cp = NULL; gboolean has_chunks = FALSE; - g_return_if_fail (ctx); - g_return_if_fail (ctx->pylonsrc); + g_return_if_fail(ctx); + g_return_if_fail(ctx->pylonsrc); - cp = GST_CHILD_PROXY (ctx->pylonsrc); - cam = gst_child_proxy_get_child_by_name (cp, "cam"); + cp = GST_CHILD_PROXY(ctx->pylonsrc); + cam = gst_child_proxy_get_child_by_name(cp, "cam"); /* fail if child not found */ - g_return_if_fail (cam); + g_return_if_fail(cam); - property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (cam), - &num_properties); + property_specs = + g_object_class_list_properties(G_OBJECT_GET_CLASS(cam), &num_properties); /* FIXME: how to check if a property is available?? */ for (size_t i = 0; i < num_properties; i++) { - const gchar *prop_name = g_param_spec_get_name (property_specs[i]); - if (g_str_has_prefix (prop_name, "ChunkModeActive")) { - g_print ("try enable chunk mode\n"); - g_object_set (cam, prop_name, TRUE, NULL); + const gchar *prop_name = g_param_spec_get_name(property_specs[i]); + if (g_str_has_prefix(prop_name, "ChunkModeActive")) { + g_print("try enable chunk mode\n"); + g_object_set(cam, prop_name, TRUE, NULL); has_chunks = TRUE; break; } } if (has_chunks) { - g_print ("-> success\n"); + g_print("-> success\n"); for (size_t i = 0; i < num_properties; i++) { - const gchar *prop_name = g_param_spec_get_name (property_specs[i]); - if (g_str_has_prefix (prop_name, "ChunkEnable")) { - g_print ("enable %s\n", prop_name); - g_object_set (cam, prop_name, TRUE, NULL); + const gchar *prop_name = g_param_spec_get_name(property_specs[i]); + if (g_str_has_prefix(prop_name, "ChunkEnable")) { + g_print("enable %s\n", prop_name); + g_object_set(cam, prop_name, TRUE, NULL); } } } - } -static GstPadProbeReturn -cb_have_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) -{ +static GstPadProbeReturn cb_have_data(GstPad *pad, GstPadProbeInfo *info, + gpointer user_data) { GstBuffer *buffer; GstPylonMeta *meta = NULL; - Context *ctx = (Context *) user_data; + Context *ctx = (Context *)user_data; gchar *meta_str = NULL; gchar *tmp_str = NULL; gint64 int_chunk; gdouble double_chunk; - g_return_val_if_fail (ctx, GST_PAD_PROBE_DROP); + g_return_val_if_fail(ctx, GST_PAD_PROBE_DROP); - buffer = GST_PAD_PROBE_INFO_BUFFER (info); - meta = (GstPylonMeta *) gst_buffer_get_meta (buffer, GST_PYLON_META_API_TYPE); + buffer = GST_PAD_PROBE_INFO_BUFFER(info); + meta = (GstPylonMeta *)gst_buffer_get_meta(buffer, GST_PYLON_META_API_TYPE); - meta_str = - g_strdup_printf - ("ID/img_num/skipped_num %lu/%lu/%lu\noffset %lu/%lu\npylon_timestamp %16lu\n", + meta_str = g_strdup_printf( + "ID/img_num/skipped_num %lu/%lu/%lu\noffset %lu/%lu\npylon_timestamp " + "%16lu\n", meta->block_id, meta->image_number, meta->skipped_images, meta->offset.offset_x, meta->offset.offset_y, meta->timestamp); /* show chunks embedded in the stream */ - for (int idx = 0; idx < gst_structure_n_fields (meta->chunks); idx++) { - const gchar *chunk_name = gst_structure_nth_field_name (meta->chunks, idx); - GType chunk_type = gst_structure_get_field_type (meta->chunks, chunk_name); + for (int idx = 0; idx < gst_structure_n_fields(meta->chunks); idx++) { + const gchar *chunk_name = gst_structure_nth_field_name(meta->chunks, idx); + GType chunk_type = gst_structure_get_field_type(meta->chunks, chunk_name); /* display double and int types */ switch (chunk_type) { case G_TYPE_INT64: - gst_structure_get_int64 (meta->chunks, chunk_name, &int_chunk); - tmp_str = - g_strdup_printf ("%s%s_%ld ", meta_str, chunk_name, int_chunk); - g_free (meta_str); + gst_structure_get_int64(meta->chunks, chunk_name, &int_chunk); + tmp_str = g_strdup_printf("%s%s_%ld ", meta_str, chunk_name, int_chunk); + g_free(meta_str); meta_str = tmp_str; break; case G_TYPE_DOUBLE: - gst_structure_get_double (meta->chunks, chunk_name, &double_chunk); + gst_structure_get_double(meta->chunks, chunk_name, &double_chunk); tmp_str = - g_strdup_printf ("%s%s_%.2f ", meta_str, chunk_name, double_chunk); - g_free (meta_str); + g_strdup_printf("%s%s_%.2f ", meta_str, chunk_name, double_chunk); + g_free(meta_str); meta_str = tmp_str; break; default: - g_print ("Skip chunk %s\n", chunk_name); + g_print("Skip chunk %s\n", chunk_name); } - } /* set overlay text */ - g_object_set (ctx->overlay, "text", meta_str, NULL); + g_object_set(ctx->overlay, "text", meta_str, NULL); - g_free (meta_str); + g_free(meta_str); return GST_PAD_PROBE_OK; } -int -main (int argc, char **argv) -{ - Context ctx = { 0 }; +int main(int argc, char **argv) { + Context ctx = {0}; GstElement *pipe = NULL; GstBus *bus = NULL; guint bus_watch = 0; @@ -229,83 +214,83 @@ main (int argc, char **argv) gulong padid = -1; GstPad *pad; const gchar *desc = - "pylonsrc capture-error=skip cam::ExposureAuto=Continuous name=" - PYLONSRC_NAME - " ! textoverlay font-desc='monospace' line-alignment=left halignment=left name=" - OVERLAY_NAME " ! queue ! videoconvert ! autovideosink"; + "pylonsrc capture-error=skip cam::ExposureAuto=Continuous " + "name=" PYLONSRC_NAME + " ! textoverlay font-desc='monospace' line-alignment=left " + "halignment=left name=" OVERLAY_NAME + " ! queue ! videoconvert ! autovideosink"; - gst_init (&argc, &argv); + gst_init(&argc, &argv); - pipe = - gst_parse_launch_full (desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error); + pipe = gst_parse_launch_full(desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &error); if (!pipe) { - g_printerr ("Unable to create pipeline: %s\n", error->message); - g_error_free (error); + g_printerr("Unable to create pipeline: %s\n", error->message); + g_error_free(error); goto out; } - ctx.pylonsrc = gst_bin_get_by_name (GST_BIN (pipe), PYLONSRC_NAME); + ctx.pylonsrc = gst_bin_get_by_name(GST_BIN(pipe), PYLONSRC_NAME); if (!ctx.pylonsrc) { - g_printerr ("No pylonsrc element found\n"); + g_printerr("No pylonsrc element found\n"); goto free_pipe; } - ctx.overlay = gst_bin_get_by_name (GST_BIN (pipe), OVERLAY_NAME); + ctx.overlay = gst_bin_get_by_name(GST_BIN(pipe), OVERLAY_NAME); if (!ctx.overlay) { - g_printerr ("No textoverlay element found\n"); + g_printerr("No textoverlay element found\n"); goto free_pylonsrc; } #ifdef G_OS_UNIX - g_unix_signal_add (SIGINT, (GSourceFunc) sig_handler, &ctx); + g_unix_signal_add(SIGINT, (GSourceFunc)sig_handler, &ctx); #endif /* Add a bus listener to receive errors, warnings and other notifications * from the pipeline */ - bus = gst_pipeline_get_bus (GST_PIPELINE (pipe)); - bus_watch = gst_bus_add_watch (bus, (GstBusFunc) bus_callback, &ctx); - gst_object_unref (bus); + bus = gst_pipeline_get_bus(GST_PIPELINE(pipe)); + bus_watch = gst_bus_add_watch(bus, (GstBusFunc)bus_callback, &ctx); + gst_object_unref(bus); /* attach a probe to the output of pylonsrc */ - pad = gst_element_get_static_pad (ctx.pylonsrc, "src"); - padid = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, - (GstPadProbeCallback) cb_have_data, &ctx, NULL); - gst_object_unref (pad); + pad = gst_element_get_static_pad(ctx.pylonsrc, "src"); + padid = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, + (GstPadProbeCallback)cb_have_data, &ctx, NULL); + gst_object_unref(pad); /* try to enable all chunks the camera supports */ - try_enable_all_chunks (&ctx); + try_enable_all_chunks(&ctx); - if (GST_STATE_CHANGE_FAILURE == gst_element_set_state (pipe, - GST_STATE_PLAYING)) { - g_printerr ("Unable to play pipeline\n"); + if (GST_STATE_CHANGE_FAILURE == + gst_element_set_state(pipe, GST_STATE_PLAYING)) { + g_printerr("Unable to play pipeline\n"); goto free_overlay; } /* Run until an interrupt is received */ - ctx.loop = g_main_loop_new (NULL, FALSE); - g_main_loop_run (ctx.loop); + ctx.loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(ctx.loop); - gst_element_set_state (pipe, GST_STATE_NULL); + gst_element_set_state(pipe, GST_STATE_NULL); - g_main_loop_unref (ctx.loop); + g_main_loop_unref(ctx.loop); ret = EXIT_SUCCESS; - g_print ("bye!\n"); + g_print("bye!\n"); - gst_pad_remove_probe (pad, padid); + gst_pad_remove_probe(pad, padid); free_overlay: - gst_object_unref (ctx.overlay); + gst_object_unref(ctx.overlay); free_pylonsrc: - gst_object_unref (ctx.pylonsrc); + gst_object_unref(ctx.pylonsrc); free_pipe: - g_source_remove (bus_watch); - gst_object_unref (pipe); + g_source_remove(bus_watch); + gst_object_unref(pipe); out: - gst_deinit (); + gst_deinit(); return ret; } From 763f26a9843a8e752f8129c5fae1d902e73e70af Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Tue, 7 Feb 2023 17:39:28 -0600 Subject: [PATCH 079/126] Add git describe result to plugin description --- ext/pylon/meson.build | 2 +- meson.build | 4 ++++ version.h.in | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 version.h.in diff --git a/ext/pylon/meson.build b/ext/pylon/meson.build index 5944f53..f85e816 100644 --- a/ext/pylon/meson.build +++ b/ext/pylon/meson.build @@ -9,7 +9,7 @@ pylon_sources = [ ] gstpylon_plugin = library('gstpylon', - pylon_sources, + pylon_sources + git_version, c_args : gst_plugin_pylon_args, cpp_args : gst_plugin_pylon_args, link_args : [noseh_link_args], diff --git a/meson.build b/meson.build index 6cef2e7..f2f3d1c 100644 --- a/meson.build +++ b/meson.build @@ -13,6 +13,10 @@ gst_dep = dependency('gstreamer-1.0', version : gst_req) gst_version = gst_dep.version() message('Building against GStreamer ' + gst_version) +git_version = vcs_tag(command : ['git', 'describe', '--tags'], + input: 'version.h.in', output: 'version.h', replace_string: '@GIT_VERSION@', + fallback: 'no git') + version_arr = gst_version.split('.') gst_version_major = version_arr[0].to_int() gst_version_minor = version_arr[1].to_int() diff --git a/version.h.in b/version.h.in new file mode 100644 index 0000000..1562e2f --- /dev/null +++ b/version.h.in @@ -0,0 +1 @@ +#define GIT_VERSION "@GIT_VERSION@" From 96782da3697717dc2f33827d4408995a9f6a2aa1 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Tue, 14 Feb 2023 11:56:46 -0600 Subject: [PATCH 080/126] Show meson project version when inspecting the element when no git is installed --- ext/pylon/gstpylonplugin.cpp | 12 ++++++------ meson.build | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ext/pylon/gstpylonplugin.cpp b/ext/pylon/gstpylonplugin.cpp index f7090c0..4bb4482 100644 --- a/ext/pylon/gstpylonplugin.cpp +++ b/ext/pylon/gstpylonplugin.cpp @@ -43,9 +43,9 @@ static gboolean plugin_init(GstPlugin* plugin) { GST_TYPE_PYLON_SRC); } -GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, pylon, - "Basler/Pylon plugin for pylon SDK " PYLON_VERSIONSTRING_MAJOR - "." PYLON_VERSIONSTRING_MINOR "." PYLON_VERSIONSTRING_SUBMINOR - "(" PYLON_VERSIONSTRING_BUILD ")", - plugin_init, VERSION, GST_PACKAGE_LICENSE, GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN) +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, + pylon, + "Basler/Pylon plugin for pylon SDK " PYLON_VERSIONSTRING_MAJOR "." + PYLON_VERSIONSTRING_MINOR "." PYLON_VERSIONSTRING_SUBMINOR "(" + PYLON_VERSIONSTRING_BUILD ")", plugin_init, GIT_VERSION, + GST_PACKAGE_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/meson.build b/meson.build index f2f3d1c..4ce6cc5 100644 --- a/meson.build +++ b/meson.build @@ -15,7 +15,7 @@ message('Building against GStreamer ' + gst_version) git_version = vcs_tag(command : ['git', 'describe', '--tags'], input: 'version.h.in', output: 'version.h', replace_string: '@GIT_VERSION@', - fallback: 'no git') + fallback: meson.project_version() + '-local') version_arr = gst_version.split('.') gst_version_major = version_arr[0].to_int() From d0840cb0739feeabcbf393704d97635235043ffc Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Wed, 15 Feb 2023 08:06:06 -0600 Subject: [PATCH 081/126] Add copyright header and guards to version file --- version.h.in | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/version.h.in b/version.h.in index 1562e2f..cf503d5 100644 --- a/version.h.in +++ b/version.h.in @@ -1 +1,38 @@ +/* Copyright (C) 2023 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _VERSION_H_ +#define _VERSION_H_ + #define GIT_VERSION "@GIT_VERSION@" + +#endif \ No newline at end of file From fcffca90fc26a4f99bc130cbe2b6e3f907c24892 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 20 Feb 2023 09:22:24 -0600 Subject: [PATCH 082/126] Remove the 'v' from the plugin version --- get_git_tags.sh | 4 ++++ meson.build | 2 +- version.h.in | 60 ++++++++++++++++++++++++------------------------- 3 files changed, 35 insertions(+), 31 deletions(-) create mode 100644 get_git_tags.sh diff --git a/get_git_tags.sh b/get_git_tags.sh new file mode 100644 index 0000000..2dda43f --- /dev/null +++ b/get_git_tags.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +GIT_VERSION=$(git describe --tags | sed 's/v//g') +echo $GIT_VERSION \ No newline at end of file diff --git a/meson.build b/meson.build index 4ce6cc5..70d80f7 100644 --- a/meson.build +++ b/meson.build @@ -13,7 +13,7 @@ gst_dep = dependency('gstreamer-1.0', version : gst_req) gst_version = gst_dep.version() message('Building against GStreamer ' + gst_version) -git_version = vcs_tag(command : ['git', 'describe', '--tags'], +git_version = vcs_tag(command : ['sh', 'get_version.sh'], input: 'version.h.in', output: 'version.h', replace_string: '@GIT_VERSION@', fallback: meson.project_version() + '-local') diff --git a/version.h.in b/version.h.in index cf503d5..2ea9861 100644 --- a/version.h.in +++ b/version.h.in @@ -1,34 +1,34 @@ /* Copyright (C) 2023 Basler AG - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above +* copyright notice, this list of conditions and the following +* disclaimer. +* 2. Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials +* provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of +* its contributors may be used to endorse or promote products +* derived from this software without specific prior written +* permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +* OF THE POSSIBILITY OF SUCH DAMAGE. +*/ #ifndef _VERSION_H_ #define _VERSION_H_ From 6c01a29883c09abbce492fb53c17621423e80503 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 20 Feb 2023 12:41:05 -0600 Subject: [PATCH 083/126] Include header of generated file --- ext/pylon/gstpylonplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/pylon/gstpylonplugin.cpp b/ext/pylon/gstpylonplugin.cpp index 4bb4482..1e94914 100644 --- a/ext/pylon/gstpylonplugin.cpp +++ b/ext/pylon/gstpylonplugin.cpp @@ -34,8 +34,9 @@ # include "config.h" #endif -#include "gstpylonsrc.h" +#include "version.h" +#include "gstpylonsrc.h" #include static gboolean plugin_init(GstPlugin* plugin) { From 5d2d76922acdc72db8348db59f9fa3615b9b3616 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Tue, 21 Feb 2023 14:28:58 -0600 Subject: [PATCH 084/126] Change name of the script that fetches the version of the plugin --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 70d80f7..9878634 100644 --- a/meson.build +++ b/meson.build @@ -13,7 +13,7 @@ gst_dep = dependency('gstreamer-1.0', version : gst_req) gst_version = gst_dep.version() message('Building against GStreamer ' + gst_version) -git_version = vcs_tag(command : ['sh', 'get_version.sh'], +git_version = vcs_tag(command : ['sh', 'get_git_tags.sh'], input: 'version.h.in', output: 'version.h', replace_string: '@GIT_VERSION@', fallback: meson.project_version() + '-local') From de57da8688c92c61269250abe76b28d00b306c0c Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Wed, 22 Feb 2023 11:02:07 -0600 Subject: [PATCH 085/126] Add script to set the correct version even if git is not on the system --- get_git_tags.sh | 4 ---- get_git_version.py | 18 ++++++++++++++++++ meson.build | 2 +- 3 files changed, 19 insertions(+), 5 deletions(-) delete mode 100644 get_git_tags.sh create mode 100644 get_git_version.py diff --git a/get_git_tags.sh b/get_git_tags.sh deleted file mode 100644 index 2dda43f..0000000 --- a/get_git_tags.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -GIT_VERSION=$(git describe --tags | sed 's/v//g') -echo $GIT_VERSION \ No newline at end of file diff --git a/get_git_version.py b/get_git_version.py new file mode 100644 index 0000000..088ee54 --- /dev/null +++ b/get_git_version.py @@ -0,0 +1,18 @@ +import subprocess +import sys, os + +meson_project_path = sys.argv[1] +git_dir = meson_project_path + "/.git" + +if not os.path.exists(git_dir): + sys.exit(1) + +cmd_result = subprocess.run(["git", "describe", "--tags"], capture_output=True) +vcs_tag = cmd_result.stdout.decode('utf-8')[:-1] + +if not len(vcs_tag): + sys.exit(1) +else: + vcs_tag = vcs_tag[1:] + +print(vcs_tag) \ No newline at end of file diff --git a/meson.build b/meson.build index 9878634..bf3a608 100644 --- a/meson.build +++ b/meson.build @@ -13,7 +13,7 @@ gst_dep = dependency('gstreamer-1.0', version : gst_req) gst_version = gst_dep.version() message('Building against GStreamer ' + gst_version) -git_version = vcs_tag(command : ['sh', 'get_git_tags.sh'], +git_version = vcs_tag(command : ['python3', 'get_git_version.py', meson.project_source_root()], input: 'version.h.in', output: 'version.h', replace_string: '@GIT_VERSION@', fallback: meson.project_version() + '-local') From 81fb8856f393a64c258b924ce72a2456026e14e0 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Wed, 22 Feb 2023 12:40:39 -0600 Subject: [PATCH 086/126] Move script to run from the meson.build --- get_git_version.py | 18 ------------------ meson.build | 23 ++++++++++++++++++++++- 2 files changed, 22 insertions(+), 19 deletions(-) delete mode 100644 get_git_version.py diff --git a/get_git_version.py b/get_git_version.py deleted file mode 100644 index 088ee54..0000000 --- a/get_git_version.py +++ /dev/null @@ -1,18 +0,0 @@ -import subprocess -import sys, os - -meson_project_path = sys.argv[1] -git_dir = meson_project_path + "/.git" - -if not os.path.exists(git_dir): - sys.exit(1) - -cmd_result = subprocess.run(["git", "describe", "--tags"], capture_output=True) -vcs_tag = cmd_result.stdout.decode('utf-8')[:-1] - -if not len(vcs_tag): - sys.exit(1) -else: - vcs_tag = vcs_tag[1:] - -print(vcs_tag) \ No newline at end of file diff --git a/meson.build b/meson.build index bf3a608..6db360b 100644 --- a/meson.build +++ b/meson.build @@ -13,10 +13,31 @@ gst_dep = dependency('gstreamer-1.0', version : gst_req) gst_version = gst_dep.version() message('Building against GStreamer ' + gst_version) -git_version = vcs_tag(command : ['python3', 'get_git_version.py', meson.project_source_root()], + +py_script = ''' +import subprocess +import sys, os + +meson_project_path = sys.argv[1] + +git_dir = meson_project_path + "/.git" + +if not os.path.exists(git_dir): + sys.exit(1) + +try: + cmd_result = subprocess.run(["git", "describe", "--tags"], capture_output=True) + vcs_tag = cmd_result.stdout.decode("utf-8")[1:-1] + print(vcs_tag) +except FileNotFoundError: + sys.exit(1) +''' + +git_version = vcs_tag(command : ['python3', '-c', py_script, meson.project_source_root()], input: 'version.h.in', output: 'version.h', replace_string: '@GIT_VERSION@', fallback: meson.project_version() + '-local') + version_arr = gst_version.split('.') gst_version_major = version_arr[0].to_int() gst_version_minor = version_arr[1].to_int() From e265feb2a124f5093cc562abe44427ac55ac5461 Mon Sep 17 00:00:00 2001 From: Marisol Zeledon Date: Tue, 31 Jan 2023 15:22:57 -0600 Subject: [PATCH 087/126] Register devices when requesting pylonobject instance if not already registered --- gst-libs/gst/pylon/gstpylonobject.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 756b4f6..3e4b25a 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -418,10 +418,11 @@ GObject* gst_pylon_object_new( GType type = g_type_from_name(type_name.c_str()); if (!type) { - std::string msg = "Camera \'" + - std::string(camera->GetDeviceInfo().GetFriendlyName()) + - "\' is not available."; - throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); + std::string cache_filename = + std::string(camera->GetDeviceInfo().GetModelName() + "_" + + Pylon::VersionInfo::getVersionString() + "_" + VERSION); + GstPylonCache feature_cache(cache_filename); + type = gst_pylon_object_register(device_name, feature_cache, *nodemap); } GObject* obj = G_OBJECT(g_object_new(type, "name", type_name.c_str(), NULL)); From 7776a57540ab49f4e461ec0f34cfd79546461123 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Wed, 1 Mar 2023 08:02:13 -0600 Subject: [PATCH 088/126] Refactor code to avoid simultaneous pipelines segfault --- ext/pylon/gstpylon.cpp | 9 ++-- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 11 +++-- gst-libs/gst/pylon/gstpylonfeaturewalker.h | 2 +- gst-libs/gst/pylon/gstpylonintrospection.cpp | 51 +++++++++++--------- gst-libs/gst/pylon/gstpylonintrospection.h | 2 +- gst-libs/gst/pylon/gstpylonobject.cpp | 13 +++-- gst-libs/gst/pylon/gstpylonobject.h | 2 +- 7 files changed, 49 insertions(+), 41 deletions(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 61630a3..f20dea2 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -93,7 +93,7 @@ static std::vector gst_pylon_pfnc_list_to_gst( static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, const std::string &device_full_name, const std::string &device_type_str, - GstPylonCache &feature_cache, GenApi::INodeMap &nodemap, + GstPylonCache *feature_cache, GenApi::INodeMap &nodemap, gchar **device_properties, guint alignment); static void gst_pylon_append_camera_properties( Pylon::CBaslerUniversalInstantCamera *camera, gchar **camera_properties, @@ -813,10 +813,11 @@ gboolean gst_pylon_set_configuration(GstPylon *self, const GstCaps *conf, static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, const std::string &device_full_name, const std::string &device_type_str, - GstPylonCache &feature_cache, GenApi::INodeMap &nodemap, + GstPylonCache *feature_cache, GenApi::INodeMap &nodemap, gchar **device_properties, guint alignment) { g_return_if_fail(camera); g_return_if_fail(device_properties); + g_return_if_fail(feature_cache); GType device_type = gst_pylon_object_register(device_full_name, feature_cache, nodemap); @@ -854,7 +855,7 @@ static void gst_pylon_append_camera_properties( std::string cache_filename = std::string(camera->DeviceModelName.GetValue() + "_" + camera->DeviceFirmwareVersion.GetValue() + "_" + VERSION); - GstPylonCache feature_cache(cache_filename); + GstPylonCache *feature_cache = new GstPylonCache(cache_filename); gst_pylon_append_properties(camera, camera_name, device_type, feature_cache, nodemap, camera_properties, alignment); @@ -872,7 +873,7 @@ static void gst_pylon_append_stream_grabber_properties( std::string cache_filename = std::string(camera->GetDeviceInfo().GetModelName() + "_" + Pylon::VersionInfo::getVersionString() + "_" + VERSION); - GstPylonCache feature_cache(cache_filename); + GstPylonCache *feature_cache = new GstPylonCache(cache_filename); gst_pylon_append_properties(camera, sgrabber_name, device_type, feature_cache, nodemap, sgrabber_properties, alignment); diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index a7e0a6f..3728f05 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -52,7 +52,7 @@ static std::vector gst_pylon_get_int_entries( GenApi::IInteger* int_node); static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const std::string& device_fullname, GstPylonCache& feature_cache); + const std::string& device_fullname, GstPylonCache* feature_cache); static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); @@ -228,7 +228,7 @@ std::vector GstPylonFeatureWalker::process_selector_features( static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const std::string& device_fullname, GstPylonCache& feature_cache) { + const std::string& device_fullname, GstPylonCache* feature_cache) { GenApi::INode* selector_node = NULL; gint64 selector_value = 0; std::vector specs_list; @@ -297,10 +297,11 @@ static void gst_pylon_camera_install_specs( void GstPylonFeatureWalker::install_properties( GObjectClass* oclass, GenApi::INodeMap& nodemap, - const std::string& device_fullname, GstPylonCache& feature_cache) { + const std::string& device_fullname, GstPylonCache* feature_cache) { g_return_if_fail(oclass); + g_return_if_fail(feature_cache); - gboolean is_cache_valid = feature_cache.IsCacheValid(); + gboolean is_cache_valid = feature_cache->IsCacheValid(); gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); @@ -350,7 +351,7 @@ void GstPylonFeatureWalker::install_properties( if (!is_cache_valid) { try { - feature_cache.CreateCacheFile(); + feature_cache->CreateCacheFile(); } catch (const Pylon::GenericException& e) { GST_WARNING("Feature cache could not be generated. %s", e.GetDescription()); diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.h b/gst-libs/gst/pylon/gstpylonfeaturewalker.h index 36fd007..1592a16 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.h +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.h @@ -42,7 +42,7 @@ class GstPylonFeatureWalker { static void install_properties(GObjectClass* oclass, GenApi::INodeMap& nodemap, const std::string& device_fullname, - GstPylonCache& feature_cache); + GstPylonCache* feature_cache); static std::vector process_selector_features( GenApi::INode* node, GenApi::INode** selector_node); }; diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 4e96e46..f0d605f 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -70,10 +70,10 @@ class GstPylonTypeAction : public GstPylonActions { /* prototypes */ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache); + GstPylonCache *feature_cache); static GParamSpec *gst_pylon_make_spec_selector_int64( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache &feature_cache); + guint64 selector_value, GstPylonCache *feature_cache); static GParamSpec *gst_pylon_make_spec_bool(GenApi::INodeMap &nodemap, GenApi::INode *node); static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, @@ -82,10 +82,10 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, guint64 selector_value); static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache); + GstPylonCache *feature_cache); static GParamSpec *gst_pylon_make_spec_selector_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache &feature_cache); + guint64 selector_value, GstPylonCache *feature_cache); static GParamSpec *gst_pylon_make_spec_str(GenApi::INodeMap &nodemap, GenApi::INode *node); static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, @@ -135,13 +135,13 @@ static std::string gst_pylon_build_cache_value_string( static void gst_pylon_query_feature_properties_double( GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache, GParamFlags &flags, + GstPylonCache *feature_cache, GParamFlags &flags, gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings, GenApi::INode *selector = NULL, gint64 selector_value = 0); static void gst_pylon_query_feature_properties_integer( GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache, GParamFlags &flags, + GstPylonCache *feature_cache, GParamFlags &flags, gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings, GenApi::INode *selector = NULL, gint64 selector_value = 0); @@ -544,10 +544,11 @@ static void gst_pylon_find_limits(GenApi::INode *node, void gst_pylon_query_feature_properties_double( GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache, GParamFlags &flags, + GstPylonCache *feature_cache, GParamFlags &flags, gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings, GenApi::INode *selector, gint64 selector_value) { g_return_if_fail(node); + g_return_if_fail(feature_cache); gchar *feature_cache_name = NULL; if (selector) { @@ -563,15 +564,16 @@ void gst_pylon_query_feature_properties_double( } /* If access to a feature cache entry fails, create new props dynamically */ - if (!feature_cache.GetDoubleProps(feature_cache_name, - minimum_under_all_settings, - maximum_under_all_settings, flags)) { + if (!feature_cache->GetDoubleProps(feature_cache_name, + minimum_under_all_settings, + maximum_under_all_settings, flags)) { flags = gst_pylon_query_access(nodemap, node); gst_pylon_find_limits( node, minimum_under_all_settings, maximum_under_all_settings); - feature_cache.SetDoubleProps(feature_cache_name, minimum_under_all_settings, - maximum_under_all_settings, flags); + feature_cache->SetDoubleProps(feature_cache_name, + minimum_under_all_settings, + maximum_under_all_settings, flags); } g_free(feature_cache_name); @@ -579,10 +581,11 @@ void gst_pylon_query_feature_properties_double( void gst_pylon_query_feature_properties_integer( GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache, GParamFlags &flags, + GstPylonCache *feature_cache, GParamFlags &flags, gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings, GenApi::INode *selector, gint64 selector_value) { g_return_if_fail(node); + g_return_if_fail(feature_cache); gchar *feature_cache_name = NULL; if (selector) { @@ -599,16 +602,16 @@ void gst_pylon_query_feature_properties_integer( } /* If access to a feature cache entry fails, create new props dynamically */ - if (!feature_cache.GetIntProps(node->GetName().c_str(), - minimum_under_all_settings, - maximum_under_all_settings, flags)) { + if (!feature_cache->GetIntProps(node->GetName().c_str(), + minimum_under_all_settings, + maximum_under_all_settings, flags)) { flags = gst_pylon_query_access(nodemap, node); gst_pylon_find_limits( node, minimum_under_all_settings, maximum_under_all_settings); - feature_cache.SetIntProps(node->GetName().c_str(), - minimum_under_all_settings, - maximum_under_all_settings, flags); + feature_cache->SetIntProps(node->GetName().c_str(), + minimum_under_all_settings, + maximum_under_all_settings, flags); } g_free(feature_cache_name); @@ -616,7 +619,7 @@ void gst_pylon_query_feature_properties_integer( static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache) { + GstPylonCache *feature_cache) { g_return_val_if_fail(node, NULL); Pylon::CIntegerParameter param(node); @@ -634,7 +637,7 @@ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_selector_int64( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache &feature_cache) { + guint64 selector_value, GstPylonCache *feature_cache) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); @@ -681,7 +684,7 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache) { + GstPylonCache *feature_cache) { g_return_val_if_fail(node, NULL); Pylon::CFloatParameter param(node); @@ -699,7 +702,7 @@ static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_selector_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache &feature_cache) { + guint64 selector_value, GstPylonCache *feature_cache) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); @@ -824,7 +827,7 @@ GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, GenApi::INode *selector, guint64 selector_value, const std::string &device_fullname, - GstPylonCache &feature_cache) { + GstPylonCache *feature_cache) { g_return_val_if_fail(node, NULL); GParamSpec *spec = NULL; diff --git a/gst-libs/gst/pylon/gstpylonintrospection.h b/gst-libs/gst/pylon/gstpylonintrospection.h index 5cc01a9..e62e150 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.h +++ b/gst-libs/gst/pylon/gstpylonintrospection.h @@ -42,7 +42,7 @@ class GstPylonParamFactory { static GParamSpec *make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, const std::string &device_fullname, - GstPylonCache &feature_cache); + GstPylonCache *feature_cache); }; #endif diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 3e4b25a..6121032 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -50,8 +50,10 @@ struct _GstPylonObjectPrivate { typedef struct _GstPylonObjectDeviceMembers GstPylonObjectDeviceMembers; struct _GstPylonObjectDeviceMembers { const std::string& device_name; - GstPylonCache& feature_cache; + GstPylonCache* feature_cache; GenApi::INodeMap& nodemap; + + ~_GstPylonObjectDeviceMembers() { delete feature_cache; } }; /************************************************************ @@ -76,7 +78,7 @@ static inline gpointer gst_pylon_object_get_instance_private( } GType gst_pylon_object_register(const std::string& device_name, - GstPylonCache& feature_cache, + GstPylonCache* feature_cache, GenApi::INodeMap& exemplar) { GstPylonObjectDeviceMembers* device_members = new GstPylonObjectDeviceMembers({device_name, feature_cache, exemplar}); @@ -117,7 +119,7 @@ GType gst_pylon_object_register(const std::string& device_name, static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, const std::string& device_name, - GstPylonCache& feature_cache); + GstPylonCache* feature_cache); /* Set a pylon feature from a gstreamer gst property */ template @@ -172,8 +174,9 @@ typedef void (*GSetEnum)(GValue*, gint); static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, const std::string& device_name, - GstPylonCache& feature_cache) { + GstPylonCache* feature_cache) { g_return_if_fail(klass); + g_return_if_fail(feature_cache); GObjectClass* oclass = G_OBJECT_CLASS(klass); @@ -421,7 +424,7 @@ GObject* gst_pylon_object_new( std::string cache_filename = std::string(camera->GetDeviceInfo().GetModelName() + "_" + Pylon::VersionInfo::getVersionString() + "_" + VERSION); - GstPylonCache feature_cache(cache_filename); + GstPylonCache* feature_cache = new GstPylonCache(cache_filename); type = gst_pylon_object_register(device_name, feature_cache, *nodemap); } diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index 540dcdd..c52b2be 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -45,7 +45,7 @@ struct _GstPylonObjectClass { }; EXT_PYLONSRC_API GType gst_pylon_object_register(const std::string& device_name, - GstPylonCache& feature_cache, + GstPylonCache* feature_cache, GenApi::INodeMap& nodemap); EXT_PYLONSRC_API GObject* gst_pylon_object_new( std::shared_ptr camera, From 1c75adb10799c30124509474be6c83f1df119382 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Wed, 1 Mar 2023 11:53:19 -0600 Subject: [PATCH 089/126] Revert refactor of the cache to use dynamic memory --- ext/pylon/gstpylon.cpp | 9 ++-- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 11 ++--- gst-libs/gst/pylon/gstpylonfeaturewalker.h | 2 +- gst-libs/gst/pylon/gstpylonintrospection.cpp | 51 +++++++++----------- gst-libs/gst/pylon/gstpylonintrospection.h | 2 +- gst-libs/gst/pylon/gstpylonobject.cpp | 13 ++--- gst-libs/gst/pylon/gstpylonobject.h | 2 +- 7 files changed, 41 insertions(+), 49 deletions(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index f20dea2..61630a3 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -93,7 +93,7 @@ static std::vector gst_pylon_pfnc_list_to_gst( static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, const std::string &device_full_name, const std::string &device_type_str, - GstPylonCache *feature_cache, GenApi::INodeMap &nodemap, + GstPylonCache &feature_cache, GenApi::INodeMap &nodemap, gchar **device_properties, guint alignment); static void gst_pylon_append_camera_properties( Pylon::CBaslerUniversalInstantCamera *camera, gchar **camera_properties, @@ -813,11 +813,10 @@ gboolean gst_pylon_set_configuration(GstPylon *self, const GstCaps *conf, static void gst_pylon_append_properties( Pylon::CBaslerUniversalInstantCamera *camera, const std::string &device_full_name, const std::string &device_type_str, - GstPylonCache *feature_cache, GenApi::INodeMap &nodemap, + GstPylonCache &feature_cache, GenApi::INodeMap &nodemap, gchar **device_properties, guint alignment) { g_return_if_fail(camera); g_return_if_fail(device_properties); - g_return_if_fail(feature_cache); GType device_type = gst_pylon_object_register(device_full_name, feature_cache, nodemap); @@ -855,7 +854,7 @@ static void gst_pylon_append_camera_properties( std::string cache_filename = std::string(camera->DeviceModelName.GetValue() + "_" + camera->DeviceFirmwareVersion.GetValue() + "_" + VERSION); - GstPylonCache *feature_cache = new GstPylonCache(cache_filename); + GstPylonCache feature_cache(cache_filename); gst_pylon_append_properties(camera, camera_name, device_type, feature_cache, nodemap, camera_properties, alignment); @@ -873,7 +872,7 @@ static void gst_pylon_append_stream_grabber_properties( std::string cache_filename = std::string(camera->GetDeviceInfo().GetModelName() + "_" + Pylon::VersionInfo::getVersionString() + "_" + VERSION); - GstPylonCache *feature_cache = new GstPylonCache(cache_filename); + GstPylonCache feature_cache(cache_filename); gst_pylon_append_properties(camera, sgrabber_name, device_type, feature_cache, nodemap, sgrabber_properties, alignment); diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 3728f05..a7e0a6f 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -52,7 +52,7 @@ static std::vector gst_pylon_get_int_entries( GenApi::IInteger* int_node); static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const std::string& device_fullname, GstPylonCache* feature_cache); + const std::string& device_fullname, GstPylonCache& feature_cache); static void gst_pylon_camera_install_specs( const std::vector& specs_list, GObjectClass* oclass, gint& nprop); @@ -228,7 +228,7 @@ std::vector GstPylonFeatureWalker::process_selector_features( static std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, - const std::string& device_fullname, GstPylonCache* feature_cache) { + const std::string& device_fullname, GstPylonCache& feature_cache) { GenApi::INode* selector_node = NULL; gint64 selector_value = 0; std::vector specs_list; @@ -297,11 +297,10 @@ static void gst_pylon_camera_install_specs( void GstPylonFeatureWalker::install_properties( GObjectClass* oclass, GenApi::INodeMap& nodemap, - const std::string& device_fullname, GstPylonCache* feature_cache) { + const std::string& device_fullname, GstPylonCache& feature_cache) { g_return_if_fail(oclass); - g_return_if_fail(feature_cache); - gboolean is_cache_valid = feature_cache->IsCacheValid(); + gboolean is_cache_valid = feature_cache.IsCacheValid(); gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); @@ -351,7 +350,7 @@ void GstPylonFeatureWalker::install_properties( if (!is_cache_valid) { try { - feature_cache->CreateCacheFile(); + feature_cache.CreateCacheFile(); } catch (const Pylon::GenericException& e) { GST_WARNING("Feature cache could not be generated. %s", e.GetDescription()); diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.h b/gst-libs/gst/pylon/gstpylonfeaturewalker.h index 1592a16..36fd007 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.h +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.h @@ -42,7 +42,7 @@ class GstPylonFeatureWalker { static void install_properties(GObjectClass* oclass, GenApi::INodeMap& nodemap, const std::string& device_fullname, - GstPylonCache* feature_cache); + GstPylonCache& feature_cache); static std::vector process_selector_features( GenApi::INode* node, GenApi::INode** selector_node); }; diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index f0d605f..4e96e46 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -70,10 +70,10 @@ class GstPylonTypeAction : public GstPylonActions { /* prototypes */ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache *feature_cache); + GstPylonCache &feature_cache); static GParamSpec *gst_pylon_make_spec_selector_int64( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache *feature_cache); + guint64 selector_value, GstPylonCache &feature_cache); static GParamSpec *gst_pylon_make_spec_bool(GenApi::INodeMap &nodemap, GenApi::INode *node); static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, @@ -82,10 +82,10 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, guint64 selector_value); static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache *feature_cache); + GstPylonCache &feature_cache); static GParamSpec *gst_pylon_make_spec_selector_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache *feature_cache); + guint64 selector_value, GstPylonCache &feature_cache); static GParamSpec *gst_pylon_make_spec_str(GenApi::INodeMap &nodemap, GenApi::INode *node); static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, @@ -135,13 +135,13 @@ static std::string gst_pylon_build_cache_value_string( static void gst_pylon_query_feature_properties_double( GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache *feature_cache, GParamFlags &flags, + GstPylonCache &feature_cache, GParamFlags &flags, gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings, GenApi::INode *selector = NULL, gint64 selector_value = 0); static void gst_pylon_query_feature_properties_integer( GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache *feature_cache, GParamFlags &flags, + GstPylonCache &feature_cache, GParamFlags &flags, gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings, GenApi::INode *selector = NULL, gint64 selector_value = 0); @@ -544,11 +544,10 @@ static void gst_pylon_find_limits(GenApi::INode *node, void gst_pylon_query_feature_properties_double( GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache *feature_cache, GParamFlags &flags, + GstPylonCache &feature_cache, GParamFlags &flags, gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings, GenApi::INode *selector, gint64 selector_value) { g_return_if_fail(node); - g_return_if_fail(feature_cache); gchar *feature_cache_name = NULL; if (selector) { @@ -564,16 +563,15 @@ void gst_pylon_query_feature_properties_double( } /* If access to a feature cache entry fails, create new props dynamically */ - if (!feature_cache->GetDoubleProps(feature_cache_name, - minimum_under_all_settings, - maximum_under_all_settings, flags)) { + if (!feature_cache.GetDoubleProps(feature_cache_name, + minimum_under_all_settings, + maximum_under_all_settings, flags)) { flags = gst_pylon_query_access(nodemap, node); gst_pylon_find_limits( node, minimum_under_all_settings, maximum_under_all_settings); - feature_cache->SetDoubleProps(feature_cache_name, - minimum_under_all_settings, - maximum_under_all_settings, flags); + feature_cache.SetDoubleProps(feature_cache_name, minimum_under_all_settings, + maximum_under_all_settings, flags); } g_free(feature_cache_name); @@ -581,11 +579,10 @@ void gst_pylon_query_feature_properties_double( void gst_pylon_query_feature_properties_integer( GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache *feature_cache, GParamFlags &flags, + GstPylonCache &feature_cache, GParamFlags &flags, gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings, GenApi::INode *selector, gint64 selector_value) { g_return_if_fail(node); - g_return_if_fail(feature_cache); gchar *feature_cache_name = NULL; if (selector) { @@ -602,16 +599,16 @@ void gst_pylon_query_feature_properties_integer( } /* If access to a feature cache entry fails, create new props dynamically */ - if (!feature_cache->GetIntProps(node->GetName().c_str(), - minimum_under_all_settings, - maximum_under_all_settings, flags)) { + if (!feature_cache.GetIntProps(node->GetName().c_str(), + minimum_under_all_settings, + maximum_under_all_settings, flags)) { flags = gst_pylon_query_access(nodemap, node); gst_pylon_find_limits( node, minimum_under_all_settings, maximum_under_all_settings); - feature_cache->SetIntProps(node->GetName().c_str(), - minimum_under_all_settings, - maximum_under_all_settings, flags); + feature_cache.SetIntProps(node->GetName().c_str(), + minimum_under_all_settings, + maximum_under_all_settings, flags); } g_free(feature_cache_name); @@ -619,7 +616,7 @@ void gst_pylon_query_feature_properties_integer( static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache *feature_cache) { + GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); Pylon::CIntegerParameter param(node); @@ -637,7 +634,7 @@ static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_selector_int64( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache *feature_cache) { + guint64 selector_value, GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); @@ -684,7 +681,7 @@ static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache *feature_cache) { + GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); Pylon::CFloatParameter param(node); @@ -702,7 +699,7 @@ static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, static GParamSpec *gst_pylon_make_spec_selector_double( GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache *feature_cache) { + guint64 selector_value, GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); g_return_val_if_fail(selector, NULL); @@ -827,7 +824,7 @@ GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, GenApi::INode *selector, guint64 selector_value, const std::string &device_fullname, - GstPylonCache *feature_cache) { + GstPylonCache &feature_cache) { g_return_val_if_fail(node, NULL); GParamSpec *spec = NULL; diff --git a/gst-libs/gst/pylon/gstpylonintrospection.h b/gst-libs/gst/pylon/gstpylonintrospection.h index e62e150..5cc01a9 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.h +++ b/gst-libs/gst/pylon/gstpylonintrospection.h @@ -42,7 +42,7 @@ class GstPylonParamFactory { static GParamSpec *make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, guint64 selector_value, const std::string &device_fullname, - GstPylonCache *feature_cache); + GstPylonCache &feature_cache); }; #endif diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 6121032..3e4b25a 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -50,10 +50,8 @@ struct _GstPylonObjectPrivate { typedef struct _GstPylonObjectDeviceMembers GstPylonObjectDeviceMembers; struct _GstPylonObjectDeviceMembers { const std::string& device_name; - GstPylonCache* feature_cache; + GstPylonCache& feature_cache; GenApi::INodeMap& nodemap; - - ~_GstPylonObjectDeviceMembers() { delete feature_cache; } }; /************************************************************ @@ -78,7 +76,7 @@ static inline gpointer gst_pylon_object_get_instance_private( } GType gst_pylon_object_register(const std::string& device_name, - GstPylonCache* feature_cache, + GstPylonCache& feature_cache, GenApi::INodeMap& exemplar) { GstPylonObjectDeviceMembers* device_members = new GstPylonObjectDeviceMembers({device_name, feature_cache, exemplar}); @@ -119,7 +117,7 @@ GType gst_pylon_object_register(const std::string& device_name, static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, const std::string& device_name, - GstPylonCache* feature_cache); + GstPylonCache& feature_cache); /* Set a pylon feature from a gstreamer gst property */ template @@ -174,9 +172,8 @@ typedef void (*GSetEnum)(GValue*, gint); static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, GenApi::INodeMap& nodemap, const std::string& device_name, - GstPylonCache* feature_cache) { + GstPylonCache& feature_cache) { g_return_if_fail(klass); - g_return_if_fail(feature_cache); GObjectClass* oclass = G_OBJECT_CLASS(klass); @@ -424,7 +421,7 @@ GObject* gst_pylon_object_new( std::string cache_filename = std::string(camera->GetDeviceInfo().GetModelName() + "_" + Pylon::VersionInfo::getVersionString() + "_" + VERSION); - GstPylonCache* feature_cache = new GstPylonCache(cache_filename); + GstPylonCache feature_cache(cache_filename); type = gst_pylon_object_register(device_name, feature_cache, *nodemap); } diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index c52b2be..540dcdd 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -45,7 +45,7 @@ struct _GstPylonObjectClass { }; EXT_PYLONSRC_API GType gst_pylon_object_register(const std::string& device_name, - GstPylonCache* feature_cache, + GstPylonCache& feature_cache, GenApi::INodeMap& nodemap); EXT_PYLONSRC_API GObject* gst_pylon_object_new( std::shared_ptr camera, From bf157e296f374c10135c54e244c403db53beddc1 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Wed, 1 Mar 2023 12:01:38 -0600 Subject: [PATCH 090/126] Manage feature cache through unique pointers to fix simultaneous pipeline segfault --- ext/pylon/gstpylon.cpp | 15 ++++++++++----- gst-libs/gst/pylon/gstpylonobject.cpp | 6 ++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 61630a3..26eb7fd 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -854,9 +854,11 @@ static void gst_pylon_append_camera_properties( std::string cache_filename = std::string(camera->DeviceModelName.GetValue() + "_" + camera->DeviceFirmwareVersion.GetValue() + "_" + VERSION); - GstPylonCache feature_cache(cache_filename); - gst_pylon_append_properties(camera, camera_name, device_type, feature_cache, + std::unique_ptr feature_cache = + std::make_unique(cache_filename); + + gst_pylon_append_properties(camera, camera_name, device_type, *feature_cache, nodemap, camera_properties, alignment); } @@ -872,10 +874,13 @@ static void gst_pylon_append_stream_grabber_properties( std::string cache_filename = std::string(camera->GetDeviceInfo().GetModelName() + "_" + Pylon::VersionInfo::getVersionString() + "_" + VERSION); - GstPylonCache feature_cache(cache_filename); - gst_pylon_append_properties(camera, sgrabber_name, device_type, feature_cache, - nodemap, sgrabber_properties, alignment); + std::unique_ptr feature_cache = + std::make_unique(cache_filename); + + gst_pylon_append_properties(camera, sgrabber_name, device_type, + *feature_cache, nodemap, sgrabber_properties, + alignment); } static gchar *gst_pylon_get_string_properties( diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 3e4b25a..d4a63c8 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -417,12 +417,14 @@ GObject* gst_pylon_object_new( GType type = g_type_from_name(type_name.c_str()); + std::unique_ptr feature_cache; + if (!type) { std::string cache_filename = std::string(camera->GetDeviceInfo().GetModelName() + "_" + Pylon::VersionInfo::getVersionString() + "_" + VERSION); - GstPylonCache feature_cache(cache_filename); - type = gst_pylon_object_register(device_name, feature_cache, *nodemap); + feature_cache = std::make_unique(cache_filename); + type = gst_pylon_object_register(device_name, *feature_cache, *nodemap); } GObject* obj = G_OBJECT(g_object_new(type, "name", type_name.c_str(), NULL)); From 3079c44bb3268a860cb5dec1ba30ce5463f116fa Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Thu, 2 Mar 2023 07:01:13 -0600 Subject: [PATCH 091/126] Remove unneeded dynamic memory instances --- ext/pylon/gstpylon.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 26eb7fd..364d036 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -855,10 +855,9 @@ static void gst_pylon_append_camera_properties( std::string(camera->DeviceModelName.GetValue() + "_" + camera->DeviceFirmwareVersion.GetValue() + "_" + VERSION); - std::unique_ptr feature_cache = - std::make_unique(cache_filename); + GstPylonCache feature_cache(cache_filename); - gst_pylon_append_properties(camera, camera_name, device_type, *feature_cache, + gst_pylon_append_properties(camera, camera_name, device_type, feature_cache, nodemap, camera_properties, alignment); } @@ -875,12 +874,10 @@ static void gst_pylon_append_stream_grabber_properties( std::string(camera->GetDeviceInfo().GetModelName() + "_" + Pylon::VersionInfo::getVersionString() + "_" + VERSION); - std::unique_ptr feature_cache = - std::make_unique(cache_filename); + GstPylonCache feature_cache(cache_filename); - gst_pylon_append_properties(camera, sgrabber_name, device_type, - *feature_cache, nodemap, sgrabber_properties, - alignment); + gst_pylon_append_properties(camera, sgrabber_name, device_type, feature_cache, + nodemap, sgrabber_properties, alignment); } static gchar *gst_pylon_get_string_properties( From a8303794a71aaf50c7fcbb80b1a096bf00f99cff Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 30 Jan 2023 15:10:53 -0600 Subject: [PATCH 092/126] Add correction property installation --- ext/pylon/gstpylon.cpp | 6 +- ext/pylon/gstpylon.h | 2 +- ext/pylon/gstpylonsrc.c | 984 ++++++++++++++++++++++++++ gst-libs/gst/pylon/gstpylonobject.cpp | 1 + 4 files changed, 989 insertions(+), 4 deletions(-) create mode 100644 ext/pylon/gstpylonsrc.c diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 364d036..9440fd3 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -196,7 +196,7 @@ static void gst_pylon_apply_set(GstPylon *self, std::string &set) { GstPylon *gst_pylon_new(GstElement *gstpylonsrc, const gchar *device_user_name, const gchar *device_serial_number, gint device_index, - GError **err) { + gboolean enable_correction, GError **err) { GstPylon *self = new GstPylon; self->gstpylonsrc = gstpylonsrc; @@ -276,13 +276,13 @@ GstPylon *gst_pylon_new(GstElement *gstpylonsrc, const gchar *device_user_name, GenApi::INodeMap &cam_nodemap = self->camera->GetNodeMap(); self->gcamera = gst_pylon_object_new( self->camera, gst_pylon_get_camera_fullname(*self->camera), - &cam_nodemap); + &cam_nodemap, enable_correction); GenApi::INodeMap &sgrabber_nodemap = self->camera->GetStreamGrabberNodeMap(); self->gstream_grabber = gst_pylon_object_new( self->camera, gst_pylon_get_sgrabber_name(*self->camera), - &sgrabber_nodemap); + &sgrabber_nodemap, enable_correction); /* Register event handlers after device instances are requested so they do * not get registered if creating the device instances fails */ diff --git a/ext/pylon/gstpylon.h b/ext/pylon/gstpylon.h index efcd810..bba1417 100644 --- a/ext/pylon/gstpylon.h +++ b/ext/pylon/gstpylon.h @@ -48,7 +48,7 @@ void gst_pylon_initialize(); GstPylon *gst_pylon_new(GstElement *gstpylonsrc, const gchar *device_user_name, const gchar *device_serial_number, gint device_index, - GError **err); + gboolean enable_correction, GError **err); gboolean gst_pylon_set_user_config(GstPylon *self, const gchar *user_set, GError **err); void gst_pylon_free(GstPylon *self); diff --git a/ext/pylon/gstpylonsrc.c b/ext/pylon/gstpylonsrc.c new file mode 100644 index 0000000..7c10227 --- /dev/null +++ b/ext/pylon/gstpylonsrc.c @@ -0,0 +1,984 @@ +/* Copyright (C) 2022 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * SECTION:element-gstpylonsrc + * + * The pylonsrc element captures images from Basler cameras. + * + * + * Example launch line + * |[ + * gst-launch-1.0 -v pylonsrc ! videoconvert ! autovideosink + * ]| + * Capture images from a Basler camera and display them. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstpylonsrc.h" + +#include "gstpylon.h" +#include "gst/pylon/gstpylonmeta.h" +#include "gst/pylon/gstpylondebug.h" + +#include + +struct _GstPylonSrc +{ + GstPushSrc base_pylonsrc; + GstPylon *pylon; + GstClockTime duration; + GstVideoInfo video_info; + + gchar *device_user_name; + gchar *device_serial_number; + gint device_index; + gchar *user_set; + gchar *pfs_location; + gboolean enable_correction; + GstPylonCaptureErrorEnum capture_error; + GObject *cam; + GObject *stream; +}; + +/* prototypes */ + +static void +gst_pylon_src_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_pylon_src_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); +static void gst_pylon_src_finalize (GObject * object); + +static GstCaps *gst_pylon_src_get_caps (GstBaseSrc * src, GstCaps * filter); +static gboolean gst_pylon_src_is_bayer (GstStructure * st); +static GstCaps *gst_pylon_src_fixate (GstBaseSrc * src, GstCaps * caps); +static gboolean gst_pylon_src_set_caps (GstBaseSrc * src, GstCaps * caps); +static gboolean gst_pylon_src_decide_allocation (GstBaseSrc * src, + GstQuery * query); +static gboolean gst_pylon_src_start (GstBaseSrc * src); +static gboolean gst_pylon_src_stop (GstBaseSrc * src); +static gboolean gst_pylon_src_unlock (GstBaseSrc * src); +static gboolean gst_pylon_src_query (GstBaseSrc * src, GstQuery * query); +static void gst_plyon_src_add_metadata (GstPylonSrc * self, GstBuffer * buf); +static GstFlowReturn gst_pylon_src_create (GstPushSrc * src, GstBuffer ** buf); + +static void gst_pylon_src_child_proxy_init (GstChildProxyInterface * iface); + +enum +{ + PROP_0, + PROP_DEVICE_USER_NAME, + PROP_DEVICE_SERIAL_NUMBER, + PROP_DEVICE_INDEX, + PROP_USER_SET, + PROP_PFS_LOCATION, + PROP_ENABLE_CORRECTION, + PROP_CAPTURE_ERROR, + PROP_CAM, + PROP_STREAM +}; + +#define PROP_DEVICE_USER_NAME_DEFAULT NULL +#define PROP_DEVICE_SERIAL_NUMBER_DEFAULT NULL +#define PROP_DEVICE_INDEX_DEFAULT -1 +#define PROP_DEVICE_INDEX_MIN -1 +#define PROP_DEVICE_INDEX_MAX G_MAXINT32 +#define PROP_USER_SET_DEFAULT NULL +#define PROP_PFS_LOCATION_DEFAULT NULL +#define PROP_ENABLE_CORRECTION_DEFAULT FALSE +#define PROP_CAM_DEFAULT NULL +#define PROP_STREAM_DEFAULT NULL +#define PROP_CAPTURE_ERROR_DEFAULT ENUM_ABORT + +/* Enum for cature_error */ +#define GST_TYPE_CAPTURE_ERROR_ENUM (gst_pylon_capture_error_enum_get_type ()) + +/* Child proxy interface names */ +static const gchar *gst_pylon_src_child_proxy_names[] = { + "cam", + "stream" +}; + +static GType +gst_pylon_capture_error_enum_get_type (void) +{ + static gsize gtype = 0; + static const GEnumValue values[] = { + {ENUM_KEEP, "keep", "Use partial or corrupt buffers"}, + {ENUM_SKIP, "skip", + "Skip partial or corrupt buffers. A maximum of 100 buffers can be skipped before the pipeline aborts."}, + {ENUM_ABORT, "abort", "Stop pipeline in case of any capture error"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (>ype)) { + GType tmp = g_enum_register_static ("GstPylonCaptureErrorEnum", values); + g_once_init_leave (>ype, tmp); + } + + return (GType) gtype; +} + +/* pad templates */ + +static GstStaticPadTemplate gst_pylon_src_src_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (" {GRAY8, RGB, BGR, YUY2, UYVY} ") ";" + "video/x-bayer,format={rggb,bggr,gbgr,grgb},width=" GST_VIDEO_SIZE_RANGE + ",height=" GST_VIDEO_SIZE_RANGE ",framerate=" GST_VIDEO_FPS_RANGE)); + + +/* class initialization */ +G_DEFINE_TYPE_WITH_CODE (GstPylonSrc, gst_pylon_src, GST_TYPE_PUSH_SRC, + gst_pylon_debug_init (); + G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY, gst_pylon_src_child_proxy_init) + ); + +static void +gst_pylon_src_class_init (GstPylonSrcClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS (klass); + GstPushSrcClass *push_src_class = GST_PUSH_SRC_CLASS (klass); + gchar *cam_params = NULL; + gchar *cam_blurb = NULL; + gchar *stream_params = NULL; + gchar *stream_blurb = NULL; + const gchar *cam_prolog = NULL; + const gchar *stream_prolog = NULL; + + gst_pylon_initialize (); + + /* Setting up pads and setting metadata should be moved to + base_class_init if you intend to subclass this class. */ + gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass), + &gst_pylon_src_src_template); + + gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass), + "Basler/Pylon source element", "Source/Video/Hardware", + "Source element for Basler cameras", + "Basler AG "); + + gobject_class->set_property = gst_pylon_src_set_property; + gobject_class->get_property = gst_pylon_src_get_property; + gobject_class->finalize = gst_pylon_src_finalize; + + g_object_class_install_property (gobject_class, PROP_DEVICE_USER_NAME, + g_param_spec_string ("device-user-name", "Device user defined name", + "The user-defined name of the device to use. May be combined" + "with other device selection properties to reduce the search.", + PROP_DEVICE_USER_NAME_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + g_object_class_install_property (gobject_class, PROP_DEVICE_SERIAL_NUMBER, + g_param_spec_string ("device-serial-number", "Device serial number", + "The serial number of the device to use. May be combined with " + "other device selection properties to reduce the search.", + PROP_DEVICE_SERIAL_NUMBER_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + g_object_class_install_property (gobject_class, PROP_DEVICE_INDEX, + g_param_spec_int ("device-index", "Device index", + "The index of the device to use.This index applies to the " + "resulting device list after applying the other device selection " + "properties. The index is mandatory if multiple devices match " + "the given search criteria.", PROP_DEVICE_INDEX_MIN, + PROP_DEVICE_INDEX_MAX, PROP_DEVICE_INDEX_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + g_object_class_install_property (gobject_class, PROP_USER_SET, + g_param_spec_string ("user-set", "Device user configuration set", + "The user-defined configuration set to use. Leaving this property " + "unset, or using 'Auto' result in selecting the " + "power-on default camera configuration.", + PROP_USER_SET_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + g_object_class_install_property (gobject_class, PROP_PFS_LOCATION, + g_param_spec_string ("pfs-location", "PFS file location", + "The filepath to the PFS file from which to load the device configuration. " + "Setting this property will override the user set property if also set.", + PROP_PFS_LOCATION_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + g_object_class_install_property (gobject_class, PROP_ENABLE_CORRECTION, + g_param_spec_boolean ("enable-correction", + "Enable correction", + "If enabled, the values from other parameters will be automatically corrected. " + " If any of the properties holds an incorrect value given an specific configuration " + "it will be corrected", + PROP_ENABLE_CORRECTION_DEFAULT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + g_object_class_install_property (gobject_class, PROP_CAPTURE_ERROR, + g_param_spec_enum ("capture-error", + "Capture error strategy", + "The strategy to use in case of a camera capture error.", + GST_TYPE_CAPTURE_ERROR_ENUM, PROP_CAPTURE_ERROR_DEFAULT, + G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); + + cam_params = gst_pylon_camera_get_string_properties (); + stream_params = gst_pylon_stream_grabber_get_string_properties (); + + if (NULL == cam_params) { + cam_prolog = "No valid cameras where found connected to the system."; + stream_prolog = cam_prolog; + cam_params = g_strdup (""); + stream_params = g_strdup (""); + } else { + cam_prolog = "The following list details the properties for each camera.\n"; + stream_prolog = + "The following list details the properties for each stream grabber.\n"; + } + + cam_blurb = g_strdup_printf ("The camera to use.\n" + "\t\t\tAccording to the selected camera " + "different properties will be available.\n " + "\t\t\tThese properties can be accessed using the " + "\"cam::\" syntax.\n" "\t\t\t%s%s", cam_prolog, cam_params); + + g_object_class_install_property (gobject_class, PROP_CAM, + g_param_spec_object ("cam", "Camera", cam_blurb, G_TYPE_OBJECT, + G_PARAM_READABLE)); + + stream_blurb = g_strdup_printf ("The stream grabber to use.\n" + "\t\t\tAccording to the selected stream grabber " + "different properties will be available.\n " + "\t\t\tThese properties can be accessed using the " + "\"stream::\" syntax.\n" "\t\t\t%s%s", stream_prolog, + stream_params); + + g_object_class_install_property (gobject_class, PROP_STREAM, + g_param_spec_object ("stream", "Stream Grabber", stream_blurb, + G_TYPE_OBJECT, G_PARAM_READABLE)); + + g_free (cam_params); + g_free (stream_params); + + base_src_class->get_caps = GST_DEBUG_FUNCPTR (gst_pylon_src_get_caps); + base_src_class->fixate = GST_DEBUG_FUNCPTR (gst_pylon_src_fixate); + base_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_pylon_src_set_caps); + base_src_class->decide_allocation = + GST_DEBUG_FUNCPTR (gst_pylon_src_decide_allocation); + base_src_class->start = GST_DEBUG_FUNCPTR (gst_pylon_src_start); + base_src_class->stop = GST_DEBUG_FUNCPTR (gst_pylon_src_stop); + base_src_class->unlock = GST_DEBUG_FUNCPTR (gst_pylon_src_unlock); + base_src_class->query = GST_DEBUG_FUNCPTR (gst_pylon_src_query); + + push_src_class->create = GST_DEBUG_FUNCPTR (gst_pylon_src_create); +} + +static void +gst_pylon_src_init (GstPylonSrc * self) +{ + GstBaseSrc *base = GST_BASE_SRC (self); + + self->pylon = NULL; + self->duration = GST_CLOCK_TIME_NONE; + self->device_user_name = PROP_DEVICE_USER_NAME_DEFAULT; + self->device_serial_number = PROP_DEVICE_SERIAL_NUMBER_DEFAULT; + self->device_index = PROP_DEVICE_INDEX_DEFAULT; + self->user_set = PROP_USER_SET_DEFAULT; + self->pfs_location = PROP_PFS_LOCATION_DEFAULT; + self->enable_correction = PROP_ENABLE_CORRECTION_DEFAULT; + self->capture_error = PROP_CAPTURE_ERROR_DEFAULT; + self->cam = PROP_CAM_DEFAULT; + self->stream = PROP_STREAM_DEFAULT; + gst_video_info_init (&self->video_info); + + gst_base_src_set_live (base, TRUE); + gst_base_src_set_format (base, GST_FORMAT_TIME); +} + +static void +gst_pylon_src_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstPylonSrc *self = GST_PYLON_SRC (object); + + GST_LOG_OBJECT (self, "set_property"); + + GST_OBJECT_LOCK (self); + + switch (property_id) { + case PROP_DEVICE_USER_NAME: + g_free (self->device_user_name); + self->device_user_name = g_value_dup_string (value); + break; + case PROP_DEVICE_SERIAL_NUMBER: + g_free (self->device_serial_number); + self->device_serial_number = g_value_dup_string (value); + break; + case PROP_DEVICE_INDEX: + self->device_index = g_value_get_int (value); + break; + case PROP_USER_SET: + g_free (self->user_set); + self->user_set = g_value_dup_string (value); + break; + case PROP_PFS_LOCATION: + g_free (self->pfs_location); + self->pfs_location = g_value_dup_string (value); + break; + case PROP_ENABLE_CORRECTION: + self->enable_correction = g_value_get_boolean(value); + break; + case PROP_CAPTURE_ERROR: + self->capture_error = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } + + GST_OBJECT_UNLOCK (self); +} + +static void +gst_pylon_src_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstPylonSrc *self = GST_PYLON_SRC (object); + + GST_LOG_OBJECT (self, "get_property"); + + GST_OBJECT_LOCK (self); + + switch (property_id) { + case PROP_DEVICE_USER_NAME: + g_value_set_string (value, self->device_user_name); + break; + case PROP_DEVICE_SERIAL_NUMBER: + g_value_set_string (value, self->device_serial_number); + break; + case PROP_DEVICE_INDEX: + g_value_set_int (value, self->device_index); + break; + case PROP_USER_SET: + g_value_set_string (value, self->user_set); + break; + case PROP_PFS_LOCATION: + g_value_set_string (value, self->pfs_location); + break; + case PROP_ENABLE_CORRECTION: + g_value_set_boolean(value, self->enable_correction); + break; + case PROP_CAPTURE_ERROR: + g_value_set_enum (value, self->capture_error); + break; + case PROP_CAM: + g_value_set_object (value, self->cam); + break; + case PROP_STREAM: + g_value_set_object (value, self->stream); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } + + GST_OBJECT_UNLOCK (self); +} + +static void +gst_pylon_src_finalize (GObject * object) +{ + GstPylonSrc *self = GST_PYLON_SRC (object); + + GST_LOG_OBJECT (self, "finalize"); + + g_free (self->device_user_name); + self->device_user_name = NULL; + + g_free (self->device_serial_number); + self->device_serial_number = NULL; + + g_free (self->user_set); + self->user_set = NULL; + + if (self->cam) { + g_object_unref (self->cam); + self->cam = NULL; + } + + if (self->stream) { + g_object_unref (self->stream); + self->stream = NULL; + } + + G_OBJECT_CLASS (gst_pylon_src_parent_class)->finalize (object); +} + +/* get caps from subclass */ +static GstCaps * +gst_pylon_src_get_caps (GstBaseSrc * src, GstCaps * filter) +{ + GstPylonSrc *self = GST_PYLON_SRC (src); + GstCaps *outcaps = NULL; + GError *error = NULL; + + if (!self->pylon) { + outcaps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (self)); + GST_INFO_OBJECT (self, + "Camera not open yet, returning src template caps %" GST_PTR_FORMAT, + outcaps); + goto out; + } + + outcaps = gst_pylon_query_configuration (self->pylon, &error); + + if (outcaps == NULL && error) { + goto log_gst_error; + } + + GST_DEBUG_OBJECT (self, "Camera returned caps %" GST_PTR_FORMAT, outcaps); + + if (filter) { + GstCaps *tmp = outcaps; + + GST_DEBUG_OBJECT (self, "Filtering with %" GST_PTR_FORMAT, filter); + + outcaps = gst_caps_intersect (outcaps, filter); + gst_caps_unref (tmp); + } + + GST_INFO_OBJECT (self, "Returning caps %" GST_PTR_FORMAT, outcaps); + + goto out; + +log_gst_error: + GST_ELEMENT_ERROR (self, LIBRARY, FAILED, + ("Failed to get caps."), ("%s", error->message)); + g_error_free (error); + +out: + return outcaps; +} + +static gboolean +gst_pylon_src_is_bayer (GstStructure * st) +{ + gboolean is_bayer = FALSE; + + g_return_val_if_fail (st, FALSE); + + if (0 == g_strcmp0 (gst_structure_get_name (st), "video/x-bayer")) { + is_bayer = TRUE; + } + return is_bayer; +} + +/* called if, in negotiation, caps need fixating */ +static GstCaps * +gst_pylon_src_fixate (GstBaseSrc * src, GstCaps * caps) +{ + GstPylonSrc *self = GST_PYLON_SRC (src); + GstCaps *outcaps = NULL; + GstStructure *st = NULL; + const GValue *width_field = NULL; + static const gint width_1080p = 1920; + static const gint height_1080p = 1080; + static const gint preferred_framerate_num = 30; + static const gint preferred_framerate_den = 1; + gint preferred_width_adjusted = 0; + + /* get the configured width/height after applying userset and pfs */ + gint preferred_width = width_1080p; + gint preferred_height = height_1080p; + gst_pylon_get_startup_geometry (self->pylon, &preferred_width, + &preferred_height); + + GST_DEBUG_OBJECT (self, "Fixating caps %" GST_PTR_FORMAT, caps); + + if (gst_caps_is_fixed (caps)) { + GST_DEBUG_OBJECT (self, "Caps are already fixed"); + return caps; + } + + outcaps = gst_caps_new_empty (); + st = gst_structure_copy (gst_caps_get_structure (caps, 0)); + width_field = gst_structure_get_value (st, "width"); + gst_caps_unref (caps); + + if (gst_pylon_src_is_bayer (st) && GST_VALUE_HOLDS_INT_RANGE (width_field)) { + preferred_width_adjusted = + GST_ROUND_DOWN_4 (gst_value_get_int_range_max (width_field)); + } else { + preferred_width_adjusted = preferred_width; + } + + gst_structure_fixate_field_nearest_int (st, "width", + preferred_width_adjusted); + gst_structure_fixate_field_nearest_int (st, "height", preferred_height); + gst_structure_fixate_field_nearest_fraction (st, "framerate", + preferred_framerate_num, preferred_framerate_den); + + gst_caps_append_structure (outcaps, st); + + /* fixate the remainder of the fields */ + outcaps = gst_caps_fixate (outcaps); + + GST_INFO_OBJECT (self, "Fixated caps to %" GST_PTR_FORMAT, outcaps); + + return outcaps; +} + +/* notify the subclass of new caps */ +static gboolean +gst_pylon_src_set_caps (GstBaseSrc * src, GstCaps * caps) +{ + GstPylonSrc *self = GST_PYLON_SRC (src); + GstStructure *st = NULL; + gint numerator = 0; + gint denominator = 0; + gint width = 0; + static const gint byte_alignment = 4; + gchar *error_msg = NULL; + GError *error = NULL; + gboolean ret = FALSE; + const gchar *action = NULL; + + GST_INFO_OBJECT (self, "Setting new caps: %" GST_PTR_FORMAT, caps); + + st = gst_caps_get_structure (caps, 0); + gst_structure_get_int (st, "width", &width); + + if (gst_pylon_src_is_bayer (st) && 0 != width % byte_alignment) { + action = "configure"; + error_msg = + g_strdup + ("Bayer formats require the width to be word aligned (4 bytes)."); + goto error; + } + + gst_structure_get_fraction (st, "framerate", &numerator, &denominator); + + GST_OBJECT_LOCK (self); + if (numerator != 0) { + self->duration = gst_util_uint64_scale (GST_SECOND, denominator, numerator); + } else { + self->duration = GST_CLOCK_TIME_NONE; + } + GST_OBJECT_UNLOCK (self); + + ret = gst_pylon_stop (self->pylon, &error); + if (FALSE == ret && error) { + action = "stop"; + goto log_error; + } + + ret = gst_pylon_set_configuration (self->pylon, caps, &error); + if (FALSE == ret && error) { + action = "configure"; + goto log_error; + } + + ret = gst_pylon_start (self->pylon, &error); + if (FALSE == ret && error) { + action = "start"; + goto log_error; + } + + ret = gst_video_info_from_caps (&self->video_info, caps); + + goto out; + +log_error: + error_msg = g_strdup (error->message); + g_error_free (error); + +error: + GST_ELEMENT_ERROR (self, LIBRARY, FAILED, + ("Failed to %s camera.", action), ("%s", error_msg)); + g_free (error_msg); + +out: + return ret; +} + +/* setup allocation query */ +static gboolean +gst_pylon_src_decide_allocation (GstBaseSrc * src, GstQuery * query) +{ + GstPylonSrc *self = GST_PYLON_SRC (src); + + GST_LOG_OBJECT (self, "decide_allocation"); + + return TRUE; +} + +/* start and stop processing, ideal for opening/closing the resource */ +static gboolean +gst_pylon_src_start (GstBaseSrc * src) +{ + GstPylonSrc *self = GST_PYLON_SRC (src); + GError *error = NULL; + gboolean ret = TRUE; + gboolean using_pfs = FALSE; + gboolean same_device = TRUE; + + GST_OBJECT_LOCK (self); + same_device = self->pylon + && gst_pylon_is_same_device (self->pylon, self->device_index, + self->device_user_name, self->device_serial_number); + GST_OBJECT_UNLOCK (self); + + if (same_device) { + goto out; + } + + if (self->pylon) { + gst_pylon_stop (self->pylon, &error); + gst_pylon_free (self->pylon); + self->pylon = NULL; + + if (error) { + ret = FALSE; + goto log_gst_error; + } + } + + GST_OBJECT_LOCK (self); + GST_INFO_OBJECT (self, + "Attempting to create camera device with the following configuration:" + "\n\tname: %s\n\tserial number: %s\n\tindex: %d\n\tuser set: %s \n\tPFS filepath: %s \n\tEnable correction: %s." + "If defined, the PFS file will override the user set configuration.", + self->device_user_name, self->device_serial_number, self->device_index, + self->user_set, self->pfs_location, ((self->enable_correction) ? "True" : "False")); + + self->pylon = + gst_pylon_new (GST_ELEMENT_CAST (self), self->device_user_name, + self->device_serial_number, self->device_index, self->enable_correction, &error); + GST_OBJECT_UNLOCK (self); + + if (error) { + ret = FALSE; + goto log_gst_error; + } + + GST_OBJECT_LOCK (self); + ret = gst_pylon_set_user_config (self->pylon, self->user_set, &error); + GST_OBJECT_UNLOCK (self); + + if (ret == FALSE && error) { + goto log_gst_error; + } + + GST_OBJECT_LOCK (self); + if (self->pfs_location) { + using_pfs = TRUE; + ret = gst_pylon_set_pfs_config (self->pylon, self->pfs_location, &error); + } + GST_OBJECT_UNLOCK (self); + + if (using_pfs && ret == FALSE && error) { + goto log_gst_error; + } + + self->duration = GST_CLOCK_TIME_NONE; + + goto out; + +log_gst_error: + GST_ELEMENT_ERROR (self, LIBRARY, FAILED, + ("Failed to start camera."), ("%s", error->message)); + g_error_free (error); + +out: + return ret; +} + +static gboolean +gst_pylon_src_stop (GstBaseSrc * src) +{ + GstPylonSrc *self = GST_PYLON_SRC (src); + GError *error = NULL; + gboolean ret = TRUE; + + GST_INFO_OBJECT (self, "Stopping camera device"); + + ret = gst_pylon_stop (self->pylon, &error); + + if (ret == FALSE && error) { + GST_ELEMENT_ERROR (self, LIBRARY, FAILED, + ("Failed to close camera."), ("%s", error->message)); + g_error_free (error); + } + + gst_pylon_free (self->pylon); + self->pylon = NULL; + + return ret; +} + +/* unlock any pending access to the resource. subclasses should unlock + * any function ASAP. */ +static gboolean +gst_pylon_src_unlock (GstBaseSrc * src) +{ + GstPylonSrc *self = GST_PYLON_SRC (src); + + GST_LOG_OBJECT (self, "unlock"); + + gst_pylon_interrupt_capture (self->pylon); + + return TRUE; +} + +/* notify subclasses of a query */ +static gboolean +gst_pylon_src_query (GstBaseSrc * src, GstQuery * query) +{ + GstPylonSrc *self = GST_PYLON_SRC (src); + gboolean res = FALSE; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_LATENCY:{ + GstClockTime min_latency = GST_CLOCK_TIME_NONE; + GstClockTime max_latency = GST_CLOCK_TIME_NONE; + + if (GST_CLOCK_TIME_NONE == self->duration) { + GST_WARNING_OBJECT (src, + "Can't report latency since framerate is not fixated yet"); + goto done; + } + + /* FIXME: we are assuming we cannot hold more than one + buffer. Eventually we want to have Pylon::StartGrabbing's + MaxNumImages extend the max_latency. + */ + max_latency = min_latency = self->duration; + + GST_DEBUG_OBJECT (self, + "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, + GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); + + gst_query_set_latency (query, TRUE, min_latency, max_latency); + + res = TRUE; + break; + } + default: + res = GST_BASE_SRC_CLASS (gst_pylon_src_parent_class)->query (src, query); + break; + } + +done: + return res; +} + +/* add time metadata to buffer */ +static void +gst_plyon_src_add_metadata (GstPylonSrc * self, GstBuffer * buf) +{ + GstClock *clock = NULL; + GstClockTime abs_time = GST_CLOCK_TIME_NONE; + GstClockTime base_time = GST_CLOCK_TIME_NONE; + GstClockTime timestamp = GST_CLOCK_TIME_NONE; + GstCaps *ref = NULL; + guint64 offset = G_GUINT64_CONSTANT (0); + GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; + GstPylonMeta *pylon_meta = NULL; + guint width = 0; + guint height = 0; + guint n_planes = 0; + gint stride[GST_VIDEO_MAX_PLANES] = { 0 }; + + g_return_if_fail (self); + g_return_if_fail (buf); + + pylon_meta = + (GstPylonMeta *) gst_buffer_get_meta (buf, GST_PYLON_META_API_TYPE); + + GST_OBJECT_LOCK (self); + /* set duration */ + GST_BUFFER_DURATION (buf) = self->duration; + + if ((clock = GST_ELEMENT_CLOCK (self))) { + /* we have a clock, get base time and ref clock */ + base_time = GST_ELEMENT (self)->base_time; + gst_object_ref (clock); + } else { + /* no clock, can't set timestamps */ + base_time = GST_CLOCK_TIME_NONE; + } + GST_OBJECT_UNLOCK (self); + + /* sample pipeline clock */ + if (clock) { + abs_time = gst_clock_get_time (clock); + gst_object_unref (clock); + } else { + abs_time = GST_CLOCK_TIME_NONE; + } + + timestamp = abs_time - base_time; + offset = pylon_meta->block_id; + + GST_BUFFER_TIMESTAMP (buf) = timestamp; + GST_BUFFER_OFFSET (buf) = offset; + GST_BUFFER_OFFSET_END (buf) = offset + 1; + + /* add pylon timestamp as reference timestamp meta */ + ref = gst_caps_from_string ("timestamp/x-pylon"); + gst_buffer_add_reference_timestamp_meta (buf, ref, pylon_meta->timestamp, + GST_CLOCK_TIME_NONE); + gst_caps_unref (ref); + + /* add video meta data */ + format = GST_VIDEO_INFO_FORMAT (&self->video_info); + width = GST_VIDEO_INFO_WIDTH (&self->video_info); + height = GST_VIDEO_INFO_HEIGHT (&self->video_info); + n_planes = GST_VIDEO_INFO_N_PLANES (&self->video_info); + + /* assuming pylon formats come in a single plane */ + for (gint p = 0; p < n_planes; p++) { + stride[p] = pylon_meta->stride; + } + + gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, format, width, + height, n_planes, self->video_info.offset, stride); +} + +/* ask the subclass to create a buffer with offset and size, the default + * implementation will call alloc and fill. */ +static GstFlowReturn +gst_pylon_src_create (GstPushSrc * src, GstBuffer ** buf) +{ + GstPylonSrc *self = GST_PYLON_SRC (src); + GError *error = NULL; + gboolean pylon_ret = TRUE; + GstFlowReturn ret = GST_FLOW_OK; + gint capture_error = -1; + + GST_OBJECT_LOCK (self); + capture_error = self->capture_error; + GST_OBJECT_UNLOCK (self); + + pylon_ret = gst_pylon_capture (self->pylon, buf, capture_error, &error); + + if (pylon_ret == FALSE) { + if (error) { + GST_ELEMENT_ERROR (self, LIBRARY, FAILED, + ("Failed to create buffer."), ("%s", error->message)); + g_error_free (error); + ret = GST_FLOW_ERROR; + } else { + GST_DEBUG_OBJECT (self, + "Buffer not created, user requested EOS or device connection was lost"); + ret = GST_FLOW_EOS; + } + goto done; + } + + gst_plyon_src_add_metadata (self, *buf); + + GST_LOG_OBJECT (self, "Created buffer %" GST_PTR_FORMAT, *buf); + +done: + return ret; +} + +static guint +gst_pylon_src_child_proxy_get_children_count (GstChildProxy * child_proxy) +{ + return sizeof (gst_pylon_src_child_proxy_names) / sizeof (gchar *); +} + +static GObject * +gst_pylon_src_child_proxy_get_child_by_name (GstChildProxy * + child_proxy, const gchar * name) +{ + GstPylonSrc *self = GST_PYLON_SRC (child_proxy); + GObject *obj = NULL; + + GST_DEBUG_OBJECT (self, "Looking for child \"%s\"", name); + + if (!gst_pylon_src_start (GST_BASE_SRC (self))) { + GST_ERROR_OBJECT (self, + "Please specify a camera before attempting to set Pylon device properties"); + return NULL; + } + + if (!g_strcmp0 (name, "cam")) { + GST_OBJECT_LOCK (self); + obj = gst_pylon_get_camera (self->pylon); + GST_OBJECT_UNLOCK (self); + } else if (!g_strcmp0 (name, "stream")) { + GST_OBJECT_LOCK (self); + obj = gst_pylon_get_stream_grabber (self->pylon); + GST_OBJECT_UNLOCK (self); + } else { + GST_ERROR_OBJECT (self, + "No child named \"%s\". Use \"cam\" or \"stream\" instead.", name); + } + + return obj; +} + +static GObject * +gst_pylon_src_child_proxy_get_child_by_index (GstChildProxy * child_proxy, + guint index) +{ + GstPylonSrc *self = GST_PYLON_SRC (child_proxy); + GObject *obj = NULL; + + GST_DEBUG_OBJECT (self, "Looking for child at index \"%d\"", index); + + if (index >= gst_pylon_src_child_proxy_get_children_count (child_proxy)) { + GST_ERROR_OBJECT (self, + "No child at index \"%d\". Use a valid child index instead.", index); + goto done; + } + + obj = + gst_pylon_src_child_proxy_get_child_by_name (child_proxy, + gst_pylon_src_child_proxy_names[index]); + +done: + return obj; +} + +static void +gst_pylon_src_child_proxy_init (GstChildProxyInterface * iface) +{ + iface->get_child_by_name = gst_pylon_src_child_proxy_get_child_by_name; + iface->get_child_by_index = gst_pylon_src_child_proxy_get_child_by_index; + iface->get_children_count = gst_pylon_src_child_proxy_get_children_count; +} diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index d4a63c8..1fe5926 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -45,6 +45,7 @@ typedef struct _GstPylonObjectPrivate GstPylonObjectPrivate; struct _GstPylonObjectPrivate { std::shared_ptr camera; GenApi::INodeMap* nodemap; + gboolean enable_correction; }; typedef struct _GstPylonObjectDeviceMembers GstPylonObjectDeviceMembers; From 82e0b88806fedd9db646be272918d5cb0242395d Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Mon, 30 Jan 2023 15:27:31 -0600 Subject: [PATCH 093/126] Implement value correction property --- gst-libs/gst/pylon/gstpylonobject.cpp | 39 ++++++++++++++++++++++----- gst-libs/gst/pylon/gstpylonobject.h | 3 ++- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 1fe5926..b93d605 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -122,7 +122,7 @@ static void gst_pylon_object_install_properties(GstPylonObjectClass* klass, /* Set a pylon feature from a gstreamer gst property */ template -static void gst_pylon_object_set_pylon_feature(GenApi::INodeMap& nodemap, +static void gst_pylon_object_set_pylon_feature(GstPylonObjectPrivate* priv, F get_value, const GValue* value, const gchar* name); @@ -201,18 +201,42 @@ static void gst_pylon_object_init(GstPylonObject* self) {} /* Set pylon feature from gst property */ template -static void gst_pylon_object_set_pylon_feature(GenApi::INodeMap& nodemap, +static void gst_pylon_object_set_pylon_feature(GstPylonObjectPrivate* priv, F get_value, const GValue* value, const gchar* name) { - P param(nodemap, name); + P param(*priv->nodemap, name); param.SetValue(get_value(value)); } +template <> +void gst_pylon_object_set_pylon_feature( + GstPylonObjectPrivate* priv, GGetInt64 get_value, const GValue* value, + const gchar* name) { + Pylon::CIntegerParameter param(*priv->nodemap, name); + + if(priv->enable_correction) + param.SetValue(get_value(value), Pylon::EIntegerValueCorrection::IntegerValueCorrection_Nearest); + else + param.SetValue(get_value(value)); +} + +template <> +void gst_pylon_object_set_pylon_feature( + GstPylonObjectPrivate* priv, GGetDouble get_value, const GValue* value, + const gchar* name) { + Pylon::CFloatParameter param(*priv->nodemap, name); + + if(priv->enable_correction) + param.SetValue(get_value(value), Pylon::EFloatValueCorrection::FloatValueCorrection_ClipToRange); + else + param.SetValue(get_value(value)); +} + template <> void gst_pylon_object_set_pylon_feature( - GenApi::INodeMap& nodemap, GGetEnum get_value, const GValue* value, + GstPylonObjectPrivate* priv, GGetEnum get_value, const GValue* value, const gchar* name) { - Pylon::CEnumParameter param(nodemap, name); + Pylon::CEnumParameter param(*priv->nodemap, name); param.SetIntValue(get_value(value)); } @@ -280,14 +304,14 @@ static void gst_pylon_object_feature_set_value( if (GST_PYLON_PARAM_FLAG_IS_SET(pspec, GST_PYLON_PARAM_IS_SELECTOR)) { gst_pylon_object_set_pylon_selector(*priv->nodemap, selector_data->selector, selector_data->selector_value); - gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, + gst_pylon_object_set_pylon_feature(priv, get_value, value, selector_data->feature); } else { /* Decanonicalize gst to pylon name */ gchar** split = g_strsplit(pspec->name, "-", -1); gchar* name_pylon = g_strjoinv("_", split); g_strfreev(split); - gst_pylon_object_set_pylon_feature(*priv->nodemap, get_value, value, + gst_pylon_object_set_pylon_feature(priv, get_value, value, name_pylon); g_free(name_pylon); } @@ -435,6 +459,7 @@ GObject* gst_pylon_object_new( priv->camera = std::move(camera); priv->nodemap = nodemap; + priv->enable_correction = enable_correction; return obj; } diff --git a/gst-libs/gst/pylon/gstpylonobject.h b/gst-libs/gst/pylon/gstpylonobject.h index 540dcdd..74a46d5 100644 --- a/gst-libs/gst/pylon/gstpylonobject.h +++ b/gst-libs/gst/pylon/gstpylonobject.h @@ -49,7 +49,8 @@ EXT_PYLONSRC_API GType gst_pylon_object_register(const std::string& device_name, GenApi::INodeMap& nodemap); EXT_PYLONSRC_API GObject* gst_pylon_object_new( std::shared_ptr camera, - const std::string& device_name, GenApi::INodeMap* nodemap); + const std::string& device_name, GenApi::INodeMap* nodemap, + gboolean enable_correction); void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, const gchar* selector_name, From 184a1a4cddcefe41e61c868f91ed3ac4a6a5d217 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Thu, 2 Feb 2023 06:59:59 -0600 Subject: [PATCH 094/126] Add warnings when correction is enabled --- gst-libs/gst/pylon/gstpylonobject.cpp | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index b93d605..0de16aa 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -214,9 +214,14 @@ void gst_pylon_object_set_pylon_feature( const gchar* name) { Pylon::CIntegerParameter param(*priv->nodemap, name); - if(priv->enable_correction) - param.SetValue(get_value(value), Pylon::EIntegerValueCorrection::IntegerValueCorrection_Nearest); - else + if (priv->enable_correction) { + GST_WARNING( + "Value correction enabled. Values outside of valid ranges will be " + "automatically corrected."); + param.SetValue( + get_value(value), + Pylon::EIntegerValueCorrection::IntegerValueCorrection_Nearest); + } else param.SetValue(get_value(value)); } @@ -226,10 +231,15 @@ void gst_pylon_object_set_pylon_feature( const gchar* name) { Pylon::CFloatParameter param(*priv->nodemap, name); - if(priv->enable_correction) - param.SetValue(get_value(value), Pylon::EFloatValueCorrection::FloatValueCorrection_ClipToRange); - else - param.SetValue(get_value(value)); + if (priv->enable_correction) { + GST_WARNING( + "Value correction enabled. Values outside of valid ranges will be " + "automatically corrected."); + param.SetValue( + get_value(value), + Pylon::EFloatValueCorrection::FloatValueCorrection_ClipToRange); + } else + param.SetValue(get_value(value)); } template <> @@ -436,7 +446,8 @@ static void gst_pylon_object_get_property(GObject* object, guint property_id, GObject* gst_pylon_object_new( std::shared_ptr camera, - const std::string& device_name, GenApi::INodeMap* nodemap) { + const std::string& device_name, GenApi::INodeMap* nodemap, + gboolean enable_correction) { std::string type_name = gst_pylon_param_spec_sanitize_name(device_name.c_str()); From 88a6df2e2bf026a7d4bfdd9c7c8ff0093dbe468c Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Tue, 31 Jan 2023 15:12:18 -0600 Subject: [PATCH 095/126] Fix pylonsrc format --- ext/pylon/gstpylonsrc.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ext/pylon/gstpylonsrc.c b/ext/pylon/gstpylonsrc.c index 7c10227..14804a1 100644 --- a/ext/pylon/gstpylonsrc.c +++ b/ext/pylon/gstpylonsrc.c @@ -240,10 +240,10 @@ gst_pylon_src_class_init (GstPylonSrcClass * klass) g_object_class_install_property (gobject_class, PROP_ENABLE_CORRECTION, g_param_spec_boolean ("enable-correction", "Enable correction", - "If enabled, the values from other parameters will be automatically corrected. " + "If enabled, the values from other parameters will be automatically corrected. " " If any of the properties holds an incorrect value given an specific configuration " "it will be corrected", - PROP_ENABLE_CORRECTION_DEFAULT, + PROP_ENABLE_CORRECTION_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY)); g_object_class_install_property (gobject_class, PROP_CAPTURE_ERROR, @@ -357,7 +357,7 @@ gst_pylon_src_set_property (GObject * object, guint property_id, self->pfs_location = g_value_dup_string (value); break; case PROP_ENABLE_CORRECTION: - self->enable_correction = g_value_get_boolean(value); + self->enable_correction = g_value_get_boolean (value); break; case PROP_CAPTURE_ERROR: self->capture_error = g_value_get_enum (value); @@ -397,7 +397,7 @@ gst_pylon_src_get_property (GObject * object, guint property_id, g_value_set_string (value, self->pfs_location); break; case PROP_ENABLE_CORRECTION: - g_value_set_boolean(value, self->enable_correction); + g_value_set_boolean (value, self->enable_correction); break; case PROP_CAPTURE_ERROR: g_value_set_enum (value, self->capture_error); @@ -680,11 +680,13 @@ gst_pylon_src_start (GstBaseSrc * src) "\n\tname: %s\n\tserial number: %s\n\tindex: %d\n\tuser set: %s \n\tPFS filepath: %s \n\tEnable correction: %s." "If defined, the PFS file will override the user set configuration.", self->device_user_name, self->device_serial_number, self->device_index, - self->user_set, self->pfs_location, ((self->enable_correction) ? "True" : "False")); + self->user_set, self->pfs_location, + ((self->enable_correction) ? "True" : "False")); self->pylon = gst_pylon_new (GST_ELEMENT_CAST (self), self->device_user_name, - self->device_serial_number, self->device_index, self->enable_correction, &error); + self->device_serial_number, self->device_index, self->enable_correction, + &error); GST_OBJECT_UNLOCK (self); if (error) { From 4dab4d7e0d08c1b0fa6c39f6a47b8dbdb5cc7d58 Mon Sep 17 00:00:00 2001 From: Marcelo Sanchez Date: Tue, 7 Mar 2023 14:28:21 -0600 Subject: [PATCH 096/126] Delete obsolete file --- ext/pylon/gstpylonsrc.c | 986 -------------------------------------- ext/pylon/gstpylonsrc.cpp | 35 +- 2 files changed, 30 insertions(+), 991 deletions(-) delete mode 100644 ext/pylon/gstpylonsrc.c diff --git a/ext/pylon/gstpylonsrc.c b/ext/pylon/gstpylonsrc.c deleted file mode 100644 index 14804a1..0000000 --- a/ext/pylon/gstpylonsrc.c +++ /dev/null @@ -1,986 +0,0 @@ -/* Copyright (C) 2022 Basler AG - * - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of - * its contributors may be used to endorse or promote products - * derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * SECTION:element-gstpylonsrc - * - * The pylonsrc element captures images from Basler cameras. - * - * - * Example launch line - * |[ - * gst-launch-1.0 -v pylonsrc ! videoconvert ! autovideosink - * ]| - * Capture images from a Basler camera and display them. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstpylonsrc.h" - -#include "gstpylon.h" -#include "gst/pylon/gstpylonmeta.h" -#include "gst/pylon/gstpylondebug.h" - -#include - -struct _GstPylonSrc -{ - GstPushSrc base_pylonsrc; - GstPylon *pylon; - GstClockTime duration; - GstVideoInfo video_info; - - gchar *device_user_name; - gchar *device_serial_number; - gint device_index; - gchar *user_set; - gchar *pfs_location; - gboolean enable_correction; - GstPylonCaptureErrorEnum capture_error; - GObject *cam; - GObject *stream; -}; - -/* prototypes */ - -static void -gst_pylon_src_set_property (GObject * object, - guint property_id, const GValue * value, GParamSpec * pspec); -static void gst_pylon_src_get_property (GObject * object, - guint property_id, GValue * value, GParamSpec * pspec); -static void gst_pylon_src_finalize (GObject * object); - -static GstCaps *gst_pylon_src_get_caps (GstBaseSrc * src, GstCaps * filter); -static gboolean gst_pylon_src_is_bayer (GstStructure * st); -static GstCaps *gst_pylon_src_fixate (GstBaseSrc * src, GstCaps * caps); -static gboolean gst_pylon_src_set_caps (GstBaseSrc * src, GstCaps * caps); -static gboolean gst_pylon_src_decide_allocation (GstBaseSrc * src, - GstQuery * query); -static gboolean gst_pylon_src_start (GstBaseSrc * src); -static gboolean gst_pylon_src_stop (GstBaseSrc * src); -static gboolean gst_pylon_src_unlock (GstBaseSrc * src); -static gboolean gst_pylon_src_query (GstBaseSrc * src, GstQuery * query); -static void gst_plyon_src_add_metadata (GstPylonSrc * self, GstBuffer * buf); -static GstFlowReturn gst_pylon_src_create (GstPushSrc * src, GstBuffer ** buf); - -static void gst_pylon_src_child_proxy_init (GstChildProxyInterface * iface); - -enum -{ - PROP_0, - PROP_DEVICE_USER_NAME, - PROP_DEVICE_SERIAL_NUMBER, - PROP_DEVICE_INDEX, - PROP_USER_SET, - PROP_PFS_LOCATION, - PROP_ENABLE_CORRECTION, - PROP_CAPTURE_ERROR, - PROP_CAM, - PROP_STREAM -}; - -#define PROP_DEVICE_USER_NAME_DEFAULT NULL -#define PROP_DEVICE_SERIAL_NUMBER_DEFAULT NULL -#define PROP_DEVICE_INDEX_DEFAULT -1 -#define PROP_DEVICE_INDEX_MIN -1 -#define PROP_DEVICE_INDEX_MAX G_MAXINT32 -#define PROP_USER_SET_DEFAULT NULL -#define PROP_PFS_LOCATION_DEFAULT NULL -#define PROP_ENABLE_CORRECTION_DEFAULT FALSE -#define PROP_CAM_DEFAULT NULL -#define PROP_STREAM_DEFAULT NULL -#define PROP_CAPTURE_ERROR_DEFAULT ENUM_ABORT - -/* Enum for cature_error */ -#define GST_TYPE_CAPTURE_ERROR_ENUM (gst_pylon_capture_error_enum_get_type ()) - -/* Child proxy interface names */ -static const gchar *gst_pylon_src_child_proxy_names[] = { - "cam", - "stream" -}; - -static GType -gst_pylon_capture_error_enum_get_type (void) -{ - static gsize gtype = 0; - static const GEnumValue values[] = { - {ENUM_KEEP, "keep", "Use partial or corrupt buffers"}, - {ENUM_SKIP, "skip", - "Skip partial or corrupt buffers. A maximum of 100 buffers can be skipped before the pipeline aborts."}, - {ENUM_ABORT, "abort", "Stop pipeline in case of any capture error"}, - {0, NULL, NULL} - }; - - if (g_once_init_enter (>ype)) { - GType tmp = g_enum_register_static ("GstPylonCaptureErrorEnum", values); - g_once_init_leave (>ype, tmp); - } - - return (GType) gtype; -} - -/* pad templates */ - -static GstStaticPadTemplate gst_pylon_src_src_template = - GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (" {GRAY8, RGB, BGR, YUY2, UYVY} ") ";" - "video/x-bayer,format={rggb,bggr,gbgr,grgb},width=" GST_VIDEO_SIZE_RANGE - ",height=" GST_VIDEO_SIZE_RANGE ",framerate=" GST_VIDEO_FPS_RANGE)); - - -/* class initialization */ -G_DEFINE_TYPE_WITH_CODE (GstPylonSrc, gst_pylon_src, GST_TYPE_PUSH_SRC, - gst_pylon_debug_init (); - G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY, gst_pylon_src_child_proxy_init) - ); - -static void -gst_pylon_src_class_init (GstPylonSrcClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS (klass); - GstPushSrcClass *push_src_class = GST_PUSH_SRC_CLASS (klass); - gchar *cam_params = NULL; - gchar *cam_blurb = NULL; - gchar *stream_params = NULL; - gchar *stream_blurb = NULL; - const gchar *cam_prolog = NULL; - const gchar *stream_prolog = NULL; - - gst_pylon_initialize (); - - /* Setting up pads and setting metadata should be moved to - base_class_init if you intend to subclass this class. */ - gst_element_class_add_static_pad_template (GST_ELEMENT_CLASS (klass), - &gst_pylon_src_src_template); - - gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass), - "Basler/Pylon source element", "Source/Video/Hardware", - "Source element for Basler cameras", - "Basler AG "); - - gobject_class->set_property = gst_pylon_src_set_property; - gobject_class->get_property = gst_pylon_src_get_property; - gobject_class->finalize = gst_pylon_src_finalize; - - g_object_class_install_property (gobject_class, PROP_DEVICE_USER_NAME, - g_param_spec_string ("device-user-name", "Device user defined name", - "The user-defined name of the device to use. May be combined" - "with other device selection properties to reduce the search.", - PROP_DEVICE_USER_NAME_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_DEVICE_SERIAL_NUMBER, - g_param_spec_string ("device-serial-number", "Device serial number", - "The serial number of the device to use. May be combined with " - "other device selection properties to reduce the search.", - PROP_DEVICE_SERIAL_NUMBER_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_DEVICE_INDEX, - g_param_spec_int ("device-index", "Device index", - "The index of the device to use.This index applies to the " - "resulting device list after applying the other device selection " - "properties. The index is mandatory if multiple devices match " - "the given search criteria.", PROP_DEVICE_INDEX_MIN, - PROP_DEVICE_INDEX_MAX, PROP_DEVICE_INDEX_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_USER_SET, - g_param_spec_string ("user-set", "Device user configuration set", - "The user-defined configuration set to use. Leaving this property " - "unset, or using 'Auto' result in selecting the " - "power-on default camera configuration.", - PROP_USER_SET_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_PFS_LOCATION, - g_param_spec_string ("pfs-location", "PFS file location", - "The filepath to the PFS file from which to load the device configuration. " - "Setting this property will override the user set property if also set.", - PROP_PFS_LOCATION_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_ENABLE_CORRECTION, - g_param_spec_boolean ("enable-correction", - "Enable correction", - "If enabled, the values from other parameters will be automatically corrected. " - " If any of the properties holds an incorrect value given an specific configuration " - "it will be corrected", - PROP_ENABLE_CORRECTION_DEFAULT, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - GST_PARAM_MUTABLE_READY)); - g_object_class_install_property (gobject_class, PROP_CAPTURE_ERROR, - g_param_spec_enum ("capture-error", - "Capture error strategy", - "The strategy to use in case of a camera capture error.", - GST_TYPE_CAPTURE_ERROR_ENUM, PROP_CAPTURE_ERROR_DEFAULT, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - cam_params = gst_pylon_camera_get_string_properties (); - stream_params = gst_pylon_stream_grabber_get_string_properties (); - - if (NULL == cam_params) { - cam_prolog = "No valid cameras where found connected to the system."; - stream_prolog = cam_prolog; - cam_params = g_strdup (""); - stream_params = g_strdup (""); - } else { - cam_prolog = "The following list details the properties for each camera.\n"; - stream_prolog = - "The following list details the properties for each stream grabber.\n"; - } - - cam_blurb = g_strdup_printf ("The camera to use.\n" - "\t\t\tAccording to the selected camera " - "different properties will be available.\n " - "\t\t\tThese properties can be accessed using the " - "\"cam::\" syntax.\n" "\t\t\t%s%s", cam_prolog, cam_params); - - g_object_class_install_property (gobject_class, PROP_CAM, - g_param_spec_object ("cam", "Camera", cam_blurb, G_TYPE_OBJECT, - G_PARAM_READABLE)); - - stream_blurb = g_strdup_printf ("The stream grabber to use.\n" - "\t\t\tAccording to the selected stream grabber " - "different properties will be available.\n " - "\t\t\tThese properties can be accessed using the " - "\"stream::\" syntax.\n" "\t\t\t%s%s", stream_prolog, - stream_params); - - g_object_class_install_property (gobject_class, PROP_STREAM, - g_param_spec_object ("stream", "Stream Grabber", stream_blurb, - G_TYPE_OBJECT, G_PARAM_READABLE)); - - g_free (cam_params); - g_free (stream_params); - - base_src_class->get_caps = GST_DEBUG_FUNCPTR (gst_pylon_src_get_caps); - base_src_class->fixate = GST_DEBUG_FUNCPTR (gst_pylon_src_fixate); - base_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_pylon_src_set_caps); - base_src_class->decide_allocation = - GST_DEBUG_FUNCPTR (gst_pylon_src_decide_allocation); - base_src_class->start = GST_DEBUG_FUNCPTR (gst_pylon_src_start); - base_src_class->stop = GST_DEBUG_FUNCPTR (gst_pylon_src_stop); - base_src_class->unlock = GST_DEBUG_FUNCPTR (gst_pylon_src_unlock); - base_src_class->query = GST_DEBUG_FUNCPTR (gst_pylon_src_query); - - push_src_class->create = GST_DEBUG_FUNCPTR (gst_pylon_src_create); -} - -static void -gst_pylon_src_init (GstPylonSrc * self) -{ - GstBaseSrc *base = GST_BASE_SRC (self); - - self->pylon = NULL; - self->duration = GST_CLOCK_TIME_NONE; - self->device_user_name = PROP_DEVICE_USER_NAME_DEFAULT; - self->device_serial_number = PROP_DEVICE_SERIAL_NUMBER_DEFAULT; - self->device_index = PROP_DEVICE_INDEX_DEFAULT; - self->user_set = PROP_USER_SET_DEFAULT; - self->pfs_location = PROP_PFS_LOCATION_DEFAULT; - self->enable_correction = PROP_ENABLE_CORRECTION_DEFAULT; - self->capture_error = PROP_CAPTURE_ERROR_DEFAULT; - self->cam = PROP_CAM_DEFAULT; - self->stream = PROP_STREAM_DEFAULT; - gst_video_info_init (&self->video_info); - - gst_base_src_set_live (base, TRUE); - gst_base_src_set_format (base, GST_FORMAT_TIME); -} - -static void -gst_pylon_src_set_property (GObject * object, guint property_id, - const GValue * value, GParamSpec * pspec) -{ - GstPylonSrc *self = GST_PYLON_SRC (object); - - GST_LOG_OBJECT (self, "set_property"); - - GST_OBJECT_LOCK (self); - - switch (property_id) { - case PROP_DEVICE_USER_NAME: - g_free (self->device_user_name); - self->device_user_name = g_value_dup_string (value); - break; - case PROP_DEVICE_SERIAL_NUMBER: - g_free (self->device_serial_number); - self->device_serial_number = g_value_dup_string (value); - break; - case PROP_DEVICE_INDEX: - self->device_index = g_value_get_int (value); - break; - case PROP_USER_SET: - g_free (self->user_set); - self->user_set = g_value_dup_string (value); - break; - case PROP_PFS_LOCATION: - g_free (self->pfs_location); - self->pfs_location = g_value_dup_string (value); - break; - case PROP_ENABLE_CORRECTION: - self->enable_correction = g_value_get_boolean (value); - break; - case PROP_CAPTURE_ERROR: - self->capture_error = g_value_get_enum (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } - - GST_OBJECT_UNLOCK (self); -} - -static void -gst_pylon_src_get_property (GObject * object, guint property_id, - GValue * value, GParamSpec * pspec) -{ - GstPylonSrc *self = GST_PYLON_SRC (object); - - GST_LOG_OBJECT (self, "get_property"); - - GST_OBJECT_LOCK (self); - - switch (property_id) { - case PROP_DEVICE_USER_NAME: - g_value_set_string (value, self->device_user_name); - break; - case PROP_DEVICE_SERIAL_NUMBER: - g_value_set_string (value, self->device_serial_number); - break; - case PROP_DEVICE_INDEX: - g_value_set_int (value, self->device_index); - break; - case PROP_USER_SET: - g_value_set_string (value, self->user_set); - break; - case PROP_PFS_LOCATION: - g_value_set_string (value, self->pfs_location); - break; - case PROP_ENABLE_CORRECTION: - g_value_set_boolean (value, self->enable_correction); - break; - case PROP_CAPTURE_ERROR: - g_value_set_enum (value, self->capture_error); - break; - case PROP_CAM: - g_value_set_object (value, self->cam); - break; - case PROP_STREAM: - g_value_set_object (value, self->stream); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } - - GST_OBJECT_UNLOCK (self); -} - -static void -gst_pylon_src_finalize (GObject * object) -{ - GstPylonSrc *self = GST_PYLON_SRC (object); - - GST_LOG_OBJECT (self, "finalize"); - - g_free (self->device_user_name); - self->device_user_name = NULL; - - g_free (self->device_serial_number); - self->device_serial_number = NULL; - - g_free (self->user_set); - self->user_set = NULL; - - if (self->cam) { - g_object_unref (self->cam); - self->cam = NULL; - } - - if (self->stream) { - g_object_unref (self->stream); - self->stream = NULL; - } - - G_OBJECT_CLASS (gst_pylon_src_parent_class)->finalize (object); -} - -/* get caps from subclass */ -static GstCaps * -gst_pylon_src_get_caps (GstBaseSrc * src, GstCaps * filter) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GstCaps *outcaps = NULL; - GError *error = NULL; - - if (!self->pylon) { - outcaps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (self)); - GST_INFO_OBJECT (self, - "Camera not open yet, returning src template caps %" GST_PTR_FORMAT, - outcaps); - goto out; - } - - outcaps = gst_pylon_query_configuration (self->pylon, &error); - - if (outcaps == NULL && error) { - goto log_gst_error; - } - - GST_DEBUG_OBJECT (self, "Camera returned caps %" GST_PTR_FORMAT, outcaps); - - if (filter) { - GstCaps *tmp = outcaps; - - GST_DEBUG_OBJECT (self, "Filtering with %" GST_PTR_FORMAT, filter); - - outcaps = gst_caps_intersect (outcaps, filter); - gst_caps_unref (tmp); - } - - GST_INFO_OBJECT (self, "Returning caps %" GST_PTR_FORMAT, outcaps); - - goto out; - -log_gst_error: - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to get caps."), ("%s", error->message)); - g_error_free (error); - -out: - return outcaps; -} - -static gboolean -gst_pylon_src_is_bayer (GstStructure * st) -{ - gboolean is_bayer = FALSE; - - g_return_val_if_fail (st, FALSE); - - if (0 == g_strcmp0 (gst_structure_get_name (st), "video/x-bayer")) { - is_bayer = TRUE; - } - return is_bayer; -} - -/* called if, in negotiation, caps need fixating */ -static GstCaps * -gst_pylon_src_fixate (GstBaseSrc * src, GstCaps * caps) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GstCaps *outcaps = NULL; - GstStructure *st = NULL; - const GValue *width_field = NULL; - static const gint width_1080p = 1920; - static const gint height_1080p = 1080; - static const gint preferred_framerate_num = 30; - static const gint preferred_framerate_den = 1; - gint preferred_width_adjusted = 0; - - /* get the configured width/height after applying userset and pfs */ - gint preferred_width = width_1080p; - gint preferred_height = height_1080p; - gst_pylon_get_startup_geometry (self->pylon, &preferred_width, - &preferred_height); - - GST_DEBUG_OBJECT (self, "Fixating caps %" GST_PTR_FORMAT, caps); - - if (gst_caps_is_fixed (caps)) { - GST_DEBUG_OBJECT (self, "Caps are already fixed"); - return caps; - } - - outcaps = gst_caps_new_empty (); - st = gst_structure_copy (gst_caps_get_structure (caps, 0)); - width_field = gst_structure_get_value (st, "width"); - gst_caps_unref (caps); - - if (gst_pylon_src_is_bayer (st) && GST_VALUE_HOLDS_INT_RANGE (width_field)) { - preferred_width_adjusted = - GST_ROUND_DOWN_4 (gst_value_get_int_range_max (width_field)); - } else { - preferred_width_adjusted = preferred_width; - } - - gst_structure_fixate_field_nearest_int (st, "width", - preferred_width_adjusted); - gst_structure_fixate_field_nearest_int (st, "height", preferred_height); - gst_structure_fixate_field_nearest_fraction (st, "framerate", - preferred_framerate_num, preferred_framerate_den); - - gst_caps_append_structure (outcaps, st); - - /* fixate the remainder of the fields */ - outcaps = gst_caps_fixate (outcaps); - - GST_INFO_OBJECT (self, "Fixated caps to %" GST_PTR_FORMAT, outcaps); - - return outcaps; -} - -/* notify the subclass of new caps */ -static gboolean -gst_pylon_src_set_caps (GstBaseSrc * src, GstCaps * caps) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GstStructure *st = NULL; - gint numerator = 0; - gint denominator = 0; - gint width = 0; - static const gint byte_alignment = 4; - gchar *error_msg = NULL; - GError *error = NULL; - gboolean ret = FALSE; - const gchar *action = NULL; - - GST_INFO_OBJECT (self, "Setting new caps: %" GST_PTR_FORMAT, caps); - - st = gst_caps_get_structure (caps, 0); - gst_structure_get_int (st, "width", &width); - - if (gst_pylon_src_is_bayer (st) && 0 != width % byte_alignment) { - action = "configure"; - error_msg = - g_strdup - ("Bayer formats require the width to be word aligned (4 bytes)."); - goto error; - } - - gst_structure_get_fraction (st, "framerate", &numerator, &denominator); - - GST_OBJECT_LOCK (self); - if (numerator != 0) { - self->duration = gst_util_uint64_scale (GST_SECOND, denominator, numerator); - } else { - self->duration = GST_CLOCK_TIME_NONE; - } - GST_OBJECT_UNLOCK (self); - - ret = gst_pylon_stop (self->pylon, &error); - if (FALSE == ret && error) { - action = "stop"; - goto log_error; - } - - ret = gst_pylon_set_configuration (self->pylon, caps, &error); - if (FALSE == ret && error) { - action = "configure"; - goto log_error; - } - - ret = gst_pylon_start (self->pylon, &error); - if (FALSE == ret && error) { - action = "start"; - goto log_error; - } - - ret = gst_video_info_from_caps (&self->video_info, caps); - - goto out; - -log_error: - error_msg = g_strdup (error->message); - g_error_free (error); - -error: - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to %s camera.", action), ("%s", error_msg)); - g_free (error_msg); - -out: - return ret; -} - -/* setup allocation query */ -static gboolean -gst_pylon_src_decide_allocation (GstBaseSrc * src, GstQuery * query) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - - GST_LOG_OBJECT (self, "decide_allocation"); - - return TRUE; -} - -/* start and stop processing, ideal for opening/closing the resource */ -static gboolean -gst_pylon_src_start (GstBaseSrc * src) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GError *error = NULL; - gboolean ret = TRUE; - gboolean using_pfs = FALSE; - gboolean same_device = TRUE; - - GST_OBJECT_LOCK (self); - same_device = self->pylon - && gst_pylon_is_same_device (self->pylon, self->device_index, - self->device_user_name, self->device_serial_number); - GST_OBJECT_UNLOCK (self); - - if (same_device) { - goto out; - } - - if (self->pylon) { - gst_pylon_stop (self->pylon, &error); - gst_pylon_free (self->pylon); - self->pylon = NULL; - - if (error) { - ret = FALSE; - goto log_gst_error; - } - } - - GST_OBJECT_LOCK (self); - GST_INFO_OBJECT (self, - "Attempting to create camera device with the following configuration:" - "\n\tname: %s\n\tserial number: %s\n\tindex: %d\n\tuser set: %s \n\tPFS filepath: %s \n\tEnable correction: %s." - "If defined, the PFS file will override the user set configuration.", - self->device_user_name, self->device_serial_number, self->device_index, - self->user_set, self->pfs_location, - ((self->enable_correction) ? "True" : "False")); - - self->pylon = - gst_pylon_new (GST_ELEMENT_CAST (self), self->device_user_name, - self->device_serial_number, self->device_index, self->enable_correction, - &error); - GST_OBJECT_UNLOCK (self); - - if (error) { - ret = FALSE; - goto log_gst_error; - } - - GST_OBJECT_LOCK (self); - ret = gst_pylon_set_user_config (self->pylon, self->user_set, &error); - GST_OBJECT_UNLOCK (self); - - if (ret == FALSE && error) { - goto log_gst_error; - } - - GST_OBJECT_LOCK (self); - if (self->pfs_location) { - using_pfs = TRUE; - ret = gst_pylon_set_pfs_config (self->pylon, self->pfs_location, &error); - } - GST_OBJECT_UNLOCK (self); - - if (using_pfs && ret == FALSE && error) { - goto log_gst_error; - } - - self->duration = GST_CLOCK_TIME_NONE; - - goto out; - -log_gst_error: - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to start camera."), ("%s", error->message)); - g_error_free (error); - -out: - return ret; -} - -static gboolean -gst_pylon_src_stop (GstBaseSrc * src) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GError *error = NULL; - gboolean ret = TRUE; - - GST_INFO_OBJECT (self, "Stopping camera device"); - - ret = gst_pylon_stop (self->pylon, &error); - - if (ret == FALSE && error) { - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to close camera."), ("%s", error->message)); - g_error_free (error); - } - - gst_pylon_free (self->pylon); - self->pylon = NULL; - - return ret; -} - -/* unlock any pending access to the resource. subclasses should unlock - * any function ASAP. */ -static gboolean -gst_pylon_src_unlock (GstBaseSrc * src) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - - GST_LOG_OBJECT (self, "unlock"); - - gst_pylon_interrupt_capture (self->pylon); - - return TRUE; -} - -/* notify subclasses of a query */ -static gboolean -gst_pylon_src_query (GstBaseSrc * src, GstQuery * query) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - gboolean res = FALSE; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY:{ - GstClockTime min_latency = GST_CLOCK_TIME_NONE; - GstClockTime max_latency = GST_CLOCK_TIME_NONE; - - if (GST_CLOCK_TIME_NONE == self->duration) { - GST_WARNING_OBJECT (src, - "Can't report latency since framerate is not fixated yet"); - goto done; - } - - /* FIXME: we are assuming we cannot hold more than one - buffer. Eventually we want to have Pylon::StartGrabbing's - MaxNumImages extend the max_latency. - */ - max_latency = min_latency = self->duration; - - GST_DEBUG_OBJECT (self, - "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); - - gst_query_set_latency (query, TRUE, min_latency, max_latency); - - res = TRUE; - break; - } - default: - res = GST_BASE_SRC_CLASS (gst_pylon_src_parent_class)->query (src, query); - break; - } - -done: - return res; -} - -/* add time metadata to buffer */ -static void -gst_plyon_src_add_metadata (GstPylonSrc * self, GstBuffer * buf) -{ - GstClock *clock = NULL; - GstClockTime abs_time = GST_CLOCK_TIME_NONE; - GstClockTime base_time = GST_CLOCK_TIME_NONE; - GstClockTime timestamp = GST_CLOCK_TIME_NONE; - GstCaps *ref = NULL; - guint64 offset = G_GUINT64_CONSTANT (0); - GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; - GstPylonMeta *pylon_meta = NULL; - guint width = 0; - guint height = 0; - guint n_planes = 0; - gint stride[GST_VIDEO_MAX_PLANES] = { 0 }; - - g_return_if_fail (self); - g_return_if_fail (buf); - - pylon_meta = - (GstPylonMeta *) gst_buffer_get_meta (buf, GST_PYLON_META_API_TYPE); - - GST_OBJECT_LOCK (self); - /* set duration */ - GST_BUFFER_DURATION (buf) = self->duration; - - if ((clock = GST_ELEMENT_CLOCK (self))) { - /* we have a clock, get base time and ref clock */ - base_time = GST_ELEMENT (self)->base_time; - gst_object_ref (clock); - } else { - /* no clock, can't set timestamps */ - base_time = GST_CLOCK_TIME_NONE; - } - GST_OBJECT_UNLOCK (self); - - /* sample pipeline clock */ - if (clock) { - abs_time = gst_clock_get_time (clock); - gst_object_unref (clock); - } else { - abs_time = GST_CLOCK_TIME_NONE; - } - - timestamp = abs_time - base_time; - offset = pylon_meta->block_id; - - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_OFFSET (buf) = offset; - GST_BUFFER_OFFSET_END (buf) = offset + 1; - - /* add pylon timestamp as reference timestamp meta */ - ref = gst_caps_from_string ("timestamp/x-pylon"); - gst_buffer_add_reference_timestamp_meta (buf, ref, pylon_meta->timestamp, - GST_CLOCK_TIME_NONE); - gst_caps_unref (ref); - - /* add video meta data */ - format = GST_VIDEO_INFO_FORMAT (&self->video_info); - width = GST_VIDEO_INFO_WIDTH (&self->video_info); - height = GST_VIDEO_INFO_HEIGHT (&self->video_info); - n_planes = GST_VIDEO_INFO_N_PLANES (&self->video_info); - - /* assuming pylon formats come in a single plane */ - for (gint p = 0; p < n_planes; p++) { - stride[p] = pylon_meta->stride; - } - - gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, format, width, - height, n_planes, self->video_info.offset, stride); -} - -/* ask the subclass to create a buffer with offset and size, the default - * implementation will call alloc and fill. */ -static GstFlowReturn -gst_pylon_src_create (GstPushSrc * src, GstBuffer ** buf) -{ - GstPylonSrc *self = GST_PYLON_SRC (src); - GError *error = NULL; - gboolean pylon_ret = TRUE; - GstFlowReturn ret = GST_FLOW_OK; - gint capture_error = -1; - - GST_OBJECT_LOCK (self); - capture_error = self->capture_error; - GST_OBJECT_UNLOCK (self); - - pylon_ret = gst_pylon_capture (self->pylon, buf, capture_error, &error); - - if (pylon_ret == FALSE) { - if (error) { - GST_ELEMENT_ERROR (self, LIBRARY, FAILED, - ("Failed to create buffer."), ("%s", error->message)); - g_error_free (error); - ret = GST_FLOW_ERROR; - } else { - GST_DEBUG_OBJECT (self, - "Buffer not created, user requested EOS or device connection was lost"); - ret = GST_FLOW_EOS; - } - goto done; - } - - gst_plyon_src_add_metadata (self, *buf); - - GST_LOG_OBJECT (self, "Created buffer %" GST_PTR_FORMAT, *buf); - -done: - return ret; -} - -static guint -gst_pylon_src_child_proxy_get_children_count (GstChildProxy * child_proxy) -{ - return sizeof (gst_pylon_src_child_proxy_names) / sizeof (gchar *); -} - -static GObject * -gst_pylon_src_child_proxy_get_child_by_name (GstChildProxy * - child_proxy, const gchar * name) -{ - GstPylonSrc *self = GST_PYLON_SRC (child_proxy); - GObject *obj = NULL; - - GST_DEBUG_OBJECT (self, "Looking for child \"%s\"", name); - - if (!gst_pylon_src_start (GST_BASE_SRC (self))) { - GST_ERROR_OBJECT (self, - "Please specify a camera before attempting to set Pylon device properties"); - return NULL; - } - - if (!g_strcmp0 (name, "cam")) { - GST_OBJECT_LOCK (self); - obj = gst_pylon_get_camera (self->pylon); - GST_OBJECT_UNLOCK (self); - } else if (!g_strcmp0 (name, "stream")) { - GST_OBJECT_LOCK (self); - obj = gst_pylon_get_stream_grabber (self->pylon); - GST_OBJECT_UNLOCK (self); - } else { - GST_ERROR_OBJECT (self, - "No child named \"%s\". Use \"cam\" or \"stream\" instead.", name); - } - - return obj; -} - -static GObject * -gst_pylon_src_child_proxy_get_child_by_index (GstChildProxy * child_proxy, - guint index) -{ - GstPylonSrc *self = GST_PYLON_SRC (child_proxy); - GObject *obj = NULL; - - GST_DEBUG_OBJECT (self, "Looking for child at index \"%d\"", index); - - if (index >= gst_pylon_src_child_proxy_get_children_count (child_proxy)) { - GST_ERROR_OBJECT (self, - "No child at index \"%d\". Use a valid child index instead.", index); - goto done; - } - - obj = - gst_pylon_src_child_proxy_get_child_by_name (child_proxy, - gst_pylon_src_child_proxy_names[index]); - -done: - return obj; -} - -static void -gst_pylon_src_child_proxy_init (GstChildProxyInterface * iface) -{ - iface->get_child_by_name = gst_pylon_src_child_proxy_get_child_by_name; - iface->get_child_by_index = gst_pylon_src_child_proxy_get_child_by_index; - iface->get_children_count = gst_pylon_src_child_proxy_get_children_count; -} diff --git a/ext/pylon/gstpylonsrc.cpp b/ext/pylon/gstpylonsrc.cpp index 8b0147c..f649cde 100644 --- a/ext/pylon/gstpylonsrc.cpp +++ b/ext/pylon/gstpylonsrc.cpp @@ -66,6 +66,7 @@ struct _GstPylonSrc { gint device_index; gchar *user_set; gchar *pfs_location; + gboolean enable_correction; GstPylonCaptureErrorEnum capture_error; GObject *cam; GObject *stream; @@ -101,6 +102,7 @@ enum { PROP_DEVICE_INDEX, PROP_USER_SET, PROP_PFS_LOCATION, + PROP_ENABLE_CORRECTION, PROP_CAPTURE_ERROR, PROP_CAM, PROP_STREAM @@ -113,6 +115,7 @@ enum { #define PROP_DEVICE_INDEX_MAX G_MAXINT32 #define PROP_USER_SET_DEFAULT NULL #define PROP_PFS_LOCATION_DEFAULT NULL +#define PROP_ENABLE_CORRECTION_DEFAULT FALSE #define PROP_CAM_DEFAULT NULL #define PROP_STREAM_DEFAULT NULL #define PROP_CAPTURE_ERROR_DEFAULT ENUM_ABORT @@ -240,6 +243,20 @@ static void gst_pylon_src_class_init(GstPylonSrcClass *klass) { PROP_PFS_LOCATION_DEFAULT, static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY))); + + g_object_class_install_property( + gobject_class, PROP_ENABLE_CORRECTION, + g_param_spec_boolean( + "enable-correction", "Enable correction", + "If enabled, the values from other parameters will be automatically " + "corrected. " + " If any of the properties holds an incorrect value given an " + "specific configuration " + "it will be corrected", + PROP_ENABLE_CORRECTION_DEFAULT, + static_cast(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY))); + g_object_class_install_property( gobject_class, PROP_CAPTURE_ERROR, g_param_spec_enum( @@ -317,6 +334,7 @@ static void gst_pylon_src_init(GstPylonSrc *self) { self->device_index = PROP_DEVICE_INDEX_DEFAULT; self->user_set = PROP_USER_SET_DEFAULT; self->pfs_location = PROP_PFS_LOCATION_DEFAULT; + self->enable_correction = PROP_ENABLE_CORRECTION_DEFAULT; self->capture_error = PROP_CAPTURE_ERROR_DEFAULT; self->cam = PROP_CAM_DEFAULT; self->stream = PROP_STREAM_DEFAULT; @@ -354,6 +372,9 @@ static void gst_pylon_src_set_property(GObject *object, guint property_id, g_free(self->pfs_location); self->pfs_location = g_value_dup_string(value); break; + case PROP_ENABLE_CORRECTION: + self->enable_correction = g_value_get_boolean(value); + break; case PROP_CAPTURE_ERROR: self->capture_error = static_cast(g_value_get_enum(value)); @@ -390,6 +411,9 @@ static void gst_pylon_src_get_property(GObject *object, guint property_id, case PROP_PFS_LOCATION: g_value_set_string(value, self->pfs_location); break; + case PROP_ENABLE_CORRECTION: + g_value_set_boolean(value, self->enable_correction); + break; case PROP_CAPTURE_ERROR: g_value_set_enum(value, self->capture_error); break; @@ -657,14 +681,15 @@ static gboolean gst_pylon_src_start(GstBaseSrc *src) { self, "Attempting to create camera device with the following configuration:" "\n\tname: %s\n\tserial number: %s\n\tindex: %d\n\tuser set: %s \n\tPFS " - "filepath: %s. " + "filepath: %s \n\tEnable correction: %s." "If defined, the PFS file will override the user set configuration.", self->device_user_name, self->device_serial_number, self->device_index, - self->user_set, self->pfs_location); + self->user_set, self->pfs_location, + ((self->enable_correction) ? "True" : "False")); - self->pylon = - gst_pylon_new(GST_ELEMENT_CAST(self), self->device_user_name, - self->device_serial_number, self->device_index, &error); + self->pylon = gst_pylon_new(GST_ELEMENT_CAST(self), self->device_user_name, + self->device_serial_number, self->device_index, + self->enable_correction, &error); GST_OBJECT_UNLOCK(self); if (error) { From e18df782a7350aab81b8308f83efcab4ce6f041e Mon Sep 17 00:00:00 2001 From: AleSoHe Date: Tue, 28 Feb 2023 21:16:25 -0600 Subject: [PATCH 097/126] Add spurious condition on get_state as a known issue --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 804f262..f38be95 100644 --- a/README.md +++ b/README.md @@ -519,3 +519,6 @@ This target will be integrated after a Basler pylon 7.x release for macOS * Bayer formats need to be 4 byte aligned to be properly processed by GStreamer. If no size is specified (or a range is provided) a word aligned width will be automatically selected. If the width is hardcoded and it is not word aligned, the pipeline will fail displaying an error. +* Under very specific conditions we've found that a set_state() followed immediately by a get_state() will report a failure. This has been found to be a bug in the GStreamer core, where a state conditional is not protected against spurious wakeups. An upstream fix has been proposed [in this Merge Request](https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4086). This issue has been reproduced in certain installations of NVIDIA Jetson boards. + * As a workaround while the fix is absorbed, you may configure `async=false` in all the sink elements in your pipeline, so that the state condition variable is not needed. Only use this is your pipeline does not require synchronization. + From b26d819e9020a44047fbceb7e3d9e608c5687325 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Wed, 8 Mar 2023 19:22:42 +0100 Subject: [PATCH 098/126] use retry loop to handle concurrent multi process open --- ext/pylon/gstpylon.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 9440fd3..edbea8c 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -46,6 +46,12 @@ #include +/* retry open camera limits in case of collision with other + * process + */ +constexpr int FAILED_OPEN_RETRY_COUNT = 30; +constexpr int FAILED_OPEN_RETRY_WAIT_TIME_MS = 1000; + /* Pixel format definitions */ typedef struct { std::string pfnc_name; @@ -264,7 +270,23 @@ GstPylon *gst_pylon_new(GstElement *gstpylonsrc, const gchar *device_user_name, device_info = device_list.at(device_index); - self->camera->Attach(factory.CreateDevice(device_info)); + /* retry loop to start camera + * handles the cornercase of multiprocess pipelines started + * concurrently + */ + for (auto retry_idx = 0; retry_idx <= FAILED_OPEN_RETRY_COUNT; + retry_idx++) { + try { + self->camera->Attach(factory.CreateDevice(device_info)); + break; + } catch (GenICam::GenericException &e) { + GST_INFO_OBJECT(gstpylonsrc, "Failed to Open %s (%s)\n", + device_info.GetSerialNumber().c_str(), + e.GetDescription()); + /* wait for before new open attempt */ + g_usleep(FAILED_OPEN_RETRY_WAIT_TIME_MS * 1000); + } + } self->camera->Open(); /* Set the camera to a valid state */ From 4d6b1c9794163c84fd8963affea12335753bcaf0 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 9 Mar 2023 22:34:01 +0100 Subject: [PATCH 099/126] fix version generation --- meson.build | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/meson.build b/meson.build index 6db360b..7b86e48 100644 --- a/meson.build +++ b/meson.build @@ -13,30 +13,33 @@ gst_dep = dependency('gstreamer-1.0', version : gst_req) gst_version = gst_dep.version() message('Building against GStreamer ' + gst_version) +python3 = import('python').find_installation() +# generate project version from git info py_script = ''' import subprocess import sys, os meson_project_path = sys.argv[1] -git_dir = meson_project_path + "/.git" - -if not os.path.exists(git_dir): - sys.exit(1) +git_dir = os.path.join(meson_project_path, ".git") try: - cmd_result = subprocess.run(["git", "describe", "--tags"], capture_output=True) + cmd_result = subprocess.run( + ["git", "--git-dir=" + git_dir, "describe", "--tags", "--abbrev=7", "--dirty=+"], + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + check=True, + ) vcs_tag = cmd_result.stdout.decode("utf-8")[1:-1] - print(vcs_tag) -except FileNotFoundError: +except (FileNotFoundError, subprocess.CalledProcessError): sys.exit(1) -''' +print(vcs_tag) +''' git_version = vcs_tag(command : ['python3', '-c', py_script, meson.project_source_root()], - input: 'version.h.in', output: 'version.h', replace_string: '@GIT_VERSION@', - fallback: meson.project_version() + '-local') - + input: 'version.h.in', output: 'version.h', replace_string: '@GIT_VERSION@', + fallback: meson.project_version() + '-local') version_arr = gst_version.split('.') gst_version_major = version_arr[0].to_int() @@ -257,7 +260,6 @@ endif presetdir = join_paths(get_option('datadir'), 'gstreamer-' + api_version, 'presets') -python3 = import('python').find_installation() pkgconfig = import('pkgconfig') plugins_pkgconfig_install_dir = join_paths(plugins_install_dir, 'pkgconfig') if get_option('default_library') == 'shared' From 99a0a90af900e1812a1146847a5c356654dfd7b3 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 27 Feb 2023 10:27:07 +0100 Subject: [PATCH 100/126] add clang-format style definition and update hook This allows to use a common .clang-format definition in editors and pre-commit hook. --- .clang-format | 18 ++++++++++++++++++ hooks/cpp-format | 30 +----------------------------- hooks/pre-commit.hook | 19 +++++++++---------- 3 files changed, 28 insertions(+), 39 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..aea8a5f --- /dev/null +++ b/.clang-format @@ -0,0 +1,18 @@ +BasedOnStyle: Google +IncludeBlocks: Regroup +IndentPPDirectives: AfterHash +SortIncludes: true +IncludeCategories: + - Regex: '^' + Priority: 3 + SortPriority: 0 + - Regex: '^<.*\.h>' + Priority: 2 + SortPriority: 0 + - Regex: '^<.*' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 + diff --git a/hooks/cpp-format b/hooks/cpp-format index 57740e4..35e4069 100755 --- a/hooks/cpp-format +++ b/hooks/cpp-format @@ -19,33 +19,5 @@ else CLANG_INDENT=clang-format fi -CLANG_INDENT_STYLE="{ - BasedOnStyle: Google, - IncludeBlocks: Regroup, - IndentPPDirectives: AfterHash, - IncludeCategories: [ - { - Regex: '^', - Priority: 3 - }, - { - Regex: '^<.*\\\.h>', - Priority: 2 - }, - { - Regex: '^<.*', - Priority: 3 - }, - { - Regex: '.*', - Priority: 1 - } - ] -}" - -CLANG_INDENT_PARAMETERS="--style=\"${CLANG_INDENT_STYLE}\" \ - --sort-includes \ - -i" - echo "--Formatting ${file}--" -eval ${CLANG_INDENT} ${CLANG_INDENT_PARAMETERS} ${file} +eval ${CLANG_INDENT} -i --style=file ${file} diff --git a/hooks/pre-commit.hook b/hooks/pre-commit.hook index 724b47c..688ecad 100755 --- a/hooks/pre-commit.hook +++ b/hooks/pre-commit.hook @@ -3,9 +3,7 @@ # Check that the code follows a consistent code style # -# Check for existence of indent, and error out if not present. -# On some *bsd systems the binary seems to be called gnunindent, -# so check for that first. +# Check for existence of clang-format, and error out if not present. echo "--Checking style--" for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep -e "\.h$" -e "\.cpp$"` ; do @@ -13,25 +11,25 @@ for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep - # revision in the index (and not the checked out version). nf=`git checkout-index --temp ${file} | cut -f 1` newfile_name=`basename $file` - touch "/tmp/$newfile_name" || exit 1 - newfile="/tmp/$newfile_name" - cp "${nf}" "${newfile}" + check_dir=$(mktemp -d) + newfile="${check_dir}/${newfile_name}" - INDENT="hooks/cpp-format" + cp "${nf}" "${newfile}" + cp ".clang-format" ${check_dir} - eval ${INDENT} $newfile 2>> /dev/null + eval hooks/cpp-format ${newfile} 2>> /dev/null diff -u -p "${nf}" "${newfile}" r=$? - rm "${newfile}" + rm -r "${check_dir}" rm "${nf}" if [ $r != 0 ] ; then echo "=================================================================================================" echo " Code style error in: $file " echo " " echo " Please fix before committing. Don't forget to run git add before trying to commit again. " -echo " If the whole file is to be committed, run as : " +echo " If the whole file is to be committed, run as (scripts may be found in hooks/): " echo " " echo " hooks/cpp-format $file; git add $file; git commit" echo " " @@ -40,3 +38,4 @@ echo "========================================================================== fi done echo "--Checking style pass--" + From 031b9e9a798552e6b2801d4c85e1a671755f2cb7 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Tue, 21 Feb 2023 22:22:39 +0100 Subject: [PATCH 101/126] fix define clash on new gstreamer versions --- gst-libs/gst/pylon/gstpylon-prelude.h | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylon-prelude.h b/gst-libs/gst/pylon/gstpylon-prelude.h index 8f14674..5da085c 100644 --- a/gst-libs/gst/pylon/gstpylon-prelude.h +++ b/gst-libs/gst/pylon/gstpylon-prelude.h @@ -46,7 +46,7 @@ #ifndef EXT_PYLONSRC_API # ifdef BUILDING_EXT_PYLONSRC -# define EXT_PYLONSRC_API GST_API_EXPORT /* from config.h */ +# define EXT_PYLONSRC_API GST_PYLON_API_EXPORT /* from config.h */ # else # define EXT_PYLONSRC_API GST_API_IMPORT # endif diff --git a/meson.build b/meson.build index 7b86e48..5c420e1 100644 --- a/meson.build +++ b/meson.build @@ -171,7 +171,7 @@ else endif # Passing this through the command line would be too messy -cdata.set('GST_API_EXPORT', export_define) +cdata.set('GST_PYLON_API_EXPORT', export_define) warning_flags = [ '-Wmissing-declarations', From ae72092203eb3298a060e2dddd06b8fb89d8e5c6 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Sun, 12 Mar 2023 18:14:54 +0100 Subject: [PATCH 102/126] refactor to classes --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 58 +-- gst-libs/gst/pylon/gstpylonintrospection.cpp | 385 ++----------------- gst-libs/gst/pylon/gstpylonintrospection.h | 21 +- gst-libs/gst/pylon/gstpylonparamfactory.cpp | 254 ++++++++++++ gst-libs/gst/pylon/gstpylonparamfactory.h | 48 +++ gst-libs/gst/pylon/meson.build | 3 +- 6 files changed, 384 insertions(+), 385 deletions(-) create mode 100644 gst-libs/gst/pylon/gstpylonparamfactory.cpp create mode 100644 gst-libs/gst/pylon/gstpylonparamfactory.h diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index a7e0a6f..3ac1568 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -36,7 +36,7 @@ #include "gstpylondebug.h" #include "gstpylonfeaturewalker.h" -#include "gstpylonintrospection.h" +#include "gstpylonparamfactory.h" #include @@ -46,16 +46,19 @@ #define MAX_INT_SELECTOR_ENTRIES 16 /* prototypes */ -static std::vector gst_pylon_get_enum_entries( +std::vector gst_pylon_get_enum_entries( GenApi::IEnumeration* enum_node); -static std::vector gst_pylon_get_int_entries( - GenApi::IInteger* int_node); -static std::vector gst_pylon_camera_handle_node( +std::vector gst_pylon_get_int_entries(GenApi::IInteger* int_node); +std::vector gst_pylon_camera_handle_node( GenApi::INode* node, GenApi::INodeMap& nodemap, const std::string& device_fullname, GstPylonCache& feature_cache); -static void gst_pylon_camera_install_specs( - const std::vector& specs_list, GObjectClass* oclass, - gint& nprop); +void gst_pylon_camera_install_specs(const std::vector& specs_list, + GObjectClass* oclass, gint& nprop); +std::vector gst_pylon_camera_handle_node( + GenApi::INode* node, GstPylonParamFactory& param_factory); +bool is_unsupported_feature(const std::string& feature_name); +bool is_unsupported_category(const std::string& category_name); +bool is_unsupported_selector(const std::string& feature_name); static const std::unordered_set propfilter_set = { "Width", @@ -91,26 +94,26 @@ static const std::unordered_set categoryfilter_set = { }; /* filter for features that are not supported */ -static bool is_unsupported_feature(const std::string& feature_name) { +bool is_unsupported_feature(const std::string& feature_name) { return propfilter_set.find(feature_name) != propfilter_set.end(); } /* filter for categories that are not supported */ -static bool is_unsupported_category(const std::string& category_name) { +bool is_unsupported_category(const std::string& category_name) { return categoryfilter_set.find(category_name) != categoryfilter_set.end(); } /* filter for selector nodes */ -static std::unordered_set selectorfilter_set = { +std::unordered_set selectorfilter_set = { "DeviceLinkSelector", }; /* filter for selectors and categories that are supported */ -static bool is_unsupported_selector(const std::string& feature_name) { +bool is_unsupported_selector(const std::string& feature_name) { return selectorfilter_set.find(feature_name) != selectorfilter_set.end(); } -static std::vector gst_pylon_get_enum_entries( +std::vector gst_pylon_get_enum_entries( GenApi::IEnumeration* enum_node) { GenApi::NodeList_t enum_entries; std::vector entry_names; @@ -138,8 +141,7 @@ static std::vector gst_pylon_get_enum_entries( return entry_names; } -static std::vector gst_pylon_get_int_entries( - GenApi::IInteger* int_node) { +std::vector gst_pylon_get_int_entries(GenApi::IInteger* int_node) { std::vector entry_names; g_return_val_if_fail(int_node, entry_names); @@ -226,9 +228,8 @@ std::vector GstPylonFeatureWalker::process_selector_features( return enum_values; } -static std::vector gst_pylon_camera_handle_node( - GenApi::INode* node, GenApi::INodeMap& nodemap, - const std::string& device_fullname, GstPylonCache& feature_cache) { +std::vector gst_pylon_camera_handle_node( + GenApi::INode* node, GstPylonParamFactory& param_factory) { GenApi::INode* selector_node = NULL; gint64 selector_value = 0; std::vector specs_list; @@ -261,22 +262,20 @@ static std::vector gst_pylon_camera_handle_node( } } - specs_list.push_back(GstPylonParamFactory::make_param( - nodemap, node, selector_node, selector_value, device_fullname, - feature_cache)); + specs_list.push_back( + param_factory.make_param(node, selector_node, selector_value)); } catch (const Pylon::GenericException& e) { - GST_FIXME("Unable to fully install property '%s-%s' on device \"%s\": %s", + GST_FIXME("Unable to fully install property '%s-%s' : %s", node->GetName().c_str(), enum_value.c_str(), - device_fullname.c_str(), e.GetDescription()); + e.GetDescription()); } } return specs_list; } -static void gst_pylon_camera_install_specs( - const std::vector& specs_list, GObjectClass* oclass, - gint& nprop) { +void gst_pylon_camera_install_specs(const std::vector& specs_list, + GObjectClass* oclass, gint& nprop) { g_return_if_fail(oclass); if (!specs_list.empty()) { @@ -300,6 +299,9 @@ void GstPylonFeatureWalker::install_properties( const std::string& device_fullname, GstPylonCache& feature_cache) { g_return_if_fail(oclass); + auto param_factory = + GstPylonParamFactory(nodemap, device_fullname, feature_cache); + gboolean is_cache_valid = feature_cache.IsCacheValid(); gint nprop = 1; @@ -324,8 +326,8 @@ void GstPylonFeatureWalker::install_properties( GenICam::gcstring attrib; try { - std::vector specs_list = gst_pylon_camera_handle_node( - node, nodemap, device_fullname, feature_cache); + std::vector specs_list = + gst_pylon_camera_handle_node(node, param_factory); gst_pylon_camera_install_specs(specs_list, oclass, nprop); diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 4e96e46..696a1c0 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -68,88 +68,43 @@ class GstPylonTypeAction : public GstPylonActions { }; /* prototypes */ -static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GstPylonCache &feature_cache); -static GParamSpec *gst_pylon_make_spec_selector_int64( - GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache &feature_cache); -static GParamSpec *gst_pylon_make_spec_bool(GenApi::INodeMap &nodemap, - GenApi::INode *node); -static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GenApi::INode *selector, - guint64 selector_value); -static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GstPylonCache &feature_cache); -static GParamSpec *gst_pylon_make_spec_selector_double( - GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache &feature_cache); -static GParamSpec *gst_pylon_make_spec_str(GenApi::INodeMap &nodemap, - GenApi::INode *node); -static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GenApi::INode *selector, - guint64 selector_value); -static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, - GenApi::INode *node, - const std::string &device_fullname); -static GParamSpec *gst_pylon_make_spec_enum(GenApi::INodeMap &nodemap, - GenApi::INode *node, - const std::string &device_fullname); -static GParamSpec *gst_pylon_make_spec_selector_enum( - GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, const std::string &device_fullname); -static GenApi::INode *gst_pylon_find_limit_node(GenApi::INode *feature_node, - const GenICam::gcstring &limit); -static std::vector gst_pylon_find_parent_features( +GenApi::INode *gst_pylon_find_limit_node(GenApi::INode *feature_node, + const GenICam::gcstring &limit); +std::vector gst_pylon_find_parent_features( GenApi::INode *feature_node); -static void gst_pylon_add_all_property_values( +void gst_pylon_add_all_property_values( GenApi::INode *feature_node, std::string value, std::unordered_map &invalidators); -static std::vector gst_pylon_get_available_features( +std::vector gst_pylon_get_available_features( const std::set &feature_list); template -static std::vector> gst_pylon_cartesian_product( +std::vector> gst_pylon_cartesian_product( std::vector> &v); template -static T gst_pylon_check_for_feature_invalidators( +T gst_pylon_check_for_feature_invalidators( GenApi::INode *feature_node, GenApi::INode *limit_node, std::string limit, std::unordered_map &invalidators); template -static T gst_pylon_query_feature_limits(GenApi::INode *feature_node, - const std::string &limit); -static std::vector> -gst_pylon_create_set_value_actions( +T gst_pylon_query_feature_limits(GenApi::INode *feature_node, + const std::string &limit); +std::vector> gst_pylon_create_set_value_actions( const std::vector &node_list); template -static void gst_pylon_find_limits( - GenApi::INode *node, double &minimum_under_all_settings, - double &maximum_under_all_settings, - std::vector &invalidators_result); +void gst_pylon_find_limits(GenApi::INode *node, + double &minimum_under_all_settings, + double &maximum_under_all_settings, + std::vector &invalidators_result); template -static std::string gst_pylon_build_cache_value_string( - GParamFlags flags, T minimum_under_all_settings, - T maximum_under_all_settings); +std::string gst_pylon_build_cache_value_string(GParamFlags flags, + T minimum_under_all_settings, + T maximum_under_all_settings); -static void gst_pylon_query_feature_properties_double( - GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache, GParamFlags &flags, - gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings, - GenApi::INode *selector = NULL, gint64 selector_value = 0); +gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node); -static void gst_pylon_query_feature_properties_integer( - GenApi::INodeMap &nodemap, GenApi::INode *node, - GstPylonCache &feature_cache, GParamFlags &flags, - gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings, - GenApi::INode *selector = NULL, gint64 selector_value = 0); - -static gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node); -static GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, - GenApi::INode *node); +std::vector gst_pylon_create_reset_value_actions( + const std::vector &node_list); -static gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node) { +gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node) { GenICam::gcstring value; GenICam::gcstring attribute; if (node->GetProperty("pIsLocked", value, attribute)) { @@ -166,8 +121,8 @@ static gboolean gst_pylon_can_feature_later_be_writable(GenApi::INode *node) { } } -static GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, - GenApi::INode *node) { +GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, + GenApi::INode *node) { gint flags = 0; g_return_val_if_fail(node, static_cast(flags)); @@ -211,8 +166,8 @@ static GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, return static_cast(flags); } -static GenApi::INode *gst_pylon_find_limit_node( - GenApi::INode *node, const GenICam::gcstring &limit) { +GenApi::INode *gst_pylon_find_limit_node(GenApi::INode *node, + const GenICam::gcstring &limit) { GenApi::INode *limit_node = NULL; GenICam::gcstring value; GenICam::gcstring attribute; @@ -228,7 +183,7 @@ static GenApi::INode *gst_pylon_find_limit_node( return limit_node; } -static std::vector gst_pylon_find_parent_features( +std::vector gst_pylon_find_parent_features( GenApi::INode *node) { std::vector parent_features; @@ -249,7 +204,7 @@ static std::vector gst_pylon_find_parent_features( return parent_features; } -static void gst_pylon_add_all_property_values( +void gst_pylon_add_all_property_values( GenApi::INode *node, std::string value, std::unordered_map &invalidators) { std::string delimiter = "\t"; @@ -271,7 +226,7 @@ static void gst_pylon_add_all_property_values( } } -static std::vector gst_pylon_get_available_features( +std::vector gst_pylon_get_available_features( const std::set &feature_list) { std::vector available_features; for (const auto &feature : feature_list) { @@ -283,7 +238,7 @@ static std::vector gst_pylon_get_available_features( } template -static std::vector> gst_pylon_cartesian_product( +std::vector> gst_pylon_cartesian_product( std::vector> &values) { std::vector> result; auto product = [](long long a, std::vector &b) { return a * b.size(); }; @@ -301,8 +256,8 @@ static std::vector> gst_pylon_cartesian_product( } template -static T gst_pylon_query_feature_limits(GenApi::INode *node, - const std::string &limit) { +T gst_pylon_query_feature_limits(GenApi::INode *node, + const std::string &limit) { g_return_val_if_fail(node, 0); P param(node); @@ -315,7 +270,7 @@ static T gst_pylon_query_feature_limits(GenApi::INode *node, } template -static T gst_pylon_check_for_feature_invalidators( +T gst_pylon_check_for_feature_invalidators( GenApi::INode *node, GenApi::INode *limit_node, std::string limit, std::unordered_map &invalidators) { T limit_under_all_settings = 0; @@ -336,8 +291,7 @@ static T gst_pylon_check_for_feature_invalidators( return limit_under_all_settings; } -static std::vector> -gst_pylon_create_set_value_actions( +std::vector> gst_pylon_create_set_value_actions( const std::vector &node_list) { std::vector> actions_list; @@ -403,7 +357,7 @@ gst_pylon_create_set_value_actions( return actions_list; } -static std::vector gst_pylon_create_reset_value_actions( +std::vector gst_pylon_create_reset_value_actions( const std::vector &node_list) { std::vector actions_list; @@ -449,9 +403,8 @@ static std::vector gst_pylon_create_reset_value_actions( } template -static void gst_pylon_find_limits(GenApi::INode *node, - T &minimum_under_all_settings, - T &maximum_under_all_settings) { +void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, + T &maximum_under_all_settings) { std::unordered_map invalidators; maximum_under_all_settings = 0; minimum_under_all_settings = 0; @@ -613,269 +566,3 @@ void gst_pylon_query_feature_properties_integer( g_free(feature_cache_name); } - -static GParamSpec *gst_pylon_make_spec_int64(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GstPylonCache &feature_cache) { - g_return_val_if_fail(node, NULL); - - Pylon::CIntegerParameter param(node); - gint64 max_value = 0; - gint64 min_value = 0; - GParamFlags flags = G_PARAM_READABLE; - - gst_pylon_query_feature_properties_integer(nodemap, node, feature_cache, - flags, min_value, max_value); - - return g_param_spec_int64(node->GetName(), node->GetDisplayName(), - node->GetToolTip(), min_value, max_value, - param.GetValue(), flags); -} - -static GParamSpec *gst_pylon_make_spec_selector_int64( - GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache &feature_cache) { - g_return_val_if_fail(node, NULL); - g_return_val_if_fail(selector, NULL); - - Pylon::CIntegerParameter param(node); - gint64 max_value = 0; - gint64 min_value = 0; - GParamFlags flags = G_PARAM_READABLE; - - gst_pylon_query_feature_properties_integer(nodemap, node, feature_cache, - flags, min_value, max_value, - selector, selector_value); - - return gst_pylon_param_spec_selector_int64( - nodemap, node->GetName(), selector->GetName(), selector_value, - node->GetDisplayName(), node->GetToolTip(), min_value, max_value, - param.GetValue(), flags); -} - -static GParamSpec *gst_pylon_make_spec_bool(GenApi::INodeMap &nodemap, - GenApi::INode *node) { - g_return_val_if_fail(node, NULL); - - Pylon::CBooleanParameter param(node); - - return g_param_spec_boolean(node->GetName(), node->GetDisplayName(), - node->GetToolTip(), param.GetValue(), - gst_pylon_query_access(nodemap, node)); -} - -static GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GenApi::INode *selector, - guint64 selector_value) { - g_return_val_if_fail(node, NULL); - g_return_val_if_fail(selector, NULL); - - Pylon::CBooleanParameter param(node); - - return gst_pylon_param_spec_selector_boolean( - nodemap, node->GetName(), selector->GetName(), selector_value, - node->GetDisplayName(), node->GetToolTip(), param.GetValue(), - gst_pylon_query_access(nodemap, node)); -} - -static GParamSpec *gst_pylon_make_spec_double(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GstPylonCache &feature_cache) { - g_return_val_if_fail(node, NULL); - - Pylon::CFloatParameter param(node); - gdouble max_value = 0; - gdouble min_value = 0; - GParamFlags flags = G_PARAM_READABLE; - - gst_pylon_query_feature_properties_double(nodemap, node, feature_cache, flags, - min_value, max_value); - - return g_param_spec_double(node->GetName(), node->GetDisplayName(), - node->GetToolTip(), min_value, max_value, - param.GetValue(), flags); -} - -static GParamSpec *gst_pylon_make_spec_selector_double( - GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, GstPylonCache &feature_cache) { - g_return_val_if_fail(node, NULL); - g_return_val_if_fail(selector, NULL); - - Pylon::CFloatParameter param(node); - gdouble max_value = 0; - gdouble min_value = 0; - GParamFlags flags = G_PARAM_READABLE; - - gst_pylon_query_feature_properties_double(nodemap, node, feature_cache, flags, - min_value, max_value, selector, - selector_value); - - return gst_pylon_param_spec_selector_double( - nodemap, node->GetName(), selector->GetName(), selector_value, - node->GetDisplayName(), node->GetToolTip(), min_value, max_value, - param.GetValue(), flags); -} - -static GParamSpec *gst_pylon_make_spec_str(GenApi::INodeMap &nodemap, - GenApi::INode *node) { - g_return_val_if_fail(node, NULL); - - Pylon::CStringParameter param(node); - - return g_param_spec_string(node->GetName(), node->GetDisplayName(), - node->GetToolTip(), param.GetValue(), - gst_pylon_query_access(nodemap, node)); -} - -static GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GenApi::INode *selector, - guint64 selector_value) { - g_return_val_if_fail(node, NULL); - g_return_val_if_fail(selector, NULL); - - Pylon::CStringParameter param(node); - - return gst_pylon_param_spec_selector_string( - nodemap, node->GetName(), selector->GetName(), selector_value, - node->GetDisplayName(), node->GetToolTip(), param.GetValue(), - gst_pylon_query_access(nodemap, node)); -} - -static GType gst_pylon_make_enum_type(GenApi::INodeMap &nodemap, - GenApi::INode *node, - const std::string &device_fullname) { - /* When registering enums to the GType system, their string pointers - must remain valid throughout the application lifespan. To achieve this - we are saving all found enums into a static hash table - */ - static std::unordered_map> persistent_values; - - g_return_val_if_fail(node, G_TYPE_INVALID); - - Pylon::CEnumParameter param(node); - - gchar *full_name = g_strdup_printf("%s_%s", device_fullname.c_str(), - node->GetName().c_str()); - std::string name = gst_pylon_param_spec_sanitize_name(full_name); - g_free(full_name); - - GType type = g_type_from_name(name.c_str()); - - if (!type) { - std::vector enumvalues; - GenApi::StringList_t values; - - param.GetSettableValues(values); - for (const auto &value_name : values) { - auto entry = param.GetEntryByName(value_name); - auto value = static_cast(entry->GetValue()); - auto tooltip = entry->GetNode()->GetToolTip(); - - /* We need a copy of the strings so that they are persistent - throughout the application lifespan */ - GEnumValue ev = {value, g_strdup(value_name.c_str()), - g_strdup(tooltip.c_str())}; - enumvalues.push_back(ev); - } - - GEnumValue sentinel = {0}; - enumvalues.push_back(sentinel); - - type = g_enum_register_static(name.c_str(), enumvalues.data()); - persistent_values.insert({type, std::move(enumvalues)}); - } - - return type; -} - -static GParamSpec *gst_pylon_make_spec_enum( - GenApi::INodeMap &nodemap, GenApi::INode *node, - const std::string &device_fullname) { - g_return_val_if_fail(node, NULL); - - Pylon::CEnumParameter param(node); - GType type = gst_pylon_make_enum_type(nodemap, node, device_fullname.c_str()); - - return g_param_spec_enum(node->GetName(), node->GetDisplayName(), - node->GetToolTip(), type, param.GetIntValue(), - gst_pylon_query_access(nodemap, node)); -} - -static GParamSpec *gst_pylon_make_spec_selector_enum( - GenApi::INodeMap &nodemap, GenApi::INode *node, GenApi::INode *selector, - guint64 selector_value, const std::string &device_fullname) { - g_return_val_if_fail(node, NULL); - g_return_val_if_fail(selector, NULL); - - Pylon::CEnumParameter param(node); - GType type = gst_pylon_make_enum_type(nodemap, node, device_fullname.c_str()); - - return gst_pylon_param_spec_selector_enum( - nodemap, node->GetName(), selector->GetName(), selector_value, - node->GetDisplayName(), node->GetToolTip(), type, param.GetIntValue(), - gst_pylon_query_access(nodemap, node)); -} - -GParamSpec *GstPylonParamFactory::make_param(GenApi::INodeMap &nodemap, - GenApi::INode *node, - GenApi::INode *selector, - guint64 selector_value, - const std::string &device_fullname, - GstPylonCache &feature_cache) { - g_return_val_if_fail(node, NULL); - - GParamSpec *spec = NULL; - GenApi::EInterfaceType iface = node->GetPrincipalInterfaceType(); - - switch (iface) { - case GenApi::intfIInteger: - if (!selector) { - spec = gst_pylon_make_spec_int64(nodemap, node, feature_cache); - } else { - spec = gst_pylon_make_spec_selector_int64( - nodemap, node, selector, selector_value, feature_cache); - } - break; - case GenApi::intfIBoolean: - if (!selector) { - spec = gst_pylon_make_spec_bool(nodemap, node); - } else { - spec = gst_pylon_make_spec_selector_bool(nodemap, node, selector, - selector_value); - } - break; - case GenApi::intfIFloat: - if (!selector) { - spec = gst_pylon_make_spec_double(nodemap, node, feature_cache); - } else { - spec = gst_pylon_make_spec_selector_double( - nodemap, node, selector, selector_value, feature_cache); - } - break; - case GenApi::intfIString: - if (!selector) { - spec = gst_pylon_make_spec_str(nodemap, node); - } else { - spec = gst_pylon_make_spec_selector_str(nodemap, node, selector, - selector_value); - } - break; - case GenApi::intfIEnumeration: - if (!selector) { - spec = gst_pylon_make_spec_enum(nodemap, node, device_fullname); - } else { - spec = gst_pylon_make_spec_selector_enum( - nodemap, node, selector, selector_value, device_fullname); - } - break; - default: - Pylon::String_t msg = - "Unsupported node of type " + GenApi::GetInterfaceName(node); - throw Pylon::GenericException(msg, __FILE__, __LINE__); - } - - return spec; -} diff --git a/gst-libs/gst/pylon/gstpylonintrospection.h b/gst-libs/gst/pylon/gstpylonintrospection.h index 5cc01a9..9fcc15f 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.h +++ b/gst-libs/gst/pylon/gstpylonintrospection.h @@ -37,12 +37,19 @@ #include #include -class GstPylonParamFactory { - public: - static GParamSpec *make_param(GenApi::INodeMap &nodemap, GenApi::INode *node, - GenApi::INode *selector, guint64 selector_value, - const std::string &device_fullname, - GstPylonCache &feature_cache); -}; +GParamFlags gst_pylon_query_access(GenApi::INodeMap &nodemap, + GenApi::INode *node); + +void gst_pylon_query_feature_properties_double( + GenApi::INodeMap &nodemap, GenApi::INode *node, + GstPylonCache &feature_cache, GParamFlags &flags, + gdouble &minimum_under_all_settings, gdouble &maximum_under_all_settings, + GenApi::INode *selector = NULL, gint64 selector_value = 0); + +void gst_pylon_query_feature_properties_integer( + GenApi::INodeMap &nodemap, GenApi::INode *node, + GstPylonCache &feature_cache, GParamFlags &flags, + gint64 &minimum_under_all_settings, gint64 &maximum_under_all_settings, + GenApi::INode *selector = NULL, gint64 selector_value = 0); #endif diff --git a/gst-libs/gst/pylon/gstpylonparamfactory.cpp b/gst-libs/gst/pylon/gstpylonparamfactory.cpp new file mode 100644 index 0000000..19cbfe9 --- /dev/null +++ b/gst-libs/gst/pylon/gstpylonparamfactory.cpp @@ -0,0 +1,254 @@ +#include "gstpylonparamfactory.h" + +#include "gstpylonintrospection.h" +#include "gstpylonparamspecs.h" + +#include + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_int64( + GenApi::INode *node) { + g_return_val_if_fail(node, NULL); + + Pylon::CIntegerParameter param(node); + gint64 max_value = 0; + gint64 min_value = 0; + GParamFlags flags = G_PARAM_READABLE; + + gst_pylon_query_feature_properties_integer(nodemap, node, feature_cache, + flags, min_value, max_value); + + return g_param_spec_int64(node->GetName(), node->GetDisplayName(), + node->GetToolTip(), min_value, max_value, + param.GetValue(), flags); +} + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_selector_int64( + GenApi::INode *node, GenApi::INode *selector, guint64 selector_value) { + g_return_val_if_fail(node, NULL); + g_return_val_if_fail(selector, NULL); + + Pylon::CIntegerParameter param(node); + gint64 max_value = 0; + gint64 min_value = 0; + GParamFlags flags = G_PARAM_READABLE; + + gst_pylon_query_feature_properties_integer(nodemap, node, feature_cache, + flags, min_value, max_value, + selector, selector_value); + + return gst_pylon_param_spec_selector_int64( + nodemap, node->GetName(), selector->GetName(), selector_value, + node->GetDisplayName(), node->GetToolTip(), min_value, max_value, + param.GetValue(), flags); +} + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_bool( + GenApi::INode *node) { + g_return_val_if_fail(node, NULL); + + Pylon::CBooleanParameter param(node); + + return g_param_spec_boolean(node->GetName(), node->GetDisplayName(), + node->GetToolTip(), param.GetValue(), + gst_pylon_query_access(nodemap, node)); +} + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_selector_bool( + GenApi::INode *node, GenApi::INode *selector, guint64 selector_value) { + g_return_val_if_fail(node, NULL); + g_return_val_if_fail(selector, NULL); + + Pylon::CBooleanParameter param(node); + + return gst_pylon_param_spec_selector_boolean( + nodemap, node->GetName(), selector->GetName(), selector_value, + node->GetDisplayName(), node->GetToolTip(), param.GetValue(), + gst_pylon_query_access(nodemap, node)); +} + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_double( + GenApi::INode *node) { + g_return_val_if_fail(node, NULL); + + Pylon::CFloatParameter param(node); + gdouble max_value = 0; + gdouble min_value = 0; + GParamFlags flags = G_PARAM_READABLE; + + gst_pylon_query_feature_properties_double(nodemap, node, feature_cache, flags, + min_value, max_value); + + return g_param_spec_double(node->GetName(), node->GetDisplayName(), + node->GetToolTip(), min_value, max_value, + param.GetValue(), flags); +} + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_selector_double( + GenApi::INode *node, GenApi::INode *selector, guint64 selector_value) { + g_return_val_if_fail(node, NULL); + g_return_val_if_fail(selector, NULL); + + Pylon::CFloatParameter param(node); + gdouble max_value = 0; + gdouble min_value = 0; + GParamFlags flags = G_PARAM_READABLE; + + gst_pylon_query_feature_properties_double(nodemap, node, feature_cache, flags, + min_value, max_value, selector, + selector_value); + + return gst_pylon_param_spec_selector_double( + nodemap, node->GetName(), selector->GetName(), selector_value, + node->GetDisplayName(), node->GetToolTip(), min_value, max_value, + param.GetValue(), flags); +} + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_str(GenApi::INode *node) { + g_return_val_if_fail(node, NULL); + + Pylon::CStringParameter param(node); + + return g_param_spec_string(node->GetName(), node->GetDisplayName(), + node->GetToolTip(), param.GetValue(), + gst_pylon_query_access(nodemap, node)); +} + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_selector_str( + GenApi::INode *node, GenApi::INode *selector, guint64 selector_value) { + g_return_val_if_fail(node, NULL); + g_return_val_if_fail(selector, NULL); + + Pylon::CStringParameter param(node); + + return gst_pylon_param_spec_selector_string( + nodemap, node->GetName(), selector->GetName(), selector_value, + node->GetDisplayName(), node->GetToolTip(), param.GetValue(), + gst_pylon_query_access(nodemap, node)); +} + +GType GstPylonParamFactory::gst_pylon_make_enum_type(GenApi::INode *node) { + /* When registering enums to the GType system, their string pointers + must remain valid throughout the application lifespan. To achieve this + we are saving all found enums into a static hash table + */ + static std::unordered_map> persistent_values; + + g_return_val_if_fail(node, G_TYPE_INVALID); + + Pylon::CEnumParameter param(node); + + gchar *full_name = g_strdup_printf("%s_%s", device_fullname.c_str(), + node->GetName().c_str()); + std::string name = gst_pylon_param_spec_sanitize_name(full_name); + g_free(full_name); + + GType type = g_type_from_name(name.c_str()); + + if (!type) { + std::vector enumvalues; + GenApi::StringList_t values; + + param.GetSettableValues(values); + for (const auto &value_name : values) { + auto entry = param.GetEntryByName(value_name); + auto value = static_cast(entry->GetValue()); + auto tooltip = entry->GetNode()->GetToolTip(); + + /* We need a copy of the strings so that they are persistent + throughout the application lifespan */ + GEnumValue ev = {value, g_strdup(value_name.c_str()), + g_strdup(tooltip.c_str())}; + enumvalues.push_back(ev); + } + + GEnumValue sentinel = {0}; + enumvalues.push_back(sentinel); + + type = g_enum_register_static(name.c_str(), enumvalues.data()); + persistent_values.insert({type, std::move(enumvalues)}); + } + + return type; +} + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_enum( + GenApi::INode *node) { + g_return_val_if_fail(node, NULL); + + Pylon::CEnumParameter param(node); + GType type = gst_pylon_make_enum_type(node); + + return g_param_spec_enum(node->GetName(), node->GetDisplayName(), + node->GetToolTip(), type, param.GetIntValue(), + gst_pylon_query_access(nodemap, node)); +} + +GParamSpec *GstPylonParamFactory::gst_pylon_make_spec_selector_enum( + GenApi::INode *node, GenApi::INode *selector, guint64 selector_value) { + g_return_val_if_fail(node, NULL); + g_return_val_if_fail(selector, NULL); + + Pylon::CEnumParameter param(node); + GType type = gst_pylon_make_enum_type(node); + + return gst_pylon_param_spec_selector_enum( + nodemap, node->GetName(), selector->GetName(), selector_value, + node->GetDisplayName(), node->GetToolTip(), type, param.GetIntValue(), + gst_pylon_query_access(nodemap, node)); +} + +GParamSpec *GstPylonParamFactory::GstPylonParamFactory::make_param( + GenApi::INode *node, GenApi::INode *selector, guint64 selector_value) { + g_return_val_if_fail(node, NULL); + + GParamSpec *spec = NULL; + GenApi::EInterfaceType iface = node->GetPrincipalInterfaceType(); + + switch (iface) { + case GenApi::intfIInteger: + if (!selector) { + spec = gst_pylon_make_spec_int64(node); + } else { + spec = + gst_pylon_make_spec_selector_int64(node, selector, selector_value); + } + break; + case GenApi::intfIBoolean: + if (!selector) { + spec = gst_pylon_make_spec_bool(node); + } else { + spec = + gst_pylon_make_spec_selector_bool(node, selector, selector_value); + } + break; + case GenApi::intfIFloat: + if (!selector) { + spec = gst_pylon_make_spec_double(node); + } else { + spec = + gst_pylon_make_spec_selector_double(node, selector, selector_value); + } + break; + case GenApi::intfIString: + if (!selector) { + spec = gst_pylon_make_spec_str(node); + } else { + spec = gst_pylon_make_spec_selector_str(node, selector, selector_value); + } + break; + case GenApi::intfIEnumeration: + if (!selector) { + spec = gst_pylon_make_spec_enum(node); + } else { + spec = + gst_pylon_make_spec_selector_enum(node, selector, selector_value); + } + break; + default: + Pylon::String_t msg = + "Unsupported node of type " + GenApi::GetInterfaceName(node); + throw Pylon::GenericException(msg, __FILE__, __LINE__); + } + + return spec; +} diff --git a/gst-libs/gst/pylon/gstpylonparamfactory.h b/gst-libs/gst/pylon/gstpylonparamfactory.h new file mode 100644 index 0000000..419b8be --- /dev/null +++ b/gst-libs/gst/pylon/gstpylonparamfactory.h @@ -0,0 +1,48 @@ +#ifndef GSTPYLONPARAMFACTORY_H +#define GSTPYLONPARAMFACTORY_H + +#include +#include + +class GstPylonParamFactory { + public: + GstPylonParamFactory(GenApi::INodeMap &nodemap, + const std::string &device_fullname, + GstPylonCache &feature_cache) + : nodemap(nodemap), + device_fullname(device_fullname), + feature_cache(feature_cache){}; + + GParamSpec *make_param(GenApi::INode *node, GenApi::INode *selector, + guint64 selector_value); + + private: + GParamSpec *gst_pylon_make_spec_int64(GenApi::INode *node); + GParamSpec *gst_pylon_make_spec_selector_int64(GenApi::INode *node, + GenApi::INode *selector, + guint64 selector_value); + GParamSpec *gst_pylon_make_spec_bool(GenApi::INode *node); + GParamSpec *gst_pylon_make_spec_selector_bool(GenApi::INode *node, + GenApi::INode *selector, + guint64 selector_value); + GParamSpec *gst_pylon_make_spec_double(GenApi::INode *node); + GParamSpec *gst_pylon_make_spec_selector_double(GenApi::INode *node, + GenApi::INode *selector, + guint64 selector_value); + GParamSpec *gst_pylon_make_spec_str(GenApi::INode *node); + GParamSpec *gst_pylon_make_spec_selector_str(GenApi::INode *node, + GenApi::INode *selector, + guint64 selector_value); + GType gst_pylon_make_enum_type(GenApi::INode *node); + GParamSpec *gst_pylon_make_spec_enum(GenApi::INode *node); + GParamSpec *gst_pylon_make_spec_selector_enum(GenApi::INode *node, + GenApi::INode *selector, + guint64 selector_value); + + private: + GenApi::INodeMap &nodemap; + const std::string &device_fullname; + GstPylonCache &feature_cache; +}; + +#endif // GSTPYLONPARAMFACTORY_H diff --git a/gst-libs/gst/pylon/meson.build b/gst-libs/gst/pylon/meson.build index a944bbc..c820c94 100644 --- a/gst-libs/gst/pylon/meson.build +++ b/gst-libs/gst/pylon/meson.build @@ -34,7 +34,8 @@ gstpylon_sources = [ 'gstpylonintrospection.cpp', 'gstpylonmeta.cpp', 'gstpylonobject.cpp', - 'gstpylonparamspecs.cpp' + 'gstpylonparamspecs.cpp', + 'gstpylonparamfactory.cpp' ] gstpylon_headers = [ From 4f18dbe9906fc5df95e639d5dee0b26ae8edc17a Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 27 Feb 2023 10:25:40 +0100 Subject: [PATCH 103/126] add missing files to cpp and format --- bindings/src/pygstpylon.cpp | 2 +- .../{gstpylondebug.c => gstpylondebug.cpp} | 18 +- gst-libs/gst/pylon/meson.build | 2 +- tests/check/generic/states.c | 185 ++++++++---------- tests/prototypes/dynamic_limits.cpp | 22 +-- 5 files changed, 106 insertions(+), 123 deletions(-) rename gst-libs/gst/pylon/{gstpylondebug.c => gstpylondebug.cpp} (83%) diff --git a/bindings/src/pygstpylon.cpp b/bindings/src/pygstpylon.cpp index 681beb0..fa653ab 100644 --- a/bindings/src/pygstpylon.cpp +++ b/bindings/src/pygstpylon.cpp @@ -31,7 +31,7 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "bindaccessfunctions.h" diff --git a/gst-libs/gst/pylon/gstpylondebug.c b/gst-libs/gst/pylon/gstpylondebug.cpp similarity index 83% rename from gst-libs/gst/pylon/gstpylondebug.c rename to gst-libs/gst/pylon/gstpylondebug.cpp index 51ebc3b..e2c3da3 100644 --- a/gst-libs/gst/pylon/gstpylondebug.c +++ b/gst-libs/gst/pylon/gstpylondebug.cpp @@ -31,20 +31,18 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" +# include "config.h" #endif #include "gstpylondebug.h" -GST_DEBUG_CATEGORY (gst_pylon_debug); +GST_DEBUG_CATEGORY(gst_pylon_debug); -void -gst_pylon_debug_init (void) -{ - if (g_once_init_enter (&gst_pylon_debug)) { - GST_DEBUG_CATEGORY (cat_done); - GST_DEBUG_CATEGORY_INIT (cat_done, "pylonsrc", 0, - "debug category for pylonsrc element"); - g_once_init_leave (&gst_pylon_debug, cat_done); +void gst_pylon_debug_init(void) { + if (g_once_init_enter(&gst_pylon_debug)) { + GST_DEBUG_CATEGORY(cat_done); + GST_DEBUG_CATEGORY_INIT(cat_done, "pylonsrc", 0, + "debug category for pylonsrc element"); + g_once_init_leave(&gst_pylon_debug, cat_done); } } diff --git a/gst-libs/gst/pylon/meson.build b/gst-libs/gst/pylon/meson.build index c820c94..f67cb78 100644 --- a/gst-libs/gst/pylon/meson.build +++ b/gst-libs/gst/pylon/meson.build @@ -29,7 +29,7 @@ endif gstpylon_sources = [ 'gstpyloncache.cpp', - 'gstpylondebug.c', + 'gstpylondebug.cpp', 'gstpylonfeaturewalker.cpp', 'gstpylonintrospection.cpp', 'gstpylonmeta.cpp', diff --git a/tests/check/generic/states.c b/tests/check/generic/states.c index 0c0197c..a08c19a 100644 --- a/tests/check/generic/states.c +++ b/tests/check/generic/states.c @@ -38,196 +38,181 @@ static GList *elements = NULL; -static void -setup (void) -{ +static void setup(void) { GList *features, *f; GList *plugins, *p; gchar **ignorelist = NULL; const gchar *STATE_IGNORE_ELEMENTS = NULL; GstRegistry *def; - GST_DEBUG ("getting elements for package %s", PACKAGE); - STATE_IGNORE_ELEMENTS = g_getenv ("GST_STATE_IGNORE_ELEMENTS"); - if (!g_getenv ("GST_NO_STATE_IGNORE_ELEMENTS") && STATE_IGNORE_ELEMENTS) { - GST_DEBUG ("Will ignore element factories: '%s'", STATE_IGNORE_ELEMENTS); - ignorelist = g_strsplit (STATE_IGNORE_ELEMENTS, " ", 0); + GST_DEBUG("getting elements for package %s", PACKAGE); + STATE_IGNORE_ELEMENTS = g_getenv("GST_STATE_IGNORE_ELEMENTS"); + if (!g_getenv("GST_NO_STATE_IGNORE_ELEMENTS") && STATE_IGNORE_ELEMENTS) { + GST_DEBUG("Will ignore element factories: '%s'", STATE_IGNORE_ELEMENTS); + ignorelist = g_strsplit(STATE_IGNORE_ELEMENTS, " ", 0); } - def = gst_registry_get (); + def = gst_registry_get(); - plugins = gst_registry_get_plugin_list (def); + plugins = gst_registry_get_plugin_list(def); for (p = plugins; p; p = p->next) { GstPlugin *plugin = p->data; - if (strcmp (gst_plugin_get_source (plugin), PACKAGE) != 0) - continue; + if (strcmp(gst_plugin_get_source(plugin), PACKAGE) != 0) continue; - features = - gst_registry_get_feature_list_by_plugin (def, - gst_plugin_get_name (plugin)); + features = gst_registry_get_feature_list_by_plugin( + def, gst_plugin_get_name(plugin)); for (f = features; f; f = f->next) { GstPluginFeature *feature = f->data; - const gchar *name = gst_plugin_feature_get_name (feature); + const gchar *name = gst_plugin_feature_get_name(feature); gboolean ignore = FALSE; - if (!GST_IS_ELEMENT_FACTORY (feature)) - continue; + if (!GST_IS_ELEMENT_FACTORY(feature)) continue; if (ignorelist) { gchar **s; for (s = ignorelist; s && *s; ++s) { - if (g_str_has_prefix (name, *s)) { - GST_DEBUG ("ignoring element %s", name); + if (g_str_has_prefix(name, *s)) { + GST_DEBUG("ignoring element %s", name); ignore = TRUE; } } - if (ignore) - continue; + if (ignore) continue; } - GST_DEBUG ("adding element %s", name); - elements = g_list_prepend (elements, (gpointer) g_strdup (name)); + GST_DEBUG("adding element %s", name); + elements = g_list_prepend(elements, (gpointer)g_strdup(name)); } - gst_plugin_feature_list_free (features); + gst_plugin_feature_list_free(features); } - gst_plugin_list_free (plugins); - g_strfreev (ignorelist); + gst_plugin_list_free(plugins); + g_strfreev(ignorelist); } -static void -teardown (void) -{ +static void teardown(void) { GList *e; for (e = elements; e; e = e->next) { - g_free (e->data); + g_free(e->data); } - g_list_free (elements); + g_list_free(elements); elements = NULL; } - -GST_START_TEST (test_state_changes_up_and_down_seq) -{ +GST_START_TEST(test_state_changes_up_and_down_seq) { GstElement *element; GList *e; for (e = elements; e; e = e->next) { const gchar *name = e->data; - GST_INFO ("testing element %s", name); - element = gst_element_factory_make (name, name); - fail_if (element == NULL, "Could not make element from factory %s", name); + GST_INFO("testing element %s", name); + element = gst_element_factory_make(name, name); + fail_if(element == NULL, "Could not make element from factory %s", name); - if (GST_IS_PIPELINE (element)) { - GST_DEBUG ("element %s is a pipeline", name); + if (GST_IS_PIPELINE(element)) { + GST_DEBUG("element %s is a pipeline", name); } - gst_element_set_state (element, GST_STATE_READY); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_PLAYING); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_READY); - gst_element_set_state (element, GST_STATE_NULL); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_READY); - gst_element_set_state (element, GST_STATE_PLAYING); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (element)); + gst_element_set_state(element, GST_STATE_READY); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_PLAYING); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_READY); + gst_element_set_state(element, GST_STATE_NULL); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_READY); + gst_element_set_state(element, GST_STATE_PLAYING); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(element)); } } GST_END_TEST; -GST_START_TEST (test_state_changes_up_seq) -{ +GST_START_TEST(test_state_changes_up_seq) { GstElement *element; GList *e; for (e = elements; e; e = e->next) { const gchar *name = e->data; - GST_INFO ("testing element %s", name); - element = gst_element_factory_make (name, name); - fail_if (element == NULL, "Could not make element from factory %s", name); + GST_INFO("testing element %s", name); + element = gst_element_factory_make(name, name); + fail_if(element == NULL, "Could not make element from factory %s", name); - if (GST_IS_PIPELINE (element)) { - GST_DEBUG ("element %s is a pipeline", name); + if (GST_IS_PIPELINE(element)) { + GST_DEBUG("element %s is a pipeline", name); } - gst_element_set_state (element, GST_STATE_READY); + gst_element_set_state(element, GST_STATE_READY); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_READY); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_READY); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_PLAYING); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_READY); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_PLAYING); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_READY); - gst_element_set_state (element, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (element)); + gst_element_set_state(element, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(element)); } } GST_END_TEST; -GST_START_TEST (test_state_changes_down_seq) -{ +GST_START_TEST(test_state_changes_down_seq) { GstElement *element; GList *e; for (e = elements; e; e = e->next) { const gchar *name = e->data; - GST_INFO ("testing element %s", name); - element = gst_element_factory_make (name, name); - fail_if (element == NULL, "Could not make element from factory %s", name); + GST_INFO("testing element %s", name); + element = gst_element_factory_make(name, name); + fail_if(element == NULL, "Could not make element from factory %s", name); - if (GST_IS_PIPELINE (element)) { - GST_DEBUG ("element %s is a pipeline", name); + if (GST_IS_PIPELINE(element)) { + GST_DEBUG("element %s is a pipeline", name); } - gst_element_set_state (element, GST_STATE_READY); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_PLAYING); + gst_element_set_state(element, GST_STATE_READY); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_PLAYING); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_PLAYING); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_PLAYING); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_READY); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_PLAYING); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_READY); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_PLAYING); - gst_element_set_state (element, GST_STATE_PAUSED); - gst_element_set_state (element, GST_STATE_READY); - gst_element_set_state (element, GST_STATE_NULL); - gst_object_unref (GST_OBJECT (element)); + gst_element_set_state(element, GST_STATE_PAUSED); + gst_element_set_state(element, GST_STATE_READY); + gst_element_set_state(element, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(element)); } } GST_END_TEST; +static Suite *states_suite(void) { + Suite *s = suite_create("states_good"); + TCase *tc_chain = tcase_create("general"); -static Suite * -states_suite (void) -{ - Suite *s = suite_create ("states_good"); - TCase *tc_chain = tcase_create ("general"); - - suite_add_tcase (s, tc_chain); - tcase_add_checked_fixture (tc_chain, setup, teardown); - tcase_add_test (tc_chain, test_state_changes_up_and_down_seq); - tcase_add_test (tc_chain, test_state_changes_up_seq); - tcase_add_test (tc_chain, test_state_changes_down_seq); + suite_add_tcase(s, tc_chain); + tcase_add_checked_fixture(tc_chain, setup, teardown); + tcase_add_test(tc_chain, test_state_changes_up_and_down_seq); + tcase_add_test(tc_chain, test_state_changes_up_seq); + tcase_add_test(tc_chain, test_state_changes_down_seq); return s; } -GST_CHECK_MAIN (states); +GST_CHECK_MAIN(states); diff --git a/tests/prototypes/dynamic_limits.cpp b/tests/prototypes/dynamic_limits.cpp index 371ab54..2d98be5 100644 --- a/tests/prototypes/dynamic_limits.cpp +++ b/tests/prototypes/dynamic_limits.cpp @@ -31,25 +31,25 @@ */ #ifdef _MSC_VER // MSVC -#pragma warning(push) -#pragma warning(disable : 4265) +# pragma warning(push) +# pragma warning(disable : 4265) #elif __GNUC__ // GCC, CLANG, MinGW -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#pragma GCC diagnostic ignored "-Wunused-variable" -#ifdef __clang__ -#pragma GCC diagnostic ignored "-Wunknown-warning-option" -#endif +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +# pragma GCC diagnostic ignored "-Woverloaded-virtual" +# pragma GCC diagnostic ignored "-Wunused-variable" +# ifdef __clang__ +# pragma GCC diagnostic ignored "-Wunknown-warning-option" +# endif #endif #include #include #ifdef _MSC_VER // MSVC -#pragma warning(pop) +# pragma warning(pop) #elif __GNUC__ // GCC, CLANG, MinWG -#pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif using namespace std; From 14ed081d60d807aa2bbf7c049e7e97071364027b Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Feb 2023 13:56:12 +0100 Subject: [PATCH 104/126] add problematic feature suppression for ace2 --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 64 ++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 696a1c0..8d72554 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -70,7 +70,7 @@ class GstPylonTypeAction : public GstPylonActions { /* prototypes */ GenApi::INode *gst_pylon_find_limit_node(GenApi::INode *feature_node, const GenICam::gcstring &limit); -std::vector gst_pylon_find_parent_features( +static std::vector gst_pylon_find_parent_features( GenApi::INode *feature_node); void gst_pylon_add_all_property_values( GenApi::INode *feature_node, std::string value, @@ -183,7 +183,36 @@ GenApi::INode *gst_pylon_find_limit_node(GenApi::INode *node, return limit_node; } -std::vector gst_pylon_find_parent_features( +/* identify the first category a node belongs to */ +static const std::string gst_pylon_find_node_category(GenApi::INode *node) { + std::string category = ""; + g_return_val_if_fail(node, category); + + GenApi::INode *curr_node = node; + + while (true) { + if (curr_node->IsFeature() && + curr_node->GetPrincipalInterfaceType() == GenApi::intfICategory) { + category = curr_node->GetName(); + break; + } else { + GenApi::NodeList_t parents; + curr_node->GetParents(parents); + if (parents.size() == 0) { + /* no parents and still no Category found, abort */ + break; + } else if (parents.size() >= 1) { + /* yes there are genicam nodes that belong to multiple categories ... + * but we ignore this here */ + curr_node = parents[0]; + } + } + } + + return category; +} + +static std::vector gst_pylon_find_parent_features( GenApi::INode *node) { std::vector parent_features; @@ -237,6 +266,17 @@ std::vector gst_pylon_get_available_features( return available_features; } +static std::vector gst_pylon_get_valid_categories( + const std::vector &feature_list) { + std::vector valid_features; + for (const auto &feature : feature_list) { + if (gst_pylon_find_node_category(feature) != "MultipleROI") { + valid_features.push_back(feature); + } + } + return valid_features; +} + template std::vector> gst_pylon_cartesian_product( std::vector> &values) { @@ -349,7 +389,8 @@ std::vector> gst_pylon_create_set_value_actions( default: std::string msg = "Action in unsupported for node of type " + std::to_string(node->GetPrincipalInterfaceType()); - throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); + GST_LOG("%s", msg.c_str()); + continue; } actions_list.push_back(values); } @@ -395,7 +436,8 @@ std::vector gst_pylon_create_reset_value_actions( default: std::string msg = "Action in unsupported for node of type " + std::to_string(node->GetPrincipalInterfaceType()); - throw Pylon::GenericException(msg.c_str(), __FILE__, __LINE__); + GST_LOG("%s", msg.c_str()); + continue; } } @@ -443,6 +485,20 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, std::vector available_parent_inv = gst_pylon_get_available_features(parent_invalidators); + /* workaround for ace2/dart2 exposuretime and short exposuretime*/ + if (node->GetName() == "ExposureTime" && + available_parent_inv.end() != + std::find_if(available_parent_inv.begin(), available_parent_inv.end(), + [](const GenApi::INode *n) { + return n->GetName() == "BslExposureTimeMode"; + })) { + minimum_under_all_settings = 1.0; + maximum_under_all_settings = 1e+07; + return; + } + + available_parent_inv = gst_pylon_get_valid_categories(available_parent_inv); + /* Save current set of values */ std::vector reset_list = gst_pylon_create_reset_value_actions(available_parent_inv); From 7a90fef64c33ffb515ab908ab40013b3d18671d8 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Tue, 28 Feb 2023 10:03:14 +0100 Subject: [PATCH 105/126] Debug logging of all introspection fix --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 42 +++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 8d72554..f57a0fb 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -443,6 +444,29 @@ std::vector gst_pylon_create_reset_value_actions( return actions_list; } +using namespace std ::literals; +class TimeLogger { + public: + TimeLogger(const std::string &message) + : t0(std::chrono::system_clock::now()), message(message) { + GST_DEBUG("Start Checking: %s ", message.c_str()); + }; + + ~TimeLogger() { + auto t1 = std::chrono::system_clock::now(); + GST_DEBUG("TIMELOGGER %s %ld msec -> ", message.c_str(), (t1 - t0) / 1ms); + for (auto &info : info_list) { + GST_DEBUG("%s ", info.c_str()); + } + } + + void add_info(const std::string &info) { info_list.push_back(info); } + + private: + const std::chrono::time_point t0; + std::string message; + std::vector info_list; +}; template void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, @@ -450,9 +474,10 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, std::unordered_map invalidators; maximum_under_all_settings = 0; minimum_under_all_settings = 0; - g_return_if_fail(node); + auto tl = TimeLogger(node->GetName().c_str()); + /* Find the maximum value of a feature under the influence of other elements * of the nodemap */ GenApi::INode *pmax_node = gst_pylon_find_limit_node(node, "pMax"); @@ -499,6 +524,10 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, available_parent_inv = gst_pylon_get_valid_categories(available_parent_inv); + for (auto &node : available_parent_inv) { + tl.add_info(node->GetName().c_str()); + } + /* Save current set of values */ std::vector reset_list = gst_pylon_create_reset_value_actions(available_parent_inv); @@ -507,11 +536,19 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, std::vector> actions_list = gst_pylon_create_set_value_actions(available_parent_inv); + /* try to get support for optimized bulk feature settings */ + auto reg_streaming_start = Pylon::CCommandParameter( + node->GetNodeMap()->GetNode("DeviceRegistersStreamingStart")); + auto reg_streaming_end = Pylon::CCommandParameter( + node->GetNodeMap()->GetNode("DeviceRegistersStreamingEnd")); + /* Create list of all possible setting permutations and execute them all */ auto action_list_permutations = gst_pylon_cartesian_product(actions_list); std::vector min_values; std::vector max_values; for (const auto &actions : action_list_permutations) { + // reg_streaming_start.TryExecute(); + for (const auto &action : actions) { /* Some states might not be valid, so just skip them */ try { @@ -520,6 +557,9 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, continue; } } + + // reg_streaming_end.TryExecute(); + /* Capture min and max values after all setting are applied*/ min_values.push_back(gst_pylon_query_feature_limits(node, "min")); max_values.push_back(gst_pylon_query_feature_limits(node, "max")); From 6121eabc8223fc40966941c06f870167bbcf1097 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:07:26 +0100 Subject: [PATCH 106/126] optimize introspection by grouping into write transactions --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index f57a0fb..3e416c1 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -547,8 +547,7 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, std::vector min_values; std::vector max_values; for (const auto &actions : action_list_permutations) { - // reg_streaming_start.TryExecute(); - + reg_streaming_start.TryExecute(); for (const auto &action : actions) { /* Some states might not be valid, so just skip them */ try { @@ -558,7 +557,7 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, } } - // reg_streaming_end.TryExecute(); + reg_streaming_end.TryExecute(); /* Capture min and max values after all setting are applied*/ min_values.push_back(gst_pylon_query_feature_limits(node, "min")); From 2aa5db3040ae7e2a087973a03342e03a01f6bbda Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Tue, 28 Feb 2023 10:03:21 +0100 Subject: [PATCH 107/126] single feature introspection for debugging fix show node --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 21 +++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 3ac1568..a8ebeab 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -299,6 +299,13 @@ void GstPylonFeatureWalker::install_properties( const std::string& device_fullname, GstPylonCache& feature_cache) { g_return_if_fail(oclass); + /* handle filter for debugging */ + const char* single_feature = NULL; + if (const char* env_p = std::getenv("PYLONSRC_SINGLE_FEATURE")) { + GST_DEBUG("LIMIT to use only feature %s\n", env_p); + single_feature = env_p; + } + auto param_factory = GstPylonParamFactory(nodemap, device_fullname, feature_cache); @@ -326,11 +333,15 @@ void GstPylonFeatureWalker::install_properties( GenICam::gcstring attrib; try { - std::vector specs_list = - gst_pylon_camera_handle_node(node, param_factory); - - gst_pylon_camera_install_specs(specs_list, oclass, nprop); - + if (!single_feature || + (single_feature && std::string(node->GetName().c_str()) == + std::string(single_feature))) { + GST_DEBUG("Install node %s", node->GetName().c_str()); + std::vector specs_list = + gst_pylon_camera_handle_node(node, param_factory); + + gst_pylon_camera_install_specs(specs_list, oclass, nprop); + } } catch (const Pylon::GenericException& e) { GST_FIXME("Unable to install property \"%s\" on device \"%s\": %s", node->GetName().c_str(), device_fullname.c_str(), From 8bde503d3fd1cf5bffef55954af3108a265dfcde Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 10:40:20 +0100 Subject: [PATCH 108/126] clear possible left open transactions on device open --- ext/pylon/gstpylon.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index edbea8c..799c58c 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -289,7 +289,15 @@ GstPylon *gst_pylon_new(GstElement *gstpylonsrc, const gchar *device_user_name, } self->camera->Open(); - /* Set the camera to a valid state */ + /* Set the camera to a valid state + * close left open transactions on the device + */ + self->camera->DeviceFeaturePersistenceEnd.TryExecute(); + self->camera->DeviceRegistersStreamingEnd.TryExecute(); + + /* Set the camera to a valid state + * load the poweron user set + */ if (self->camera->UserSetSelector.IsWritable()) { std::string default_set = "Auto"; gst_pylon_apply_set(self, default_set); @@ -916,6 +924,21 @@ static gchar *gst_pylon_get_string_properties( Pylon::CBaslerUniversalInstantCamera camera(factory.CreateDevice(device), Pylon::Cleanup_Delete); camera.Open(); + + /* Set the camera to a valid state + * close left open transactions on the device + */ + camera.DeviceFeaturePersistenceEnd.TryExecute(); + camera.DeviceRegistersStreamingEnd.TryExecute(); + + /* Set the camera to a valid state + * load the factory default set + */ + if (camera.UserSetSelector.IsWritable()) { + camera.UserSetSelector.SetValue("Default"); + camera.UserSetLoad.Execute(); + } + get_device_string_properties(&camera, &camera_properties, DEFAULT_ALIGNMENT); camera.Close(); From f5e062ea1700b018b7f95db39c070408bae98659 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 17:39:50 +0100 Subject: [PATCH 109/126] python script to list all features that should be mapped to gstreamer --- tests/prototypes/featurewalker.py | 98 +++++++++++++++++++++++++++ tests/prototypes/list_all_features.py | 37 ++++++++++ 2 files changed, 135 insertions(+) create mode 100644 tests/prototypes/featurewalker.py create mode 100644 tests/prototypes/list_all_features.py diff --git a/tests/prototypes/featurewalker.py b/tests/prototypes/featurewalker.py new file mode 100644 index 0000000..3eade76 --- /dev/null +++ b/tests/prototypes/featurewalker.py @@ -0,0 +1,98 @@ +from queue import Queue +import pypylon.genicam as geni + +import itertools + + +class FeatureSelector(object): + def __init__(self, selector_node, value): + self.selector_node = selector_node + self.value = value + + def __repr__(self): + return f"SEL<{self.selector_node.Node.GetName()}/{self.value}>" + + +class FeatureNode(object): + """ + a feature node is the break down of each camera feature + under each specific selector + """ + + def __init__( + self, + node, + selectors: [ + [FeatureSelector], + ] = [], + ): + self.node = node + self.selectors = selectors + + def __repr__(self): + repr = f"FeatureNode {self.node.Node.GetName()} " + if self.selectors: + for sel in self.selectors: + repr += " " + str(sel) + else: + repr += "direct" + return repr + + +def get_node_selectors(node): + selectors = [] + for s in node.Node.GetSelectingFeatures(): + selector_entries = [] + if type(s) == geni.IInteger: + for idx in range(s.GetMin(), s.GetMax() + s.GetInc(), s.GetInc()): + selector_entries.append(FeatureSelector(s, idx)) + elif type(s) == geni.IEnumeration: + for enum_val in s.Symbolics: + if geni.IsImplemented(s.GetEntryByName(enum_val)): + selector_entries.append(FeatureSelector(s, enum_val)) + + selectors.append(selector_entries) + + return selectors + + +# feature walker +# walks down feature tree to get all implemented features +def get_feature_nodes(nodemap, with_selectors: bool, only_implemented: bool): + import queue + + worklist = queue.Queue() + worklist.put(nodemap.GetNode("Root")) + + node_list = [] + while not worklist.empty(): + current_node = worklist.get() + + if only_implemented and not geni.IsImplemented(current_node): + # print(f"skip not implemented node {current_node.Node.Name}") + continue + + if len(current_node.Node.GetSelectedFeatures()): + # print(f"skip selector {current_node.Node.Name}") + continue + + if type(current_node) == geni.ICategory: + # push children of category + children = current_node.Node.GetChildren() + for c in children: + worklist.put(c) + continue + + # loop over all selector options of current node + if with_selectors and len(current_node.Node.GetSelectingFeatures()): + node_selectors = get_node_selectors(current_node) + for selectors in itertools.product(*node_selectors): + node_list.append(FeatureNode(current_node, selectors)) + + # for features with only a single selector output the direct form too + if len(current_node.Node.GetSelectingFeatures()) == 1: + node_list.append(FeatureNode(current_node)) + else: + node_list.append(FeatureNode(current_node)) + + return node_list diff --git a/tests/prototypes/list_all_features.py b/tests/prototypes/list_all_features.py new file mode 100644 index 0000000..5cfd178 --- /dev/null +++ b/tests/prototypes/list_all_features.py @@ -0,0 +1,37 @@ +#! /usr/bin/env python3 + +import featurewalker + +import pypylon.pylon as py + +def create_gst_feature_name(fn: featurewalker.FeatureNode, prefix: str): + f_name = f"{prefix}::{fn.node.Node.GetName()}" + for sel in fn.selectors: + f_name += f"-{sel.value}" + return f_name + + +tlf = py.TlFactory.GetInstance() + + +cam = py.InstantCamera(tlf.CreateFirstDevice()) +cam.Open() + + +features = featurewalker.get_feature_nodes( + cam.GetNodeMap(), with_selectors=True, only_implemented=True +) +for f in features: + print(create_gst_feature_name(f, "cam")) + +features = featurewalker.get_feature_nodes( + cam.GetStreamGrabberNodeMap(), with_selectors=True, only_implemented=True +) +for f in features: + print(create_gst_feature_name(f, "stream")) + +features = featurewalker.get_feature_nodes( + cam.GetTLNodeMap(), with_selectors=True, only_implemented=True +) +for f in features: + print(create_gst_feature_name(f, "tl")) From 981b3fed0ca5eac825e83ad90ec79254d4ae8f07 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:00:11 +0100 Subject: [PATCH 110/126] refactor supported pfnc formats into central location --- ext/pylon/gstpylon.cpp | 20 +-------- gst-libs/gst/pylon/gstpylonformatmapping.h | 47 ++++++++++++++++++++++ 2 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 gst-libs/gst/pylon/gstpylonformatmapping.h diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index 799c58c..b530ec8 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -36,6 +36,7 @@ #include "gst/pylon/gstpyloncache.h" #include "gst/pylon/gstpylondebug.h" +#include "gst/pylon/gstpylonformatmapping.h" #include "gst/pylon/gstpylonincludes.h" #include "gst/pylon/gstpylonmetaprivate.h" #include "gst/pylon/gstpylonobject.h" @@ -52,12 +53,6 @@ constexpr int FAILED_OPEN_RETRY_COUNT = 30; constexpr int FAILED_OPEN_RETRY_WAIT_TIME_MS = 1000; -/* Pixel format definitions */ -typedef struct { - std::string pfnc_name; - std::string gst_name; -} PixelFormatMappingType; - /* Mapping of GstStructure with its corresponding formats */ typedef struct { const std::string st_name; @@ -128,19 +123,6 @@ struct _GstPylon { gint requested_device_index; }; -static const std::vector pixel_format_mapping_raw = { - {"Mono8", "GRAY8"}, {"RGB8Packed", "RGB"}, - {"BGR8Packed", "BGR"}, {"RGB8", "RGB"}, - {"BGR8", "BGR"}, {"YCbCr422_8", "YUY2"}, - {"YUV422_8_UYVY", "UYVY"}, {"YUV422_8", "YUY2"}, - {"YUV422Packed", "UYVY"}, {"YUV422_YUYV_Packed", "YUY2"}}; - -static const std::vector pixel_format_mapping_bayer = { - {"BayerBG8", "bggr"}, - {"BayerGR8", "grbg"}, - {"BayerRG8", "rggb"}, - {"BayerGB8", "gbrg"}}; - static const std::vector gst_structure_formats = { {"video/x-raw", pixel_format_mapping_raw}, {"video/x-bayer", pixel_format_mapping_bayer}}; diff --git a/gst-libs/gst/pylon/gstpylonformatmapping.h b/gst-libs/gst/pylon/gstpylonformatmapping.h new file mode 100644 index 0000000..2a873cc --- /dev/null +++ b/gst-libs/gst/pylon/gstpylonformatmapping.h @@ -0,0 +1,47 @@ +#ifndef _GST_PYLON_FORMAT_MAPPING_ +#define _GST_PYLON_FORMAT_MAPPING_ + +#include +#include + +bool isSupportedPylonFormat(const std::string &format); + +/* Pixel format definitions */ +typedef struct { + std::string pfnc_name; + std::string gst_name; +} PixelFormatMappingType; + +const std::vector pixel_format_mapping_raw = { + {"Mono8", "GRAY8"}, {"RGB8Packed", "RGB"}, + {"BGR8Packed", "BGR"}, {"RGB8", "RGB"}, + {"BGR8", "BGR"}, {"YCbCr422_8", "YUY2"}, + {"YUV422_8_UYVY", "UYVY"}, {"YUV422_8", "YUY2"}, + {"YUV422Packed", "UYVY"}, {"YUV422_YUYV_Packed", "YUY2"}}; + +const std::vector pixel_format_mapping_bayer = { + {"BayerBG8", "bggr"}, + {"BayerGR8", "grbg"}, + {"BayerRG8", "rggb"}, + {"BayerGB8", "gbrg"}}; + +bool isSupportedPylonFormat(const std::string &format) { + bool res = false; + for (const auto &fd : pixel_format_mapping_raw) { + if (fd.pfnc_name == format) { + res = true; + break; + } + } + if (!res) { + for (const auto &fd : pixel_format_mapping_bayer) { + if (fd.pfnc_name == format) { + res = true; + break; + } + } + } + return res; +} + +#endif From 79e68454d47b7f2d07eafd3267d28cbd67989aeb Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:04:26 +0100 Subject: [PATCH 111/126] fix cache handling during development --- gst-libs/gst/pylon/gstpyloncache.cpp | 16 ++++++++++------ gst-libs/gst/pylon/gstpyloncache.h | 7 ++++--- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 4 +--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/gst-libs/gst/pylon/gstpyloncache.cpp b/gst-libs/gst/pylon/gstpyloncache.cpp index 7db2cf9..37564ff 100644 --- a/gst-libs/gst/pylon/gstpyloncache.cpp +++ b/gst-libs/gst/pylon/gstpyloncache.cpp @@ -68,11 +68,16 @@ static std::string gst_pylon_cache_create_filepath( GstPylonCache::GstPylonCache(const std::string &name) : filepath(gst_pylon_cache_create_filepath(name)), feature_cache_dict(g_key_file_new()), - is_empty(TRUE) {} + is_modified(FALSE) { + /* load initial cache file */ + if (!LoadCacheFile()) { + GST_LOG("No feature cache file found"); + } +} GstPylonCache::~GstPylonCache() { g_key_file_free(this->feature_cache_dict); } -gboolean GstPylonCache::IsCacheValid() { +gboolean GstPylonCache::LoadCacheFile() { gboolean ret = TRUE; /* Check if file exists */ @@ -88,13 +93,10 @@ gboolean GstPylonCache::IsCacheValid() { if (!ret) { return FALSE; } - - this->is_empty = FALSE; - return TRUE; } -gboolean GstPylonCache::IsEmpty() { return this->is_empty; } +gboolean GstPylonCache::HasNewSettings() { return is_modified; } void GstPylonCache::CreateCacheFile() { GError *file_err = NULL; @@ -128,12 +130,14 @@ void GstPylonCache::SetIntegerAttribute(const char *feature, const char *attribute, const gint64 val) { g_key_file_set_int64(this->feature_cache_dict, feature, attribute, val); + is_modified = true; } void GstPylonCache::SetDoubleAttribute(const char *feature, const char *attribute, const gdouble val) { g_key_file_set_double(this->feature_cache_dict, feature, attribute, val); + is_modified = true; } bool GstPylonCache::GetIntegerAttribute(const char *feature, diff --git a/gst-libs/gst/pylon/gstpyloncache.h b/gst-libs/gst/pylon/gstpyloncache.h index 0fa7f0a..0b57859 100644 --- a/gst-libs/gst/pylon/gstpyloncache.h +++ b/gst-libs/gst/pylon/gstpyloncache.h @@ -41,8 +41,7 @@ class GST_PLUGIN_EXPORT GstPylonCache { public: GstPylonCache(const std::string &name); ~GstPylonCache(); - gboolean IsCacheValid(); - gboolean IsEmpty(); + gboolean HasNewSettings(); void SetIntProps(const gchar *feature_name, const gint64 min, const gint64 max, const GParamFlags flags); @@ -54,6 +53,8 @@ class GST_PLUGIN_EXPORT GstPylonCache { bool GetDoubleProps(const gchar *feature_name, gdouble &min, gdouble &max, GParamFlags &flags); + /* Load from file system */ + gboolean LoadCacheFile(); /* Persist cache to filesystem */ void CreateCacheFile(); @@ -70,7 +71,7 @@ class GST_PLUGIN_EXPORT GstPylonCache { std::string filepath; GKeyFile *feature_cache_dict; - gboolean is_empty; + gboolean is_modified; }; #endif diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index a8ebeab..f0dcf6e 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -309,8 +309,6 @@ void GstPylonFeatureWalker::install_properties( auto param_factory = GstPylonParamFactory(nodemap, device_fullname, feature_cache); - gboolean is_cache_valid = feature_cache.IsCacheValid(); - gint nprop = 1; GenApi::INode* root_node = nodemap.GetNode("Root"); auto worklist = std::queue(); @@ -361,7 +359,7 @@ void GstPylonFeatureWalker::install_properties( } } - if (!is_cache_valid) { + if (feature_cache.HasNewSettings()) { try { feature_cache.CreateCacheFile(); } catch (const Pylon::GenericException& e) { From 5454b69037e179e1c3fc2b254af8d8186eb43d9c Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:05:06 +0100 Subject: [PATCH 112/126] handle indexed feature nodes --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 3e416c1..2fc36d3 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -180,6 +180,12 @@ GenApi::INode *gst_pylon_find_limit_node(GenApi::INode *node, } else if (node->GetProperty("pValue", value, attribute)) { limit_node = gst_pylon_find_limit_node(node->GetNodeMap()->GetNode(value), limit); + } else if (node->GetProperty("pValueDefault", value, attribute)) { + /* FIXME: pValueDefault might not cover the limits of all selector entries + * properly + */ + limit_node = + gst_pylon_find_limit_node(node->GetNodeMap()->GetNode(value), limit); } return limit_node; } From 6a359aad3585db6dee7671193108ded9bc97c424 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:06:20 +0100 Subject: [PATCH 113/126] filter introspection pixelformats by supported formats --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 2fc36d3..c68b472 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -35,6 +35,7 @@ #endif #include "gstpylondebug.h" +#include "gstpylonformatmapping.h" #include "gstpylonintrospection.h" #include "gstpylonobject.h" #include "gstpylonparamspecs.h" @@ -380,13 +381,11 @@ std::vector> gst_pylon_create_set_value_actions( GenApi::StringList_t settable_values; param.GetSettableValues(settable_values); for (const auto &value : settable_values) { - /* Skip unsupported packed mono and bayer formats */ + /* Skip only check plugin supported formats */ if (node->GetName() == "PixelFormat" && - (Pylon::IsMonoPacked(static_cast( - param.GetEntryByName(value)->GetValue())) || - Pylon::IsBayerPacked(static_cast( - param.GetEntryByName(value)->GetValue())))) + !isSupportedPylonFormat(value.c_str())) { continue; + } values.push_back( new GstPylonTypeAction( param, value)); From 411abd1a9fe7c1eb3ec920703d9cee73709c564c Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:08:04 +0100 Subject: [PATCH 114/126] update filter tables for introspection --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index f0dcf6e..0ce8e80 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -67,29 +67,25 @@ static const std::unordered_set propfilter_set = { "AcquisitionFrameRateEnable", "AcquisitionFrameRate", "AcquisitionFrameRateAbs", - "ChunkData", "AcquisitionStart", "AcquisitionStop", "UserSetLoad", "UserSetSave", "TriggerSoftware", "DeviceReset", - "FileAccessControl", + "DeviceFeaturePersistenceStart", + "DeviceFeaturePersistenceEnd", "DeviceRegistersStreamingStart", "DeviceRegistersStreamingEnd", - "FileAccessControl" /* has to be implemented in access library */ - "EventControl", /* disable full event section until mapped to gst - events/msgs */ - "SequencerControl" /* sequencer control relies on cmd feature */ }; static const std::unordered_set categoryfilter_set = { "ChunkData", - "FileAccessControl" /* has to be implemented in access library */ - "EventControl", /* disable full event section until mapped to gst - events/msgs */ - "SequencerControl", /* sequencer control relies on cmd feature */ - "MultipleROI" /* workaround skip to avoid issues with ace2/dart2 + "FileAccessControl", /* has to be implemented in access library */ + "EventControl", /* disable full event section until mapped to gst + events/msgs */ + "SequencerControl", /* sequencer control relies on cmd feature */ + "MultipleROI", /* workaround skip to avoid issues with ace2/dart2 FIXME: this has to be fixed in feature walker */ }; From a93bdb9872aecd589b48c05ac88d71640bb8ea4a Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:08:30 +0100 Subject: [PATCH 115/126] properly filter sub categories --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 0ce8e80..589f6b2 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -318,7 +318,9 @@ void GstPylonFeatureWalker::install_properties( /* Only handle real features that are not in the filter set, are not * selectors and are available */ auto sel_node = dynamic_cast(node); - if (node->IsFeature() && (node->GetVisibility() != GenApi::Invisible) && + auto category_node = dynamic_cast(node); + if (!category_node && node->IsFeature() && + (node->GetVisibility() != GenApi::Invisible) && GenApi::IsImplemented(node) && !is_unsupported_feature(std::string(node->GetName())) && node->GetPrincipalInterfaceType() != GenApi::intfICategory && @@ -344,7 +346,6 @@ void GstPylonFeatureWalker::install_properties( } /* Walk down all categories */ - auto category_node = dynamic_cast(node); if (category_node && !is_unsupported_category(std::string(node->GetName()))) { GenApi::FeatureList_t features; From 783bfc073506a5a1dc0299d1a034b538ab23943a Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:11:05 +0100 Subject: [PATCH 116/126] reduce loglevel of known introspection isues --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 4 ++-- gst-libs/gst/pylon/gstpylonintrospection.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index 589f6b2..c50e9e0 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -261,7 +261,7 @@ std::vector gst_pylon_camera_handle_node( specs_list.push_back( param_factory.make_param(node, selector_node, selector_value)); } catch (const Pylon::GenericException& e) { - GST_FIXME("Unable to fully install property '%s-%s' : %s", + GST_DEBUG("Unable to fully install property '%s-%s' : %s", node->GetName().c_str(), enum_value.c_str(), e.GetDescription()); } @@ -339,7 +339,7 @@ void GstPylonFeatureWalker::install_properties( gst_pylon_camera_install_specs(specs_list, oclass, nprop); } } catch (const Pylon::GenericException& e) { - GST_FIXME("Unable to install property \"%s\" on device \"%s\": %s", + GST_DEBUG("Unable to install property \"%s\" on device \"%s\": %s", node->GetName().c_str(), device_fullname.c_str(), e.GetDescription()); } diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index c68b472..4837f76 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -393,9 +393,9 @@ std::vector> gst_pylon_create_set_value_actions( break; } default: - std::string msg = "Action in unsupported for node of type " + - std::to_string(node->GetPrincipalInterfaceType()); - GST_LOG("%s", msg.c_str()); + std::string msg = + "No test for node " + std::string(node->GetName().c_str()); + GST_DEBUG("%s", msg.c_str()); continue; } actions_list.push_back(values); @@ -440,9 +440,9 @@ std::vector gst_pylon_create_reset_value_actions( break; } default: - std::string msg = "Action in unsupported for node of type " + - std::to_string(node->GetPrincipalInterfaceType()); - GST_LOG("%s", msg.c_str()); + std::string msg = + "No test for node " + std::string(node->GetName().c_str()); + GST_DEBUG("%s", msg.c_str()); continue; } } From 6b5fbc5a1540a4e8e03a4c1f9000c6a59bf088ca Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:11:36 +0100 Subject: [PATCH 117/126] catch correct exception for failed introspection --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 4837f76..b91b0a1 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -557,7 +557,8 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, /* Some states might not be valid, so just skip them */ try { action->set_value(); - } catch (const Pylon::GenericException &) { + } catch (const GenICam::GenericException &e) { + GST_DEBUG("failed to set action"); continue; } } From 6d8f79cc12ce3f7f841f64bfc474ab20e8a0bece Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 13 Mar 2023 21:12:24 +0100 Subject: [PATCH 118/126] extend and document introspection filter rules --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index b91b0a1..7f6495f 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -515,16 +515,25 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, std::vector available_parent_inv = gst_pylon_get_available_features(parent_invalidators); - /* workaround for ace2/dart2 exposuretime and short exposuretime*/ + /* workarounds for ace2/dart2 exposuretime and short exposuretime + * and other nodes with large dependencies + * FIXME: refactor this into a filter class + */ if (node->GetName() == "ExposureTime" && available_parent_inv.end() != std::find_if(available_parent_inv.begin(), available_parent_inv.end(), [](const GenApi::INode *n) { return n->GetName() == "BslExposureTimeMode"; })) { + GST_DEBUG("Apply ExposureTime feature workaround"); minimum_under_all_settings = 1.0; maximum_under_all_settings = 1e+07; return; + } else if (node->GetName() == "AcquisitionBurstFrameCount") { + minimum_under_all_settings = 1; + maximum_under_all_settings = 1023; + GST_DEBUG("Apply AcquisitionBurstFrameCount feature workaround"); + return; } available_parent_inv = gst_pylon_get_valid_categories(available_parent_inv); From edaa6278e6a4ea8472b21a2209cacce8f163c6f6 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 16 Mar 2023 18:38:17 +0100 Subject: [PATCH 119/126] add license header --- gst-libs/gst/pylon/gstpylonformatmapping.h | 32 +++++++++++++++++++++ gst-libs/gst/pylon/gstpylonparamfactory.cpp | 32 +++++++++++++++++++++ gst-libs/gst/pylon/gstpylonparamfactory.h | 32 +++++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/gst-libs/gst/pylon/gstpylonformatmapping.h b/gst-libs/gst/pylon/gstpylonformatmapping.h index 2a873cc..9f11c77 100644 --- a/gst-libs/gst/pylon/gstpylonformatmapping.h +++ b/gst-libs/gst/pylon/gstpylonformatmapping.h @@ -1,3 +1,35 @@ +/* Copyright (C) 2023 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #ifndef _GST_PYLON_FORMAT_MAPPING_ #define _GST_PYLON_FORMAT_MAPPING_ diff --git a/gst-libs/gst/pylon/gstpylonparamfactory.cpp b/gst-libs/gst/pylon/gstpylonparamfactory.cpp index 19cbfe9..1fc2c0c 100644 --- a/gst-libs/gst/pylon/gstpylonparamfactory.cpp +++ b/gst-libs/gst/pylon/gstpylonparamfactory.cpp @@ -1,3 +1,35 @@ +/* Copyright (C) 2023 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "gstpylonparamfactory.h" #include "gstpylonintrospection.h" diff --git a/gst-libs/gst/pylon/gstpylonparamfactory.h b/gst-libs/gst/pylon/gstpylonparamfactory.h index 419b8be..e1749e6 100644 --- a/gst-libs/gst/pylon/gstpylonparamfactory.h +++ b/gst-libs/gst/pylon/gstpylonparamfactory.h @@ -1,3 +1,35 @@ +/* Copyright (C) 2023 Basler AG + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #ifndef GSTPYLONPARAMFACTORY_H #define GSTPYLONPARAMFACTORY_H From 196d76bc4ded71a83a043c373cfe016dad26656e Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 16 Mar 2023 18:42:30 +0100 Subject: [PATCH 120/126] use open lists in target tables --- gst-libs/gst/pylon/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/pylon/meson.build b/gst-libs/gst/pylon/meson.build index f67cb78..1b617e3 100644 --- a/gst-libs/gst/pylon/meson.build +++ b/gst-libs/gst/pylon/meson.build @@ -35,7 +35,7 @@ gstpylon_sources = [ 'gstpylonmeta.cpp', 'gstpylonobject.cpp', 'gstpylonparamspecs.cpp', - 'gstpylonparamfactory.cpp' + 'gstpylonparamfactory.cpp', ] gstpylon_headers = [ @@ -47,7 +47,7 @@ gstpylon_headers = [ 'gstpylonmeta.h', 'gstpylonmetaprivate.h', 'gstpylonobject.h', - 'gstpylonparamspecs.h' + 'gstpylonparamspecs.h', ] install_headers(gstpylon_headers, subdir : 'gstreamer-1.0/gst/pylon/') From c3d3abf85893c1135250f3d23ba8712041cdcde0 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 16 Mar 2023 19:52:45 +0100 Subject: [PATCH 121/126] disable command and register until support in introspection --- gst-libs/gst/pylon/gstpylonfeaturewalker.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp index c50e9e0..aa6fb50 100644 --- a/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp +++ b/gst-libs/gst/pylon/gstpylonfeaturewalker.cpp @@ -324,6 +324,8 @@ void GstPylonFeatureWalker::install_properties( GenApi::IsImplemented(node) && !is_unsupported_feature(std::string(node->GetName())) && node->GetPrincipalInterfaceType() != GenApi::intfICategory && + node->GetPrincipalInterfaceType() != GenApi::intfICommand && + node->GetPrincipalInterfaceType() != GenApi::intfIRegister && sel_node && !sel_node->IsSelector()) { GenICam::gcstring value; GenICam::gcstring attrib; From 704fb3f2105d2a32efe11ca6a8bd2438c3411c50 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Thu, 16 Mar 2023 19:53:17 +0100 Subject: [PATCH 122/126] add more heuristics for complex introspection targets --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 64 ++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 7f6495f..31e1591 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -529,6 +529,70 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, minimum_under_all_settings = 1.0; maximum_under_all_settings = 1e+07; return; + } else if (node->GetName() == "OffsetX") { + GST_DEBUG("Apply OffsetX feature workaround"); + Pylon::CIntegerParameter sensor_width( + node->GetNodeMap()->GetNode("SensorWidth")); + Pylon::CIntegerParameter width(node->GetNodeMap()->GetNode("Width")); + /* try to shortcut if sensor width is available */ + if (sensor_width.IsValid() && width.IsValid()) { + minimum_under_all_settings = 0; + maximum_under_all_settings = sensor_width.GetValue() - width.GetInc(); + return; + } + } else if (node->GetName() == "OffsetY") { + GST_DEBUG("Apply OffsetY feature workaround"); + Pylon::CIntegerParameter sensor_height( + node->GetNodeMap()->GetNode("SensorHeight")); + Pylon::CIntegerParameter height(node->GetNodeMap()->GetNode("Height")); + /* try to shortcut if sensor height is available */ + if (sensor_height.IsValid() && height.IsValid()) { + minimum_under_all_settings = 0; + maximum_under_all_settings = sensor_height.GetValue() - height.GetInc(); + return; + } + } else if (node->GetName() == "AutoFunctionROIOffsetX") { + GST_DEBUG("Apply AutoFunctionROIOffsetX feature workaround"); + Pylon::CIntegerParameter sensor_width( + node->GetNodeMap()->GetNode("SensorWidth")); + Pylon::CIntegerParameter width(node->GetNodeMap()->GetNode("Width")); + /* try to shortcut if sensor width is available */ + if (sensor_width.IsValid() && width.IsValid()) { + minimum_under_all_settings = 0; + maximum_under_all_settings = sensor_width.GetValue() - width.GetInc(); + return; + } + } else if (node->GetName() == "AutoFunctionROIOffsetY") { + GST_DEBUG("Apply AutoFunctionROIOffsetY feature workaround"); + Pylon::CIntegerParameter sensor_height( + node->GetNodeMap()->GetNode("SensorHeight")); + Pylon::CIntegerParameter height(node->GetNodeMap()->GetNode("Height")); + /* try to shortcut if sensor height is available */ + if (sensor_height.IsValid() && height.IsValid()) { + minimum_under_all_settings = 0; + maximum_under_all_settings = sensor_height.GetValue() - height.GetInc(); + return; + } + } else if (node->GetName() == "AutoFunctionROIWidth") { + GST_DEBUG("Apply AutoFunctionROIWidth feature workaround"); + Pylon::CIntegerParameter sensor_width( + node->GetNodeMap()->GetNode("SensorWidth")); + /* try to shortcut if sensor width is available */ + if (sensor_width.IsValid()) { + minimum_under_all_settings = 0; + maximum_under_all_settings = sensor_width.GetValue(); + return; + } + } else if (node->GetName() == "AutoFunctionROIHeight") { + GST_DEBUG("Apply AutoFunctionROIHeight feature workaround"); + Pylon::CIntegerParameter sensor_height( + node->GetNodeMap()->GetNode("SensorHeight")); + /* try to shortcut if sensor height is available */ + if (sensor_height.IsValid()) { + minimum_under_all_settings = 0; + maximum_under_all_settings = sensor_height.GetValue(); + return; + } } else if (node->GetName() == "AcquisitionBurstFrameCount") { minimum_under_all_settings = 1; maximum_under_all_settings = 1023; From ed6e9e3f49d67d44d1e3cd4c7341a6150030a664 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Fri, 17 Mar 2023 14:43:27 +0100 Subject: [PATCH 123/126] create diff of gst and camera features --- tests/prototypes/featurewalker.py | 52 ++++++++-- tests/prototypes/list_all_features.py | 37 ------- tests/prototypes/list_missing_features.py | 116 ++++++++++++++++++++++ 3 files changed, 159 insertions(+), 46 deletions(-) delete mode 100644 tests/prototypes/list_all_features.py create mode 100755 tests/prototypes/list_missing_features.py diff --git a/tests/prototypes/featurewalker.py b/tests/prototypes/featurewalker.py index 3eade76..69fc641 100644 --- a/tests/prototypes/featurewalker.py +++ b/tests/prototypes/featurewalker.py @@ -1,6 +1,37 @@ +# Copyright (C) 2023 Basler AG +# +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# 3. Neither the name of the copyright holder nor the names of +# its contributors may be used to endorse or promote products +# derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# from queue import Queue +from typing import List import pypylon.genicam as geni - import itertools @@ -22,11 +53,11 @@ class FeatureNode(object): def __init__( self, node, - selectors: [ - [FeatureSelector], - ] = [], + selectors: List[List[FeatureSelector,]] = None, ): self.node = node + if selectors is None: + selectors = [] self.selectors = selectors def __repr__(self): @@ -83,14 +114,17 @@ def get_feature_nodes(nodemap, with_selectors: bool, only_implemented: bool): worklist.put(c) continue + if type(current_node) in (geni.ICommand, geni.IRegister): + continue + # loop over all selector options of current node if with_selectors and len(current_node.Node.GetSelectingFeatures()): node_selectors = get_node_selectors(current_node) - for selectors in itertools.product(*node_selectors): - node_list.append(FeatureNode(current_node, selectors)) - - # for features with only a single selector output the direct form too - if len(current_node.Node.GetSelectingFeatures()) == 1: + if len(list(itertools.product(*node_selectors))) > 1: + for selectors in itertools.product(*node_selectors): + node_list.append(FeatureNode(current_node, selectors)) + else: + # for features with only a single selector output the direct form too node_list.append(FeatureNode(current_node)) else: node_list.append(FeatureNode(current_node)) diff --git a/tests/prototypes/list_all_features.py b/tests/prototypes/list_all_features.py deleted file mode 100644 index 5cfd178..0000000 --- a/tests/prototypes/list_all_features.py +++ /dev/null @@ -1,37 +0,0 @@ -#! /usr/bin/env python3 - -import featurewalker - -import pypylon.pylon as py - -def create_gst_feature_name(fn: featurewalker.FeatureNode, prefix: str): - f_name = f"{prefix}::{fn.node.Node.GetName()}" - for sel in fn.selectors: - f_name += f"-{sel.value}" - return f_name - - -tlf = py.TlFactory.GetInstance() - - -cam = py.InstantCamera(tlf.CreateFirstDevice()) -cam.Open() - - -features = featurewalker.get_feature_nodes( - cam.GetNodeMap(), with_selectors=True, only_implemented=True -) -for f in features: - print(create_gst_feature_name(f, "cam")) - -features = featurewalker.get_feature_nodes( - cam.GetStreamGrabberNodeMap(), with_selectors=True, only_implemented=True -) -for f in features: - print(create_gst_feature_name(f, "stream")) - -features = featurewalker.get_feature_nodes( - cam.GetTLNodeMap(), with_selectors=True, only_implemented=True -) -for f in features: - print(create_gst_feature_name(f, "tl")) diff --git a/tests/prototypes/list_missing_features.py b/tests/prototypes/list_missing_features.py new file mode 100755 index 0000000..97171e3 --- /dev/null +++ b/tests/prototypes/list_missing_features.py @@ -0,0 +1,116 @@ +#! /usr/bin/env python3 +# Copyright (C) 2023 Basler AG +# +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# 3. Neither the name of the copyright holder nor the names of +# its contributors may be used to endorse or promote products +# derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +import featurewalker +import pypylon.pylon as py +import gi +import os + +gi.require_version("Gst", "1.0") +from gi.repository import Gst + +Gst.init() + + +def create_gst_feature_name(fn: featurewalker.FeatureNode, prefix: str): + f_name = f"{prefix}::{fn.node.Node.GetName()}" + for sel in fn.selectors: + f_name += f"-{sel.value}" + return f_name + +def patch_to_gst_name_convention(name: str): + return name.replace("_", "-") + +def get_pylon_features(device_index:int = 0): + tlf = py.TlFactory.GetInstance() + devs = tlf.EnumerateDevices() + # capture all_features + cam = py.InstantCamera(tlf.CreateDevice(devs[device_index])) + cam.Open() + + features = featurewalker.get_feature_nodes( + cam.GetNodeMap(), with_selectors=True, only_implemented=True + ) + cam_features = [] + for f in features: + cam_features.append(create_gst_feature_name(f, "cam")) + + + features = featurewalker.get_feature_nodes( + cam.GetStreamGrabberNodeMap(), with_selectors=True, only_implemented=True + ) + + stream_features = [] + for f in features: + stream_features.append(create_gst_feature_name(f, "stream")) + + features = featurewalker.get_feature_nodes( + cam.GetTLNodeMap(), with_selectors=True, only_implemented=True + ) + tl_features = [] + for f in features: + tl_features.append(create_gst_feature_name(f, "tl")) + + cam.Close() + + return cam_features, stream_features, tl_features + + +def get_gst_features(device_index:int = 0): + pipe = Gst.parse_launch(f"pylonsrc name=src device-index={device_index} ! fakesink") + pylon = pipe.get_by_name("src") + cam = pylon.get_child_by_name("cam") + stream = pylon.get_child_by_name("stream") + + + gst_cam_features = [] + for f in cam.props: + gst_cam_features.append(f"cam::{f.name}") + + + gst_stream_features = [] + for f in stream.props: + gst_stream_features.append(f"stream::{f.name}") + + return gst_cam_features, gst_stream_features, [] + + +print("MISSING FEATURES") +pylon_features = get_pylon_features(0) +gst_features = get_gst_features(0) + +for p_feat, g_feat in zip(pylon_features, gst_features): + for f in [x for x in p_feat if patch_to_gst_name_convention(x) not in set(g_feat)]: + print(f) + From 20ee61e82c9ee50bec07992b5bc00ba6c87a624d Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Mon, 20 Mar 2023 15:57:28 +0100 Subject: [PATCH 124/126] add info logging of feature accesses proper connection to the correct pylonsrc obj missing for now. requires further restructuring --- ext/pylon/gstpylon.cpp | 5 ++++- gst-libs/gst/pylon/gstpylonobject.cpp | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ext/pylon/gstpylon.cpp b/ext/pylon/gstpylon.cpp index b530ec8..418b939 100644 --- a/ext/pylon/gstpylon.cpp +++ b/ext/pylon/gstpylon.cpp @@ -793,9 +793,11 @@ gboolean gst_pylon_set_configuration(GstPylon *self, const GstCaps *conf, Pylon::CIntegerParameter width(nodemap, "Width"); width.SetValue(gst_width, Pylon::IntegerValueCorrection_None); + GST_INFO("Set Feature Width: %d", gst_width); Pylon::CIntegerParameter height(nodemap, "Height"); height.SetValue(gst_height, Pylon::IntegerValueCorrection_None); + GST_INFO("Set Feature Height: %d", gst_height); Pylon::CBooleanParameter framerate_enable(nodemap, "AcquisitionFrameRateEnable"); @@ -804,13 +806,14 @@ gboolean gst_pylon_set_configuration(GstPylon *self, const GstCaps *conf, framerate_enable.TrySetValue(true); gdouble div = 1.0 * gst_numerator / gst_denominator; - if (self->camera->GetSfncVersion() >= Pylon::Sfnc_2_0_0) { Pylon::CFloatParameter framerate(nodemap, "AcquisitionFrameRate"); framerate.TrySetValue(div, Pylon::FloatValueCorrection_None); + GST_INFO("Set Feature AcquisitionFrameRate: %f", div); } else { Pylon::CFloatParameter framerate(nodemap, "AcquisitionFrameRateAbs"); framerate.TrySetValue(div, Pylon::FloatValueCorrection_None); + GST_INFO("Set Feature AcquisitionFrameRateAbs: %f", div); } } catch (const Pylon::GenericException &e) { diff --git a/gst-libs/gst/pylon/gstpylonobject.cpp b/gst-libs/gst/pylon/gstpylonobject.cpp index 0de16aa..ce9574c 100644 --- a/gst-libs/gst/pylon/gstpylonobject.cpp +++ b/gst-libs/gst/pylon/gstpylonobject.cpp @@ -206,6 +206,7 @@ static void gst_pylon_object_set_pylon_feature(GstPylonObjectPrivate* priv, const gchar* name) { P param(*priv->nodemap, name); param.SetValue(get_value(value)); + GST_INFO("Set Feature %s: %s", name, param.ToString().c_str()); } template <> @@ -223,6 +224,8 @@ void gst_pylon_object_set_pylon_feature( Pylon::EIntegerValueCorrection::IntegerValueCorrection_Nearest); } else param.SetValue(get_value(value)); + + GST_INFO("Set Feature %s: %s", name, param.ToString().c_str()); } template <> @@ -240,6 +243,7 @@ void gst_pylon_object_set_pylon_feature( Pylon::EFloatValueCorrection::FloatValueCorrection_ClipToRange); } else param.SetValue(get_value(value)); + GST_INFO("Set Feature %s: %s", name, param.ToString().c_str()); } template <> @@ -248,6 +252,7 @@ void gst_pylon_object_set_pylon_feature( const gchar* name) { Pylon::CEnumParameter param(*priv->nodemap, name); param.SetIntValue(get_value(value)); + GST_INFO("Set Feature %s: %s", name, param.ToString().c_str()); } /* Get gst property from pylon feature */ @@ -257,6 +262,7 @@ static void gst_pylon_object_get_pylon_feature(GenApi::INodeMap& nodemap, const gchar* name) { P param(nodemap, name); set_value(value, param.GetValue()); + GST_DEBUG("Get Feature %s: %s", name, param.ToString().c_str()); } template <> @@ -265,6 +271,7 @@ void gst_pylon_object_get_pylon_feature( const gchar* name) { Pylon::CEnumParameter param(nodemap, name); set_value(value, param.GetIntValue()); + GST_DEBUG("Get Feature %s: %s", name, param.ToString().c_str()); } template <> @@ -273,6 +280,7 @@ void gst_pylon_object_get_pylon_feature( const gchar* name) { Pylon::CStringParameter param(nodemap, name); set_value(value, param.GetValue().c_str()); + GST_DEBUG("Get Feature %s: %s", name, param.ToString().c_str()); } void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, @@ -283,9 +291,15 @@ void gst_pylon_object_set_pylon_selector(GenApi::INodeMap& nodemap, switch (selector_type) { case GenApi::intfIEnumeration: Pylon::CEnumParameter(nodemap, selector_name).SetIntValue(selector_value); + GST_INFO( + "Set Selector-Feature %s: %s", selector_name, + Pylon::CEnumParameter(nodemap, selector_name).ToString().c_str()); break; case GenApi::intfIInteger: Pylon::CIntegerParameter(nodemap, selector_name).SetValue(selector_value); + GST_INFO( + "Set Selector-Feature %s: %s", selector_name, + Pylon::CIntegerParameter(nodemap, selector_name).ToString().c_str()); break; default: std::string error_msg = "Selector \"" + std::string(selector_name) + @@ -300,7 +314,9 @@ template static T gst_pylon_object_get_pylon_property(GenApi::INodeMap& nodemap, const gchar* name) { P param(nodemap, name); - return param.GetValue(); + T val = param.GetValue(); + GST_DEBUG("Get Feature %s: %s", name, param.ToString().c_str()); + return val; } template From 181f8eca83032b71dac9789c1a743ecadf3eed51 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Fri, 24 Mar 2023 10:18:06 +0100 Subject: [PATCH 125/126] add BslColorAdjustmentHue/Saturation to workaround list --- gst-libs/gst/pylon/gstpylonintrospection.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/pylon/gstpylonintrospection.cpp b/gst-libs/gst/pylon/gstpylonintrospection.cpp index 31e1591..098959c 100644 --- a/gst-libs/gst/pylon/gstpylonintrospection.cpp +++ b/gst-libs/gst/pylon/gstpylonintrospection.cpp @@ -515,8 +515,8 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, std::vector available_parent_inv = gst_pylon_get_available_features(parent_invalidators); - /* workarounds for ace2/dart2 exposuretime and short exposuretime - * and other nodes with large dependencies + /* workarounds for ace2/dart2/boost features high + * dependency count * FIXME: refactor this into a filter class */ if (node->GetName() == "ExposureTime" && @@ -598,6 +598,16 @@ void gst_pylon_find_limits(GenApi::INode *node, T &minimum_under_all_settings, maximum_under_all_settings = 1023; GST_DEBUG("Apply AcquisitionBurstFrameCount feature workaround"); return; + } else if (node->GetName() == "BslColorAdjustmentHue") { + minimum_under_all_settings = -1; + maximum_under_all_settings = 1; + GST_DEBUG("Apply BslColorAdjustmentHue feature workaround"); + return; + } else if (node->GetName() == "BslColorAdjustmentSaturation") { + minimum_under_all_settings = 0; + maximum_under_all_settings = 2; + GST_DEBUG("Apply BslColorAdjustmentSaturation feature workaround"); + return; } available_parent_inv = gst_pylon_get_valid_categories(available_parent_inv); From b20861640eae85e13c497d6372a568b5c0bc3595 Mon Sep 17 00:00:00 2001 From: Thies Moeller Date: Fri, 24 Mar 2023 13:02:32 +0100 Subject: [PATCH 126/126] update to version 0.6.0 --- CHANGELOG.md | 33 ++++++++++++++++++++++++++++++++ README.md | 53 +++++++++++++++++++++++++++++++++++----------------- meson.build | 2 +- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dda461..2f7f631 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,39 @@ # Changelog All notable changes to this project will be documented in this file. +## [0.6.0] - 2023-03-24 + +### Added +- Caching infrastructure to reduce runtime of property introspection process + * ranges and access behaviour of features are saved during introspection + * cache data is saved in [glib_user_cache_dir](https://docs.gtk.org/glib/func.get_user_cache_dir.html)/gstpylon/ +- Python bindings to access pylon image metadata from python-gstreamer scripts + * can be enabled during configuration using meson option `-Dpython-bindings=enabled` +- gstreamer property added to automatically round properties to the nearest valid camera values + * `enable-correction=` activates automatic correction of values. +- git version is reflected in the plugin version string + + +### Changed +- Changed codebase from mixed c/c++ to c++ + * symbol default visibility 'hidden' on all platforms +- Exclude the following feature groups from introspection until properly supported + * SequencerControl + * FileAccessControl + * MultiROI + * Events + * Commmands + +### Fixed +- Disable the `DeviceLinkSelector` on all devices + * fixes an issue with specific dart1 models +- Concurrent start of pylonsrc from multiple processes + * opening a device is now retried for 30s in case of multiprocess collision + * fixes #25 +- ace2/dart2/boost feature dependency introspection fixed + * fixes #32 + + ## [0.5.1] - 2022-12-28 ### Fixed diff --git a/README.md b/README.md index f38be95..5bc6d1d 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ You are welcome to post any questions or issues on [GitHub](https://github.com/b The next chapters describe how to [use](#getting-started) and [build](#Building) the *pylonsrc* plugin. -# Getting started +# Getting started To display the video stream of a single Basler camera is as simple as: @@ -23,7 +23,7 @@ To display the video stream of a single Basler camera is as simple as: gst-launch-1.0 pylonsrc ! videoconvert ! autovideosink ``` -The dynamic registration of camera features in the plugin can take ~5s on some camera models. An optimization is scheduled for the next release. +> The camera features are registered dynamically to gstreamer. This registration is executed once the first time a camera model is used in gstreamer and can take up to ~10s. The registration information is cached in the filesystem to speed up subsequent uses of the camera. The following sections describe how to select and configure the camera. @@ -73,7 +73,7 @@ gst-launch-1.0 pylonsrc device-user-name="top-left" ! videoconvert ! autovideosi The configuration of the camera is defined by * gstreamer pipeline capabilities * the active UserSet or supplied PFS file -* feature properties of the plugin +* feature properties of the plugin ### Capabilities @@ -119,7 +119,7 @@ The mapping of the camera pixel format names to the gstreamer format names is: | BayerRG8 | rggb | | BayerGB8 | gbrg | -### Fixation +### Fixation If two pipeline elements don't specify which capabilities to choose, a fixation step gets applied. @@ -147,9 +147,25 @@ As an example, the following pipeline will skip corrupted or partial buffers: gst-launch-1.0 pylonsrc capture-error=skip ! videoconvert ! autovideosink ``` +### Automatic rounding/correction of property values + +The gstreamer model for properties only represents a static range of a property. The pylon feature model has dynamic ranges and increments. These values can change depending on the current values of other properties. + +In the registration phase the absolute minimum and maximum values of a feature are registered as gstreamer property. + +Per default pylon and the camera still require to set the exact/correct values. + +By using the gstreamer boolean property `enable-correction` the plugin will automatically round/correct to the nearest valid value. + +The options for this property are: + +* `enable-correction=false` the exact value has to be set. If the value is not valid ( out of range or wrong increment) the property setting is ignored and an error log message generated. This is the default behaviour +* `enable-correction=true` the plugin will round or adjust to the nearest valid value. + + ### UserSet handling -`pylonsrc` always loads a UserSet of the camera before applying any further properties. +`pylonsrc` always loads a UserSet of the camera before applying any further properties. This feature is controlled by the enumeration property `user-set`. @@ -269,11 +285,12 @@ The plugin meta data is defined in [gstpylonmeta.h](gst-libs/gst/pylon/gstpylonm A programming sample using these defintions to decode the data is in [show_meta](tests/examples/pylon/show_meta.c) -**Access to GstMetaPylon from python ** + +**Access to GstMetaPylon from python** To access the metadata a Python support library is available. The `pygstpylon` provides the required access helper to decode the metadata from plugins and probes. -Note that Python bindings are disabled by default, refer to the build section for instructions on how to enable them. +> Note that Python bindings are disabled by default, refer to the build section for instructions on how to enable them. One usage example to access camera chunk and metadata from a python plugin is in [snapshot_gpio.py](tests/examples/python/snapshot_gpio.py) @@ -281,13 +298,13 @@ This sample plugin will check the LineStatusAll chunk to detect an edge on one o The below usage example will show live video and store a snapshot if the gpio edge is detected on Line4 of the camera. -```bash +```bash # the plugin path for python code has to point to a directory with a 'python' subdirectory export GST_PLUGIN_PATH=/tests/examples gst-launch-1.0 pylonsrc cam::ChunkModeActive=True cam::ChunkEnable-LineStatusAll=True \ ! tee name=t \ t. ! queue ! pylongpiosnapshot_py trigger-source=4 rising-edge=true ! videoconvert ! pngenc ! multifilesink location=image%05d.png async=false\ - t. ! queue ! videoconvert ! autovideosink + t. ! queue ! videoconvert ! autovideosink ``` @@ -431,8 +448,10 @@ meson setup builddir --prefix /usr/ --werror --buildtype=debug -Dgobject-cast-ch TBD #### YOCTO recipe -TBD -A yocto recipe will be provided in [meta-basler-tools](https://github.com/basler/meta-basler-tools) layer on github. +A reference yocto recipe for honister is available in the [meta-basler-tools](https://github.com/basler/meta-basler-tools/tree/honister/recipes-multimedia/gstreamer) +on github. This recipe still needs a backport patch due to the version of meson tool in honister. + +Builds on yocto kirkstone and later work without the patch. ## Windows Install the dependencies: @@ -484,11 +503,11 @@ This will generate a Visual Studio solution in the build directory To test without install: ``` -set GST_PLUGIN_PATH=build/ext/pylon +set GST_PLUGIN_PATH=build/ext/pylon -%GSTREAMER_1_0_ROOT_MSVC_X86_64%\bin\gst-launch-1.0.exe +%GSTREAMER_1_0_ROOT_MSVC_X86_64%\bin\gst-launch-1.0.exe -pylonsrc ! videoconvert ! autovideosink +pylonsrc ! videoconvert ! autovideosink ``` To install into main gstreamer directory @@ -497,8 +516,8 @@ To install into main gstreamer directory ninja -C build install ``` ->Workaround for running from normal cmdshell in a non US locale: ->As visual studio currently ships a broken vswhere.exe tool, that meson relies on. +>Workaround for running from normal cmdshell in a non US locale: +>As visual studio currently ships a broken vswhere.exe tool, that meson relies on. Install a current vswhere.exe from [Releases · microsoft/vswhere · GitHub](https://github.com/microsoft/vswhere/releases) that fixes ( [Initialize console after parsing arguments by heaths · Pull Request #263 · microsoft/vswhere · GitHub](https://github.com/microsoft/vswhere/pull/263) ) @@ -518,7 +537,7 @@ This target will be integrated after a Basler pylon 7.x release for macOS * Due to an old issue in the pipeline parser, typos and unsupported feature names will be silently ignored on old GStreamer versions. Typos on top-level properties will be ignored on versions prior to 1.18. Typos on child::properties will be ignored on versions prior to 1.21. * Bayer formats need to be 4 byte aligned to be properly processed by GStreamer. If no size is specified (or a range is provided) a word aligned width will be automatically selected. If the width is hardcoded and it is not word aligned, the pipeline will fail displaying an error. - + * Under very specific conditions we've found that a set_state() followed immediately by a get_state() will report a failure. This has been found to be a bug in the GStreamer core, where a state conditional is not protected against spurious wakeups. An upstream fix has been proposed [in this Merge Request](https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4086). This issue has been reproduced in certain installations of NVIDIA Jetson boards. * As a workaround while the fix is absorbed, you may configure `async=false` in all the sink elements in your pipeline, so that the state condition variable is not needed. Only use this is your pipeline does not require synchronization. diff --git a/meson.build b/meson.build index 5c420e1..333ae8c 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('gst-plugin-pylon', 'c', 'cpp', - version : '0.5.1', + version : '0.6.0', meson_version : '>= 0.61', default_options : [ 'warning_level=1', 'buildtype=debugoptimized' ])