ADTF
Overview of writing and reading samples

ADTF standard data

By using ADTF standard data and the supported types following components can be connected: Qt5 Media Description Display Qt5 JavaScript Filter Qt5 QML Filter Qt5 Stream Display DDL Mapping Filter DDL Mapping Filter Substream Dissector

Additionally, if the samples content is described via DDL, it is possible to use DDL based DAT File Exporter and Importer.

Arithmetic data types

Arithmetic data

Supported data types
uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, int64_t, float, double
Recommended Stream Type to use
Use the stream_type_plain as instance of Stream Meta Type "adtf/plaintype" for single small arithmetic data.
Output
Describe the data with stream_type_plain
using namespace adtf::streaming; // to use stream_type_plain<T>
using namespace adtf::filter; // to use pin_writer<T>
// create the adtf::filter::pin_writer<uint8_t>* m_pWriter_1 instance
// by using stream_type_plain<T> generator template
m_pWriter_1 = CreateOutputPin<pin_writer<uint8_t>>("out_plain_1", stream_type_plain<uint8_t>());
// create a adtf::streaming::ISampleWriter* m_pWriter_2 instance
// by using stream_type_plain<T> generator template
m_pWriter_2 = CreateOutputPin("out_plain_2", stream_type_plain<uint8_t>());
// create a adtf::streaming::IRunner to process every 100ms
m_pRunner = CreateRunner("write_plains", cTimerTriggerHint(100));
Namespace for the ADTF Filter SDK.
Namespace for the ADTF Streaming SDK.
Write Samples
Write the data with the help of operator<< or output_sample_data
tResult Process(adtf::base::tNanoSeconds tmTrigger, adtf::streaming::IRunner* pRunner) override
{
using namespace adtf::streaming;
if (pRunner == m_pRunner)
{
uint8_t nValue = 42;
// for pin_writer<T>
// write the value into a new sample with time of trigger
RETURN_IF_FAILED(m_pWriter_1->Write(tmTrigger, nValue));
using namespace adtf::streaming; // to use output_sample_data<T>
// for ISampleWriter
// write the sample by creating an output_sample_data with time of trigger
*m_pWriter_2 << output_sample_data(tmTrigger, nValue);
}
}
#define RETURN_IF_FAILED(s)
Return if expression is failed, which requires the calling function's return type to be tResult.
#define RETURN_NOERROR
Return status ERR_NOERROR, which requires the calling function's return type to be tResult.
The Interface defines a runnable item of the GraphObjects providing a IRuntimeBehaviour.
Definition: runner_intf.h:24
Input
Describe the expected input with stream_type_plain
using namespace adtf::streaming; // to use stream_type_plain<T>
// create the adtf::streaming::ISampleReader* m_pReader_1 instance
// by using stream_type_plain<T> generator template
m_pReader_1 = CreateInputPin("in_plain_1", stream_type_plain<uint8_t>());
// create the adtf::streaming::ISampleReader* m_pReader_2 instance
// by using stream_type_plain<T> generator template
m_pReader_2 = CreateInputPin("in_plain_2", stream_type_plain<uint8_t>());
Read Samples
Read the data with the help of sample_data
{
using namespace adtf::streaming; // to use sample_data<T> for the incoming sample
if (pReader == m_pReader_1)
{
// use the sample_data<T> template to access the samples content
sample_data<uint8_t> oSampleData(pSample);
// i.e. access the value with operator*
uint8_t nValue = *oSampleData;
// i.e. access the value with GetData()
nValue = oSampleData.GetData();
// log the value
LOG_INFO("Value is %d", int(nValue));
}
// ... do the same for m_pReader_2
}
Interface for sample reads that read from sample streams via input pins.
Base object pointer to realize binary compatible reference counting in interface methods.

Array of arithmetic data

