6단계. COM에 대한 지원 추가
[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngine 및 Media Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드에서 DirectShow 대신 MediaPlayer, IMFMediaEngine 및 오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]
변환 필터 작성 자습서의 6단계입니다.
마지막 단계는 COM에 대한 지원을 추가하는 것입니다.
참조 계산
IUnknown::AddRef 또는 IUnknown::Release를 구현할 필요가 없습니다. 모든 필터 및 핀 클래스는 참조 계산을 처리하는 CUnknown에서 파생됩니다.
QueryInterface
모든 필터 및 핀 클래스는 상속하는 모든 COM 인터페이스에 대해 IUnknown::QueryInterface 를 구현합니다. 예를 들어 CTransformFilter는 CBaseFilter를 통해 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;
}
관련 항목