다음을 통해 공유


6단계. COM에 대한 지원 추가

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

변환 필터 작성 자습서의 6단계입니다.

마지막 단계는 COM에 대한 지원을 추가하는 것입니다.

참조 계산

IUnknown::AddRef 또는 IUnknown::Release를 구현할 필요가 없습니다. 모든 필터 및 핀 클래스는 참조 계산을 처리하는 CUnknown에서 파생됩니다.

QueryInterface

모든 필터 및 핀 클래스는 상속하는 모든 COM 인터페이스에 대해 IUnknown::QueryInterface 를 구현합니다. 예를 들어 CTransformFilterCBaseFilter를 통해 IBaseFilter를 상속합니다. 필터가 추가 인터페이스를 노출하지 않는 경우 다른 작업을 수행할 필요가 없습니다.

추가 인터페이스를 노출하려면 CUnknown::NonDelegatingQueryInterface 메서드를 재정의 합니다. 예를 들어 필터가 IMyCustomInterface라는 사용자 지정 인터페이스를 구현한다고 가정합니다. 이 인터페이스를 클라이언트에 노출하려면 다음을 수행합니다.

  • 해당 인터페이스에서 필터 클래스를 파생합니다.
  • 공용 선언 섹션에 DECLARE_IUNKNOWN 매크로를 배치합니다.
  • NonDelegatingQueryInterface를 재정의하여 인터페이스의 IID에 대한 검사 필터에 대한 포인터를 반환합니다.

다음은 이러한 단계를 보여 주는 코드입니다.

CMyFilter : public CBaseFilter, public IMyCustomInterface
{
public:
    DECLARE_IUNKNOWN
    STDMETHODIMP NonDelegatingQueryInterface(REFIID iid, void **ppv);
};
STDMETHODIMP CMyFilter::NonDelegatingQueryInterface(REFIID iid, void **ppv)
{
    if (riid == IID_IMyCustomInterface) {
        return GetInterface(static_cast<IMyCustomInterface*>(this), ppv);
    }
    return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
}

자세한 내용은 IUnknown을 구현하는 방법을 참조하세요.

개체 만들기

필터를 DLL로 패키지하고 다른 클라이언트에서 사용할 수 있도록 하려는 경우 CoCreateInstance 및 기타 관련 COM 함수를 지원해야 합니다. 기본 클래스 라이브러리는 이 중 대부분을 구현합니다. 필터에 대한 몇 가지 정보만 제공하면 됩니다. 이 섹션에서는 수행할 작업을 간략하게 설명합니다. 자세한 내용은 DirectShow 필터 DLL을 만드는 방법을 참조하세요.

먼저 필터의 새 instance 반환하는 정적 클래스 메서드를 작성합니다. 이 메서드의 이름을 원하는 항목으로 지정할 수 있지만 서명은 다음 예제와 일치해야 합니다.

CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
    CRleFilter *pFilter = new CRleFilter();
    if (pFilter== NULL) 
    {
        *pHr = E_OUTOFMEMORY;
    }
    return pFilter;
}

다음으로, g_Templates 라는 CFactoryTemplate 클래스 인스턴스의 전역 배열을 선언합니다. 각 CFactoryTemplate 클래스에는 하나의 필터에 대한 레지스트리 정보가 포함됩니다. 여러 필터가 단일 DLL에 상주할 수 있습니다. 추가 CFactoryTemplate 항목을 포함하기만 하면 됩니다. 속성 페이지와 같은 다른 COM 개체를 선언할 수도 있습니다.

static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] = 
{
  { 
    g_wszName,
    &CLSID_RLEFilter,
    CRleFilter::CreateInstance,
    NULL,
    NULL
  }
};

값이 g_Templates 배열의 길이와 같은 g_cTemplates 라는 전역 정수 정의:

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);  

마지막으로 DLL 등록 함수를 구현합니다. 다음 예제에서는 이러한 함수에 대한 최소 구현을 보여 줍니다.

STDAPI DllRegisterServer()
{
    return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
    return AMovieDllRegisterServer2( FALSE );
}

레지스트리 항목 필터링