Supported data types
std::array<T, N>, where T is: uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, int64_t, float, double
T[N], where T is: uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, int64_t, float, double
Recommended Stream Type to use
Use stream_type_plain as instance of Stream Meta Type "adtf/plaintype" for arrays of arithmetic data.
Output for std::array<T, N>
Describe the data with stream_type_plain
using namespace adtf::streaming; // to use stream_type_plain<T>
using namespace adtf::filter; // to use pin_writer<T>
// create the pin_writer<std::array<uint8_t, 4>>* m_pWriter_1 instance
// by using stream_type_plain<T> generator template
m_pWriter_1 = CreateOutputPin<pin_writer<std::array<uint8_t, 4>>>("out_plain_std_array_1",
stream_type_plain<std::array<uint8_t, 4>>());
// create the adtf::streaming::ISampleWriter* m_pWriter_2 instance
// by using using stream_type_plain<T> generator template
m_pWriter_2 = CreateOutputPin("out_plain_std_array_2", stream_type_plain<std::array<uint8_t, 4>>());
// create a adtf::streaming::IRunner to process every 100ms
m_pRunner = CreateRunner("write_std_arrays", cTimerTriggerHint(100));
Write Samples for std::array<T, N>
Write the data with the help of the pin_writer<T>::Write method or output_sample_data
tResult Process(adtf::base::tNanoSeconds tmTigger, adtf::streaming::IRunner* pRunner) override
{
if (pRunner == m_pRunner)
{
std::array<uint8_t, 4> aStdArrayValues = {1, 2, 3, 4};
// for pin_writer<T>
// write the value into a new sample with time of trigger
RETURN_IF_FAILED(m_pWriter_1->Write(tmTigger, aStdArrayValues));
using namespace adtf::streaming; // to use output_sample_data<T>
// for ISampleWriter
// writes the sample by creating output_sample_data with time of trigger
*m_pWriter_2 << output_sample_data(tmTigger, aStdArrayValues);
}
}
Input for std::array<T, N>
Describe the expected input with stream_type_plain
using namespace adtf::streaming; // to use stream_type_plain<T>
// create the adtf::streaming::ISampleReader* m_pReader_1 instance
// by using stream_type_plain<T> generator template
m_pReader_1 = CreateInputPin("in_plain_std_array_1", stream_type_plain<std::array<uint8_t, 4>>());
// create the adtf::streaming::ISampleReader* m_pReader_2 instance
// by using stream_type_plain<T> generator template
m_pReader_2 = CreateInputPin("in_plain_std_array_2", stream_type_plain<std::array<uint8_t, 4>>());
Read Samples for std::array<T, N>
Read the data with the help of sample_data
{
using namespace adtf::streaming; // to use sample_data<T> for the incoming sample
if (pReader == m_pReader_1)
{
// use the sample_data<T> template to access the samples content of the std::array
sample_data<std::array<uint8_t, 4>> oSampleDataStdArray(pSample);
// i.e. access the value with operator*
std::array<uint8_t, 4> aStdArrayValues = *oSampleDataStdArray;
// i.e. access the value with GetData()
aStdArrayValues = oSampleDataStdArray.GetData();
}
// ... do the same for m_pReader_2
}
Output for T[N]
Describe the data with stream_type_plain
using namespace adtf::streaming; // to use stream_type_plain<T>
using namespace adtf::filter; // to use pin_writer<T>
// create the adtf::filter::pin_writer<uint8_t[4]>* m_pWriter_1 instance
// by using stream_type_plain<T> template
m_pWriter_1 = CreateOutputPin<pin_writer<uint8_t[4]>>("out_plain_array_1", stream_type_plain<uint8_t[4]>());
// create the adtf::streaming::ISampleWriter* m_pWriter_2 instance
// by using stream_type_plain<T> template
m_pWriter_2 = CreateOutputPin("out_plain_array_2", stream_type_plain<uint8_t[4]>());
// create a adtf::streaming::IRunner to process every 100ms
m_pRunner = CreateRunner("write_arrays", cTimerTriggerHint(100));
Write Samples for for T[N]
Write the data with the help of pin_writer<T>::Write method or output_sample_data
{
if (pRunner == m_pRunner)
{
uint8_t aArrayValues[4] = {1, 2, 3, 4};
// for pin_writer<T[N]>
// write the value into a new sample with time of trigger
RETURN_IF_FAILED(m_pWriter_1->Write(tmTrigger, aArrayValues));
using namespace adtf::streaming; // to use output_sample_data<T>
// for ISampleWriter
// writes the sample by creating output_sample_data with time of trigger
*m_pWriter_2 << output_sample_data(tmTrigger, aArrayValues);
}
}
Input for T[N]
Describe the expected input with stream_type_plain
using namespace adtf::streaming; // to use stream_type_plain<T>
// create the adtf::streaming::ISampleReader* m_pReader_1 instance
// i.e. using stream_type_plain<T> generator template
m_pReader_1 = CreateInputPin("in_plain_array_1", stream_type_plain<uint8_t[4]>());
// create the adtf::streaming::ISampleReader* m_pReader_2 instance
// i.e. using stream_type_plain<T> generator template
m_pReader_2 = CreateInputPin("in_plain_array_2", stream_type_plain<uint8_t[4]>());
Read Samples for T[N]
Read the data with the help of sample_data
{
using namespace adtf::streaming; // to use sample_data<T> for the incoming sample
if (pReader == m_pReader_1)
{
// use the sample_data<T> template to access the samples content of the std::array
sample_data<uint8_t[4]> oSampleDataArray(pSample);
// i.e. access the value with operator*
for (auto nIndex = 0; nIndex < 4; ++nIndex)
{
LOG_INFO("Value[%d]=%d", int(nIndex), int((*oSampleDataArray)[nIndex]));
}
// i.e. access the value with GetData()
for (auto nIndex = 0; nIndex < 4; ++nIndex)
{
LOG_INFO("Value[%d]=%d", int(nIndex), int(oSampleDataArray.GetData()[nIndex]));
}
}
// ... do the same for m_pReader_2
}

