April 28, 2009

How To: Handle dynamic format change in ReceiveConnection function on a renderer filter.

I was trying to correctly handle dynamic format change on my video null renderer and had fought against it for several days.

The following code snippet is my final work for handling dynamic format change, it seems to work fine, I hope so :p


STDMETHODIMP CNullRendererInputPin::ReceiveConnection(IPin * pConnector, const AM_MEDIA_TYPE *pmt)
{
  CAutoLock lock(m_pLock);

  CMediaType newMediaType(*pmt);

  HRESULT hr = E_FAIL;

  if(m_Connected && m_Connected == pConnector && newMediaType != m_mt)
  {
    do {

      hr = CheckMediaType(&newMediaType);
      if(FAILED(hr)) break;

      BITMAPINFO bmpinfo = {0};
      if(FORMAT_VideoInfo == pmt->formattype && 1 == pmt->bFixedSizeSamples)
      {
        VIDEOINFOHEADER* t = (VIDEOINFOHEADER*)(pmt->pbFormat);
        bmpinfo.bmiHeader = t->bmiHeader;
      }
      else if(FORMAT_VideoInfo2 == pmt->formattype && 1 == pmt->bFixedSizeSamples)
      {
        VIDEOINFOHEADER2* t = (VIDEOINFOHEADER2*)(pmt->pbFormat);
        bmpinfo.bmiHeader = t->bmiHeader;
      }
      else
      {
        hr = E_UNEXPECTED;
        break;
      }

      ALLOCATOR_PROPERTIES allocProperties = {0};
      {
        hr = m_pAllocator->GetProperties(&allocProperties);
        if(FAILED(hr)) break;

        allocProperties.cbBuffer = bmpinfo.bmiHeader.biSizeImage;
      }

      hr = SetMediaType(&newMediaType);
      if(FAILED(hr)) break;

      hr = m_pAllocator->Decommit();
      if(FAILED(hr)) break;

      {
        ALLOCATOR_PROPERTIES newAllocProperties = {0};
        hr = m_pAllocator->SetProperties(&allocProperties, &newAllocProperties);
        if(FAILED(hr)) break;
      }

      hr = m_pAllocator->Commit();
      if(FAILED(hr)) break;

      hr = S_OK;

    } while(false);
  }
  else
  {
    hr = CBasePin::ReceiveConnection(pConnector, pmt);
  }

  return hr;
}