I'm simply trying to use a while loop to help control the frames per second of my program that displays a live camera feed along with data corresponding to what that camera is looking at. The reason this is not trivial is because the loop that is calling getFramesAfterCapture()
is running much faster than the camera can acquire images (since it is being called in an update method that collects the current frame and the data that both need to be displayed).
My idea was to have this function simply wait like using a mutex until the the condition in my while loop is no longer met. The callback is running in another thread and captureComplete
is a static member variable of the class so it is the only instance of it. The value of this bool changes when the callback that captures the frames from my camera completes capturing a new image. It must be done in this way because I need the data that is being displayed to the screen to be synched with the capture of the frames this way the data and video display match.
Here is my code:
long CALLBACK FrameGrabber::destCallback(LPVOID lpUser, LPVOID lpReserved) {
// copy the data into the bitmap
if (WaitForSingleObject(hMutex, 10) == WAIT_OBJECT_0)
{
DWORD dwSize = VIDEO_SIZE;
//get bitmap
dpGetSurfaceData(hDest, bitmap + sizeof(BITMAPINFOHEADER), &dwSize);
ReleaseMutex(hMutex);
// set capture to complete so that waitForCapture releases from the do-nothing loop
WaitForSingleObject(captureCmpltMutex, INFINITE);
captureComplete = true;
ReleaseMutex(captureCmpltMutex);
}
return 0;
}
BYTE* FrameGrabber::getFrameAfterCapture() {
// loop while capture is still not completed
////while (!captureComplete);
while (!captureComplete) {
std::cout << "Waiting for capture to complete..." << std::endl;
}
//std::cout << "Capture Complete!" << std::endl;
// when capture is completed set captureComplete back to false so that this waits again until the next frame is acquired
WaitForSingleObject(captureCmpltMutex, INFINITE);
captureComplete = false;
ReleaseMutex(captureCmpltMutex);
return bitmap;
}
My loop works fine as it is...
while (!captureComplete) {
std::cout << "Waiting for capture to complete..." << std::endl;
}
But does not work when I change it to this...
while (!captureComplete);
Or this...
while (!captureComplete) { }
Or this...
while (!captureComplete) continue;
Or this...
while (!captureComplete){ continue; }
I prefer any of the other options because I would rather not keep a print statement in my program when it is complete. I want my code here to look nice and clean like the other options that don't seem to work.
If there is another more elegant option I am willing to change it I just need a solution that works and looks clean.
I was able to figure out a more elegant solution using a binary semaphore instead of a mutex or a static member boolean. The difference between using a mutex and a binary semaphore is that a binary semaphore does not require me to release the semaphore at the end of getFrameCapture(). Basically when a semaphore is released, the count it holds is increased by one. And oppositely when the wait function returns, the count the semaphore holds is decreased by one.
This allowed for the signal behavior where if I were to wait for the mutex at the beginning and release it just before the getFrameCapture() method returns the whole point of the function waiting for the frame to be captured is lost. Likewise if I were to not release it just before the function is returned, the mutex will return WAIT_ABANDONED telling the programmer that the thread exited unexpectedly and the mutex has been abandoned by it.
Sol:
long CALLBACK FrameGrabber::destCallback(LPVOID lpUser, LPVOID lpReserved) {
// copy the data into the bitmap
if (WaitForSingleObject(hMutex, 10) == WAIT_OBJECT_0)
{
DWORD dwSize = VIDEO_SIZE;
//get bitmap
dpGetSurfaceData(hDest, bitmap + sizeof(BITMAPINFOHEADER), &dwSize);
ReleaseMutex(hMutex);
//Release semaphore (emit signal)
ReleaseSemaphore(captureCmpltSemaphore, 1, NULL);
}
return 0;
}
BYTE* FrameGrabber::getFrameAfterCapture() {
//Wait for semaphore to be released (Signaled)
WaitForSingleObject(captureCmpltSemaphore, INFINITE);
//return bitmap
return bitmap;
}
I referenced this link to find my solution: https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-releasesemaphore