Structured data types

Structured data

Supported data types
The conditions to use structured data as content of a sample is:
  • The type has to fulfill the condition of std::is_trivially_copyable<T>::value to be true
  • No pointer types are allowed as member
  • All members has to fullfill the condition of std::is_trivially_copyable<T>::value to be true
    // example structure that is trivially copyable
    struct tMyType
    {
    int32_t m_nValue1;
    double m_fValue2;
    bool m_bArray[2];
    };
  • It is also possible to define a DDL description file and use the generated type by MD Generator Tool.
    // this file is generated with MD Generator Tool
    #include <my_type.h>
Recommended Stream Type to use
Use the stream_type_default as instance of Stream Meta Type "adtf/default" for structured data.
Usually, you are allowed to use every kind of your own Custom Stream Meta Types to describe the structured data you want to write. The big advantage of using the stream_type_default is to describe the content by the help of the Data Definition Language (DDL). See also DDL and ADTF 3, how to create a description for your structured data.
Output
Describe the data with stream_type_default
using namespace adtf::mediadescription; // to use stream_type_default<T>
using namespace adtf::filter; // to use pin_writer<T>
// i.e. we create a structure ddl description with the help of "type reflection"
auto oDescriptionForMyType = structure<tMyType>("tMyType")
.Add("m_nValue1", &tMyType::m_nValue1)
.Add("m_fValue2", &tMyType::m_fValue2)
.Add("m_bArray", &tMyType::m_bArray);
// create the adtf::filter::pin_writer<tMyType>* m_pWriter_1 instance
// i.e. by using stream_type_default<> generator template
m_pWriter_1 = CreateOutputPin<pin_writer<tMyType>>("out_default_1",
stream_type_default<>(oDescriptionForMyType));
// create the adtf::streaming::ISampleWriter* m_pWriter_2 instance
// i.e. by using CreateOutputPin overload take structure<> as parameter
m_pWriter_2 = CreateOutputPin("out_default_2", oDescriptionForMyType);
// create the adtf::streaming::ISampleWriter* m_pWriter_3 instance
// i.e. by using stream_type_default<T> creator function
// to use this method you MUST create <my_type.h> with MD Generator Tool to use tMyTypeWithMDGen
m_pWriter_3 = CreateOutputPin("out_default_2", stream_type_default<tMyTypeWithMDGen>());
// create a adtf::streaming::IRunner to process every 100ms
m_pRunner = CreateRunner("write_defaults", cTimerTriggerHint(100));
Namespace for the ADTF Media Description SDK.
Write Samples
Write the data with the help of pin_writer<T>::Write method or output_sample_data
tResult Process(adtf::base::tNanoSeconds tmTrigger, adtf::streaming::IRunner* pRunner) override
{
if (pRunner == m_pRunner)
{
tMyType sValues = {1, 2.0, {true, false}};
// for pin_writer<T>
// Write the value into a new sample with time of trigger
RETURN_IF_FAILED(m_pWriter_1->Write(tmTrigger, sValues));
using namespace adtf::streaming; // to use output_sample_data<T>
// for ISampleWriter
// Write the value by creating an output_sample_data<T> with time of trigger
*m_pWriter_2 << output_sample_data(tmTrigger, sValues);
// for ISampleWriter with MD Generator Tool generated description <my_type.h>
tMyTypeWithMDGen sValuesWithMDGen = {1, 2.0, {true, false}};
// Write the value by creating an output_sample_data<T> with time of trigger
*m_pWriter_3 << output_sample_data(tmTrigger, sValuesWithMDGen);
}
}
Input
Describe the expected input with stream_type_default
using namespace adtf::mediadescription; // to use stream_type_default<T>
// create the adtf::streaming::ISampleReader* m_pReader_1 instance
// i.e. using stream_type_default<T> generator template
m_pReader_1 = CreateInputPin("in_default_1", stream_type_default<>(oDescriptionForMyType));
// create the adtf::streaming::ISampleReader* m_pReader_2 instance
// i.e. using CreateInputPin overload take structure<> as parameter
m_pReader_2 = CreateInputPin("in_default_2", oDescriptionForMyType);
// create the adtf::streaming::ISampleReader* m_pReader_3 instance
// i.e. by using stream_type_default<T> creator function
// to use this method you MUST create <my_type.h> with MD Generator Tool to use tMyTypeWithMDGen
m_pReader_3 = CreateInputPin("in_default_3", stream_type_default<tMyTypeWithMDGen>());
Read Samples
Read the data with the help of sample_data
{
using namespace adtf::streaming; // to use sample_data<T> for the incoming sample
if (pReader == m_pReader_1)
{
// use the sample_data<T> template to access the samples content
sample_data<tMyType> oSampleData(pSample);
// i.e. access the values with operator*
tMyType sValuesCopy = *oSampleData;
// i.e. access the value with GetData()
sValuesCopy = oSampleData.GetData();
}
// ... do the same for m_pReader_2
// ...
else if (pReader == m_pReader_3)
{
// use the sample_data<T> template to access the samples content
sample_data<tMyTypeWithMDGen> oSampleData(pSample);
// i.e. access the values with operator*
tMyTypeWithMDGen sValuesCopy = *oSampleData;
// i.e. access the value with GetData()
sValuesCopy = oSampleData.GetData();
}
}

