Spinnaker SDK C++
4.2.0.21
 
 

 
Loading...
Searching...
No Matches
BufferHandling.cpp

BufferHandling.cpp shows how the different buffer handling modes work.

BufferHandling.cpp shows how the different buffer handling modes work.It relies on information provided in the Acquisition and Trigger examples.

Buffer handling determines the ordering in which images are retrieved, and what occurs when an image is transmitted while the buffer is full. There are four different buffer handling modes available; NewestFirst, NewestOnly, OldestFirst and OldestFirstOverwrite.

This example explores retrieving images in a set pattern; triggering the camera while not retrieving an image (letting the buffer fill up), and retrieving images while not triggering. We cycle through the different buffer handling modes to see which images are retrieved, confirming their identities via their Frame ID values.

Please leave us feedback at: https://www.surveymonkey.com/r/TDYMVAPI More source code examples at: https://github.com/Teledyne-MV/Spinnaker-Examples Need help? Check out our forum at: https://teledynevisionsolutions.zendesk.com/hc/en-us/community/topics

//=============================================================================
// Copyright (c) 2024 FLIR Integrated Imaging Solutions, Inc. All Rights Reserved.
//
// This software is the confidential and proprietary information of FLIR
// Integrated Imaging Solutions, Inc. ("Confidential Information"). You
// shall not disclose such Confidential Information and shall use it only in
// accordance with the terms of the license agreement you entered into
// with FLIR Integrated Imaging Solutions, Inc. (FLIR).
//
// FLIR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
// SOFTWARE, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE, OR NON-INFRINGEMENT. FLIR SHALL NOT BE LIABLE FOR ANY DAMAGES
// SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
// THIS SOFTWARE OR ITS DERIVATIVES.
//=============================================================================
#include "Spinnaker.h"
#include <iostream>
#include <sstream>
// Total number of GenTL buffers. 1-2 buffers unavailable for some buffer modes
constexpr int numBuffers = 6;
// Number of triggers to load images from camera to Spinnaker
constexpr int numTriggers = 10;
// Number of times attempted to grab an image from Spinnaker to application
constexpr int numGrabs = 10;
using namespace Spinnaker;
using namespace Spinnaker::GenApi;
using namespace Spinnaker::GenICam;
using namespace std;
// This helper function allows the example to sleep in both Windows and Linux
// systems. Note that Windows sleep takes milliseconds as a parameter while
// Linux systems take microseconds as a parameter.
void SleepyWrapper(int milliseconds)
{
#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
Sleep(milliseconds);
#else
usleep(1000 * milliseconds);
#endif
}
// This helper function determines the appropriate number of images to expect
// when running this example on various cameras and stream modes.
int GetExpectedImageCount(INodeMap& nodeMapTLDevice, INodeMap& snodeMap)
{
// Check DeviceType and only adjust count for GigEVision device
CEnumerationPtr ptrDeviceType = nodeMapTLDevice.GetNode("DeviceType");
if (IsReadable(ptrDeviceType) && ptrDeviceType->GetIntValue() == DeviceType_GigEVision)
{
// Check StreamMode
CEnumerationPtr ptrStreamMode = snodeMap.GetNode("StreamMode");
if (!IsAvailable(ptrStreamMode) || !IsReadable(ptrStreamMode))
{
cout << "Unable to get device's stream mode. Aborting..." << endl << endl;
return -1;
}
// Adjust the expected image count to account for the trash buffer in
// TeledyneGigeVision driver, where we expect one less image than the
// total number of buffers
if (ptrStreamMode->GetIntValue() == StreamMode_TeledyneGigeVision)
{
return (numBuffers - 1);
}
}
return numBuffers;
}
// This function configures the camera to use a trigger. First, trigger mode is
// set to off in order to select the trigger source. Once the trigger source
// has been selected, trigger mode is then enabled, which has the camera
// capture only a single image upon the execution of the trigger.
int ConfigureTrigger(INodeMap& nodeMap)
{
int result = 0;
cout << endl << "*** CONFIGURING TRIGGER ***" << endl;
try
{
//
// Ensure trigger mode on
//
// *** NOTES ***
// The trigger must be enabled in order to configure the
// trigger source.
//
CEnumerationPtr ptrTriggerMode = nodeMap.GetNode("TriggerMode");
if (!IsReadable(ptrTriggerMode) || !IsWritable(ptrTriggerMode))
{
cout << "Unable to enable trigger mode (node retrieval). Aborting..." << endl;
return -1;
}
CEnumEntryPtr ptrTriggerModeOn = ptrTriggerMode->GetEntryByName("On");
if (!IsReadable(ptrTriggerModeOn))
{
cout << "Unable to enable trigger mode (enum entry retrieval). Aborting..." << endl;
return -1;
}
ptrTriggerMode->SetIntValue(ptrTriggerModeOn->GetValue());
cout << endl << "Trigger mode enabled..." << endl;
// Set trigger source to software
CEnumerationPtr ptrTriggerSource = nodeMap.GetNode("TriggerSource");
if (!IsReadable(ptrTriggerSource) || !IsWritable(ptrTriggerSource))
{
cout << "Unable to get or set trigger mode (node retrieval). Aborting..." << endl;
return -1;
}
CEnumEntryPtr ptrTriggerSourceSoftware = ptrTriggerSource->GetEntryByName("Software");
if (!IsReadable(ptrTriggerSourceSoftware))
{
cout << "Unable to set trigger mode (enum entry retrieval). Aborting..." << endl;
return -1;
}
ptrTriggerSource->SetIntValue(ptrTriggerSourceSoftware->GetValue());
cout << "Trigger source set to software..." << endl;
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function retrieves a single image using the trigger. In this example,
// only a single image is captured and made available for acquisition - as such,
// attempting to acquire two images for a single trigger execution would cause
// the example to hang. This is different from other examples, whereby a
// constant stream of images are being captured and made available for image
// acquisition.
int GrabNextImageByTrigger(INodeMap& nodeMap)
{
int result = 0;
try
{
// Execute software trigger
CCommandPtr ptrSoftwareTriggerCommand = nodeMap.GetNode("TriggerSoftware");
if (!IsWritable(ptrSoftwareTriggerCommand))
{
cout << "Unable to execute trigger. Aborting..." << endl;
return -1;
}
ptrSoftwareTriggerCommand->Execute();
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function returns the camera to a normal state by turning off trigger
// mode.
int ResetTrigger(INodeMap& nodeMap)
{
int result = 0;
try
{
//
// Turn trigger mode back off
//
// *** NOTES ***
// Once all images have been captured, turn trigger mode back off to
// restore the camera to a clean state.
//
CEnumerationPtr ptrTriggerMode = nodeMap.GetNode("TriggerMode");
if (!IsReadable(ptrTriggerMode) || !IsWritable(ptrTriggerMode))
{
cout << "Unable to disable trigger mode (node retrieval). Non-fatal error..." << endl;
return -1;
}
CEnumEntryPtr ptrTriggerModeOff = ptrTriggerMode->GetEntryByName("Off");
if (!IsReadable(ptrTriggerModeOff))
{
cout << "Unable to disable trigger mode (enum entry retrieval). Non-fatal error..." << endl;
return -1;
}
ptrTriggerMode->SetIntValue(ptrTriggerModeOff->GetValue());
cout << endl << endl << "Trigger mode disabled..." << endl << endl;
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function prints the device information of the camera from the transport
// layer; please see NodeMapInfo example for more in-depth comments on printing
// device information from the nodemap.
int PrintDeviceInfo(INodeMap& nodeMap)
{
int result = 0;
cout << endl << "*** DEVICE INFORMATION ***" << endl << endl;
try
{
// Retrieve and display Device Information
CCategoryPtr category = nodeMap.GetNode("DeviceInformation");
if (IsReadable(category))
{
FeatureList_t features;
category->GetFeatures(features);
for (FeatureList_t::const_iterator it = features.begin(); it != features.end(); ++it)
{
CNodePtr pfeatureNode = *it;
cout << pfeatureNode->GetName() << " : ";
CValuePtr pValue = (CValuePtr)pfeatureNode;
cout << (IsReadable(pValue) ? pValue->ToString() : "Node not readable");
cout << endl;
}
}
else
{
cout << "Device control information not readable." << endl;
}
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function cycles through the four different buffer handling modes.
// It saves three images for three of the buffer handling modes
// (NewestFirst, OldestFirst, and OldestFirstOverwrite). For NewestOnly,
// it saves one image.
int AcquireImages(const CameraPtr& pCam, INodeMap& nodeMap, INodeMap& nodeMapTLDevice)
{
int result = 0;
cout << endl << "*** IMAGE ACQUISITION ***" << endl << endl;
try
{
// Set acquisition mode to continuous
CEnumerationPtr ptrAcquisitionMode = nodeMap.GetNode("AcquisitionMode");
if (!IsReadable(ptrAcquisitionMode) || !IsWritable(ptrAcquisitionMode))
{
cout << "Unable to set acquisition mode to continuous (node retrieval). Aborting..." << endl << endl;
return -1;
}
CEnumEntryPtr ptrAcquisitionModeContinuous = ptrAcquisitionMode->GetEntryByName("Continuous");
if (!IsReadable(ptrAcquisitionModeContinuous))
{
cout << "Unable to set acquisition mode to continuous (entry 'continuous' retrieval). Aborting..." << endl
<< endl;
return -1;
}
ptrAcquisitionMode->SetIntValue(ptrAcquisitionModeContinuous->GetValue());
cout << "Acquisition mode set to continuous..." << endl;
// Set pixel format to mono8
CEnumerationPtr ptrPixelFormat = nodeMap.GetNode("PixelFormat");
if (!IsWritable(ptrPixelFormat))
{
cout << "Unable to set Pixel Format mode (node retrieval). Aborting..." << endl << endl;
return false;
}
CEnumEntryPtr ptrMono8 = ptrPixelFormat->GetEntryByName("Mono8");
if (!IsReadable(ptrMono8))
{
cout << "Unable to set pixel format (entry 'mono8' retrieval). Aborting..." << endl << endl;
return false;
}
ptrPixelFormat->SetIntValue(ptrMono8->GetValue());
cout << "Pixel format set to " << ptrPixelFormat->GetCurrentEntry()->GetName() << endl;
// Retrieve device serial number for filename
gcstring deviceSerialNumber("");
CStringPtr ptrStringSerial = nodeMapTLDevice.GetNode("DeviceSerialNumber");
if (IsReadable(ptrStringSerial))
{
deviceSerialNumber = ptrStringSerial->GetValue();
cout << "Device serial number retrieved as " << deviceSerialNumber << "..." << endl;
}
// Retrieve Stream Parameters device nodemap
Spinnaker::GenApi::INodeMap& sNodeMap = pCam->GetTLStreamNodeMap();
// Retrieve Buffer Handling Mode Information
CEnumerationPtr ptrHandlingMode = sNodeMap.GetNode("StreamBufferHandlingMode");
if (!IsReadable(ptrHandlingMode) || !IsWritable(ptrHandlingMode))
{
cout << "Unable to set Buffer Handling mode (node retrieval). Aborting..." << endl << endl;
return -1;
}
CEnumEntryPtr ptrHandlingModeEntry = ptrHandlingMode->GetCurrentEntry();
if (!IsReadable(ptrHandlingModeEntry))
{
cout << "Unable to get Buffer Handling mode (Entry retrieval). Aborting..." << endl << endl;
return -1;
}
// Set stream buffer Count Mode to manual
CEnumerationPtr ptrStreamBufferCountMode = sNodeMap.GetNode("StreamBufferCountMode");
if (!IsReadable(ptrStreamBufferCountMode) || !IsWritable(ptrStreamBufferCountMode))
{
cout << "Unable to get or set Buffer Count Mode (node retrieval). Aborting..." << endl << endl;
return -1;
}
CEnumEntryPtr ptrStreamBufferCountModeManual = ptrStreamBufferCountMode->GetEntryByName("Manual");
if (!IsReadable(ptrStreamBufferCountModeManual))
{
cout << "Unable to get Buffer Count Mode entry (Entry retrieval). Aborting..." << endl << endl;
return -1;
}
ptrStreamBufferCountMode->SetIntValue(ptrStreamBufferCountModeManual->GetValue());
cout << "Stream Buffer Count Mode set to manual..." << endl;
// Retrieve and modify Stream Buffer Count
CIntegerPtr ptrBufferCount = sNodeMap.GetNode("StreamBufferCountManual");
if (!IsReadable(ptrBufferCount) || !IsWritable(ptrBufferCount))
{
cout << "Unable to get or set Buffer Count (Integer node retrieval). Aborting..." << endl << endl;
return -1;
}
// Display Buffer Info
cout << endl << "Default Buffer Handling Mode: " << ptrHandlingModeEntry->GetDisplayName() << endl;
cout << "Default Buffer Count: " << ptrBufferCount->GetValue() << endl;
cout << "Maximum Buffer Count: " << ptrBufferCount->GetMax() << endl;
ptrBufferCount->SetValue(numBuffers);
cout << "Buffer count now set to: " << ptrBufferCount->GetValue() << endl;
cout << endl
<< "Camera will be triggered " << numTriggers << " times in a row, followed by " << numGrabs
<< " image retrieval attempts" << endl;
cout << endl << "Note - Buffer behaviour is different for USB3 and GigE cameras" << endl;
cout << " - USB3 cameras buffer images internally if no host buffers are available" << endl;
cout << " - Once the stream buffer is released, the USB3 camera will fill that buffer" << endl;
cout << " - GigE cameras do not buffer images" << endl;
cout << " - In TeledyneGigEVision stream mode an extra buffer will be reserved for trashing" << endl;
const std::vector<gcstring> bufferHandlingModes = {
"NewestFirst", "OldestFirst", "NewestOnly", "OldestFirstOverwrite"};
for (unsigned int i = 0; i < bufferHandlingModes.size(); i++)
{
ptrHandlingModeEntry = ptrHandlingMode->GetEntryByName(bufferHandlingModes[i]);
ptrHandlingMode->SetIntValue(ptrHandlingModeEntry->GetValue());
const std::string bufferModeName = ptrHandlingMode->GetCurrentEntry()->GetDisplayName().c_str();
cout << endl << endl << "*** Buffer Handling Mode has been set to " << bufferModeName << " ***" << endl;
// Begin capturing images
pCam->BeginAcquisition();
// Sleep for one second; only necessary when using non-BFS/ORX cameras on startup
if (i == 0)
{
}
try
{
for (int j = 0; j < numTriggers; j++)
{
// Retrieve the next image from the trigger
result = result | GrabNextImageByTrigger(nodeMap);
// Control framerate
}
cout << endl << "Camera triggered " << numTriggers << " times" << endl;
cout << endl << "Retrieving images from library until no image data is returned (errors out)" << endl;
// Software Trigger the camera then save images
for (int j = 1; j < numGrabs; j++)
{
// Create a unique filename
ostringstream filename;
filename << ptrHandlingModeEntry->GetSymbolic() << "-";
if (!deviceSerialNumber.empty())
{
filename << deviceSerialNumber.c_str() << "-";
}
filename << j << ".jpg";
const ImagePtr pResultImage = pCam->GetNextImage(500);
if (pResultImage->IsIncomplete())
{
cout << "Image #" << j << " incomplete with image status " << pResultImage->GetImageStatus()
<< "..." << endl
<< endl;
}
// Retrieve and Save image
pResultImage->Save(filename.str().c_str());
cout << "GetNextImage() #" << j << ", Frame ID: " << pResultImage->GetFrameID()
<< ", Image saved at " << filename.str() << endl;
// Release image
pResultImage->Release();
}
}
{
cout << "Error: " << e.what() << endl << endl;
if (ptrHandlingModeEntry->GetSymbolic() == "NewestFirst" ||
ptrHandlingModeEntry->GetSymbolic() == "OldestFirst")
{
// In this mode, one buffer is used to cycle images within spinnaker acquisition engine.
// Only numBuffers - 1 images will be stored in the library; additional triggered images will be
// dropped.
// Calling GetNextImage() more than buffered images will return an error.
// Note: These two modes differ in the order of images returned.
const unsigned int expectedImageCount = GetExpectedImageCount(nodeMapTLDevice, sNodeMap);
cout << endl << "EXPECTED: error getting image # " << expectedImageCount + 1
<< " with handling mode set "
"to NewestFirst or OldestFirst in GigE Streaming"
<< endl;
}
else if (ptrHandlingModeEntry->GetSymbolic() == "NewestOnly")
{
// In this mode, a single buffer is overwritten if not read out in time
cout << endl << "EXPECTED: error occur when getting image #2 with handling mode set to NewestOnly" << endl;
}
if (ptrHandlingModeEntry->GetSymbolic() == "OldestFirstOverwrite")
{
// In this mode, two buffers are used to cycle images within
// the spinnaker acquisition engine. Only numBuffers - 2 images will return to the user.
// Calling GetNextImage() without additional triggers will return an error
cout << endl << "EXPECTED: error occur when getting image #" << numBuffers - 1
<< " with handling mode set to"
" OldestFirstOverwrite"
<< endl;
}
result = -1;
}
// End acquisition
pCam->EndAcquisition();
}
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// This function acts as the body of the example; please see NodeMapInfo example
// for more in-depth comments on setting up cameras.
int RunSingleCamera(const CameraPtr& pCam)
{
int result = 0;
int err = 0;
try
{
// Retrieve TL device nodemap and print device information
INodeMap& nodeMapTLDevice = pCam->GetTLDeviceNodeMap();
result = PrintDeviceInfo(nodeMapTLDevice);
// Initialize camera
pCam->Init();
// Retrieve GenICam nodemap
INodeMap& nodeMap = pCam->GetNodeMap();
// Configure trigger
err = ConfigureTrigger(nodeMap);
if (err < 0)
{
return err;
}
// Acquire images
result = result | AcquireImages(pCam, nodeMap, nodeMapTLDevice);
// Reset trigger
result = result | ResetTrigger(nodeMap);
// Deinitialize camera
pCam->DeInit();
}
{
cout << "Error: " << e.what() << endl;
result = -1;
}
return result;
}
// Example entry point; please see Enumeration example for more in-depth
// comments on preparing and cleaning up the system.
int main(int /*argc*/, char** /*argv*/)
{
// Since this application saves images in the current folder
// we must ensure that we have permission to write to this folder.
// If we do not have permission, fail right away.
FILE* tempFile = fopen("test.txt", "w+");
if (tempFile == nullptr)
{
cout << "Failed to create file in current folder. Please check "
"permissions."
<< endl;
cout << "Press any key to exit..." << endl;
cin.ignore();
return -1;
}
fclose(tempFile);
remove("test.txt");
int result = 0;
// Print application build information
cout << "Application build date: " << __DATE__ << " " << __TIME__ << endl << endl;
// Retrieve singleton reference to system object
SystemPtr system = System::GetInstance();
// Retrieve list of cameras from the system
CameraList camList = system->GetCameras();
unsigned int numCameras = camList.GetSize();
cout << "Number of cameras detected: " << numCameras << endl << endl;
// Finish if there are no cameras
if (numCameras == 0)
{
// Clear camera list before releasing system
camList.Clear();
// Release system
system->ReleaseInstance();
cout << "Not enough cameras!" << endl;
cout << "Done! Press any key to exit..." << endl;
cin.ignore();
return -1;
}
// Run example on each camera
for (unsigned int i = 0; i < numCameras; i++)
{
cout << endl << "Running example for camera " << i << "..." << endl;
result = result | RunSingleCamera(camList.GetByIndex(i));
cout << "Camera " << i << " example complete..." << endl << endl;
}
// Clear camera list before releasing system
camList.Clear();
// Release system
system->ReleaseInstance();
cout << endl << "Done! Press any key to exit..." << endl;
cin.ignore();
return result;
}
int AcquireImages(CameraPtr pCam, INodeMap &nodeMap, INodeMap &nodeMapTLDevice)
Definition Acquisition.cpp:199
int main(int, char **)
Definition Acquisition.cpp:527
int RunSingleCamera(CameraPtr pCam)
Definition Acquisition.cpp:479
int PrintDeviceInfo(INodeMap &nodeMap)
Definition Acquisition.cpp:441
void SleepyWrapper(int milliseconds)
Definition AcquisitionMultipleCameraRecovery.cpp:144
int ConfigureTrigger(INodeMap &nodeMap)
Definition BufferHandling.cpp:103
int GrabNextImageByTrigger(INodeMap &nodeMap)
Definition BufferHandling.cpp:170
constexpr int numGrabs
Definition BufferHandling.cpp:52
constexpr int numTriggers
Definition BufferHandling.cpp:49
constexpr int numBuffers
Definition BufferHandling.cpp:46
int GetExpectedImageCount(INodeMap &nodeMapTLDevice, INodeMap &snodeMap)
Definition BufferHandling.cpp:73
int ResetTrigger(INodeMap &nodeMap)
Definition BufferHandling.cpp:197
Used to hold a list of camera objects.
Definition CameraList.h:42
void Clear()
Clears the list of cameras and destroys their corresponding reference counted objects.
CameraPtr GetByIndex(unsigned int index) const
Returns a pointer to a camera object at the "index".
unsigned int GetSize() const
Returns the size of the camera list.
A reference tracked pointer to a camera object.
Definition CameraPtr.h:44
The Exception object represents an error that is returned from the library.
Definition Exception.h:51
virtual const char * what() const
virtual override for what().
Encapsulates a GenApi pointer dealing with the dynamic_cast automatically.
Definition Pointer.h:75
Definition GCString.h:43
A reference tracked pointer to an image object.
Definition ImagePtr.h:46
A reference tracked pointer to a system object.
Definition SystemPtr.h:44
bool IsWritable(EAccessMode AccessMode)
Tests if writable.
Definition INode.h:277
bool IsReadable(EAccessMode AccessMode)
Tests if readable.
Definition INode.h:253
interface SPINNAKER_API_ABSTRACT INodeMap
Interface to access the node map.
Definition INodeMap.h:54
Definition Autovector.h:36
Definition GCString.h:31
Definition BasePtr.h:24