Common Vision Blox 15.1
Loading...
Searching...
No Matches
GigE Vision Server


 C++ 

 .Net API (C#) 

 Python 
 Cvb::GevServer   Stemmer.Cvb.GevServer   cvb.gevserver 

Introduction

The Common Vision Blox GigE Vision Server (CVB GEV Server) presents any source of data, like a frame grabber or proprietary camera, images, or even merged containers of different types and sources, as a GigE Vision camera.

Functionality

Using the CVB GEV Server can be as simple as assigning an image source and starting the server. The tool takes care of the rest. However, if you wish, you also have the option of fine-tuning its behavior, from defining custom payload containers and image preprocessing to defining your own GenICam GenAPI functions. The latter allows you to easily control the PC and hardware running the CVB GEV Server remotely.

Key Facts

  • Function: The CVB GigE Vision Server provides streaming and device/camera control services over a Gigabit Ethernet network.
  • Client-Server Model:
    • Client: The host that receives image data and controls the server.
    • Server: The machine that produces the stream and responds to client commands.
  • NIC Details:
    • Identified by a unique MAC address and requires an assigned IP address.
    • Each interface has a subnet mask defining the logical network.
  • Visibility:
    • Only devices in the same subnet can see each other.
    • Automatic GigE Vision discovery works within one subnet.
  • Protocols:
    • UDP for fast data transfer.
    • GEV protocol adds camera control and streaming functionality.
    • GenICam: Provides a generic interface for camera features and control.

Usage

GigE Vision Server Creation Process

A CVB GEV Server instance acts as one GEV camera using one NIC. Only one instance is allowed per IP address; One instance can send one data stream. The following steps describe the typical process of a CVB GEV Server instance:

Which version to use?

If the device only holds a static or dynamically scalable image, no complex payload is needed and no chunk is needed, the simple Cvb::GevServer::Server class can be used. It provides all necessary functionality to stream images and control the server via GenICam features. If the device needs to stream complex payloads, e.g. multiple images, 3D point clouds, metadata (chunk) or other data types, the Cvb::GevServer::ServerGev3 class must be used. It is fully compliant with the GigE Vision 3.0 standard and uses GenDC as the payload format. This is currently only available in CVB++.

Gev Server Lifetime

Each server - regardless of the class used - has a lifetime consisting of the following phases:

1. Creation

Before anything can be done a CVB GEV Server instance has to be created. There are two versions available:

  1. Cvb::ServerGev3, where all use cases can be accomplished
  2. Cvb::Server, where several simple cases can be done.

The latter one can be instantiated with the following three functions:

#include <cvb/gevserver/server.hpp>
#include <cvb/gevserver/stream.hpp>
// a server instance without stream
// OR a server with a stream with fixed input image size
auto server = Cvb::GevServer::Server::CreateWithConstSize(<parameters>);
// OR a server with a stream with variable input image size
static ServerPtr CreateNonStreaming()
static ServerPtr CreateWithVariableSize(Size2D< int > maxSize, ColorModel colorModel, DataType dataType, GevServer::DriverType driverType=GevServer::DriverType::Auto)
static ServerPtr CreateWithConstSize(Size2D< int > size, PfncFormat pixelFormat, GevServer::DriverType driverType=GevServer::DriverType::Auto)

using Cvb;
// a server instance without stream
var server = GevServer();
// OR a server with a stream with fixed input image size
var server = GevServer.CreateWithConstSize(<params>);
// a server with a stream with variable input image size
var server = GevServer.CreateWithVariableSize(<params>);

import cvb
import cvb.gevserver as gs
# a server instance without stream
server = gs.Server.create_non_streaming()
# OR a server with a stream with fixed input image size
server = gs.Server.create_with_variable_size(<parameters>)
# OR a server with a stream with variable input image size
server = gs.Server.create_with_const_size(<paarameters>)

where

  • a non streaming server has no image source assigned and thus no stream channel,
  • a const size server has an image source assigned with a fixed image size (width, height and color/pixel format), and
  • a variable size server is initialized with a maximum image size, where width and height can be configured by the user.

For total freedom with respect to the transferred payload type, size and format, the Cvb::ServerGev3 class can be used. It uses the payload format GenDC, where different payloads are fused to a single container format. This class (currently CVB++ only) is instantiated like this:

#include <cvb/gevserver/stream_gev3.hpp>
// a GEV 3.0 compatible server with a GenDC stream
serverGev3 = Cvb::GevServer::ServerGev3::Create(<parameters>);
static ServerGev3Ptr Create(GevServer::DriverType driverType)

When a server instance is created the following happens: By default the server determines the fastest available transfer driver (filter or socket driver). No IP address is assigned to the server at this time and thus the server is not running yet.

2. Configuration

After creating a CVB GEV Server instance the server is in the configuration phase. In this phase the image source can be set, the acquisition mode can be changed and/or GenICam features can be added.

3. Startup

After the configuration is finished the server has to be started. Now the CVB GEV Server library dynamically creates a GenICam XML description for the current instance. After that is done the server goes online in an idle state. Each server object has a function ".Start()" which opens the service on the given IP.

auto ip = Cvb::NetworkConnection::IPAdress("10.10.10.10");
auto server.Start(ip);

using System.Net;
var ip = IPAddress.Parse("10.10.10.10");
server.Start(ip);

ip = "10.10.10.10"
server.start(ip)

4. Discovery:

On the client side, the CVB GEV Server is available on discovery (if correctly configured).

5. Connection:

As soon as a client connects the server goes to the Connected state. There is always only one controlling client to which the acquisition control is transferred to. As long as the connection exists no other client can connect to the server. When the client starts the acquisition the server state changes to Acquiring. The state of the server can be queried with

auto state = server.State();

var state = server.State;

state = server.state()

6. Sending

A started server now can handle payload sending. This is done by issuing sending requests to the server instance. The simple server stream accepts the payload object directly. The payload must fulfill the configuration of the server (maximum image size and pixel format). A Cvb::Image can be pushed to the server stream as follows:

// Non-throwing
server.Stream()->TrySend(*image);
// or throwing
server.Stream()->Send(*image);

// Non-throwing
server.Stream.TrySend(image);
// or throwing
server.Stream.Send(image);

# Non-throwing
server.stream.try_send(image)
# or throwing
server.stream.send(image)

GenDC payloads require a different handling, as fully described in this section.

7. Receiving

The client streaming can be implemented as described in the Acquisition and Configuration chapter.

8. Stopping

When the acquisition is stopped by the client, the server goes back to the Connected state. The server can be stopped by the application at any time. This will close the connection to the client and stop the service. The server can be started again after that.

server.Stop();

server.Stop();

server.stop()

Startup Options and Configuration

Different modes and options are available to configure the CVB GEV Server instance. The following sections describe the most important ones.

Driver Type

The transfer driver is referred to as the driver type in the CVB GEV Server interface. It defines which driver is used to stream images to the client. The two possibilities are:

  • Filter Driver
    This is the default driver to be used. It yields the best performance and lower CPU load for transfers to a remote PC.
  • Socket Driver
    If you want to use the CVB GEV Server on the same PC where your client application is running you cannot use the Filter Driver, because the operating system redirects the packets in the IP stack before they reach the Filter Driver. To be able to acquire images, use the Socket Driver both in the server and the client application.

If installed, the CVB GEV Server uses the Filter Driver by default. If not, it automatically falls back to the Socket Driver. The driver type is specified when the server instance is created and cannot be changed afterwards. Also ServerGev3 currently only supports the Socket Driver. If possible, use the filter driver as it minimizes the overhead of the normal Windows IP stack and reduces the CPU load significantly. Only use the Socket Driver if for example loopback transfer is needed.

GenDC Payload Description and FlowSet Pool Registration

In the ServerGev3 class the payload is predefined via a GenDC descriptor. A detailed introduction in the usage within CVB can be found in this chapter.

Flow Set Pool registration

For the correct operation a GenDC descriptor and a matching flow set pool must be registered to the server instance before starting it. The flow set pool defines how many buffers of which size are preallocated for the streaming. This pool is then iteratively used for sending payloads. A GenDC descriptor has to be defined to communicate the payload format and size to the user. The GenDC descriptor - by definition of the standard - always starts at the beginning of a sent buffer. Both descriptor and pool must be compatible with regards to flow counts and sizes. See this example (Step 1, 2, 3 and 6) on how to create flow set pools from a given flow set info. The registration in code is done as follows:

std::vector<GenDcDescriptorPartConfig> parts;
// Define one 2D image part
Driver::GenDcDescriptorPartConfig imagePart(
GenDCPartType::Part2D,
PfncFormat::Mono8, // PFNC pixel format
0, // Flow ID
0, // Flow offset
640*480 // Data size in bytes
);
// attach the part to the array of parts for this component
parts.emplace_back(imagePart);
// pass the parts to a component, with meta information
Driver::GenDcDescriptorComponentConfig component{ComponentId::Intensity, PfncFormat::Mono8, parts};
// append component to descriptor config
Driver::GenDcDescriptorConfig descriptorConfig;
// to the array of components
descriptorConfig.Components.emplace_back(component);
// create descriptor from this configuration
const auto customDesc = Driver::GenDcDescriptor::Create(descriptorConfig);
// accordingly define storage properties
const auto flowCount = 2; // one flow for the descriptor, one for the image
const auto alignment = 1; // one byte alignment
// create flow information for this payload
std::vector<FlowInfo> infos{flowCount, {0, alignment}};
// let the first flows size be the size of a descriptor
infos[0].Size = customDesc->GetDescriptorSize();
auto inputPartHeader = prefetchDescriptorInput->GetComponents()
.at(componentIdx)
.GetParts()
.at(0);
// let the second flows size be the size of the image (tops)
infos[1].Size = Cvb::visit([](const GenDcPart &part) -> size_t { return part.GetDataSize(); }, inputPartHeader);
// based on the given info, create the flow set pool for sending.
// (...)
// with a callback a user is informed about the flow set pool end of life
auto onReleaseCallback[]() { std::cout << "Flow set pool released" << std::endl; }
// register everything to the server
server->RegisterFlowSetPool(*customDesc, flowSetPool, onReleaseCallback);

In this example a simple GenDC descriptor with one image part is created. The flow set pool is created with two flows, one for the descriptor and one for the image data. The flow sizes must match the sizes defined in the descriptor. Finally, the descriptor and flow set pool are registered with the server instance. After that, the server can be started.

Note
For more efficient storage usage and less copies, flow set pools of input devices (such as another camera) can be reused for sending. For this, allocate external memory, register it to a acquisition stream and reuse the flows in the GEV Server within a sending scenario.

Sending GenDC Payloads

If the payload is a GenDC payload, the sending is defined by issuing the desired flow set index to the server stream, which was previously filled with data. The flow set index is the index of the flow set in the flow set pool, which was registered with the server instance. As within GenDC the data size can vary, a vector of sizes has to be passed with the actual fill levels of the flows to be sent. Then, the sending is done as follows:

// the callback helps informing the sender about the possibility to use the flow set again.
auto onSendSuccessCallback[]() { std::cout << "Sending successful" << std::endl; }
// here, for simplicity the original sizes are given.
std::vector<size_t> actualSendSizes{customDesc->GetDescriptorSize(), imageDataSize};
// with a controlled logic flow set indices have to be chosen, not to use the same flow set concurrently.
serverGev3->Stream()->SendFlowSet(flowSetIndex, actualSendSizes, onSendSuccessCallback);

GenICam Features

The CVB GEV Server provides an interface to create and modify GenICam GenAPI Features presented to the client. This chapter gives an instruction how to work with these features and how they can be accessed by an application using the CVB GigE Vision Server library. See the chapter about GenICam for a detailed introduction on the GenICam standard behind the API.

CVB GigE Vision Server and the GenICam Features

GEV Server creates the minimum needed set of nodes that is required to connect to the CVB GEV Server and for acquisition is provided. So only the application specific custom features have to be provided.

Available Feature Types

Currently the following node types are available in the CVB GEV Server and can be created by the user inside the server application.

Node Type Description
Boolean Node A boolean node represents a true/false value.
Category Node A Category node is useful to group features and is normally only used in user interfaces. In the GenICam Browser they appear as top level category for a set of leaf nodes.
Command Node A Command node is used to submit commands to the device. Commands are used for prolonged actions which are executed asynchronously.
Enumeration and EnumEntry Nodes A predefined set of symbolic (string) values which are mapped to an integer number Enumeration nodes.
Integer and IntReg Nodes Integer nodes represent integer values. IntReg nodes are backed in the register map.
IntSwissKnife Node To perform mathematical computations on the client side, not on a low computational power cam.
StringReg Node To store ASCII strings.
ChunkIntRegister Node To attach integer values from the chunk data.
ChunkFloatRegister Node To attach floating point values from the chunk data.

Those nodes are always assigned to the servers node map. On the user side, they appear within the "Device" node map which is automatically created by the CVB GEV Server.

Special Nodes

Every node map regardless of transport technology used has three mandatory nodes. Depending on the associated device there can be more mandatory nodes.

Root Category

The root category is the first node for a graphical user interface to access. With this node it queries which nodes are available. Thus every node that should be publicly accessible must be within this category. Also it is recommended to only have Category nodes as the direct children of the Root category which resemble the names of the GenICam Standard Features Naming Convention document.

TLParamsLocked Integer

This integer node is used by the transport layer to lock all features which have an effect on the payload size. The payload size is the overall frame size transferred by the camera. This is necessary to make sure that the preallocated buffers stay valid as long as streaming is in progress. Thus if you have a feature which must not be changed when the server is sending data you can use the TLParamsLocked node in the. Locked features which are readable and writable become read-only. Write-only features become not available (e.g. Command nodes).

Node creation in code

Nodes can be created and added to the server node map as follows:

auto catNode =
Cvb::GevServer::CategoryNode::Create(CVB_LIT("Cust::CustomFeatures"));
server->NodeMap()->AddNode(catNode);
catNode->SetDisplayName(CVB_LIT("Custom Features"));
catNode->SetToolTip(CVB_LIT("Contains all application defined features."));
auto rootNode = server->NodeMap()->Node(CVB_LIT("Root"));
rootNode->Add(catNode, Cvb::GevServer::NodeList::Child);
windowStateRegNode =
Cvb::GevServer::Int32RegNode::Create(CVB_LIT("Cust::WindowStateReg"));
server->NodeMap()->AddNode(windowStateRegNode);
windowStateRegNode->SetVisibility(Cvb::GenApi::Visibility::Invisible);
windowStateRegNode->SetCacheMode(Cvb::GenApi::CacheMode::NoCache);
windowStateRegNode->SetPollingTime<float, std::ratio<1, 1000>>(
std::chrono::duration<float, std::ratio<1, 1000>>(333));
windowStateRegNode->SetValue(1); // View in normal mode
windowStateRegNode->RegisterEventWrittenUpdated(
[this](const Cvb::GevServer::ValueNode &value) {
OnWindowSizeChanged(value);
});
auto enumerationNode =
Cvb::GevServer::EnumerationNode::Create(CVB_LIT("Cust::WindowState"));
server_->NodeMap()->AddNode(enumerationNode);
enumerationNode->SetDisplayName(CVB_LIT("Window State"));
enumerationNode->SetToolTip(
CVB_LIT("Current window state of server application."));
enumerationNode->SetValueConfig<Cvb::GevServer::IntegerBaseNodePtr>(
windowStateRegNode);
auto minimized =
Cvb::GevServer::EnumEntryNode::Create(CVB_LIT("Cust::Minimized"));
minimized->SetNumericValue(0);
enumerationNode->Add(minimized, Cvb::GevServer::NodeList::Child);
auto normalNode =
Cvb::GevServer::EnumEntryNode::Create(CVB_LIT("Cust::Normal"));
normalNode->SetNumericValue(1); // Must be ascending entry in vector
enumerationNode->Add(normalNode, Cvb::GevServer::NodeList::Child);
auto maxNode =
Cvb::GevServer::EnumEntryNode::Create(CVB_LIT("Cust::Maximized"));
maxNode->SetNumericValue(2); // Must be ascending entry in vector
enumerationNode->Add(maxNode, Cvb::GevServer::NodeList::Child);
catNode->Add(enumerationNode, Cvb::GevServer::NodeList::Child);
static CategoryNodePtr Create(const String &name, const GevServer::Namespace &nameSpace)
static EnumEntryNodePtr Create(const String &name, const GevServer::Namespace &nameSpace)
static EnumerationNodePtr Create(const String &name, const GevServer::Namespace &nameSpace)
static Int32RegNodePtr Create(const String &name, const GevServer::Namespace &nameSpace, const std::int64_t &address)
std::shared_ptr< IntegerBaseNode > IntegerBaseNodePtr

Device and XML Description Versions

The main identification of the CVB GEV Server is the vendor and model name. To distinguish between different versions or instances of the tool the Device Version field is used. If you do not add your own custom features you do not need to change the user version. By default the CVB GEV Server device version is its DLL version. If custom features are added it is recommended to enter an additional user version which makes this instance with its feature set uniquely identifiable. If this is not done, different xml descriptions can lead to invalid register access. The user version can be set on the CVB GEV Server object with

server.SetUserVersion("MyCustomVersion_1.0");

server.UserVersion = "MyCustomVersion_1.0";

server.user_version = "MyCustomVersion_1.0"

GEV Server Configuration

Several configuration options are available to tune the behavior of the CVB GEV Server. The most important ones are described in the following sections.

Packet Size

On the receiving side larger packet sizes reduce the CPU load. The same is true for the sender and thus the server side. The larger the packets the fewer packets need to be sent. This reduces the number of events to be processed and it improves the net transfer rate as fewer header data needs to be sent.

Firewalls

Applications using the CVB GEV Server library need at least full access rights in a firewall for the entire application. Ports are requested dynamically from the system for streaming data and therefore a simple port rule would not be sufficient. Per application settings for a local firewall also introduce a significant performance penalty as the firewall still has to touch all the packets to check which is the sending/receiving application. It is recommended to use a dedicated network card for the image data transfer and disable the firewall for the whole interface.

Examples

Example Description
QMLGevServer (C++ version) The QmlGevServer example starts a QML GevServer which can load a device and stream the device image. (QML C++ version)
CLIGevServerSpeedtest Speed test with predefined payloads
QMLGevServer (Python version) The QmlGevServer example starts a QML GevServer which can load a device and stream the device image. (QML Python version)