Array of structured data

Supported data types
The conditions to use an array of structured data as content of a sample is:
  • The data type has to fulfill the condition of std::is_trivially_copyable<T>::value to be true
  • No pointer types are allowed as member
  • All members has to fullfill the condition of std::is_trivially_copyable<T>::value to be true
    // example structure that is trivially copyable
    struct tMyType
    {
    int32_t m_nValue1;
    double m_fValue2;
    bool m_bArray[2];
    };
    std::array<T, N>, where T is a supported structured data type (i.e. std::array<tMyType, 4> aValues;)
    T[N], where T is a supported structured data type (i.e. tMyType aValues[4];)
  • It is also possible to define a DDL description file and use the generated type by MD Generator Tool.
    // this file is generated with MD Generator Tool
    #include <my_type.h>
Recommended Stream Type to use
Use the stream_type_default_array as instance of Stream Meta Type "adtf/default" for structured data. You are allowed to use every kind of your own Custom Stream Meta Types to describe the structured data you want to write. The advantage of using the stream_type_default_array is to describe the content by the help of the Data Definition Language (DDL). See also DDL and ADTF 3 how to create a description for your structured data. It will additionally handle the creation of the array type within description.
Output
Describe the data with stream_type_default_array
using namespace adtf::mediadescription; // to use stream_type_default_array<T>
using namespace adtf::filter; // to use pin_writer<T>
// i.e. we create a structure ddl description with the help of "type reflection"
auto oDescriptionForMyType = structure<tMyType>("tMyType")
.Add("m_nValue1", &tMyType::m_nValue1)
.Add("m_fValue2", &tMyType::m_fValue2)
.Add("m_bArray", &tMyType::m_bArray);
// create the adtf::streaming::ISampleWriter* m_pWriter_1 instance
// by using stream_type_default_array<> generator template
m_pWriter_1 = CreateOutputPin("out_default_array_1",
stream_type_default_array<>(oDescriptionForMyType, 4));
// create the pin_writer<tMyType[4]>* m_pWriter_2 instance
// by using stream_type_default_array<> generator template
m_pWriter_2 = CreateOutputPin<pin_writer<tMyType[4]>>("out_default_array_2",
stream_type_default_array<>(oDescriptionForMyType, 4));
// create the adtf::streaming::ISampleWriter* m_pWriter_3 instance
// by using stream_type_default_array<T> generator template
// to use this method you MUST create <my_type.h> with MD Generator Tool to use type tMyTypeWithMDGen
m_pWriter_3 = CreateOutputPin("out_default_array_3", stream_type_default_array<tMyTypeWithMDGen[4]>());
// create a adtf::streaming::IRunner to process every 100ms
m_pRunner = CreateRunner("write_default_arrays", cTimerTriggerHint(100));
Write Samples
Write the data with the help of pin_writer<T>::Write method or output_sample_data
{
if (pRunner == m_pRunner)
{
std::array<tMyType, 4> aStdArray = {tMyType{1, 2.0, {true, false}}, tMyType{2, 3.0, {false, false}},
tMyType{3, 4.0, {true, true}}, tMyType{4, 5.0, {false, true}}};
using namespace adtf::streaming; // to use output_sample_data<T>
// for ISampleWriter*
// write the value by creating output_sample_data<T> and set the time of trigger
*m_pWriter_1 << output_sample_data(tmTrigger, aStdArray);
// for pin_writer<T[N]>
tMyType aValues[4] = {tMyType{1, 2.0, {true, false}}, tMyType{2, 3.0, {false, false}},
tMyType{3, 4.0, {true, true}}, tMyType{4, 5.0, {false, true}}};
// use output_sample_data<T[N]>
*m_pWriter_2 << output_sample_data(tmTrigger, aValues);
// or use pin_writer<T>::Write method
RETURN_IF_FAILED(m_pWriter_2->Write(tmTrigger, aValues));
// for ISampleWriter*
// write the value by creating output_sample_data<T> and set the time of trigger
tMyTypeWithMDGen aValuesMDGen[4] = {tMyTypeWithMDGen{1, 2.0, {true, false}},
tMyTypeWithMDGen{2, 3.0, {false, false}},
tMyTypeWithMDGen{3, 4.0, {true, true}},
tMyTypeWithMDGen{4, 5.0, {false, true}}};
// use output_sample_data<T[N]>
*m_pWriter_3 << output_sample_data(tmTrigger, aValuesMDGen);
}
}
Input
Describe the expected input with stream_type_default_array
using namespace adtf::mediadescription; // to use stream_type_default<T>
// create the adtf::streaming::ISampleReader* m_pReader_1 instance
// by using stream_type_default_array<> generator template
m_pReader_1 = CreateInputPin("in_default_array_1",
stream_type_default_array<>(oDescriptionForMyType, 4));
// create the adtf::streaming::ISampleReader* m_pReader_2 instance
// by using stream_type_default_array<> generator template
m_pReader_2 = CreateInputPin("in_default_array_2",
stream_type_default_array<>(oDescriptionForMyType, 4));
// create the adtf::streaming::ISampleReader* m_pReader_3 instance
// by using stream_type_default_array<T> generator template
// to use this method you MUST create <my_type.h> with MD Generator Tool to use type tMyTypeWithMDGen
m_pReader_3 = CreateInputPin("in_default_array_2",
stream_type_default_array<tMyTypeWithMDGen[4]>());
Read Samples
Read the data with the help of sample_data
{
using namespace adtf::streaming; // to use sample_data<T> for the incoming sample
if (pReader == m_pReader_1)
{
// use the sample_data<T> template to access the samples content
sample_data<std::array<tMyType, 4>> oSampleStdArrayData(pSample);
// i.e. access the values with operator*
std::array<tMyType, 4> aStdArrayCopy = *oSampleStdArrayData;
// i.e. access the value with GetData()
aStdArrayCopy = oSampleStdArrayData.GetData();
}
else if (pReader == m_pReader_2)
{
// for T[N]
// use the sample_data<T> template to access the samples content
sample_data<tMyType[4]> oSampleArrayData(pSample);
// i.e. access the values with operator*
tMyType aValuesCopy[4];
for (auto nIdx = 0; nIdx < 4; ++nIdx)
{
aValuesCopy[nIdx] = (*oSampleArrayData)[nIdx];
}
// i.e. access the value with GetData()
for (auto nIdx = 0; nIdx < 4; ++nIdx)
{
aValuesCopy[nIdx] = oSampleArrayData.GetData()[nIdx];
}
}
else if (pReader == m_pReader_3)
{
// for T[N]
// use the sample_data<T> template to access the samples content
sample_data<tMyTypeWithMDGen[4]> oSampleArrayData(pSample);
// ...
}
}

Video types

Video image data

Supported type
A bitmap array of byte which can be described via tStreamImageFormat
Recommended Stream Type to use
Use the stream_type_image as instance of Stream Meta Type "adtf/image" for a sequence of images.
Output
Describe the data with stream_type_image
using namespace adtf::streaming; // to use stream_type_image<T>
// use a grey scale image (8bit)
tStreamImageFormat sFormat{stream_image_format::GREYSCALE_8::FormatName, 800, 600, 800 * 600};
// create the adtf::streaming::ISampleWriter* m_pWriter_1 instance
// i.e. by using stream_type_image<T> generator template
m_pWriter_1 = CreateOutputPin("out_video_1", stream_type_image(sFormat));
// create a adtf::streaming::IRunner to process every 100ms
m_pRunner = CreateRunner("write_videos", cTimerTriggerHint(100));
Write Samples
Write the data with the help of operator<< for the sample
tResult Process(adtf::base::tNanoSeconds tmTrigger, adtf::streaming::IRunner* pRunner) override
{
using namespace adtf::streaming; // to use alloc_sample, ISample, ISampleBuffer
// use the current time of trigger for the sample
RETURN_IF_FAILED(alloc_sample(pSample, tmTrigger));
{ // MIND: Before transmitting, the buffer must be unlocked!
RETURN_IF_FAILED(pSample->WriteLock(pSampleBuffer, 800 * 600)); // create a sample with 800*600*8Bit
memset(pSampleBuffer->GetPtr(), pSampleBuffer->GetSize(), 0xF0); // this is an example set up a grey image
} // this closure will unlock the buffer
// write the sample
*m_pWriter_1 << pSample;
}
Implementation for a exclusive lock guard.
Object pointer implementation used for reference counting on objects of type IObject.
Definition: object_ptr.h:163
tResult alloc_sample(ucom::ant::iobject_ptr< ucom::ant::IObject > &pSampleObject, const char *strSampleCID)
Helper Function to get a Sample Instance through the adtf::ucom::ant::IRuntime.
Input
Describe the expected input with stream_type_image
using namespace adtf::streaming; // to use stream_type_image<T>
// accept a grey scale image (8bit)
tStreamImageFormat sFormat{stream_image_format::GREYSCALE_8::FormatName, 800, 600, 800*600};
// create the adtf::streaming::ISampleReader* m_pReader_1 instance
// by using stream_type_image<T> generator template
m_pReader_1 = CreateInputPin("in_video_1", stream_type_image(sFormat));
Read Samples
Read the data directly from the sample
{
using namespace adtf::streaming; // to use ISampleBuffer
if (pReader == m_pReader_1)
{
// use the sample buffer to access the content
RETURN_IF_FAILED(pSample->Lock(pSampleBuffer));
// check if the image is in the right size
if (pSampleBuffer->GetSize() == 800 * 600)
{
const uint8_t* pPixels = static_cast<const uint8_t*>(pSampleBuffer->GetPtr());
LOG_INFO("The 8Bit greyscale pixel[0] has following value: %d", int(pPixels[0]));
}
else
{
RETURN_ERROR_DESC(ERR_MEMORY, "The size of the image is not as expected 800*600*8Bit");
}
}
// ... do the same for m_pReader_2
}
#define RETURN_ERROR_DESC(_code,...)
Same as RETURN_ERROR(_error) using a printf like parameter list for detailed error description.
Implementation for a shared lock guard.

