Continuous High-Speed Capture
These are the steps to create a program that pushes the performance of the GbE-2 (Ethernet model) to its limit, continuously capturing high-speed image data while preventing dropped frames.
-
Write the source code
Open the main file (e.g.
GbE2_ContinuousCapture.cpp) and replace its contents with the following code.#include <stdio.h>#include <stdlib.h>#include <windows.h>#include <PUCLIB.h> // Load the PUCLIB header// Context structure passed to the callback functionstruct CaptureContext {UINT32 width;UINT32 height;UINT32 lineBytes;unsigned short qVals[PUC_Q_COUNT];unsigned char* pDecodedBuffer;LONG frameCount;DWORD startTime;};// Callback function automatically invoked by the SDK internally when an image is receivedvoid WINAPI ImageCallback(PPUC_XFER_DATA_INFO pXferData, void* pUserParam) {CaptureContext* pCtx = (CaptureContext*)pUserParam;if (!pXferData || !pXferData->pData || !pCtx) {return;}/** --------------------------------------------------------------------------------* [Structure of the received data: pXferData (PPUC_XFER_DATA_INFO)]* --------------------------------------------------------------------------------* - pXferData->pData* A pointer to "one frame's worth of compressed RAW data" transferred over UDP from the camera.* The first 16 bytes contain a GbE-2-specific transfer header (frame number, timestamp, etc.),* followed by the fixed-length compressed pixel data (in 8x8 block units).* - pXferData->nDataSize* The total byte size of the compressed data.* - pXferData->nSequenceNo* A 16-bit sequence number (0-65535), used to detect dropped frames.* - pXferData->isDamaged* A flag indicating whether the data has been corrupted due to packet loss, etc. (1 = abnormal).* --------------------------------------------------------------------------------*/// Check for packet damage / dropped framesif (pXferData->isDamaged) {printf("Warning: Frame corrupted (packet loss occurred). Sequence No: %u\n", pXferData->nSequenceNo);return;}// Parse the GbE-2-specific transfer header (retrieve frame state information as needed)PUC_GBE2_XFER_HEADER gbe2Header = { 0 };if (PUC_ExtractGbe2XferHeader(pXferData->pData, &gbe2Header) == PUC_SUCCEEDED) {// gbe2Header.epochTime : The camera's timestamp (epoch seconds)// gbe2Header.nImageNo : The camera's internal frame sequence number// gbe2Header.isPacketDropped : Whether a drop occurred at the network layer}/** --------------------------------------------------------------------------------* [Structure of the decoded data: pCtx->pDecodedBuffer]* --------------------------------------------------------------------------------* When PUC_DecodeDataMultiThread is executed, the compressed data (pXferData->pData) is decompressed* and 8-bit monochrome brightness data is stored in pCtx->pDecodedBuffer with the following layout.** [Memory layout]* - Data type : unsigned char (1 pixel = 1 byte, 0 = black ... 255 = white)* - Array layout: a 1-dimensional array (raster scan order: contiguous from the image's* top-left origin (0, 0) to the bottom right)* - Row size : lineBytes bytes (aligned to a 4-byte boundary for faster memory access)** [Example of accessing an arbitrary coordinate (x, y)]* unsigned char pixel = pCtx->pDecodedBuffer[y * pCtx->lineBytes + x];* --------------------------------------------------------------------------------*/PUCRESULT ret = PUC_DecodeDataMultiThread(pCtx->pDecodedBuffer, // [out] Buffer to which the decoded image data is written0, 0, // [in] Decode start coordinates X, YpCtx->width, // [in] Resolution width (pixels)pCtx->height, // [in] Resolution height (pixels)pCtx->lineBytes, // [in] Bytes per row in memorypXferData->pData, // [in] The received compressed datapCtx->qVals, // [in] The quantization table4 // [in] Number of CPU threads to use);if (ret == PUC_SUCCEEDED) {LONG currentFrame = InterlockedIncrement(&pCtx->frameCount);/** --------------------------------------------------------------------------------* [Example: saving as a PGM image file]* --------------------------------------------------------------------------------* An example of saving the decoded data (pCtx->pDecodedBuffer) in PGM (P5 format).* Note: Since saving every frame to disk during high-speed continuous capture would make* disk I/O the bottleneck, it is recommended to save only specific frames, or* to delegate the saving process to a separate thread.** char filename[64];* sprintf_s(filename, "captured_%05ld.pgm", currentFrame);* FILE* fp = NULL;* if (fopen_s(&fp, filename, "wb") == 0 && fp != NULL) {* // Write the PGM header (P5 / width / height / max gray value 255)* fprintf(fp, "P5\n%u %u\n255\n", pCtx->width, pCtx->height);** // Write the valid image data (the width in bytes, excluding padding) one row at a time* for (UINT32 y = 0; y < pCtx->height; y++) {* fwrite(pCtx->pDecodedBuffer + (y * pCtx->lineBytes), sizeof(unsigned char), pCtx->width, fp);* }* fclose(fp);* }* --------------------------------------------------------------------------------*/// Display the reception performance (FPS) every 100 framesif (currentFrame % 100 == 0) {DWORD elapsed = GetTickCount() - pCtx->startTime;if (elapsed > 0) {double fps = (double)currentFrame * 1000.0 / elapsed;printf("Received: %ld frames | Average speed: %.1f FPS (SeqNo: %u)\n",currentFrame, fps, pXferData->nSequenceNo);}}}}int main() {printf("Starting INFINICAM GbE-2 continuous high-speed capture...\n");// 1. Initialize the SDKPUCRESULT ret = PUC_Initialize();if (ret != PUC_SUCCEEDED) {printf("Error: Failed to initialize the SDK. ErrorCode: %d\n", ret);return EXIT_FAILURE;}// 2. Search for a GbE-2 devicePUC_DETECT_FILTER filter = { 0 };filter.nDeviceTypeFlags = PUC_DETECT_TARGET_GBE2;PUC_DETECT_INFO detectInfo = { 0 };ret = PUC_DetectDevice2(&filter, &detectInfo);if (ret != PUC_SUCCEEDED || detectInfo.nDeviceCount == 0) {printf("Error: No GbE-2 camera was found. ErrorCode: %d\n", ret);return EXIT_FAILURE;}// 3. Open the devicePUC_HANDLE hDevice = NULL;ret = PUC_OpenDevice2(0, &hDevice);if (ret != PUC_SUCCEEDED) {printf("Error: Failed to open the device. ErrorCode: %d\n", ret);return EXIT_FAILURE;}// 4. Get the resolution and quantization tableUINT32 width = 0, height = 0;PUC_GetResolution(hDevice, &width, &height);unsigned short qVals[PUC_Q_COUNT] = { 0 };PUC_GetQuantization2(hDevice, qVals);printf("Capture resolution: %u x %u pixels\n", width, height);// 5. Set the ring buffer count for continuous transfer (to prevent dropped frames)ret = PUC_SetRingBufferCount(hDevice, 64);if (ret != PUC_SUCCEEDED) {printf("Warning: Failed to set the ring buffer count.\n");}// 6. Prepare the decode buffer and context// Round up the row byte count (lineBytes) to a multiple of 4 for more efficient memory transferUINT32 lineBytes = (width + 3) & ~3;unsigned long decodedSize = (unsigned long)lineBytes * height;unsigned char* pDecodedBuffer = (unsigned char*)malloc(decodedSize);if (pDecodedBuffer == NULL) {printf("Error: Memory allocation failed.\n");PUC_CloseDevice(hDevice);return EXIT_FAILURE;}CaptureContext ctx = { 0 };ctx.width = width;ctx.height = height;ctx.lineBytes = lineBytes;ctx.pDecodedBuffer = pDecodedBuffer;memcpy(ctx.qVals, qVals, sizeof(qVals));ctx.frameCount = 0;ctx.startTime = GetTickCount();// 7. Start continuous transfer (register the callback function)ret = PUC_BeginXferData(hDevice, ImageCallback, &ctx);if (ret != PUC_SUCCEEDED) {printf("Error: Failed to start continuous transfer. ErrorCode: %d\n", ret);free(pDecodedBuffer);PUC_CloseDevice(hDevice);return EXIT_FAILURE;}printf("Continuous transfer started. Press Enter to stop...\n");getchar(); // Wait for key input// 8. Stop the continuous transfer and closeprintf("Stopping continuous transfer...\n");PUC_EndXferData(hDevice);printf("Total frames captured: %ld\n", ctx.frameCount);// 9. Cleanupfree(pDecodedBuffer);PUC_CloseDevice(hDevice);return EXIT_SUCCESS;} -
Build and run
- Press
Ctrl+Shift+Bto build. - Run with
Ctrl+F5. - Press
Enterto safely stop the transfer and end the program.
- Press
How Image Data Is Stored (Supplementary Notes)
Section titled “How Image Data Is Stored (Supplementary Notes)”1. Structure of the receive buffer (pXferData->pData)
Section titled “1. Structure of the receive buffer (pXferData->pData)”- Data type: One frame’s worth of fixed-length compressed RAW data transferred from the camera.
- Header structure: The GbE-2-specific transfer header (
PUC_GBE2_XFER_HEADER) is written in the first 16 bytes, and passing it throughPUC_ExtractGbe2XferHeaderallows you to extract the timestamp, the camera’s internal sequence number, and other information.
2. Structure of the decode buffer (pCtx->pDecodedBuffer)
Section titled “2. Structure of the decode buffer (pCtx->pDecodedBuffer)”- Data type: The expanded 8-bit monochrome brightness data (
0= pure black,255= pure white). - Array layout: A 1-dimensional array in raster scan order, from the image’s top-left origin
(0, 0)toward the bottom right. - Row width in memory (
lineBytes): Allocated with the width (in pixels) rounded up to a multiple of 4 bytes, to speed up memory access and GPU/OpenCV integration.
