⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 camera.cpp

📁 BCAM 1394 Driver
💻 CPP
📖 第 1 页 / 共 4 页
字号:
{
  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 + -