Dynamic data in size

String data

Supported type
std::string
std::u16string
Recommended Stream Type to use
Use the stream_type_string as instance of Stream Meta Type "adtf/string" for string data.
Output for std::string
Describe the data with stream_type_string
using namespace adtf::streaming; // to use stream_type_string<T>
using namespace adtf::filter; // to use pin_writer<T>
// create the adtf::filter::pin_writer<std::string>* m_pWriter_1 instance
// by using stream_type_string<T> generator template
m_pWriter_1 = CreateOutputPin<pin_writer<std::string>>("out_string_1",
stream_type_string<std::string>());
// create the adtf::filter::pin_writer<std::u16string>* m_pWriter_2 instance
// by using stream_type_string<T> generator template
m_pWriter_2 = CreateOutputPin<pin_writer<std::u16string>>("out_string_2",
stream_type_string<std::u16string>());
// create a adtf::streaming::IRunner to process every 100ms
m_pRunner = CreateRunner("write_strings", cTimerTriggerHint(100));
Write Samples for std::string
Write the data with the help of operator<<
{
if (pRunner == m_pRunner)
{
std::string strStringToTransmit = "This is the output string";
// for pin_writer<T>
// write the value into a new sample with current time of trigger
RETURN_IF_FAILED(m_pWriter_1->Write(tmTrigger, strStringToTransmit));
std::u16string strU16StringToTransmit = u"This is the output u16string";
// for pin_writer<T>
// write the value into a new sample with current time of trigger
RETURN_IF_FAILED(m_pWriter_2->Write(tmTrigger, strU16StringToTransmit));
}
}
Input for std::string
Describe the expected input with stream_type_string
using namespace adtf::streaming; // to use stream_type_string<T>
// create the adtf::streaming::ISampleReader* m_pReader_1 instance
// by using stream_type_string<T> generator template
m_pReader_1 = CreateInputPin("in_string_1", stream_type_string<std::string>());
// create the adtf::streaming::ISampleReader* m_pReader_2 instance
// by using stream_type_string<T> generator template
m_pReader_2 = CreateInputPin("in_string_2", stream_type_string<std::u16string>());
Read Samples for std::string
Read the data with the help of sample_data
Remark: An instance of sample_data will copy the buffers content of the sample to an instance of std::string
{
using namespace adtf::streaming; // to use sample_data<T> for the incoming sample
if (pReader == m_pReader_1)
{
// use the sample_data<T> template to access the samples content as string
sample_data<std::string> oSampleData(pSample);
// i.e. access the values with operator*
std::string strCopy = *oSampleData;
// i.e. access the value with GetData()
strCopy = oSampleData.GetData();
}
else if (pReader == m_pReader_2)
{
// use the sample_data<T> template to access the samples content as string
sample_data<std::u16string> oSampleData(pSample);
// i.e. access the values with operator*
std::u16string strU16Copy = *oSampleData;
// i.e. access the value with GetData()
strU16Copy = oSampleData.GetData();
}
}

Dynamic arrays within structured data

