Share via


© 2004 Microsoft Corporation. All rights reserved.

Figure 1 Filter Graph

Figure 1 Filter Graph Figure 2 Building a File Playback Graph
  #include <dshow.h>
void main(void)
{
    IGraphBuilder *pGraph = 0;
    IMediaControl *pMediaControl = 0;
    IMediaEvent   *pEvent = 0;
    CoInitialize(NULL);
    
    // Create the FGM and query for interfaces.
    CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
                IID_IGraphBuilder, (void **)&pGraph);
    // Obtain the interface used to run, stop, and pause the graph
    pGraph->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
    // Obtain the interface to receive events from the graph
    pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
    // Build the graph. IMPORTANT: Change string to a file on your 
    // system.
    pGraph->RenderFile(L"C:\\Example.avi", NULL);
    // Run the graph.
    pMediaControl->Run();
    // Wait for completion. 
    long evCode;
    pEvent->WaitForCompletion(INFINITE, &evCode);
    // Clean up.
    pMediaControl->Release();
    pEvent->Release();
    pGraph->Release();
    CoUninitialize();
}

Figure 4 Building a Video Capture Graph
  #include <dshow.h>
int main (void)
{
    IGraphBuilder *pGraph = 0;
    ICreateDevEnum *pDevEnum = 0;
    ICaptureGraphBuilder2 *pBuild = 0;
    HRESULT hr;
    CoInitialize(NULL);
     
    // Create the FGM.
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
        IID_IGraphBuilder, (void **)&pGraph );
    // Create the capture graph builder helper object
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
        CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, 
        (void **)&pBuild );
     
    // Tell the capture graph builder about the FGM.
    hr = pBuild->SetFiltergraph(pGraph);
    // Create a helper object to find the capture device.
    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, 
        CLSCTX_INPROC_SERVER,
        IID_ICreateDevEnum, (LPVOID*)&pDevEnum);
    // Use the first capture filter that we find.
    IEnumMoniker* pEnum = 0;
    IMoniker* pMoniker = 0;
    IBaseFilter *pCapture = 0;
    hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
        &pEnum, 0);
    if (S_OK == pEnum->Next(1, &pMoniker, NULL))
    {
        hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void 
        **)&pCapture);
    }
    pMoniker->Release();
    pEnum->Release();
    pDevEnum->Release();
    // Add the capture filter to the filter graph
    hr = pGraph->AddFilter(pCapture, L"CaptureFilter");
    // Build the preview part of the graph.
    hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, 
        pCapture, NULL, NULL);
    // Build the file writing part of the graph.
    IBaseFilter *pMux = 0;
    pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi, L"C:\\test.avi", 
    &pMux, 0);
    hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
       pCapture, NULL, pMux);
    
    // Run the graph. (Not shown.)
    pGraph->Release();
    pBuild->Release();
    pCapture->Release();
    pMux->Release();
    CoUninitialize();
    return 0;
}

Figure 9 CheckInputType Method
  HRESULT CYuvGray::CheckInputType(const CMediaType *pmt)
{
    if ((pmt->majortype == MEDIATYPE_Video) &&
        (pmt->subtype == MEDIASUBTYPE_UYVY) &&
        (pmt->formattype == FORMAT_VideoInfo) &&
        (pmt->pbFormat != NULL) &&
        (pmt->cbFormat >= sizeof(VIDEOINFOHEADER)))
    {
        VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER*>
            (pmt->pbFormat);
        BITMAPINFOHEADER *pBmi = &(pVih->bmiHeader);
        if ((pBmi->biBitCount == 16) &&
            (pBmi->biCompression == FCC('UYVY')) &&
            (pBmi->biSizeImage >= DIBSIZE(*pBmi)))
        {
            return S_OK;
        }
    }
    return VFW_E_TYPE_NOT_ACCEPTED;
}

Figure 10 CheckTransform Method
  HRESULT CYuvGray::CheckTransform(const CMediaType *mtIn, const 
    CMediaType *mtOut)
{
    if (!IsValidUYVY(mtOut))
    {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }
    BITMAPINFOHEADER *pBmi = HEADER(mtIn);
    BITMAPINFOHEADER *pBmi2 = HEADER(mtOut);
    if ((pBmi->biWidth <= pBmi2->biWidth) &&
        (pBmi->biHeight == abs(pBmi2->biHeight)))
    {
       return S_OK;
    }
    return VFW_E_TYPE_NOT_ACCEPTED;
}

