Common Vision Blox 15.0
Loading...
Searching...
No Matches
Acquisition and Streaming - User Managed Memory

Attention
External Memory is only supported in the C++ API.

By default, the CVB acquisition engine will manage memory for image buffers internally on the heap. In some cases, this is not desirable (e.g. embedded systems, streaming to the GPU) and memory has to be managed outside of the CVB acquisition engine.

This can be done by allocating a custom Cvb::FlowSetPool and registering it in the acquisition engine. If using multiple data streams, each one can have a different Cvb::FlowSetPool, allowing for each to be streamed to a different memory location (e.g. stream 0 goes to the GPU, stream 1 to the system memory, etc).

The Cvb::FlowSetInfo provided by each stream gives parameters about the memory requirements for that flow as reported by the device. These parameters should be followed to ensure that all buffers are large enough to hold the received images and prevent errors during acquisition.

using namespace Cvb;
class UserFlowSetPool : public FlowSetPool // (1)
{
public:
UserFlowSetPool(const std::vector<FlowInfo>& flowSetInfo, std::size_t numFlowSets)
: FlowSetPool(flowSetInfo, FlowSetPool::ProtectedTag{})
{
for (int i = 0; i < numFlowSets; ++i) {
std::vector<void*> flowSet{};
for (const FlowInfo& flowInfo : flowSetInfo) {
flowSet.push_back(malloc(flowInfo.Size)); // (2)
}
this->PushBack(flowSet);
}
}
virtual ~UserFlowSetPool()
{
for (std::vector<Flow>& flowSet : *this) {
for (Flow& flow : flowSet) {
free(flow.Buffer); // (3)
}
}
}
};
const std::size_t NUM_FLOWSETS = 3;
auto stream = device->Stream<ImageStream>(); // (4)
auto flowSetInfo = stream->FlowSetInfo(); // (5)
auto flowSetPoolPtr = std::make_shared<UserFlowSetPool>(flowSetInfo, NUM_FLOWSETS); // (6)
stream->RegisterExternalFlowSetPool(flowSetPoolPtr); // (7)
stream->Start();
// Acquire and process images
stream->Abort();
stream->DeregisterFlowSetPool() // (9)
std::vector< FlowInfo > FlowSetInfo() const

Note: Error handling has been omitted from the above example.

  1. The custom flow set pool is instantiated.
  2. All devices are discovered across all interfaces and transport layers except for the legacy VIN transport layers.
  3. The first discovered device is opened using the GenTL acquisition stack and internally allocated buffers.
  4. The data stream is instantiated.
  5. The parameters reported by the device for the stream is read.
  6. The buffers are allocated according the parameters read from the device.
  7. The custom flow set pool is registered in the acquisition engine.
  8. Acquisition is started.
  9. Each composite will need to be proactively waited for by means of a call to wait on the stream. The returned image will be located in the memory allocated by the custom flow set pool.
  10. Acquisition is stopped.
  11. The flow set pool is deregistered from the acquisition engine, allowing it to be cleaned up.