Impact Acquire SDK C++
ContinuousCaptureMultiPart.cpp

The ContinuousCaptureMultiPart program is based on the ContinuousCapture.cpp example concerning the acquisition implementation. The sample is intended for devices that can deliver data in the multi-part format like GigE Vision™ 2.1 (or greater) devices or the mvVirtualDevice. The sample will set up a device in a way that multi-part data will be delivered, will display the first buffer part that can be displayed and will store every buffer that is JPEG encoded into a file.

Program location
The source file ContinuousCaptureMultiPart.cpp can be found under:
%INSTALLDIR%\apps\ContinuousCaptureMultiPart\
Note
If you have installed the package without example applications, this file will not be available. On Windows® the sample application can be installed or removed from the target system at any time by simply restarting the installation package.
ContinuousCaptureMultiPart example:
  1. Opens a Balluff device.
  2. Configures the device in a way it will deliver multi-part data OR will terminate with an error message if the configuration fails
  3. Captures buffer continuously and will display(Windows®) or output information(Linux) for the first part that is actually an uncompressed image and will store every part that is JPEG compressed into a file
How it works
After getting the device from user input the sample opens the device (pDev->open()). Then the sample will try to set up the device accordingly and will make use of the mvIMPACT::acquire::helper::RequestProvider class discussed in the ContinuousCapture.cpp example application.
Source code
//
// @description: Example applications for Impact Acquire
// @copyright: Copyright (C) 2005 - 2025 Balluff GmbH
// @authors: APIs and drivers development team at Balluff GmbH
// @initial date: 2005-03-15
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#include <algorithm>
#include <functional>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <thread>
#include <apps/Common/exampleHelper.h>
#include <common/crt/mvstdio.h>
#include <mvIMPACT_CPP/mvIMPACT_acquire_GenICam.h>
#include <mvIMPACT_CPP/mvIMPACT_acquire_helper.h>
#ifdef _WIN32
# include <mvDisplay/Include/mvIMPACT_acquire_display.h>
# define USE_DISPLAY
#endif // #ifdef _WIN32
using namespace std;
using namespace mvIMPACT::acquire;
//=============================================================================
//================= Data type definitions =====================================
//=============================================================================
//-----------------------------------------------------------------------------
struct ThreadParameter
//-----------------------------------------------------------------------------
{
Device* pDev_;
unsigned int requestsCaptured_;
Statistics statistics_;
#ifdef USE_DISPLAY
ImageDisplayWindow displayWindow_;
#endif // #ifdef USE_DISPLAY
explicit ThreadParameter( Device* pDev ) : pDev_( pDev ), requestsCaptured_( 0 ), statistics_( pDev )
#ifdef USE_DISPLAY
// initialise display window
// IMPORTANT: It's NOT safe to create multiple display windows in multiple threads!!!
, displayWindow_( "mvIMPACT_acquire sample, Device " + pDev_->serial.read() )
#endif // #ifdef USE_DISPLAY
{}
ThreadParameter( const ThreadParameter& src ) = delete;
ThreadParameter& operator=( const ThreadParameter& rhs ) = delete;
};
//=============================================================================
//================= function declarations =====================================
//=============================================================================
static void configureDevice( Device* pDev );
static void configureBlueCOUGAR_X( Device* pDev );
static void configureVirtualDevice( Device* pDev );
static bool isDeviceSupportedBySample( const Device* const pDev );
static void reportProblemAndExit( Device* pDev, const string& prologue, const string& epilogue = "" );
//=============================================================================
//================= implementation ============================================
//=============================================================================
//-----------------------------------------------------------------------------
inline bool isBlueCOUGAR_X( const Device* const pDev )
//-----------------------------------------------------------------------------
{
return ( pDev->product.read().find( "mvBlueCOUGAR-X" ) == 0 ) ||
( pDev->product.read().find( "mvBlueCOUGAR-2X" ) == 0 ) ||
( pDev->product.read().find( "mvBlueCOUGAR-3X" ) == 0 );
}
//-----------------------------------------------------------------------------
// Check if all features needed by this application are actually available
// and set up these features in a way that the multi-part streaming is active.
// If a crucial feature is missing/not available this function will terminate
// with an error message.
void configureDevice( Device* pDev )
//-----------------------------------------------------------------------------
{
if( pDev->product.read() == "VirtualDevice" )
{
configureVirtualDevice( pDev );
}
else if( isBlueCOUGAR_X( pDev ) )
{
configureBlueCOUGAR_X( pDev );
}
else
{
reportProblemAndExit( pDev, "The selected device is not supported by this application!" );
}
}
//-----------------------------------------------------------------------------
void configureVirtualDevice( Device* pDev )
//-----------------------------------------------------------------------------
{
if( !cs.bufferPartCount.isValid() )
{
reportProblemAndExit( pDev, "This version of the mvVirtualDevice driver does not support the multi-part format. An update will fix this problem!" );
}
cs.bufferPartCount.write( cs.bufferPartCount.getMaxValue() );
// because every jpg image is written to disk we limit the frames per sec to 5 fps
cs.frameDelay_us.write( 200000 );
}
//-----------------------------------------------------------------------------
void configureBlueCOUGAR_X( Device* pDev )
//-----------------------------------------------------------------------------
{
// make sure the device is running with default parameters
usc.userSetSelector.writeS( "Default" );
usc.userSetLoad.call();
// now set up the device
if( !tlc.gevGVSPExtendedIDMode.isValid() )
{
reportProblemAndExit( pDev, "This device does not support the multi-part format. A firmware update will fix this problem!" );
}
//enable extended ID mode - this is mandatory in order to stream JPEG and/or multi part data
tlc.gevGVSPExtendedIDMode.writeS( "On" );
//enable JPEGWithRaw mode
ac.mvFeatureMode.writeS( "mvJPEGWithRaw" );
}
//-----------------------------------------------------------------------------
// This function will allow to select devices that support the GenICam interface
// layout(these are devices, that claim to be compliant with the GenICam standard)
// and that are bound to drivers that support the user controlled start and stop
// of the internal acquisition engine. Other devices will not be listed for
// selection as the code of the example relies on these features in the code.
bool isDeviceSupportedBySample( const Device* const pDev )
//-----------------------------------------------------------------------------
{
return ( pDev->product.read() == "VirtualDevice" ) || isBlueCOUGAR_X( pDev );
}
//-----------------------------------------------------------------------------
// Stores data that cannot be displayed into a file. Please note that at higher frame/data
// rates this might result in lost images during the capture process as storing files
// to hard-disk might be the limiting factor. Real world applications should therefore move these operations
// into a thread. It even might make sense to copy the buffer part into another RAM location
// in order to free this capture buffer as fast as possible.
void storeBufferPartToDisc( Device* pDev, const shared_ptr<Request> pRequest, const BufferPart& bufferPart, unsigned int partIndex, const string& fileExtension )
//-----------------------------------------------------------------------------
{
ostringstream oss;
oss << "Buffer.part" << partIndex
<< "id" << std::setfill( '0' ) << std::setw( 16 ) << pRequest->infoFrameID.read() << "."
<< "ts" << std::setfill( '0' ) << std::setw( 16 ) << pRequest->infoTimeStamp_us.read() << "."
<< fileExtension;
FILE* pFile = mv_fopen_s( oss.str().c_str(), "wb" );
if( pFile )
{
if( fwrite( bufferPart.address.read(), static_cast<size_t>( bufferPart.dataSize.read() ), 1, pFile ) != 1 )
{
reportProblemAndExit( pDev, "Could not write file '" + oss.str() + "'" );
}
cout << "Buffer Part handled: " << bufferPart.dataType.readS() << "(index " << partIndex << "): Stored to disc as '" << oss.str() << "'." << endl;
fclose( pFile );
}
}
//-----------------------------------------------------------------------------
void myThreadCallback( shared_ptr<Request> pRequest, ThreadParameter& threadParameter )
//-----------------------------------------------------------------------------
{
if( pRequest->isOK() )
{
const unsigned int bufferPartCount = pRequest->getBufferPartCount();
++threadParameter.requestsCaptured_;
// display some statistical information every 100th image
if( threadParameter.requestsCaptured_ % 100 == 0 )
{
const Statistics& s = threadParameter.statistics_;
cout << "Info from " << threadParameter.pDev_->serial.read();
if( bufferPartCount == 0 )
{
cout << " NOT running in multi-part mode";
}
else
{
cout << " running in multi-part mode, delivering " << bufferPartCount << " parts";
}
cout << ": " << s.framesPerSecond.name() << ": " << s.framesPerSecond.readS()
<< ", " << s.errorCount.name() << ": " << s.errorCount.readS()
<< ", " << s.captureTime_s.name() << ": " << s.captureTime_s.readS()
<< ", " << s.bandwidthConsumed.name() << ": " << ( s.bandwidthConsumed.read() / 1024 ) << " MB/s" << endl;
}
if( bufferPartCount == 0 )
{
// the device is not running in multi-part mode
#ifdef USE_DISPLAY
ImageDisplay& display = threadParameter.displayWindow_.GetImageDisplay();
display.SetImage( pRequest );
display.Update();
#else
cout << "Image captured: " << pRequest->imageOffsetX.read() << "x" << pRequest->imageOffsetY.read() << "@" << pRequest->imageWidth.read() << "x" << pRequest->imageHeight.read() << endl;
#endif // #ifdef USE_DISPLAY
}
else
{
#ifdef USE_DISPLAY
// we have just one display so only show the first buffer part that can be displayed there, output text for all others
bool boImageDisplayed = false;
ImageDisplay& display = threadParameter.displayWindow_.GetImageDisplay();
#endif // #ifdef USE_DISPLAY
for( unsigned int i = 0; i < bufferPartCount; i++ )
{
const BufferPart& bufferPart = pRequest->getBufferPart( i );
switch( bufferPart.dataType.read() )
{
{
#ifdef USE_DISPLAY
if( !boImageDisplayed )
{
display.SetImage( bufferPart.getImageBufferDesc().getBuffer() );
display.Update();
boImageDisplayed = true;
}
else
#endif // #ifdef USE_DISPLAY
{
cout << "Buffer Part handled: " << bufferPart.dataType.readS() << "(index " << i << "), dimensions: " << bufferPart.offsetX.read() << "x" << bufferPart.offsetY.read() << "@" << bufferPart.width.read() << "x" << bufferPart.height.read() << endl;
}
}
break;
case bpdtJPEG:
storeBufferPartToDisc( threadParameter.pDev_, pRequest, bufferPart, i, "jpeg" );
break;
storeBufferPartToDisc( threadParameter.pDev_, pRequest, bufferPart, i, "chunk" );
break;
storeBufferPartToDisc( threadParameter.pDev_, pRequest, bufferPart, i, "xml" );
break;
storeBufferPartToDisc( threadParameter.pDev_, pRequest, bufferPart, i, "h264" );
break;
cout << "Buffer Part" << "(index " << i << ") has an unknown data type. Skipped!" << endl;
break;
}
}
}
}
else
{
cout << "Error: " << pRequest->requestResult.readS() << endl;
}
}
//-----------------------------------------------------------------------------
// When a crucial feature needed for this example application is not available
// this function will get called. It reports an error and then terminates the
// application.
void reportProblemAndExit( Device* pDev, const string& prologue, const string& epilogue /* = "" */ )
//-----------------------------------------------------------------------------
{
cout << prologue << " by device " << pDev->serial.read() << "(" << pDev->product.read() << ", Firmware version: " << pDev->firmwareVersion.readS() << ")." << epilogue << endl
<< "Press [ENTER] to end the application..." << endl;
cin.get();
exit( 42 );
}
//-----------------------------------------------------------------------------
int main( void )
//-----------------------------------------------------------------------------
{
DeviceManager devMgr;
Device* pDev = getDeviceFromUserInput( devMgr, isDeviceSupportedBySample );
if( pDev == nullptr )
{
cout << "Unable to continue! Press [ENTER] to end the application" << endl;
cin.get();
return 1;
}
try
{
cout << "Initialising the device. This might take some time..." << endl << endl;
pDev->open();
}
catch( const ImpactAcquireException& e )
{
// this e.g. might happen if the same device is already opened in another process...
cout << "An error occurred while opening device " << pDev->serial.read()
<< "(error code: " << e.getErrorCodeAsString() << ")." << endl
<< "Press [ENTER] to end the application..." << endl;
cin.get();
return 1;
}
try
{
configureDevice( pDev );
// start the execution of the 'live' thread.
cout << "Press [ENTER] to end the application" << endl;
ThreadParameter threadParam( pDev );
helper::RequestProvider requestProvider( pDev );
requestProvider.acquisitionStart( myThreadCallback, std::ref( threadParam ) );
cin.get();
requestProvider.acquisitionStop();
}
catch( const ImpactAcquireException& e )
{
// this e.g. might happen if the same device is already opened in another process...
cout << "An error occurred while setting up device " << pDev->serial.read()
<< "(error code: " << e.getErrorCodeAsString() << ")." << endl
<< "Press [ENTER] to end the application..." << endl;
cin.get();
return 1;
}
return 0;
}
Contains information about a specific part of a captured buffer.
Definition mvIMPACT_acquire.h:8410
const ImageBufferDesc & getImageBufferDesc(void) const
Returns a const reference to the image buffer descriptor of this buffer part.
Definition mvIMPACT_acquire.h:8465
PropertyI64 dataSize
A 64-bit integer property (read-only) containing the size (in bytes) of this buffer part.
Definition mvIMPACT_acquire.h:8508
PropertyI64 width
A 64-bit integer property (read-only) containing the width of the buffer part in pixels.
Definition mvIMPACT_acquire.h:8520
PropertyI64BufferPartDataType dataType
An enumerated 64-bit integer property (read-only) containing the data type of this buffer part.
Definition mvIMPACT_acquire.h:8513
PropertyI64 offsetY
A 64-bit integer property (read-only) containing the Y-offset of the buffer part in pixels.
Definition mvIMPACT_acquire.h:8526
PropertyPtr address
A pointer property (read-only) containing the start address of this buffer part.
Definition mvIMPACT_acquire.h:8502
PropertyI64 height
A 64-bit integer property (read-only) containing the height of the buffer part in pixels.
Definition mvIMPACT_acquire.h:8522
PropertyI64 offsetX
A 64-bit integer property (read-only) containing the X-offset of the buffer part in pixels.
Definition mvIMPACT_acquire.h:8524
mvVirtualDevice related camera settings(Device specific interface layout only).
Definition mvIMPACT_acquire.h:18903
std::string name(void) const
Returns the name of the component referenced by this object.
Definition mvIMPACT_acquire.h:1206
Grants access to devices that can be operated by this software interface.
Definition mvIMPACT_acquire.h:7171
This class and its functions represent an actual device detected by this interface in the current sys...
Definition mvIMPACT_acquire.h:6118
PropertyI firmwareVersion
An integer property (read-only) containing the firmware version of this device.
Definition mvIMPACT_acquire.h:6610
PropertyS product
A string property (read-only) containing the product name of this device.
Definition mvIMPACT_acquire.h:6537
PropertyS serial
A string property (read-only) containing the serial number of this device.
Definition mvIMPACT_acquire.h:6551
void open(void)
Opens a device.
Definition mvIMPACT_acquire.h:6420
ZYX read(int index=0) const
Reads a value from a property.
Definition mvIMPACT_acquire.h:3853
ZYX read(int index=0) const
Reads a value from a property.
Definition mvIMPACT_acquire.h:4907
Category for the acquisition and trigger control features.
Definition mvIMPACT_acquire_GenICam.h:2117
Category that contains the transport Layer control features.
Definition mvIMPACT_acquire_GenICam.h:13083
Category that contains the User Set control features.
Definition mvIMPACT_acquire_GenICam.h:9634
ImageBuffer * getBuffer(void) const
Grants access to the underlying mvIMPACT::acquire::ImageBuffer structure managed by this object.
Definition mvIMPACT_acquire.h:8313
A base class for exceptions generated by Impact Acquire.
Definition mvIMPACT_acquire.h:256
std::string getErrorCodeAsString(void) const
Returns a string representation of the error associated with the exception.
Definition mvIMPACT_acquire.h:288
void * read(int index=0) const
Reads a value from a property.
Definition mvIMPACT_acquire.h:5176
std::string read(int index=0) const
Reads a value from a property.
Definition mvIMPACT_acquire.h:5323
std::string readS(int index=0, const std::string &format="") const
Reads data from this property as a string.
Definition mvIMPACT_acquire.h:3340
Contains basic statistical information.
Definition mvIMPACT_acquire.h:14517
PropertyF framesPerSecond
A float property (read-only) containing the current number of frames captured per second.
Definition mvIMPACT_acquire.h:14594
PropertyF bandwidthConsumed
A float property (read-only) containing the current bandwidth consumed by this device in KB/s based o...
Definition mvIMPACT_acquire.h:14573
PropertyF captureTime_s
A float property (read-only) containing the overall time an image request spent in the device drivers...
Definition mvIMPACT_acquire.h:14568
PropertyI errorCount
An integer property (read-only) containing the overall count of image requests which returned with an...
Definition mvIMPACT_acquire.h:14576
A class that can be used to display images in a window.
Definition mvIMPACT_acquire_display.h:606
A class that can be used for displaying images within existing windows or GUI elements that can provi...
Definition mvIMPACT_acquire_display.h:176
void SetImage(const void *pData, int width, int height, int bitsPerPixel, int pitch)
Sets the next image to display.
Definition mvIMPACT_acquire_display.h:316
void Update(void) const
Immediately redraws the current image.
Definition mvIMPACT_acquire_display.h:405
A helper class that can be used to implement a simple continuous acquisition from a device.
Definition mvIMPACT_acquire_helper.h:432
@ bpdtGDC_JPEG
JPEG image data (GenDC).
Definition TBufferPartDataType.h:134
@ bpdt3DPlaneTriplanar
Single color plane of a planar (3D) image (GenTL).
Definition TBufferPartDataType.h:86
@ bpdt3DImage
3D image (pixel coordinates) (GenTL).
Definition TBufferPartDataType.h:74
@ bpdtGDC_GenICamXML
GenICam XML data (GenDC).
Definition TBufferPartDataType.h:124
@ bpdt3DPlaneBiplanar
Single color plane of a planar (3D) image (GenTL).
Definition TBufferPartDataType.h:80
@ bpdt2DImage
Color or monochrome (2D) image (GenTL).
Definition TBufferPartDataType.h:51
@ bpdtConfidenceMap
Confidence of the individual pixel values (GenTL).
Definition TBufferPartDataType.h:99
@ bpdtJPEG
JPEG image data (GenTL).
Definition TBufferPartDataType.h:108
@ bpdtGDC_2DImage
Color or monochrome (2D) image (GenDC).
Definition TBufferPartDataType.h:129
@ bpdtUnknown
The framework is not aware of the data type of the data in the provided buffer part.
Definition TBufferPartDataType.h:46
@ bpdtGenICamChunkData
Chunk data (GenTL).
Definition TBufferPartDataType.h:106
@ bpdt3DPlaneQuadplanar
Single color plane of a planar (3D) image (GenTL).
Definition TBufferPartDataType.h:92
@ bpdt2DPlaneBiplanar
Single color plane of a planar (2D) image (GenTL).
Definition TBufferPartDataType.h:57
@ bpdtJPEG2000
JPEG 2000 image data (GenTL).
Definition TBufferPartDataType.h:110
@ bpdt2DPlaneTriplanar
Single color plane of a planar (2D) image (GenTL).
Definition TBufferPartDataType.h:63
@ bpdtGDC_JPEG2000
JPEG 2000 image data (GenDC).
Definition TBufferPartDataType.h:139
@ bpdtGDC_H264
A H.264 buffer (GenDC).
Definition TBufferPartDataType.h:146
@ bpdtGDC_GenICamChunkData
Chunk data (GenDC).
Definition TBufferPartDataType.h:117
@ bpdt2DPlaneQuadplanar
Single color plane of a planar (2D) image (GenTL).
Definition TBufferPartDataType.h:69
This namespace contains classes and functions that can be used to display images.
This namespace contains classes and functions belonging to the image acquisition module of this SDK.
Definition mvCommonDataTypes.h:34