See beginning in microsoft.public.win32.programmer.directx.video newsgroup.
This sample is demonstrating COM aggregation to embed an existing filter an re-expose it as a new filter having inner filter pre-initialized.
The Visual Studio C++.NET 2008 projects contains a DirectShow filter class that registers itself under Video Capture Sources category and embeds File Source (Async) Filter inside initialized to stream clock.avi file from Windows directory.
The code of interest is in Filter.h. CFilter class is the implementation of the DirectShow filter.
CFilter registers itself as a filter through static UpdateRegistry method, which overrides stock DECLARE_REGISTRY_RESOURCEID macro and adds IFilterMapper2 interface calls to register/unregister the filter.
To take an advantage of aggregating another object we need DECLARE_PROTECT_FINAL_CONSTRUCT macro to be able to instantiate inner (that is aggregated) object on the very start (we cannot do this right in constructor), DECLARE_GET_CONTROLLING_UNKNOWN macro to declare member menthod that exposes controlling unknown.
In a FinalConstruct method we instantiate aggregated object (note GetControllingUnknown() argument which indicates instantiating as aggregated):
ATLENSURE_SUCCEEDED(m_pInnerUnknown.CoCreateInstance(CLSID_AsyncReader, GetControllingUnknown()));
and initialize the object through IFileSourceFilter::Load. The inner object is ready and we are to expose its functionality as if implemented natively. We need to update object’s COM MAP for this:
BEGIN_COM_MAP(CFilter) COM_INTERFACE_ENTRY(IFilter) // NOTE: We still implement IDispatch through IFilter but we hide it to hopefully expose inner filter's IDispatch //COM_INTERFACE_ENTRY(IDispatch) // NOTE: We are hiding inner filter IFileSourceFilter to avoid GraphEdit prompts for file path on filter insertion COM_INTERFACE_ENTRY_NOINTERFACE(IFileSourceFilter) COM_INTERFACE_ENTRY_AGGREGATE_BLIND(m_pInnerUnknown) END_COM_MAP()
COM_INTERFACE_ENTRY_AGGREGATE_BLIND will expose all inner object interfaces (except mentioned higher on the map) to the outside world. And we explicitly suppress IFileSourceFilter through COM_INTERFACE_ENTRY_NOINTERFACE to prevent GraphEdit from discovering it and popping up a file dialog to select a source file.
Source code: DirectShowWrapperSourceFilterSample.01.zip (note that Release build binary is included)
Source code in SVN online: http://code.assembla.com/roatl-utilities/subversion/nodes/trunk/DirectShowWrapperSourceFilterSample
hi,Alax
I compiled sucessfully with your src code On Vista32 Sp1+ VC2008, but run with a graphedit error message when try insert your source filter:
The Filter Could not be created. Resource used by this filter may be already be in use.
…
Return code: 0x80070002
after that, I did the same thing on another Comp which has Xp Sp2 + VC2008 SP1,
,this time it’s Ok to display the clock with pulsed sound.
RGS!
Mr. ShiRui, perhaps the device was indeed in use so that you could not open it? It could be, for example, locked by another application.
Hello ..thanks for posting this …I am successfully able to compile and see the filter in graph edit and play clock.avi file.
Now in WMEncoder, I can see this ‘Alax.InfoWrapper Source Sample’ entry in the Video source. But when I select this, it is showing error dialog
‘One or more codecs required to open this content could not be found. (0xC00D1B83)’
I would like this filter to work as a source in WMEncoder and stream the video thru the filter.
Please help…
The error is quite descriptive but I am not sure how it is related to this source filter. My guess would be however that this kind of sample is nicely illustrating COM aggregation but AVI file source is quite far from real video source.
File source is delivering raw file contents. OK, it may supply data with AVI subtype, but that’s all. On the other hand even simplest video source is expected to at least deliver video samples with media type of MEDIATYPE_Video. I think it is the cause. WMEncoder just does not see what it can do with this lind of data. And a video source is also generally expected to implement IAMStreamConfig, so what is actually required is to take a better base for aggregation.
Alax
I am new to DirectX Filters. Are you telling to use different base filter instead of AsyncReader, if so, which filter?
WMEncoder might be using the same filters requires to play avi, i.e AsyncReader->AVISplitter->ColorSpaceConverter->Renderer or streamer.
Thanks again..
There was no other suitable filter to wrap, so I wrapped that AVI. There should have been a proper inner filter for a solid demo. Actually I still have plans to make one but there has been no time so far.
If such filter wrapped AsyncReader and AVISplitter together and showed these two as a single source filter with an output pin corresponding to splitter’s video output pin – this would work, including WMEcnoder. But with COM aggregation you can only embed one filter, not the chain.
So perhaps stay tuned here and there will be another sample, compatible with Windows Media Encoder…
P.S. Filters are DirectShow, not DirectX. DirectShow now is a part of Windows/Platform SDK, that is “the core”. DirectX is not.
I appreciate your help. Looking forward for your another sample..
“But with COM aggregation you can only embed one filter, not the chain.”
Hi Alax:
Can you give me some advice to wrap a filter chain in a sigle directshow filter?
In my project, i want play dvb by windows media player. I think i should write a filter which contains NetworkProvoder–>tuner–>capturer–>mpeg2demux, and assotiate it with a cumtom file extension(.dvb). Is that right and what is your advice for that?
thanks.
You need to create a full filter which internally embeds graph of your interest. For source filter that you mention, you will have the chain you mention + some sink renderer filter (some prefer Sample Grabber Filter + Null Renderer for this purpose) and each time this renderer generates a media sample, you delivery it from output pin of your top level filter.
Yes, you can associate your filter with a file extension or a protocol, so that WMP pick it up.
Also, I see your post on MSDN Forums: http://social.msdn.microsoft.com/Forums/en-US/windowsdirectshowdevelopment/thread/c651939d-c530-4a0a-a0b4-7bb32b70b847/
Roman :
Thanks for your reply, i will try it.
“Also, I see your post on MSDN Forums: http://social.msdn.microsoft.com/Forums/en-US/windowsdirectshowdevelopment/thread/c651939d-c530-4a0a-a0b4-7bb32b70b847/”
:)
Hi Roman:
I wrote a DVBSrcFilter(a fake src) derived from CBaseFilter with a output pin derived from CBaseOutputPin. It do nothing and just for connecting to downstream filter
filter information code like these:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
const AMOVIESETUP_MEDIATYPE sudOpPinTypes =
{
&MEDIATYPE_Video,
&MEDIASUBTYPE_MPEG2_VIDEO
};
const AMOVIESETUP_PIN sudOpPin =
{ L”VideoOutput” // strName
, FALSE // bRendered
, TRUE // bOutput
, FALSE // bZero
, FALSE // bMany
, &CLSID_NULL // clsConnectsToFilter
, NULL // strConnectsToPin
, 1 // nTypes
, &sudOpPinTypes } ; // lpTypes;
const AMOVIESETUP_FILTER DVBSrcFilter =
{ &CLSID_DVBSrcFilter // clsID
, L”DVBSrcFilter” // strName
, MERIT_UNLIKELY // dwMerit
, 1 // nPins
, &sudOpPin };
#endif
//
// Object creation template
//
CFactoryTemplate g_Templates[1] = {
{ L”DVBSrcFilter”
, &CLSID_DVBSrcFilter
, CDVBSrcFilter::CreateInstance
, NULL
, &DVBSrcFilter }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ffdshow Video Decoder in graphedit,
visual studio pop warning like this:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Windows has triggered a breakpoint in graphedt.exe.
This may be due to a corruption of the heap, and indicates a bug in graphedt.exe or any of the DLLs it has loaded.
The output window may have more diagnostic information
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>
These filters cannot agree on a connection. Verify type compatibility of input pin and output pin. No combination of intermediate filters could be found to make the connection
(Return code: 0x80040217)
<<<<<<<<<Sample Grabber
It was ok;
I’m new for directshow development, please help me, thanks a lot.
Hi Roman:
I am sorry for above puzzel comments. I cannot edit comment after submit, so i post it again as following:
I wrote a DVBSrcFilter(a fake src) derived from CBaseFilter with a output pin derived from CBaseOutputPin. It do nothing and just for connecting to downstream filter
filter information code like this:
===================begin==============================
const AMOVIESETUP_MEDIATYPE sudOpPinTypes =
{
&MEDIATYPE_Video,
&MEDIASUBTYPE_MPEG2_VIDEO
};
const AMOVIESETUP_PIN sudOpPin =
{ L”VideoOutput” // strName
, FALSE // bRendered
, TRUE // bOutput
, FALSE // bZero
, FALSE // bMany
, &CLSID_NULL // clsConnectsToFilter
, NULL // strConnectsToPin
, 1 // nTypes
, &sudOpPinTypes } ; // lpTypes;
const AMOVIESETUP_FILTER DVBSrcFilter =
{ &CLSID_DVBSrcFilter // clsID
, L”DVBSrcFilter” // strName
, MERIT_UNLIKELY // dwMerit
, 1 // nPins
, &sudOpPin };
#endif
//
// Object creation template
//
CFactoryTemplate g_Templates[1] = {
{ L”DVBSrcFilter”
, &CLSID_DVBSrcFilter
, CDVBSrcFilter::CreateInstance
, NULL
, &DVBSrcFilter }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
========================end=====================
When i attemp to connect DVBSrcFilter –>ffdshow Video Decoder in graphedit,
visual studio pop warning like this:
========================begin===========================
Windows has triggered a breakpoint in graphedt.exe.
This may be due to a corruption of the heap, and indicates a bug in graphedt.exe or any of the DLLs it has loaded.
The output window may have more diagnostic information
=======================end===============
if chose continue, pop something like this:
========================begin=================================
These filters cannot agree on a connection. Verify type compatibility of input pin and output pin. No combination of intermediate filters could be found to make the connection
(Return code: 0x80040217)
========================end=====================================
I verified that output pin and input pin both have the media type of MEDIATYPE_Video/MEDIASUBTYPE_MPEG2_VIDEO, why cannot they connect?
ps :
if connect like this :
DVBSrcFilter –>Sample Grabber
It was ok;
I’m new for directshow development, please help me, thanks a lot.
Hi Roman:
The first warning:
========================begin===========================
Windows has triggered a breakpoint in graphedt.exe.
This may be due to a corruption of the heap, and indicates a bug in graphedt.exe or any of the DLLs it has loaded.
The output window may have more diagnostic information
=======================end===============
may be caused by DVBworld software :M2AToM1A.ax.
I have rename it to M2AToM1A.ax.renamed, and this warning was handled.
But, the second warning still pop.
“This may be due to a corruption of the heap, and indicates a bug in…” indicates that memory heap is damaged, e.g. something wrote to a memory block out side of allocated size and destroyed fields responsible for memory heap integrity. It is likely that it is your filter, but you provided only registration code so I have no ideas as for what code could destroy the heap. There is no other way but find it and fix it so that memory is properly used.
Roman:
Thanks for your reply.
Here is my complete code.
/**********
DVBSrcFilter.h
***********/
#include
#include
#include
#include
// {68DD561A-E069-4c75-BB76-6D2FE30234D1}
DEFINE_GUID(CLSID_DVBSrcFilter,
0x68dd561a, 0xe069, 0x4c75, 0xbb, 0x76, 0x6d, 0x2f, 0xe3, 0x2, 0x34, 0xd1);
class CVideoOutputPin ;
class CDVBSrcFilter ;
class CVideoOutputPin :
public CBaseOutputPin
{
public :
CVideoOutputPin (
IN TCHAR * szName,
IN CBaseFilter * pFilter,
IN CCritSec * pLock,
OUT HRESULT * pHr,
IN LPCWSTR pszName
) ;
~CVideoOutputPin () ;
HRESULT
GetMediaType (
IN int iPosition,
OUT CMediaType * pmt
) ;
HRESULT
CheckMediaType (
IN const CMediaType * pmt
) ;
HRESULT
DecideBufferSize (
IN IMemAllocator *,
OUT ALLOCATOR_PROPERTIES *
) ;
} ;
class CDVBSrcFilter : public CBaseFilter
{
CCritSec m_crtFilterLock ; // filter lock
CVideoOutputPin * m_pVideoOutput ; // video output pin
public :
CDVBSrcFilter (
IN TCHAR * tszName,
IN LPUNKNOWN punk,
OUT HRESULT * phr
) ;
~CDVBSrcFilter (
) ;
void LockFilter () { m_crtFilterLock.Lock () ; }
void UnlockFilter () { m_crtFilterLock.Unlock () ; }
// ——————————————————————–
// CBaseFilter methods
int GetPinCount ()
{ return 1 ; }
CBasePin * GetPin (IN int Index) ;
DECLARE_IUNKNOWN
STDMETHODIMP NonDelegatingQueryInterface (
IN REFIID riid,
OUT void ** ppv
)
{
return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
}
static
CUnknown *
CreateInstance (
IN LPUNKNOWN punk,
OUT HRESULT * phr
) ;
} ;
/*************
DVBSrcFilter.cpp
**************/
#include “DVBSrcFilter.h”
const AMOVIESETUP_MEDIATYPE sudOpPinTypes =
{
&MEDIATYPE_Video,
&MEDIASUBTYPE_MPEG2_VIDEO
};
const AMOVIESETUP_PIN sudOpPin =
{ L”VideoOutput” // strName
, FALSE // bRendered
, TRUE // bOutput
, FALSE // bZero
, FALSE // bMany
, &CLSID_NULL // clsConnectsToFilter
, NULL // strConnectsToPin
, 1 // nTypes
, &sudOpPinTypes } ; // lpTypes;
const AMOVIESETUP_FILTER DVBSrcFilter =
{ &CLSID_DVBSrcFilter // clsID
, L”DVBSrcFilter” // strName
, MERIT_UNLIKELY // dwMerit
, 1 // nPins
, &sudOpPin };
//
// Object creation template
//
CFactoryTemplate g_Templates[1] = {
{ L”DVBSrcFilter”
, &CLSID_DVBSrcFilter
, CDVBSrcFilter::CreateInstance
, NULL
, &DVBSrcFilter }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2(TRUE);
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2(FALSE);
}
//
// DllEntryPoint
//
extern “C” BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
LPVOID lpReserved)
{
return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}
CVideoOutputPin::CVideoOutputPin (
IN TCHAR * szName,
IN CBaseFilter * pFilter,
IN CCritSec * pLock,
OUT HRESULT * pHr,
IN LPCWSTR pszName
) : CBaseOutputPin (szName,
pFilter,
pLock,
pHr,
pszName
)
{
}
CVideoOutputPin::~CVideoOutputPin (
)
{
}
HRESULT
CVideoOutputPin::GetMediaType (
IN int iPosition,
OUT CMediaType * pmt
)
{
HRESULT hr ;
if (iPosition == 0) {
ASSERT (pmt) ;
pmt -> InitMediaType () ;
pmt -> SetType (& MEDIATYPE_Video) ;
pmt -> SetSubtype (& MEDIASUBTYPE_MPEG2_VIDEO) ;
hr = S_OK ;
}
else {
hr = VFW_S_NO_MORE_ITEMS ;
}
return hr ;
}
HRESULT
CVideoOutputPin::CheckMediaType (
IN const CMediaType * pmt
)
{
HRESULT hr ;
ASSERT (pmt) ;
if (pmt -> majortype == MEDIATYPE_Video &&
pmt -> subtype == MEDIASUBTYPE_MPEG2_VIDEO) {
hr = S_OK ;
}
else {
hr = S_FALSE ;
}
return hr ;
}
HRESULT
CVideoOutputPin::DecideBufferSize (
IN IMemAllocator * pIMemAllocator,
OUT ALLOCATOR_PROPERTIES * pProp
)
{
HRESULT hr ;
ALLOCATOR_PROPERTIES pActual;
hr = pIMemAllocator->SetProperties (pProp, &pActual);
if (hr != S_OK) {
printf (“%s: SetProperties return hr(%d)\n”, __FUNCTION__, hr);
}
return hr;
}
CDVBSrcFilter::CDVBSrcFilter (
IN TCHAR * tszName,
IN LPUNKNOWN punk,
OUT HRESULT * phr
) : CBaseFilter (
tszName,
punk,
& m_crtFilterLock,
CLSID_DVBSrcFilter
),
m_pVideoOutput (NULL)
{
// instantiate the output pin
m_pVideoOutput = new CVideoOutputPin (
NAME (“xxVideoOutputPin”),
this,
& m_crtFilterLock,
phr,
L”yyMPEG-2 Video”
) ;
if (m_pVideoOutput == NULL ||
FAILED (* phr)) {
(* phr) = (FAILED (* phr) ? * phr : E_OUTOFMEMORY) ;
return ;
}
}
CDVBSrcFilter::~CDVBSrcFilter ()
{
delete m_pVideoOutput ;
}
CBasePin *
CDVBSrcFilter::GetPin (
IN int Index
)
{
CBasePin * pPin ;
LockFilter () ;
if (Index == 0) {
pPin = m_pVideoOutput ;
}
#ifdef USE_AUDIO
else if (Index == 1) {
pPin = m_pAudioOutput;
}
#endif
else {
pPin = NULL ;
}
UnlockFilter () ;
return pPin ;
}
CUnknown * WINAPI CDVBSrcFilter::CreateInstance (
IN LPUNKNOWN punk,
OUT HRESULT * phr
)
{
ASSERT(phr);
return new CDVBSrcFilter (
NAME (“CDVBSrcFilter”),
punk,
phr
) ;
}
OK, everything looks straghtforward. I suppose you don’t have USE_AUDIO
defined or it would be use of uninitialized object.
My CDVBSrcFilter just has 1 output pin for mpeg2 video, m_pAudioOutput is not a member of CDVBSrcFilter. So, “don’t having USE_AUDIO defined” is what i expect.
I modified the code and it is now:
CBasePin *
CDVBSrcFilter::GetPin (IN int Index)
{
CBasePin * pPin ;
LockFilter () ;
if (Index == 0) {
pPin = m_pVideoOutput ;
}
else {
pPin = NULL ;
}
UnlockFilter () ;
return pPin ;
}
Follow-up from bikekiller: