PVCAM  3.9.x
Programmable Virtual Camera Access Method library
Live Image Polling
Warning
Please note that the example below describes an obsolete acquisition technique. This mode may not work reliably for large frames and fast frame rates and will not be supported by future PVCAM revisions. Please refer to Live Image Callbacks for a recommended way to acquire frames continuously.

This sample shows how to set up and run camera in continuous mode with circular buffer and polling for frame readout notification. This is typically used to run the camera until user stops the acquisition, or until other condition is met.

This sample code collects 50 frames and stops, however the stop condition can be replaced by a UI event such as user pressing a button or similar.

Initialize PVCAM and open the first available camera. Please refer to the actual code sample in the SDK installation directory for more details about the common helper functions used in this documentation.

std::vector<CameraContext*> contexts;
if (!InitAndOpenOneCamera(contexts, cSingleCamIndex))
return APP_EXIT_ERROR;
CameraContext* ctx = contexts[cSingleCamIndex];

Prepare the continuous acquisition with circular buffer mode. The pl_exp_setup_cont function returns the size of one frame (unlike the pl_exp_setup_seq which returns the full buffer size). See more in Acquisition Configuration section.

uns32 exposureBytes;
const uns32 exposureTime = 40; // milliseconds
const uns16 circBufferFrames = 20;
const int16 bufferMode = CIRC_OVERWRITE;
if (PV_OK != pl_exp_setup_cont(ctx->hcam, 1, &ctx->region, exposureMode,
exposureTime, &exposureBytes, bufferMode))
{
PrintErrorMessage(pl_error_code(), "pl_exp_setup_cont() error");
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}
Note
For detailed information about error handling, please refer to Getting Error Messages.
This example uses the extended trigger mode configuration and sets up the camera to use internal trigger with first-row expose out mode. However, legacy cameras do not support the extended modes and the list of supported expose out modes may differ as well. It is important to always discover the supported modes using the PARAM_EXPOSURE_MODE and PARAM_EXPOSE_OUT_MODE parameters when working with multiple camera models.

Now allocate the buffer memory. The application is in control of the circular buffer and should allocate memory of appropriate size.

const uns32 circBufferBytes = circBufferFrames * exposureBytes;
uns8* circBufferInMemory = new (std::nothrow) uns8[circBufferBytes];
if (!circBufferInMemory)
{
printf("Unable to allocate buffer for camera %d\n", ctx->hcam);
CloseAllCamerasAndUninit(contexts);
return APP_EXIT_ERROR;
}

Start the continuous acquisition. By passing the entire size of the buffer to pl_exp_start_cont function, PVCAM can calculate the capacity of the circular buffer.

if (PV_OK != pl_exp_start_cont(ctx->hcam, circBufferInMemory, circBufferBytes))
{
PrintErrorMessage(pl_error_code(), "pl_exp_start_cont() error");
CloseAllCamerasAndUninit(contexts);
delete [] circBufferInMemory;
return APP_EXIT_ERROR;
}

Loop to acquire 50 frames:

bool errorOccured = false;
uns32 framesAcquired = 0;
while (framesAcquired < 50)
{

Keep checking the camera readout status. If readout succeeds, print the ADU values of the first five pixels. Sleep is used to reduce CPU load while polling for status.

while (PV_OK == pl_exp_check_cont_status(ctx->hcam, &status, &byte_cnt, &buffer_cnt)
&& status != FRAME_AVAILABLE && status != READOUT_NOT_ACTIVE
&& !ctx->threadAbortFlag)
{
// Waiting for frame exposure and readout
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (ctx->threadAbortFlag)
{
// This flag is set on ctrl+c, just break the loop, the acquisition
// is aborted after that
printf("Processing aborted on camera %d\n", ctx->hcam);
break;
}
if (status == READOUT_FAILED)
{
printf("Frame #%u readout failed on camera %d\n",
framesAcquired + 1, ctx->hcam);
errorOccured = true;
break;
}
Warning
When acquisition is running, the status changes in the following order: EXPOSURE_IN_PROGRESS -> READOUT_IN_PROGRESS -> FRAME_AVAILABLE -> EXPOSURE_IN_PROGRESS and so on. This means that the FRAME_AVAILABLE status can be obtained only momentarily between the frames (between the last EOF and next BOF). Due to this constraint, the polling approach introduces higher risk of lost frames than the callbacks approach because some frames may be lost unnoticed.
Removing the sleep or setting it to a value too low may significantly increase the CPU load. Shorter sleeps do not guarantee the code won't miss a frame if the frame rate is too high.

Obtain the address of the latest frame in the buffer with the pl_exp_get_latest_frame function. Optionally, the pl_exp_get_latest_frame_ex can be used to receive the address together with a FRAME_INFO structure. This structure contains frame number and timestamps.

void* frameAddress;
if (PV_OK != pl_exp_get_latest_frame(ctx->hcam, &frameAddress))
{
PrintErrorMessage(pl_error_code(), "pl_exp_get_latest_frame() error");
errorOccured = true;
break;
}
printf("Frame #%u readout successfully completed on camera %d\n",
framesAcquired + 1, ctx->hcam);
ShowImage(ctx, frameAddress, exposureBytes);
framesAcquired++;
} // End of while cycle

Acquisition is aborted when the desired number of frames is acquired or when the user aborts the acquisition. Please, refer to the Closing Camera and Uninitializing PVCAM for more details.

if (PV_OK != pl_exp_abort(ctx->hcam, CCS_HALT))
PrintErrorMessage(pl_error_code(), "pl_exp_abort() error");
delete [] circBufferInMemory;
CloseAllCamerasAndUninit(contexts);
if (errorOccured)
return APP_EXIT_ERROR;
return 0;