📄 camera.cpp
字号:
{
return reinterpret_cast<CCamera::CDisplayThread*>(pParameter)->Run();
}
/**
* The non-static threadp procedure of the display thread.
*
* The thread processes the buffers acquired by the acquisition thread.
* If a color conversion is necessary, it is done by the display thread
*/
DWORD CCamera::CDisplayThread::Run()
{
HANDLE lpHandles[] = { m_evtNewBufferAvailable, m_evtCancelRequest, m_evtTerminate };
CBcamBitmap* pCurrentBuffer = NULL;
bool updateUI = false;
DWORD result;
while (1)
{
#if VERBOSE
ATLTRACE("DisplayThread: Sleep\n");
#endif
result = WaitForMultipleObjects(3, lpHandles, FALSE, INFINITE);
{
switch ( result )
{
case WAIT_OBJECT_0: // new image to process
{
# if VERBOSE
ATLTRACE("DisplayThread: Wake up\n");
# endif
while ( 1 )
{
// process next available buffer as long a buffer is available
HDC DC = NULL;
try
{
m_csNextBuffer.Lock();
pCurrentBuffer = m_pNextBuffer;
m_pNextBuffer = NULL;
m_csNextBuffer.Unlock();
# if VERBOSE
ATLTRACE("DisplayThread: processing %x\n", pCurrentBuffer);
# endif
if ( pCurrentBuffer == NULL )
break; // no new buffer available, sleep until a new one arrives
if ( ( ( Parent->m_ColorCode == DCSColor_Mono8 || Parent->m_ColorCode == DCSColor_Raw8 ) && ! Parent->m_ConvertMono8ToRGB ) || Parent->m_ColorCode == DCSColor_RGB8 )
{
// If we are displaying raw bitmaps no conversion is needed. Pass old buffer back to the acquisition thread and display current buffer
if ( Parent->m_pBitmap != NULL )
Parent->Notify(NotifyUser, Parent->m_pBitmap);
// We are displaying raw bitmaps. Actualize the bitmap
Parent->m_pBitmap = pCurrentBuffer;
}
else
{
// The buffer has to be converted into a color bitmap. After the conversion is done, the buffer is enqueued again
Parent->ConvertBitmap(&Parent->m_pBitmap, &pCurrentBuffer);
if ( Parent->IsAutoWhiteBalanceActive() )
NextWhiteBalanceIteration();
// pass buffer to the acquisition thread
Parent->Notify(NotifyUser, pCurrentBuffer);
}
if ( ! Parent->m_fBitmapValid )
{
Parent->m_fBitmapValid = true;
// mark bitmap as valid
PostMessage(Parent->m_MainFrame, WM_UPDATEUI, 0, 0);
}
// Force drawing of m_pBitmap
DC = Parent->m_pChildFrame->m_View.GetDC();
Parent->m_pChildFrame->m_View.BitBlt(DC, Parent->m_pBitmap);
Parent->m_pChildFrame->m_View.ReleaseDC(DC);
DC = NULL;
if ( Parent->IsContinuousGrabActive() )
// actualize moving average ( for fps display purposes)
Parent->m_DisplayAvg.Add(Parent->m_DisplayWatch.Stop(true));
}
catch (BcamException& e )
{
PostMessage(Parent->m_MainFrame, WM_ERROR, e.Error(), (long) Parent);
}
catch (...)
{
PostMessage(Parent->m_MainFrame, WM_ERROR, DISP_E_EXCEPTION, (long) Parent);
}
// if we ran in an exception before releasing the device context, release it now
if ( DC != NULL )
Parent->m_pChildFrame->m_View.ReleaseDC(DC);
}
break;
}
case WAIT_OBJECT_0 + 1: // cancel
// Confirm that we got the cancel request. If we reach this point we are sure not beeing processing
// a buffer. The client is now allowed to free the resources
ATLTRACE("Display Thread: Got cancel request.\n");
m_evtCancelComplete.Set();
break;
case WAIT_OBJECT_0 + 2: // terminate
return 0;
default: // an error occured
PostMessage(Parent->m_MainFrame, WM_ERROR, ::GetLastError(), (long) Parent);
}
}
}
assert(false && "This point should never be reached");
return 0;
}
/**
* Perform the next iteration of the white balance operation
*
*/
void CCamera::CDisplayThread::NextWhiteBalanceIteration()
{
Parent->m_WhiteBalancer.Next(*Parent->m_pBitmap, Parent->m_pBitmap->GetSize());
long ub = Parent->m_WhiteBalancer.GetUBValue();
long vr = Parent->m_WhiteBalancer.GetVRValue();
// update the sliders
if ( Parent->m_MainFrame.m_CameraManager.GetCurrentDevice() == Parent )
{
CWhiteBalanceView* view = (CWhiteBalanceView*) Parent->m_MainFrame.m_Features[FeatureID_WhiteBalance];
view->PostMsgEnable(false);
view->SetUBValue(ub);
view->SetVRValue(vr);
view->PostMsgEnable(true);
}
// Set the new white balance values.
// This is done synchronously, because we must ensure to enque the next buffer not before
// the settings are done.
if ( Parent->IsWhiteBalanceSupported() )
{
Parent->WhiteBalance.Raw.UBValue = ub;
Parent->WhiteBalance.Raw.VRValue = vr;
}
else
{
Parent->SetBGain(ub / 100.0);
Parent->SetRGain(vr / 100.0);
}
}
/**
* Waits until the display thread is idle, i.e. is not processing buffers
*
* \return error code. 0 indicates success
*/
//------------------------------------------------------------------------------
DWORD CCamera::CDisplayThread::WaitUntilIdle()
{
if ( HANDLE(*this) != NULL )
{
m_evtNewBufferAvailable.Reset();
DWORD error = 0;
// signal the display thread to set the m_evtCancelComplete event. If the display thread
// has set this event, we are sure, it is no longer operating on a buffer (e.g. color conversion)
m_evtCancelRequest.Set();
bool displayThreadReady = false;
// waiting in a message loop....
while ( ! displayThreadReady )
{
DWORD res = MsgWaitForMultipleObjects(1, & m_evtCancelComplete, FALSE, NEARLYINFINITE, QS_PAINT | QS_SENDMESSAGE );
switch ( res )
{
case WAIT_OBJECT_0:
displayThreadReady = true;
break;
case WAIT_OBJECT_0 + 1: // message received
{
MSG msg;
// local message loop
while (PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE))
{
// If it's a quit message, we're out of here.
if (msg.message == WM_QUIT)
{
error = 0;
goto quit2;
}
// Otherwise, dispatch the message.
DispatchMessage(&msg);
} // End of local message loop
}
continue;
case WAIT_TIMEOUT:
error = ERROR_TIMEOUT;
assert(false);
goto quit2;
default:
error = ::GetLastError();
assert(false);
goto quit2;
}
}
quit2:
return error;
}
return 0;
}
CBcamBitmap* CCamera::CDisplayThread::SetBuffer(CBcamBitmap* pBuffer)
{
m_csNextBuffer.Lock();
CBcamBitmap* pOldBuffer = m_pNextBuffer;
m_pNextBuffer = pBuffer;
m_csNextBuffer.Unlock();
if ( pBuffer )
m_evtNewBufferAvailable.Set();
return pOldBuffer;
}
/// Terminate display Thread
void CCamera::CDisplayThread::Destroy()
{
if ( HANDLE(*this) == NULL )
return;
SetEvent(m_evtTerminate);
switch ( WaitForSingleObject(HANDLE(*this), NEARLYINFINITE) )
{
case WAIT_OBJECT_0:
ATLTRACE("Display thread terminated.\n");
CThread::Release();
break;
default:
ATLTRACE("Display thread did not terminate.\n");
CThread::Terminate(-1);
CThread::Release();
break;
}
}
BOOL CCamera::CAcquisitionThread::Create(int Priority)
{
return CThread::Create(&ThreadProc, this, Priority, 0);
}
/**
* Thread procedure of the image acquisition thread.
*/
DWORD CCamera::CAcquisitionThread::ThreadProc(void* pThis)
{
// call the non-static thread procedure
return reinterpret_cast<CAcquisitionThread*>(pThis)->Run();
}
/**
* Thread procedure of the image acquisition thread. The thread removes buffers from the
* completion port and either pass them to the display thread or enqueue them again
* into the driver's queue when the display thread is busy
*
*/
DWORD CCamera::CAcquisitionThread::Run()
{
Parent->SetCurrentThreadPriority(16);
void* pContext;
FunctionCode_t func;
unsigned long error;
while ( 1 )
{ // main loop. Process buffers retrieved from the completion port
try
{
Parent->WaitForCompletion(&func, &error, &pContext, INFINITE);
if ( error == ERROR_OPERATION_ABORTED || error == ERROR_DEVICE_REMOVED )
{
# if VERBOSE
if ( error == ERROR_OPERATION_ABORTED )
ATLTRACE("cancel %x\n", pContext);
# endif
Parent->m_DisplayThread.SetBuffer(NULL);
continue;
}
if (error && ( ! Parent->IsContinuousGrabActive() || error != STATUS_BCAM_BUS_RESET ) ) // ignore STATUS_BCAM_BUS_RESET when grabbing continuously images
{
throw BcamException( error, "AcquisitionThreadProc()" );
}
switch ( func )
{
case AsyncGrabImage:
ProcessImage(reinterpret_cast<CBcamBitmap*>(pContext), error == STATUS_BCAM_BUS_RESET);
break;
case NotifyUser:
// we got back a buffer processed by the display thread.
ProcessUserNotification(reinterpret_cast<CBcamBitmap*>(pContext));
break;
case NotifyQuit:
// Retrieved request to terminate
return 0;
}
}
catch (BcamException& e )
{
ATLTRACE("AcquisistionThreadProc: Error: %s\n", (LPCSTR) e.Description());
if ( ! Parent->m_fSurpressFurtherErrorMessages )
{
PostMessage(Parent->m_MainFrame, WM_ERROR, e.Error(), (long) Parent);
Parent->m_fSurpressFurtherErrorMessages = true; // avoid continuous popping-up of message boxes
}
continue;
}
catch (...)
{
ATLTRACE("AcquisitionThreadProc: Exception occured.");
PostMessage(Parent->m_MainFrame, WM_ERROR, DISP_E_EXCEPTION, (long) Parent);
continue;
}
}
// this point should never be reached
assert(false);
return 0;
}
/**
* Process completed buffers collected from the completion port
*/
void CCamera::CAcquisitionThread::ProcessImage(CBcamBitmap* pBitmap, bool omitBuffer)
{
CAutoLock<CCriticalSection> lock(Parent->m_csAcquisition);
// we got back one buffer
# if VERBOSE
ATLTRACE("BufferCompleted: %x\n", pBitmap);
# endif
switch ( Parent->m_State )
{
case sIdle:
// grab has been switched off, ignore buffer
break;
case sSingleGrab:
// single grab has been finished
FinishSingleGrab(); // cleanup and transition to idle state
// intentionally fall through to next cases
case sAutoWhiteBalanceCont:
case sAutoWhiteBalanceIdle:
Parent->m_DisplayThread.SetBuffer(pBitmap); // next buffer to be processed by the display thread
break;
case sContinuousGrab:
{
if ( ! omitBuffer )
// update information to calculate frame rate
Parent->m_AcquisitionAvg.Add(Parent->m_AcquisitionWatch.Stop(true));
else
// at least restart the stop watch
Parent->m_AcquisitionWatch.Stop(true);
// If m_pNextBuffer (i.e. the next buffer to be processed by the display thread) is not
// null, up to now the display hasn't processed this buffer. We have got a new one, so
// replace the old one with the new one. Enqueue the old one again.
if ( ! omitBuffer )
{
CBcamBitmap* pOldBuffer = Parent->m_DisplayThread.SetBuffer(pBitmap);
if ( pOldBuffer != NULL )
{
// the display thread hasn't processed the latest buffer, enqueue it again
# if VERBOSE
ATLTRACE("Enqueue Parent->m_pNextBuffer\n");
# endif
Parent->Enqueue( pOldBuffer );
}
}
else
{
// Either the the display thread is modifiying the m_pNextBuffer, so we can't exchange it,
// or the latest buffer should be ommitted because it could be corrupted by a bus reset.
// Instead of waiting for the access to the buffer we enqueue the new buffer again to keep the
// queue full.
# if VERBOSE
ATLTRACE("Enqueue pBitmap\n");
# endif
Parent->Enqueue( pBitmap );
}
}
break;
}
}
/**
*
* Process buffers passed by the display to the completion port via user
* notifications
*/
void CCamera::CAcquisitionThread::ProcessUserNotification(CBcamBitmap* pBitmap)
{
CAutoLock<CCriticalSection> lock(Parent->m_csAcquisition);
if ( pBitmap )
{
switch ( Parent->m_State )
{
case sIdle:
break;
case sContinuousGrabSuspended:
break;
case sSingleGrab:
break;
case sContinuousGrab:
// enqueue the buffer again
Parent->Enqueue( pBitmap );
break;
case sAutoWhiteBalanceCont:
case sAutoWhiteBalanceIdle:
if ( Parent->m_WhiteBalancer.m_fConverged )
{
// The white balancing operation has been finished.
ATLTRACE("converged. UB = %d, VR = %d\n", Parent->m_WhiteBalancer.m_UB, Parent->m_WhiteBalancer.m_VR);
CCamera::eState oldState = Parent->m_State;
FinishSingleGrab(); // clean-up and transition to sIdle state
if ( oldState == sAutoWhiteBalanceCont )
{
// restart the continuous grab
Parent->GrabContinuous(false); // false: don't invalidate the current bitmap
}
}
else
{
// enqueue the buffer again and trigger one shot
Parent->Enqueue( pBitmap, true );
}
break;
}
}
}
/// clean-up when single grab has been completed.
/// A state transition to the sIdle state is performed.
void CCamera::CAcquisitionThread::FinishSingleGrab()
{
Parent->m_State = sIdle;
Parent->FreeResources();
PostMessage(Parent->m_MainFrame, WM_UPDATEUI, 0, 0);
}
void CCamera::CAcquisitionThread::Destroy()
{
if ( HANDLE(*this) != NULL )
{
// terminate acquisition thread
assert(Parent->IsOpen());
if ( Parent->IsOpen() )
{
try
{
Parent->Notify(NotifyQuit); // signal the thread to stop grab and to terminate
switch ( WaitForSingleObject(HANDLE(*this), NEARLYINFINITE) )
{
case WAIT_OBJECT_0:
ATLTRACE("AcquisitionThread terminated.\n");
CThread::Release();
break;
default:
CThread::Terminate(-1);
CThread::Release();
ATLTRACE("Acquisition thread did not terminate.\n");
break;
}
}
catch ( BcamException )
{
// We could not notify the bcam object (perhaps the device has been removed).
// We must go the hard way
CThread::Terminate(-1);
CThread::Release();
ATLTRACE("Forced AcquisitionThreads termination.\n");
}
}
else
{
CThread::Terminate(-1);
CThread::Release();
ATLTRACE("Forced AcquisitionThreads termination.\n");
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -