Common Vision Blox 15.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Friends Modules Pages
Image Manager/Cvb++/CppUserAllocatedMemory

This example program is located in your CVB installation under %CVB%Tutorial/Image Manager/Cvb++/CppUserAllocatedMemory.

main.cpp:

// Demonstrates how to pass user-allocated memory as the target buffer(s) for image acquisition from a
// camera. This option is useful if, for example, the image data buffers need to satisfy extraordinary
// conditions like e.g. address alignment (if extensions like SSE or AVX are going to be used on the
// data) or a particular block of memory (if the image is to be used by a GPU, see the CppCudaMemory
// example for this).
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <cstdlib>
#include <cvb/device_factory.hpp>
#include <cvb/global.hpp>
#include <cvb/driver/driver.hpp>
#include <cvb/image.hpp>
#include <cvb/composite.hpp>
#include <cvb/utilities/utilities.hpp>
#include <cvb/driver/image_stream.hpp>
static const constexpr auto TIMEOUT = std::chrono::milliseconds(3000);
static const constexpr int NUM_ELEMENTS_TO_ACQUIRE = 10;
static const constexpr int NUM_BUFFERS = 4;
namespace helper
{
// An alternative of std::aligned_alloc that is available in C++17.
static inline void *aligned_alloc(size_t alignment, size_t size) noexcept
{
#ifdef _MSC_VER
return _aligned_malloc(size, alignment);
#else
void *memptr = nullptr;
return !posix_memalign(&memptr, alignment, size) ? memptr : nullptr; // posix_memalign returns 0 on success.
#endif
}
// An alternative of std::free that is available in C++17.
static inline void free(void *ptr) noexcept
{
#ifdef _MSC_VER
_aligned_free(ptr);
#else
free(ptr);
#endif
}
/* FlowSetPool does not store the FlowSets for further
* use, therefore we create a subclass to release the
* buffer later
*/
class UserFlowSetPool final
: public Cvb::Driver::FlowSetPool
{
using UserFlowSetPoolPtr = std::shared_ptr<UserFlowSetPool>;
public:
UserFlowSetPool(const std::vector<Cvb::FlowInfo>& flowInfo) noexcept
: Cvb::FlowSetPool(flowInfo, Cvb::FlowSetPool::ProtectedTag{})
{
}
virtual ~UserFlowSetPool()
{
for (auto& flowSet : *this)
for (auto& flow : flowSet)
helper::free(flow.Buffer);
}
static UserFlowSetPoolPtr Create(const std::vector<Cvb::FlowInfo>& flowInfos)
{
return std::make_shared<UserFlowSetPool>(flowInfos);
}
};
}
void AcquireData(const Cvb::CompositeStreamPtr& stream)
{
for (auto i = 0; i < NUM_ELEMENTS_TO_ACQUIRE; i++)
{
auto [composite, waitStatus, enumerator] = stream->WaitFor(TIMEOUT);
switch (waitStatus)
{
default:
std::cout << "wait status unknown.\n";
case Cvb::WaitStatus::Abort:
case Cvb::WaitStatus::Timeout:
{
std::cout << "wait status not ok\n";
continue;
}
case Cvb::WaitStatus::Ok:
{
break;
}
}
// assume the composites first element is an image
auto firstElement = composite->ItemAt(0);
{
std::cout << "composite does not contain an image at the first element\n";
continue;
}
auto image = Cvb::get<Cvb::ImagePtr>(firstElement);
auto linearAccess = image->Plane(0).LinearAccess();
std::cout << "acquired image: " << i << " at memory location: " << reinterpret_cast<intptr_t>(linearAccess.BasePtr()) << "\n";
}
}
int main()
{
try
{
// discover transport layers
auto infoList = Cvb::DeviceFactory::Discover(Cvb::DiscoverFlags::IgnoreVins);
// can't continue the demo if there's no available device
if (infoList.empty())
throw std::runtime_error("There is no available device for this demonstration.");
// instantiate the first device in the discovered list
auto device = Cvb::DeviceFactory::Open<Cvb::GenICamDevice>(infoList[0].AccessToken(), Cvb::AcquisitionStack::GenTL);
if (device->StreamCount() == 0)
throw std::runtime_error("There is no available stream for this demonstration.");
// get the first stream
auto stream = device->Stream<Cvb::CompositeStream>(0);
// get the flow set information that is needed for the current stream
auto flowSetInfo = stream->FlowSetInfo();
// create a subclass of FlowSetPool to store the created buffer
auto flowSetPoolPtr = helper::UserFlowSetPool::Create(flowSetInfo);
std::generate_n(std::back_inserter(*flowSetPoolPtr), NUM_BUFFERS, [&flowSetInfo]() {
auto flows = std::vector<void *>(flowSetInfo.size());
std::transform(flowSetInfo.begin(), flowSetInfo.end(), flows.begin(), [](Cvb::Driver::FlowInfo info) {
void* memptr = helper::aligned_alloc(info.Alignment, info.Size);
if (!memptr)
throw std::runtime_error("Failed to allocate a memory.");
return memptr;
});
return flows;
});
// register the user flow set pool
stream->RegisterExternalFlowSetPool(std::move(flowSetPoolPtr));
// start the data acquisition for that stream
stream->EngineStart();
stream->DeviceStart();
AcquireData(stream);
stream->DeviceAbort();
stream->EngineAbort();
// deregister the user flow set pool to get free buffer (releaseCallback)
stream->DeregisterFlowSetPool();
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
std::vector< FlowInfo > FlowSetInfo() const
static std::vector< DiscoveryInformation > Discover()
static std::shared_ptr< T > Open(const String &provider, AcquisitionStack acquisitionStack=AcquisitionStack::PreferVin)
std::shared_ptr< CompositeStream > CompositeStreamPtr
const variant_alternative_t< I, variant< TS... > > & get(const variant< TS... > &var)
bool holds_alternative(const variant< TS... > &var) noexcept