PVCAM  3.9.x
Programmable Virtual Camera Access Method library
Single Image on Multiple Cameras

This sample is similar to Single Image Callbacks except that most PVCAM functions are called from a background thread - this allows us to control multiple cameras simultaneously.

Initialize PVCAM and open multiple cameras using the InitAndOpenMultipleCameras helper function. The cMultiCamCount is a constant defined in a common code part that is set to 2. If there are fewer than cMultiCamCount cameras available, the nrOfCameras value is updated with actual number of opened cameras.

std::vector<CameraContext*> contexts;
uns16 nrOfCameras = cMultiCamCount;
if (!InitAndOpenMultipleCameras(contexts, nrOfCameras))
return APP_EXIT_ERROR;

The only task of the main thread is to execute a separate background thread for each camera. If an error occurs, all existing threads are requested to exit and the application proceeds with cleanup and termination. The threadAbortFlag is checked inside WaitForEofEvent function that is running for every camera.

bool errorOccurred = false;
for (int16 i = 0; i < nrOfCameras; i++)
{
CameraContext* ctx = contexts[i];
ctx->threadAbortFlag = false;
ctx->thread = new(std::nothrow) std::thread(ThreadFunc, ctx);
if (!ctx->thread)
{
errorOccurred = true;
g_printMutex.lock();
printf("Failed to start acquisition thread for camera %d\n", ctx->hcam);
g_printMutex.unlock();
for (int16 j = 0; j < i; j++)
{
CameraContext* ctx2 = contexts[j];
{
std::lock_guard<std::mutex> lock(ctx2->eofEvent.mutex);
ctx2->threadAbortFlag = true;
}
ctx2->eofEvent.cond.notify_all();
}
break;
}
}

The callback handler registration, acquisition setup, buffer memory allocation, acquisition capture loop and resource cleanup is identical to Single Image Callbacks. Here, this call sequence is repeated for every camera. The only difference is usage of global mutex g_printMutex to serialize access to standard output stream to avoid corruption of output messages.

At the end we have to wait for all background threads to finish, either by completing the sequence acquisition or by user interruption. After that, the program can proceed with cleanup and termination. For more details, please, refer to the Closing Camera and Uninitializing PVCAM section.

for (int i = 0; i < nrOfCameras; i++)
{
CameraContext* ctx = contexts[i];
if (ctx->thread && ctx->thread->joinable())
ctx->thread->join();
delete ctx->thread;
ctx->thread = nullptr;
}
CloseAllCamerasAndUninit(contexts);
if (errorOccured)
return APP_EXIT_ERROR;
return 0;