이전 예제에서는 COM용 필터의 CLSID를 등록하는 방법을 보여 줍니다. 많은 필터의 경우 이것으로 충분합니다. 그런 다음 클라이언트는 CoCreateInstance 를 사용하여 필터를 만들고 IFilterGraph::AddFilter를 호출하여 필터 그래프에 추가해야 합니다. 그러나 경우에 따라 레지스트리의 필터에 대한 추가 정보를 제공할 수 있습니다. 이 정보는 다음을 수행합니다.

  • 클라이언트가 필터 매퍼 또는 시스템 디바이스 열거자를 사용하여 필터를 검색할 수 있도록 합니다.
  • 필터 그래프 관리자가 자동 그래프 빌드 중에 필터를 검색할 수 있도록 합니다.

다음 예제에서는 비디오 압축기 범주에 RLE 인코더 필터를 등록합니다. 자세한 내용은 DirectShow 필터를 등록하는 방법을 참조하세요. 필터 등록에 권장되는 방법을 설명하는 필터 등록 지침 섹션을 읽어보세요.

// Declare media type information.
FOURCCMap fccMap = FCC('MRLE'); 
REGPINTYPES sudInputTypes = { &MEDIATYPE_Video, &GUID_NULL };
REGPINTYPES sudOutputTypes = { &MEDIATYPE_Video, (GUID*)&fccMap };

// Declare pin information.
REGFILTERPINS sudPinReg[] = {
    // Input pin.
    { 0, FALSE, // Rendered?
         FALSE, // Output?
         FALSE, // Zero?
         FALSE, // Many?
         0, 0, 
         1, &sudInputTypes  // Media types.
    },
    // Output pin.
    { 0, FALSE, // Rendered?
         TRUE, // Output?
         FALSE, // Zero?
         FALSE, // Many?
         0, 0, 
         1, &sudOutputTypes      // Media types.
    }
};
 
// Declare filter information.
REGFILTER2 rf2FilterReg = {
    1,                // Version number.
    MERIT_DO_NOT_USE, // Merit.
    2,                // Number of pins.
    sudPinReg         // Pointer to pin information.
};

STDAPI DllRegisterServer(void)
{
    HRESULT hr = AMovieDllRegisterServer2(TRUE);
    if (FAILED(hr))
    {
        return hr;
    }
    IFilterMapper2 *pFM2 = NULL;
    hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
            IID_IFilterMapper2, (void **)&pFM2);
    if (SUCCEEDED(hr))
    {
        hr = pFM2->RegisterFilter(
            CLSID_RLEFilter,                // Filter CLSID. 
            g_wszName,                       // Filter name.
            NULL,                            // Device moniker. 
            &CLSID_VideoCompressorCategory,  // Video compressor category.
            g_wszName,                       // Instance data.
            &rf2FilterReg                    // Filter information.
            );
        pFM2->Release();
    }
    return hr;
}

STDAPI DllUnregisterServer()
{
    HRESULT hr = AMovieDllRegisterServer2(FALSE);
    if (FAILED(hr))
    {
        return hr;
    }
    IFilterMapper2 *pFM2 = NULL;
    hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
            IID_IFilterMapper2, (void **)&pFM2);
    if (SUCCEEDED(hr))
    {
        hr = pFM2->UnregisterFilter(&CLSID_VideoCompressorCategory, 
            g_wszName, CLSID_RLEFilter);
        pFM2->Release();
    }
    return hr;
}

또한 필터는 DLL 내에 패키지할 필요가 없습니다. 경우에 따라 특정 애플리케이션에 대해서만 설계된 특수 필터를 작성할 수 있습니다. 이 경우 다음 예제와 같이 애플리케이션에서 직접 필터 클래스를 컴파일하고 연산자를 new 사용하여 만들 수 있습니다.

#include "MyFilter.h"  // Header file that declares the filter class.
// Compile and link MyFilter.cpp.
int main()
{
    IBaseFilter *pFilter = 0;
    {
        // Scope to hide pF.
        CMyFilter* pF = new MyFilter();
        if (!pF)
        {
            printf("Could not create MyFilter.\n");
            return 1;
        }
        pF->QueryInterface(IID_IBaseFilter, 
            reinterpret_cast<void**>(&pFilter));
    }
    
    /* Now use pFilter as normal. */
    
    pFilter->Release();  // Deletes the filter.
    return 0;
}

Intelligent Connect

DirectShow 필터 작성

변환 필터 작성