Remarks
Please keep in mind, that this type is not supported within any displays by default!
Possible data types
The conditions to use an array of structured data with dynamic content within samples is:
  • The structured data must be allocated in one whole block of memory.
  • No pointer types are allowed as member
  • All members except the flexible array member has to fullfill the condition of std::is_trivially_copyable<T>::value to be true
    REMARK: Dynamic memory allocations requires increased attention by the programmer!
    Since these conditions has to be met we recommend to use a static array and mark valid and invalid array positions.
    Dynamic content is mostly not supported by any ADTF standard display.
    // example structure that is a dynamic type
    // Mind: flexible array members must be always at the end of the structure!
    // using this flexible array members always needs attention by the programmer!
    struct tMyTypeDynamic
    {
    uint64_t m_nArraySize;
    int32_t m_aDynamicArray[];
    static size_t EvaluateSize(size_t nArraySize)
    {
    return sizeof(struct tMyTypeDynamic) + nArraySize * sizeof(int32_t);
    }
    };
Recommended Stream Type to use
Use the stream_type_default as instance of Stream Meta Type "adtf/default" for structured data. The dynamic content can be described via arraysize within the DDL description.
Output
Describe the data with stream_type_default
using namespace adtf::mediadescription; // to use stream_type_default<T>
// i.e. we need to define the dynamic array in a description
constexpr auto strStructNameForMyTypeDynamic = "tMyTypeDynamic";
constexpr auto strDescriptionForMyTypeDynamic =
R"(<struct name="tMyTypeDynamic" alignment="8" version="1">
<element name="m_nArraySize" type="uint64_t" arraysize="1">
<deserialized alignment="8"/>
<serialized bytpos="0" byteorder="LE"/>
</element>
<element name="m_aDynamicArray" type="int32_t" arraysize="m_nArraySize">
<deserialized alignment="4"/>
<serialized bytpos="8" byteorder="LE"/>
</element>
</struct>)";
// create the adtf::streaming::ISampleWriter* m_pWriter instance
// by using stream_type_default<> generator template
m_pWriter_1 = CreateOutputPin("out_dynamic_1",
stream_type_default<>(strStructNameForMyTypeDynamic, strDescriptionForMyTypeDynamic));
// create the adtf::filter::pin_writer<tMyType>* m_pWriter_2 instance
// by using stream_type_default<> generator template
m_pWriter_2 = CreateOutputPin("out_default_2",
stream_type_default<>(strStructNameForMyTypeDynamic, strDescriptionForMyTypeDynamic));
// create a adtf::streaming::IRunner to process every 100ms
m_pRunner = CreateRunner("write_dynamics", cTimerTriggerHint(100));
Write Samples
Write the data directly within samples memory
tResult Process(adtf::base::tNanoSeconds tmTrigger, adtf::streaming::IRunner* pRunner) override
{
using namespace adtf::streaming; // to use alloc_sample
if (pRunner == m_pRunner)
{
RETURN_IF_FAILED(alloc_sample(pSample, tmTrigger));
{ // MIND: pSampleBuffer must be unlocked before transmitting the sample!
RETURN_IF_FAILED(pSample->WriteLock(pSampleBuffer, tMyTypeDynamic::EvaluateSize(4)));
tMyTypeDynamic* pMyDynamicArray = static_cast<tMyTypeDynamic*>(pSampleBuffer->GetPtr());
pMyDynamicArray->m_nArraySize = 4; // this must be the same value as used in WriteLock call!
for (auto nIdx = 0; nIdx < 4; ++nIdx)
{
pMyDynamicArray->m_aDynamicArray[nIdx] = nIdx;
}
} // this closure will unlock the pSampleBuffer
// write the sample
*m_pWriter_1 << pSample;
// ... do the same for m_pWriter_2
}
}
Input
Describe the expected input with stream_type_default
using namespace adtf::mediadescription; // to use stream_type_default<T>
// create the adtf::streaming::ISampleReader* m_pReader_1 instance
// by using stream_type_default<> generator template
m_pReader_1 = CreateInputPin("in_default_1",
stream_type_default<>(strStructNameForMyTypeDynamic, strDescriptionForMyTypeDynamic));
// create the adtf::streaming::ISampleReader* m_pReader_2 instance
// by using stream_type_default<> generator template
m_pReader_2 = CreateInputPin("in_default_2",
stream_type_default<>(strStructNameForMyTypeDynamic, strDescriptionForMyTypeDynamic));
Read Samples
Read the data directly from the samples buffer
{
using namespace adtf::streaming; // to acces the sample
if (pReader == m_pReader_1)
{
RETURN_IF_FAILED(pSample->Lock(pSampleBuffer));
const tMyTypeDynamic* pMyArray = static_cast<const tMyTypeDynamic*>(pSampleBuffer->GetPtr());
// we should check array size and expected sample buffer size
if (tMyTypeDynamic::EvaluateSize(pMyArray->m_nArraySize) == pSampleBuffer->GetSize())
{
// i.e. access the value with GetData()
LOG_INFO("The current array size is %zu", size_t(pMyArray->m_nArraySize));
}
else
{
RETURN_ERROR_DESC(ERR_MEMORY, "set dynamic array size and sample size does not fit!");
}
}
//... do the same for m_pReader_2
}

