This guide teaches you how to:
Property Variables are members of your Filter class and are linked to a Property. These members will always reflect the value of the assigned Property.
Use the adtf::base::property_variable
template to create Property Variables of the required type.
#pragma once
// Include all necessary headers from the ADTF SDK
#include <adtffiltersdk/adtf_filtersdk.h>
// For simplicity use the necessary namespaces
using namespace adtf::util;
using namespace adtf::ucom;
using namespace adtf::base;
using namespace adtf::streaming;
using namespace adtf::filter;
// To implement a Filter we subclass adtf::filter::cFilter
class cPropertiesFilter: public cFilter
{
public:
// This macros provides some meta information about our Filter Implementation
// This will be exposed by the plugin class factory.
ADTF_CLASS_ID_NAME(cPropertiesFilter,
"properties_filter.filter.adtf_guides.cid",
"Properties Filter");
public:
// In the constructor, we setup all aspects of our Filter.
cPropertiesFilter();
tResult Init(tInitStage eStage) override;
private:
// Here are all the Property Variables for our Filter
property_variable<double> m_fFloatProperty = 3.1415;
property_variable<uint32_t> m_nGroupedProperty1 = 1;
property_variable<uint32_t> m_nGroupedProperty2 = 2;
property_variable<cString> m_strListProperty1 = {"device1"};
property_variable<cFilename> m_oConfigFilename;
enum tMyEnum: int32_t
{
eFirst = 0,
eSecond = 1,
eThird = 2,
};
property_variable<tMyEnum> m_eEnumProperty = eFirst;
property_variable<uint32_t> m_nHiddenProperty = 3;
};
#include "properties_filter.h"
// The code behind the macro creates a plugin and the main entries to the plugin DLL or shared object.
// The cPropertyFilter will be available through the plugins class factory.
ADTF_PLUGIN("Properties Filter Plugin",
cPropertiesFilter);
cPropertiesFilter::cPropertiesFilter()
{
// We register all our "visible" Property Variables in the Constructor.
// you can set descriptions for properties, these will be shown in a tooltip when the use hovers
// over the name of the Property in the ADTF Configuration editor.
m_fFloatProperty.SetDescription("A property that holds floating-point values");
// This is a hint for the ADTF Configuration Editor that defines a range of valid Property values.
m_fFloatProperty.SetValidRange(0.0, 10.0);
// Register the property variable.
RegisterPropertyVariable("float_property", m_fFloatProperty);
// To group or organise properties you can create a tree structure.
m_nGroupedProperty1.SetDescription("Property to show grouping.");
RegisterPropertyVariable("group/property1", m_nGroupedProperty1);
m_nGroupedProperty2.SetDescription("Property to show another grouping.");
RegisterPropertyVariable("group/property2", m_nGroupedProperty2);
// This gives the user a list of Property value choices.
m_strListProperty1.SetValueList({{"device1", "Nice Device"},
{"device2", "Super Nice Device"},
{"device3", "Awesome Device"}});
m_strListProperty1.SetDescription("Property to show lists.");
RegisterPropertyVariable("string_property", m_strListProperty1);
// Set optional filename extension filters for the ADTF Configuration Editor FileDialogs of cFilename
// and cFilenameList properties.
m_oConfigFilename.SetFilenameExtensionFilter("Config files (*.xml *.json)");
m_oConfigFilename.SetDescription("Property to show file extension filter.");
RegisterPropertyVariable("config_filename_property", m_oConfigFilename);
// Enums are mapped to Properties of the underlying type.
// Here we offer the user a list to choose from.
m_eEnumProperty.SetValueList({{eFirst, "First"},
{eSecond, "Second"},
{eThird, "Third"}});
m_eEnumProperty.SetDescription("Property to show enumeration.");
RegisterPropertyVariable("enum_property", m_eEnumProperty);
// set basic information about the component itself and purpose
SetDescription("This filter shows the different options using properties.");
}
void function_that_takes_an_integer(uint32_t)
{
}
tResult cPropertiesFilter::Init(tInitStage eStage)
{
RETURN_IF_FAILED(cFilter::Init(eStage));
// Note that the Property values are updated from the ADTF Properties File of the current Session
// right before Init is called with eStage == StageNormal. So you can access these settings from
// this point of your Filter life-cycle onwards.
if (eStage == StageNormal)
{
// If you register a property variable in StageNormal, the associated Property will not be made
// available via the plugin description and thus not shown in the ADTF Configuration Editor.
// To set it, manually add it to the .adtfproperties file.
RegisterPropertyVariable("hidden_property", m_nHiddenProperty);
// to access the values of a Property Variable you can either just pass it to methods that
// take parameters of the type of the property variable
function_that_takes_an_integer(m_nGroupedProperty1);
// or use it in calculations
auto fProduct = m_fFloatProperty * m_nGroupedProperty2;
LOG_INFO("product = %f", fProduct);
// or use the pointer operator to access member methods
LOG_INFO("string_property value is %zu characters long.",
m_strListProperty1->GetLength());
// or access specific functions like
LOG_INFO("Type of chosen config_filename_property is '%s'.",
m_oConfigFilename->GetExtension().GetPtr());
// or dereference them manually
LOG_INFO("My properties are set to:\n"
" float_property = %f\n"
" group/property1 = %u\n"
" group/property2 = %u\n"
" string_property = %s\n"
" enum_property = %d\n"
" hidden_property = %u\n"
" config_filename_property = %s\n",
*m_fFloatProperty,
*m_nGroupedProperty1,
*m_nGroupedProperty2,
m_strListProperty1->GetPtr(),
*m_eEnumProperty,
*m_nHiddenProperty,
m_oConfigFilename->GetPtr());
}
RETURN_NOERROR;
}
After you have built this Filter you can add it by drag and drop from the Component View to a Filter Graph within the ADTF Configuration Editor. Select/click on the Filter let's you edit the Properties in the Property Editor:
IPropertyObserver
interface or use property_variable<T>::SetPropertyChangedCallback(const std::function & fnCallback)
.
IPropertyObserver
:
#pragma once
// Include all necessary headers from the ADTF SDK
#include <adtffiltersdk/adtf_filtersdk.h>
// For simplicity use the necessary namespaces
using namespace adtf::util;
using namespace adtf::ucom;
using namespace adtf::base;
using namespace adtf::streaming;
using namespace adtf::filter;
// To implement a Filter we subclass adtf::filter::cFilter.
// We implement IPropertyObserver as well in order to be notified about changes to our Properties.
class cPropertiesObserverFilter: public cFilter, public IPropertyObserver
{
public:
// This macros provides some meta information about our Filter Implementation
// This will be exposed by the plugin class factory.
ADTF_CLASS_ID_NAME(cPropertiesObserverFilter,
"properties_observer_filter.filter.adtf_guides.cid",
"Properties Observer Filter");
public:
// In the constructor, we setup all aspects of our Filter.
cPropertiesObserverFilter();
// This is our callback implementation.
void Notify(const IProperty& oProperty) override;
};
#include "properties_observer_filter.h"
// The code behind the macro creates a plugin and the main entries to the plugin DLL or shared object.
// The cPropertyFilter will be available through the plugins class factory.
ADTF_PLUGIN("Properties Filter Plugin",
cPropertiesObserverFilter);
cPropertiesObserverFilter::cPropertiesObserverFilter()
{
// first we get a pointer to our properties.
object_ptr<IProperties> pProperties;
THROW_IF_FAILED(GetProperties(pProperties));
// we set some properties directly without the use of any Property Variables.
// mind that observing changes to Property Variables work just the same.
adtf::util::cString strProp1 = "observed_property_1";
adtf::util::cString strProp2 = "observed_property_2";
adtf::util::cString strSubPropertySeparator = "/";
set_property<tInt>(*pProperties, strProp1, 10);
set_property_by_path<adtf::util::cString>(*pProperties, strProp1 + strSubPropertySeparator + adtf::base::giant::detail::tReservedProperties::strDescription, "Property to observe");
set_property<tInt>(*pProperties, strProp2, 20);
set_property_by_path<adtf::util::cString>(*pProperties, strProp2 + strSubPropertySeparator + adtf::base::giant::detail::tReservedProperties::strDescription, "Another property to observe");
// now register ourselfs as an observer.
THROW_IF_FAILED(pProperties->RegisterPropertyObserver("observed_property_1", *this));
THROW_IF_FAILED(pProperties->RegisterPropertyObserver("observed_property_2", *this));
// set basic information about the component itself and purpose
SetDescription("This filter shows how to observe property changes.");
}
// This method will be called for each change to a Property.
void cPropertiesObserverFilter::Notify(const IProperty& oProperty)
{
// get the name of the property
cString strPropertyName;
oProperty.GetName(adtf_string_intf(strPropertyName));
// we know our properties are of type int, so we use a helper object to access the value:
property<int> oChangedProperty;
oChangedProperty.Set(oProperty);
LOG_INFO("Property '%s' has been changed to '%d'", strPropertyName.GetPtr(), oChangedProperty.GetValueT());
}
property_variable<T>::SetPropertyChangedCallback(...)
since ADTF 3.7.0:
#pragma once
// Include all necessary headers from the ADTF SDK
#include <adtffiltersdk/adtf_filtersdk.h>
// For simplicity use the necessary namespaces
using namespace adtf::util;
using namespace adtf::ucom;
using namespace adtf::base;
using namespace adtf::streaming;
using namespace adtf::filter;
// To implement a Filter we subclass adtf::filter::cFilter.
class cPropertyVariableCallbackFilter: public cFilter
{
public:
// This macros provides some meta information about our Filter Implementation
// This will be exposed by the plugin class factory.
ADTF_CLASS_ID_NAME(cPropertyVariableCallbackFilter,
"property_variable_callback.filter.adtf_guides.cid",
"Property Variable Callback Filter");
public:
// In the constructor, we setup all aspects of our Filter.
cPropertyVariableCallbackFilter();
private:
adtf::base::property_variable<double> m_oObservedProperty = 0.0;
};
#include "property_variable_callback_filter.h"
// The code behind the macro creates a plugin and the main entries to the plugin DLL or shared object.
// The cPropertyFilter will be available through the plugins class factory.
ADTF_PLUGIN("Property Variable Callback Filter Plugin",
cPropertyVariableCallbackFilter);
cPropertyVariableCallbackFilter::cPropertyVariableCallbackFilter()
{
// Let's register the property_variable
m_oObservedProperty.SetDescription("Property to observe.");
RegisterPropertyVariable("observed_property", m_oObservedProperty);
// Now add the callback to the property_variable and listen to changes
// To access the property in the lambda function let's capture the filter pointer
m_oObservedProperty.SetPropertyChangedCallback([this]()
{
LOG_INFO("Property observed_property has been changed to '%f'", *m_oObservedProperty);
});
// set basic information about the component itself and purpose
SetDescription("This filter shows the usage of callbacks regarding property changes.");
}
adtf::base::property_variable::SetResolveMacros()
function to disable automatic marco resolving.
See property_variable_macros_filter.cpp:
#include <adtffiltersdk/adtf_filtersdk.h>
class cMacroFilter: public adtf::filter::cFilter
{
public:
ADTF_CLASS_ID_NAME(cMacroFilter,
"property_variable_macros.filter.adtf_guides.cid",
"Property Variable Macro Filter");
public:
cMacroFilter()
{
// mark this property such that marcos are not resolved during initialization.
m_strLogString.SetResolveMacros(false);
m_strLogString.SetDescription("Property which will be resolved manually.");
RegisterPropertyVariable("log_string", m_strLogString);
// provide a runner to trigger resolving
CreateRunner("log_message");
SetDescription("log_message", "Runner pin to trigger manual resolving.");
// common description for the component
SetDescription("This filter shows the usage of manual macro resolving for a given property.");
}
tResult Process(adtf::base::tNanoSeconds, adtf::streaming::IRunner*) override
{
// resolve macros manually each time.
const auto strResolved = adtf::services::adtf_resolve_macros(m_strLogString->c_str());
LOG_INFO("%s", strResolved.GetPtr());
RETURN_NOERROR;
}
private:
adtf::base::property_variable<std::string> m_strLogString;
};
// The code behind the macro creates a plugin and the main entries to the plugin DLL or shared object.
// The cPropertyFilter will be available through the plugins class factory.
ADTF_PLUGIN("Property Variable Macro Filter Plugin",
cMacroFilter);
To change properties at runtime (after session has been launched), there exist several possibilities to adapt them:
adtf> rl 5
2019-05-02 14:57:21 [DUMP]: Will increase runlevel to "RL_Running" [runtime.cpp(714)]
2019-05-02 14:57:21 [INFO]: Property 'observed_property_1' has been changed to '10' [properties_observer_filter.cpp(35)]
2019-05-02 14:57:21 [INFO]: Property 'observed_property_2' has been changed to '20' [properties_observer_filter.cpp(35)]
2019-05-02 14:57:21 [INFO]: Property 'observed_property_1' has been changed to '10' [properties_observer_filter.cpp(35)]
2019-05-02 14:57:21 [INFO]: Property 'observed_property_2' has been changed to '20' [properties_observer_filter.cpp(35)]
2019-05-02 14:57:21 [INFO]: product = 6.283000 [properties_filter.cpp(62)]
2019-05-02 14:57:21 [INFO]: string_property value is 7 characters long. [properties_filter.cpp(66)]
2019-05-02 14:57:21 [INFO]: My properties are set to:
float_property = 3.141500
group/property1 = 1
group/property2 = 2
string_property = device1
enum_property = 0
hidden_property = 3 [properties_filter.cpp(81)]
adtf> sessionobjects
default_streaming_graph
default_streaming_graph/default_filter_graph
default_streaming_graph/default_filter_graph/Properties Filter
default_streaming_graph/default_filter_graph/Properties Observer Filter
[session_manager.system.adtf]
adtf> listprops "default_streaming_graph/default_filter_graph/Properties Observer Filter"
observed_property_1=10
observed_property_2=20
adtf> setprop "default_streaming_graph/default_filter_graph/Properties Observer Filter" "observed_property_1" 30
2019-05-02 14:57:45 [INFO]: Property 'observed_property_1' has been changed to '30' [properties_observer_filter.cpp(35)]
adtf>
Since ADTF 3.7.0 it is possible to create dynamic properties by implementing a Filter Editor and accessing the QML API from ADTF Configuration Editor, please have a look at ADTF Configuration Editor - Filter Editor. This is very useful by creating them based on some scripting metric, e.g. other property values, conditions, external files and more.
Another possibility is adding them manually to an ADTF Component, which is possible within the Property Editor of ADTF Configuration Editor since ADTF 3.8.0. This works also for a whole ADTF Filter Graph and its graph properties are accessable when included as Subgraph. You can link those graph properties to existing properties of ADTF Components to let them parameterized from "outside" when including the ADTF Filter Graph as Subgraph (especially when we talk about ADTF Include Mechanism, see Session Editor).
Let's have a look at a short example which includes a Subgraph that makes the display title property of the containing Qt5 Media Description Display accessable in the parent graph:
display
with an Qt5 Media Description Display
generation
with any stimuli Filter (e.g. Demo Data Load Generator
) and add the display
SubgraphHave a look at Generate Plugin Description to learn how to describe ADTF Components and generate this meta files.