ImFusion SDK 4.3
Instantiating Streams in ImFusion Suite

Utilities to make Streams available in the ImFusion Suite. More...

+ Collaboration diagram for Instantiating Streams in ImFusion Suite:

Detailed Description

Utilities to make Streams available in the ImFusion Suite.

When using streams directly from the SDK in an application, a user only needs to instantiate the Stream object. But in order to make any Data available in the ImFusion Suite and add it to the data model, it has to be created through an Algorithm. This is also true for Streams, regardless of whether they are IO streams interfacing with external devices or processing streams that create new data from existing streams.

The Algorithm also acts as a bridge between the Stream and the corresponding Controller and manages the Stream object's lifetime.

For this purpose, the ImFusion SDK provides a set of templated Stream creation Algorithms, that can be used to instantiate the majority of custom Streams in any plugin:

For both of these Algorithms you can also use the simple StreamControllerBase as the associated Controller. This allows interaction with the Stream, as well as its configuration with autogenerated GUI elements. This allows you to quickly create a Stream that can be used in the ImFusion Suite.

Usage in Plugin Factory

Example usage of the CreateStreamAlgorithm in the Algorithm and Controller factories of a plugin:

// A custom processing stream that processes images from an input ImageStream
class DemoProcessingStream : public ImFusion::ImageStream, public ImFusion::SignalReceiver
{
public:
static bool isCompatible(const DataList& inputData)
{
// Check if the input data contains an ImageStream
return inputData.getFirst<ImageStream>() != nullptr;
}
explicit DemoProcessingStream(const DataList& inputData) : ImageStream("processed images")
{
m_inputStream = inputData.getFirst<ImageStream>();
if (!m_inputStream) throw std::runtime_error("DemoProcessingStream requires an ImageStream as input data");
m_inputStream->signalStreamData.connect(this, &DemoProcessingStream::processImage);
}
~DemoProcessingStream() override
{
disconnectAll(); // Ensure our signal connections are cleaned up
}
void processImage(std::shared_ptr<const StreamData> inputData)
{
const auto imageData = std::dynamic_pointer_cast<const ImageStreamData>(inputData);
// Here you would process the input image data and emit the processed image.
// For demonstration, we just print a message and emit the same images.
std::cout << "Processing image from input stream: " << m_inputStream->name() << std::endl;
// Emit a new ImageStreamData with processed data
auto outputData = std::make_shared<ImageStreamData>(this);
outputData->setImages(imageData->images2()); // Just passing through the input image(s) for now
signalStreamData.emitSignal(outputData);
}
std::optional<WorkContinuation> doWork() override { return {}; };
bool openImpl() override { return true; };
bool closeImpl() override { return true; };
bool startImpl() override { return true; };
bool stopImpl() override { return true; }
std::string uuid() override { return "DemoProcessingStream"; }
private:
const ImageStream* m_inputStream;
};
// Register the DemoProcessingStream in the AlgorithmFactory and ControllerFactory
// Create a type alias, to not have to repeat the template arguments
using DemoProcessingAlgorithm = ImFusion::CreateStreamAlgorithm<DemoProcessingStream, true, true, true>;
MyAlgorithmFactory::MyAlgorithmFactory() : AlgorithmFactory("MyPlugin", false)
{
// register the DemoProcessingAlgorithm, which creates a DemoProcessingStream with the Algorithm inputs
registerAlgorithm<DemoProcessingAlgorithm>("DemoProcessingAlgorithm", "Demo;Demo Processing Stream");
}
MyControllerFactory::MyControllerFactory() : AlgorithmControllerFactory("MyPlugin", false) { }
AlgorithmController* MyControllerFactory::create(Algorithm* a) const
{
// use the StreamControllerBase for the DemoProcessingAlgorithm
if (auto alg = dynamic_cast<DemoProcessingAlgorithm*>(a))
return new StreamControllerBase(alg);
return nullptr;
}

Example usage of the CreateStreamIoAlgorithm in the Algorithm and Controller factories of a plugin:

// class DemoInputStream : public ImFusion::Stream...
// Create a type alias, to not have to repeat the template arguments
using DemoInputIoAlgorithm = ImFusion::CreateStreamIoAlgorithm<DemoInputStream, true, true>;
MyAlgorithmFactory::MyAlgorithmFactory() : AlgorithmFactory("MyPlugin", false)
{
// register the DemoInputIoAlgorithm, which creates a DemoInputStream
registerAlgorithm<DemoInputIoAlgorithm>("DemoInputIoAlgorithm", "Demo;Demo Input Stream");
}
MyControllerFactory::MyControllerFactory() : AlgorithmControllerFactory("MyPlugin", false) { }
AlgorithmController* MyControllerFactory::create(Algorithm* a) const
{
// use the StreamControllerBase for the DemoInputIoAlgorithm
if (auto alg = dynamic_cast<DemoInputIoAlgorithm*>(a))
return new StreamControllerBase(alg);
return nullptr;
}

For cases in which you want to specialize the stream Controller, you can also create a class deriving from the StreamControllerBase.

Classes

class  CreateStreamAlgorithm< T, autoOpenDefaultValue, autoConnectDefaultValue, takesArguments >
 Algorithm template to create streams. More...
 
class  CreateStreamIoAlgorithm< T, autoOpenDefaultValue, autoConnectDefaultValue >
 IO algorithm template to create streams. More...
 
class  StreamAlgorithm
 Type-erased base of CreateStreamAlgorithm. More...
 
class  StreamAlgorithmBase
 Interface for algorithms that work on streams. More...
 
class  StreamController
 Implementation of the DataController interface for manipulating streams. More...
 
class  StreamControllerBase
 Base AlgorithmController for creating controllers of streaming algorithms, but it can also be used directly to show a auto generated UI for a Stream. More...
 
class  StreamIoAlgorithm
 Type-erased base of CreateStreamIoAlgorithm. More...
 
Search Tab / S to search, Esc to close