Custom data

You may define your own Meta Type to describe the data you want to transmit and receive. See also Custom Stream Meta Types.
The differences between the other ADTF standard data and the recommended stream types are:

  • You can define own properties to describe the content
  • You are able to implement an own my_custom_stream_meta_type::IsCompatible
  • You can hide the content of the samples, because only you know the properties meanings
  • As long as you not set the "md_struct" and "md_definition" property, you can not use any Standard Displays within ADTF
Example definition
struct my_custom_stream_meta_type
{
// you must define the Metatype name as a variable "MetaTypeName"
static constexpr const tChar* const MetaTypeName = "cppDev/my_custom_type";
// this is a property to define a property name which identifies the content by the help of a number
static constexpr const tChar* const SecretContentID = "secret_content_id";
static constexpr const tChar* const Version = "version_of_type";
static void SetProperties(const adtf::ucom::iobject_ptr<adtf::base::IProperties>& pProperties)
{
// we set the default values of the stream type
pProperties->SetProperty(adtf::base::property<uint16_t>(SecretContentID, 0));
pProperties->SetProperty(adtf::base::property<adtf_util::cString>(Version, "cppDev 2020-1.0"));
}
};
struct my_custom_stream_type : public adtf::streaming::stream_type<my_custom_stream_meta_type>
{
my_custom_stream_type()
{
}
my_custom_stream_type(uint16_t nSecretContentNo)
{
THROW_IF_FAILED(GetConfig(pConfig));
adtf::base::set_property<uint16_t>(*pConfig, my_custom_stream_meta_type::SecretContentID,
nSecretContentNo);
}
};
struct tMyCustomData1
{
uint64_t nValue1;
int64_t nValue2;
uint32_t nValue3;
};
struct tMyCustomData2
{
double nValue1;
tMyCustomData1 aArrayData[3];
};
char tChar
The tChar defines the type for platform character set (platform and compiler dependent type).
Generator template to implement a ant::IStreamType based on a Stream Meta Type - see Stream Type and ...
Definition: streamtype.h:376
#define THROW_IF_FAILED(s)
throws if the expression returns a failed tResult
Output
Describe the data with your own meta type
using namespace adtf::filter; // to use pin_writer<T>
// create the adtf::filter::pin_writer<std::string>* m_pWriter_1 instance
m_pWriter_1 = CreateOutputPin<pin_writer<tMyCustomData1>>("out_custom_1", my_custom_stream_type(1));
// create the adtf::streaming::ISampleWriter* m_pWriter_2 instance
m_pWriter_2 = CreateOutputPin("out_custom_2", my_custom_stream_type(2));
// create a adtf::streaming::IRunner to process every 100ms
m_pRunner = CreateRunner("write_customs", cTimerTriggerHint(100));
Write Samples
Write the samples with the operator<< or output_sample_data
tResult Process(adtf::base::tNanoSeconds tmTrigger, adtf::streaming::IRunner* pRunner) override
{
if (pRunner == m_pRunner)
{
// for the pin_writer<tMyCustomData1>
// write the value into a new sample with time of trigger
m_pWriter_1->Write(tmTrigger, tMyCustomData1{1, 2, 3});
// for ISampleWriter*
// write the sample with the help of output_sample_data
*m_pWriter_2 << adtf::streaming::output_sample_data(tmTrigger, tMyCustomData2{1.0, {{1, 2, 3}, {}, {}}});
}
}
Wrapper class that facilitates the handling of output samples.
Definition: sample.h:353
Input
Describe the expected input with your own meta type
using namespace adtf::streaming; // to use stream_type_string<T>
// create the adtf::streaming::ISampleReader* m_pReader_1 instance
m_pReader_1 = CreateInputPin("in_custom_1", my_custom_stream_type(1));
// create the adtf::streaming::ISampleReader* m_pReader_2 instance
m_pReader_2 = CreateInputPin("in_custom_2", my_custom_stream_type(2));
Read Samples
Read the data with the help of sample_data
{
if (pReader == m_pReader_1)
{
using namespace adtf::streaming; // to use sample_data<T> for the incoming sample
// use the sample_data<T> template to access the samples content
sample_data<tMyCustomData1> oSampleData(pSample);
// i.e. access the values with operator*
tMyCustomData1 sCopyOfCustomData = *oSampleData;
// i.e. access the value with GetData()
sCopyOfCustomData = oSampleData.GetData();
}
// ... the same for m_pReader_2
// and sample_data<tMyCustomData2>
}