다음을 통해 공유


Kernel-Mode 필터 만들기

[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngineMedia Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드에서 DirectShow 대신 MediaPlayer, IMFMediaEngine오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]

특정 커널 모드 필터는 CoCreateInstance를 통해 만들 수 없으므로 CLSID가 없습니다. 이러한 필터에는 Tee/Sink-to-Sink 변환기, CC 디코더 필터 및 WST 코덱 필터가 포함됩니다. 이러한 필터 중 하나를 만들려면 시스템 디바이스 열거자 개체를 사용하고 필터 이름으로 검색합니다.

  1. 시스템 디바이스 열거자를 만듭니다.
  2. 해당 필터에 대한 필터 범주의 CLSID를 사용하여 ICreateDevEnum::CreateClassEnumerator 메서드를 호출합니다. 이 메서드는 필터 범주에 대한 열거자를 만듭니다. ( 열거자는 정의된 COM 인터페이스를 사용하여 다른 개체 목록을 반환하는 개체일 뿐입니다.) 열거자는 해당 범주의 필터를 나타내는 IMoniker 포인터를 반환합니다.
  3. 각 모니커에 대해 IMoniker::BindToStorage 를 호출하여 IPropertyBag 인터페이스를 가져옵니다.
  4. IPropertyBag::Read를 호출하여 필터의 이름을 가져옵니다.
  5. 이름이 일치하면 IMoniker::BindToObject 를 호출하여 필터를 만듭니다.

다음 코드는 다음 단계를 수행하는 함수를 보여 줍니다.

HRESULT CreateKernelFilter(
    const GUID &guidCategory,  // Filter category.
    LPCOLESTR szName,          // The name of the filter.
    IBaseFilter **ppFilter     // Receives a pointer to the filter.
)
{
    HRESULT hr;
    ICreateDevEnum *pDevEnum = NULL;
    IEnumMoniker *pEnum = NULL;
    if (!szName || !ppFilter) 
    {
        return E_POINTER;
    }

    // Create the system device enumerator.
    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
        IID_ICreateDevEnum, (void**)&pDevEnum);
    if (FAILED(hr))
    {
        return hr;
    }

    // Create a class enumerator for the specified category.
    hr = pDevEnum->CreateClassEnumerator(guidCategory, &pEnum, 0);
    pDevEnum->Release();
    if (hr != S_OK) // S_FALSE means the category is empty.
    {
        return E_FAIL;
    }

    // Enumerate devices within this category.
    bool bFound = false;
    IMoniker *pMoniker;
    while (!bFound && (S_OK == pEnum->Next(1, &pMoniker, 0)))
    {
        IPropertyBag *pBag = NULL;
        hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
        if (FAILED(hr))
        {
            pMoniker->Release();
            continue; // Maybe the next one will work.
        }
        // Check the friendly name.
        VARIANT var;
        VariantInit(&var);
        hr = pBag->Read(L"FriendlyName", &var, NULL);
        if (SUCCEEDED(hr) && (lstrcmpiW(var.bstrVal, szName) == 0))
        {
            // This is the right filter.
            hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter,
                (void**)ppFilter);
            bFound = true;
        }
        VariantClear(&var);
        pBag->Release();
        pMoniker->Release();
    }
    pEnum->Release();
    return (bFound ? hr : E_FAIL);
}

다음 코드 예제에서는 이 함수를 사용하여 CC 디코더 필터를 만들고 필터 그래프에 추가합니다.

IBaseFilter *pCC = NULL;
hr = CreateKernelFilter(AM_KSCATEGORY_VBICODEC, 
    OLESTR("CC Decoder"), &pCC);
if (SUCCEEDED(hr))
{
    hr = pGraph->AddFilter(pCC, L"CC Decoder");
    pCC->Release();
}

고급 캡처 항목

시스템 디바이스 열거자 사용