Figure 11 DecideBufferSize Method
  HRESULT CYuvGray::DecideBufferSize(
    IMemAllocator *pAlloc,         // Pointer the downstream allocator
    ALLOCATOR_PROPERTIES *pProp)   // Downstream filter's buffer 
                                   // requirements (may be all zeroes)
{
    // Make sure our input pin connected.
    if (!m_pInput->IsConnected()) 
    {
        return E_UNEXPECTED;
    }
    // Find out the existing properties on the upstream allocator. 
    // First, get a pointer to the upstream allocator...
    ALLOCATOR_PROPERTIES InputProps;
    IMemAllocator *pAllocInput = 0;
    HRESULT hr = m_pInput->GetAllocator(&pAllocInput);
    if (FAILED(hr))
    {
        return hr;
    }
    // ... then get the properties.
    hr = pAllocInput->GetProperties(&InputProps);
    pAllocInput->Release();
    if (FAILED(hr)) 
    {
        return hr;
    }
    // Now find a suitable set of properties for the downstream 
    // allocator.
    if (pProp->cbAlign == 0)
    {
        pProp->cbAlign = 1;
    }
    if (pProp->cbBuffer == 0)
    {
        pProp->cBuffers = 1;
    }
    pProp->cbBuffer = max(InputProps.cbBuffer, pProp->cbBuffer);
   
    // Set the allocator properties
    ALLOCATOR_PROPERTIES ActualProp;
    hr = pAlloc->SetProperties(pProp, &ActualProp);
    if (FAILED(hr)) 
    {
        return hr;
    }
    
    // Check what we got.... Even if SetProperties() succeeds, the
    // allocator might not cooperate. The only property we care about
    // is buffer size.
    if (InputProps.cbBuffer > ActualProp.cbBuffer) 
    {
        return E_FAIL;
    }
    return S_OK;
}

Figure 13 Transform Method
  HRESULT CYuvGray::Transform(IMediaSample *pSource, IMediaSample *pDest)
{
    // Look for format changes from the video renderer.
    CMediaType *pmt = 0;
    if (S_OK == pDest->GetMediaType((AM_MEDIA_TYPE**)&pmt) && pmt)
    {
        // Notify our own output pin about the new type.
        m_pOutput->SetMediaType(pmt);
        DeleteMediaType(pmt);
    } 
   BYTE *pBufferIn, *pBufferOut;
    pSource->GetPointer(&pBufferIn);
    pDest->GetPointer(&pBufferOut);
    // Process the buffers.
    long cbByte = m_VihOut.bmiHeader.biSizeImage;
    HRESULT hr = ProcessFrame(pBufferIn, pBufferOut);
    pDest->SetActualDataLength(cbByte);
    return hr;
}

Figure 14 ProcessFrame Method
  HRESULT CYuvGray::ProcessFrame(BYTE *pbInput, BYTE *pbOutput)
{
    DWORD dwWidth, dwHeight;
    LONG  lStrideIn, lStrideOut;  // Stride in bytes
    BYTE  *pbSource, *pbTarget;
    GetVideoInfoParameters(&m_VihIn, pbOutput, &dwWidth, &dwHeight, 
      &lStride, &pbTarget, true);
    GetVideoInfoParameters(&m_VihOut, pbInput, &dwWidth, &dwHeight, 
      &lStride, &pbSource, true);
    for (DWORD y = 0; y < dwHeight; y++)
    {
        WORD *pwTarget = (WORD*)pbTarget;
        WORD *pwSource = (WORD*)pbSource;
        for (DWORD x = 0; x < dwWidth; x++)
        {
            // Each WORD is a 'UY' or 'VY' block. 
            // Set the low byte (chroma) to 0x80 and leave the high byte 
            // (luma)
            WORD pixel = pwSource[x] & 0xFF00;
            pixel |= 0x0080;
            pwTarget[x] = pixel;
        }
        // Advance the stride on both buffers.
        pbTarget += lStrideIn;
        pbSource += lStrideOut;
    }
    return S_OK;
}

Figure 16 Class Factory Template
  static const WCHAR g_wszName[] = L"YUV Filter"; // Friendly name.
AMOVIESETUP_FILTER FilterInfo =
{
    &CLSID_YuvGray,     // CLSID
    g_wszName,          // Name
    MERIT_DO_NOT_USE,   // Merit
    0,                  // Number of AMOVIESETUP_PIN structs
    NULL                // Pin registration information.
};
CFactoryTemplate g_Templates[1] = 
{
    { 
      g_wszName,                // Name
      &CLSID_YuvGray,           // CLSID
      CYuvGray::CreateInstance, // Method to create an instance of 
                                // MyComponent
      NULL,                     // Initialization function
      &FilterInfo               // Set-up information (for filters)
    }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);