A PvDeviceInfo object serves to identify a discovered GigE Vision or USB3 Vision device and holds its essential connection parameters. This information is then crucial for establishing communication links to control the device and stream data from it using the eBUS SDK.
Generally, we prefer to use "=" to directly obtain a pointer to an object. However, the PvDeviceInfo object retrieved from the PvInterface object via PvSystem is a temporary object.This may lead to some issues, let us illustrate with an example.
First, we create a structure to manage the necessary information for the camera.
typedef std::vector<const PvDeviceInfo *> PvDeviceInfoVector;//Convenient storage of PvDeviceInfo objects obtained from the PvSystem
//
// Structure: Used to manage resources and status for a single camera
//
struct CameraContext
{
PvString mConnectionID; // Connection ID
const PvDeviceInfo* mDeviceInfo; // Pointer to device information (used to get serial number, etc.)
std::string mSerialNumber; // Stores the device serial number
PvDevice* mDevice; // Device object pointer
PvStream* mStream; // Stream object pointer
PvPipeline* mPipeline; // Pipeline object pointer
bool mConnectionLost; // Connection lost flag
bool mTriggerEnabled; // Whether sending trigger commands is allowed
bool mIsGEV; // Whether it is a GigE Vision device
int mIndex; // Camera index
// Constructor initialization
CameraContext()
: mDeviceInfo(nullptr)
, mDevice(nullptr)
, mStream(nullptr)
, mPipeline(nullptr)
, mConnectionLost(false)
, mTriggerEnabled(true) // Triggering is enabled by default
, mIsGEV(false)
, mIndex(-1)
{
}
};
std::vector<CameraContext> mCameras; //Mange all cameras
The process of obtaining camera information.
Please pay attention to the two methods of obtaining the *PvDeviceInfo object in the code:
Method 1:mCameras[i].mDeviceInfo = vDeviceInfos[i];
Method 2:mCameras[i].mDeviceInfo = vDeviceInfos[i]->Copy();
bool MultiCameraApp::SelectDevices()
{
cout << "--> SelectDevices (" << NUM_CAMERAS << " cameras)" << endl;
PvSystem lSystem;
lSystem.Find();
PvDeviceInfoVector vDeviceInfos;
for (uint32_t i = 0; i < lSystem.GetInterfaceCount(); i++)
{
const PvInterface *lInterface = lSystem.GetInterface(i);
if (lInterface == nullptr) {
continue;
}
// Iterate through all devices on the interface.
for (uint32_t j = 0; j < lInterface->GetDeviceCount(); j++)
{
const PvDeviceInfo *lDeviceInfo = lInterface->GetDeviceInfo(j);
if (lDeviceInfo != nullptr) {
// Only add accessible devices
if (lDeviceInfo->IsConfigurationValid())
{
vDeviceInfos.push_back(lDeviceInfo);
}
}
}
}
// --- Select the first NUM_CAMERAS devices found ---
for (int i = 0; i < NUM_CAMERAS; ++i)
{
// Store the information into the CameraContext structure
/* Store PvDeviceInfo */
//mCameras[i].mDeviceInfo = vDeviceInfos[i]; //Method 1: Typically, the pointer is copied directly. However, this PvDeviceInfo pointer is a temporary variable, and its usage in other functions may lead to program crashes. Nevertheless, it functions normally within this function.
mCameras[i].mDeviceInfo = vDeviceInfos[i]->Copy();//Method 2: Using the copy function in PvDeviceInfo creates a duplicate of a PvDeviceInfo object, which is not a temporary object and can be utilized in other functions. You may refer to the first additional line of code in the MultiCameraApp::ConnectDevice function, where the PvDeviceInfo object obtained via the copy function executes properly. However, directly acquiring the PvDeviceInfo object through Method 1 will cause the program to crash.
mCameras[i].mConnectionID = vDeviceInfos[i]->GetConnectionID();
// : Store the serial number correctly ===
mCameras[i].mSerialNumber = mCameras[i].mDeviceInfo->GetSerialNumber().GetAscii();
// Handle cases where serial number might be empty
if (mCameras[i].mSerialNumber.empty()) {
mCameras[i].mSerialNumber = "N/A";
}
// === End ===
cout<< "SN: " << mCameras[i].mDeviceInfo->GetSerialNumber().GetAscii()<< endl; // Within the same function, the PvDeviceInfo object obtained using Method 1 can be executed correctly.
}
return true;
}
The second-to-last line of code can be executed correctly using either Method 1 or Method 2.
Test code has been added to the ConnectDevice function. Please refer to the comments on the first line of code within the ConnectDevice function.
bool MultiCameraApp::ConnectDevice(CameraContext& aContext)
{
//Additional test code
std::cout << aContext.mDeviceInfo->GetSerialNumber().GetAscii();//The PvDeviceInfo object obtained using Method 1 cannot be executed correctly when used across different functions and will cause the program to crash. In contrast, the PvDeviceInfo object retrieved via the copy() function in Method 2 operates as expected.
//End
// Use the serial number stored in the context
cout << "--> ConnectDevice Cam " << aContext.mIndex << " (SN: " << aContext.mSerialNumber << ") - " << aContext.mConnectionID.GetAscii() << endl;
if (aContext.mDevice != nullptr) {
cout << " Already connected?" << endl;
return true; //
}
PvResult lResult;
aContext.mDevice = PvDevice::CreateAndConnect(aContext.mConnectionID, &lResult);
if (!lResult.IsOK() || aContext.mDevice == nullptr)
{
cout << " Error connecting to device Cam " << aContext.mIndex << ": " << lResult.GetDescription().GetAscii() << endl;
aContext.mDevice = nullptr; // Ensure the pointer is null
return false;
}
// Register event callback
aContext.mDevice->RegisterEventSink(this);
// Connection Status Indicator
aContext.mConnectionLost = false;
return true;
}
Summary:
The object obtained by Method 1 is a temporary object, and using it in another function may cause the system to crash.
It is recommended to use Method 2: acquire the *PvDeviceInfo object via the copy() function. However, please note that when the *PvDeviceInfo object copy (obtained through the Copy() function) is no longer needed, you must use the delete operator to release the memory it occupies to prevent memory leaks.
Comments
0 comments
Please sign in to leave a comment.