2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
24 #include "..\..\DSUtil\DSUtil.h"
25 #include "DX7AllocatorPresenter.h"
26 #include "DX9AllocatorPresenter.h"
27 #include "..\..\..\include\moreuuids.h"
33 CFGFilter::CFGFilter(const CLSID
& clsid
, CStringW name
, UINT64 merit
)
40 const CAtlList
<GUID
>& CFGFilter::GetTypes() const
45 void CFGFilter::SetTypes(const CAtlList
<GUID
>& types
)
48 m_types
.AddTailList(&types
);
51 void CFGFilter::AddType(const GUID
& majortype
, const GUID
& subtype
)
53 m_types
.AddTail(majortype
);
54 m_types
.AddTail(subtype
);
57 bool CFGFilter::CheckTypes(const CAtlArray
<GUID
>& types
, bool fExactMatch
)
59 POSITION pos
= m_types
.GetHeadPosition();
62 const GUID
& majortype
= m_types
.GetNext(pos
);
63 if(!pos
) {ASSERT(0); break;}
64 const GUID
& subtype
= m_types
.GetNext(pos
);
66 for(int i
= 0, len
= types
.GetCount() & ~1; i
< len
; i
+= 2)
70 if(majortype
== types
[i
] && majortype
!= GUID_NULL
71 && subtype
== types
[i
+1] && subtype
!= GUID_NULL
)
76 if((majortype
== GUID_NULL
|| types
[i
] == GUID_NULL
|| majortype
== types
[i
])
77 && (subtype
== GUID_NULL
|| types
[i
+1] == GUID_NULL
|| subtype
== types
[i
+1]))
90 CFGFilterRegistry::CFGFilterRegistry(IMoniker
* pMoniker
, UINT64 merit
)
91 : CFGFilter(GUID_NULL
, L
"", merit
)
92 , m_pMoniker(pMoniker
)
94 if(!m_pMoniker
) return;
97 if(FAILED(m_pMoniker
->GetDisplayName(0, 0, &str
))) return;
98 m_DisplayName
= m_name
= str
;
99 CoTaskMemFree(str
), str
= NULL
;
101 CComPtr
<IPropertyBag
> pPB
;
102 if(SUCCEEDED(m_pMoniker
->BindToStorage(0, 0, IID_IPropertyBag
, (void**)&pPB
)))
105 if(SUCCEEDED(pPB
->Read(CComBSTR(_T("FriendlyName")), &var
, NULL
)))
107 m_name
= var
.bstrVal
;
111 if(SUCCEEDED(pPB
->Read(CComBSTR(_T("CLSID")), &var
, NULL
)))
113 CLSIDFromString(var
.bstrVal
, &m_clsid
);
117 if(SUCCEEDED(pPB
->Read(CComBSTR(_T("FilterData")), &var
, NULL
)))
120 if(SUCCEEDED(SafeArrayAccessData(var
.parray
, (void**)&pstr
)))
122 ExtractFilterData((BYTE
*)pstr
, var
.parray
->cbElements
*(var
.parray
->rgsabound
[0].cElements
));
123 SafeArrayUnaccessData(var
.parray
);
130 if(merit
!= MERIT64_DO_USE
) m_merit
.val
= merit
;
133 CFGFilterRegistry::CFGFilterRegistry(CStringW DisplayName
, UINT64 merit
)
134 : CFGFilter(GUID_NULL
, L
"", merit
)
135 , m_DisplayName(DisplayName
)
137 if(m_DisplayName
.IsEmpty()) return;
139 CComPtr
<IBindCtx
> pBC
;
140 CreateBindCtx(0, &pBC
);
143 if(S_OK
!= MkParseDisplayName(pBC
, CComBSTR(m_DisplayName
), &chEaten
, &m_pMoniker
))
146 CComPtr
<IPropertyBag
> pPB
;
147 if(SUCCEEDED(m_pMoniker
->BindToStorage(0, 0, IID_IPropertyBag
, (void**)&pPB
)))
150 if(SUCCEEDED(pPB
->Read(CComBSTR(_T("FriendlyName")), &var
, NULL
)))
152 m_name
= var
.bstrVal
;
156 if(SUCCEEDED(pPB
->Read(CComBSTR(_T("CLSID")), &var
, NULL
)))
158 CLSIDFromString(var
.bstrVal
, &m_clsid
);
162 if(SUCCEEDED(pPB
->Read(CComBSTR(_T("FilterData")), &var
, NULL
)))
165 if(SUCCEEDED(SafeArrayAccessData(var
.parray
, (void**)&pstr
)))
167 ExtractFilterData((BYTE
*)pstr
, var
.parray
->cbElements
*(var
.parray
->rgsabound
[0].cElements
));
168 SafeArrayUnaccessData(var
.parray
);
175 if(merit
!= MERIT64_DO_USE
) m_merit
.val
= merit
;
178 CFGFilterRegistry::CFGFilterRegistry(const CLSID
& clsid
, UINT64 merit
)
179 : CFGFilter(clsid
, L
"", merit
)
181 if(m_clsid
== GUID_NULL
) return;
183 CString guid
= CStringFromGUID(m_clsid
);
187 if(ERROR_SUCCESS
== key
.Open(HKEY_CLASSES_ROOT
, _T("CLSID\\") + guid
, KEY_READ
))
190 if(ERROR_SUCCESS
== key
.QueryStringValue(NULL
, NULL
, &nChars
))
193 if(ERROR_SUCCESS
== key
.QueryStringValue(NULL
, name
.GetBuffer(nChars
), &nChars
))
195 name
.ReleaseBuffer(nChars
);
205 if(ERROR_SUCCESS
== catkey
.Open(HKEY_CLASSES_ROOT
, _T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance"), KEY_READ
))
207 if(ERROR_SUCCESS
!= key
.Open(catkey
, guid
, KEY_READ
))
209 // illiminable pack uses the name of the filter and not the clsid, have to enum all keys to find it...
213 DWORD len
= countof(buff
);
214 for(DWORD i
= 0; ERROR_SUCCESS
== catkey
.EnumKey(i
, buff
, &len
, &ft
); i
++, len
= countof(buff
))
216 if(ERROR_SUCCESS
== key
.Open(catkey
, buff
, KEY_READ
))
219 len
= countof(clsid
);
220 if(ERROR_SUCCESS
== key
.QueryStringValue(_T("CLSID"), clsid
, &len
) && GUIDFromCString(clsid
) == m_clsid
)
231 if(ERROR_SUCCESS
== key
.QueryStringValue(_T("FriendlyName"), NULL
, &nChars
))
234 if(ERROR_SUCCESS
== key
.QueryStringValue(_T("FriendlyName"), name
.GetBuffer(nChars
), &nChars
))
236 name
.ReleaseBuffer(nChars
);
242 if(ERROR_SUCCESS
== key
.QueryBinaryValue(_T("FilterData"), NULL
, &nBytes
))
244 CAutoVectorPtr
<BYTE
> buff
;
245 if(buff
.Allocate(nBytes
) && ERROR_SUCCESS
== key
.QueryBinaryValue(_T("FilterData"), buff
, &nBytes
))
247 ExtractFilterData(buff
, nBytes
);
255 if(merit
!= MERIT64_DO_USE
) m_merit
.val
= merit
;
258 HRESULT
CFGFilterRegistry::Create(IBaseFilter
** ppBF
, CInterfaceList
<IUnknown
, &IID_IUnknown
>& pUnks
)
260 CheckPointer(ppBF
, E_POINTER
);
266 if(SUCCEEDED(hr
= m_pMoniker
->BindToObject(0, 0, IID_IBaseFilter
, (void**)ppBF
)))
268 m_clsid
= ::GetCLSID(*ppBF
);
271 else if(m_clsid
!= GUID_NULL
)
273 CComQIPtr
<IBaseFilter
> pBF
;
275 if(FAILED(pBF
.CoCreateInstance(m_clsid
)))
278 *ppBF
= pBF
.Detach();
286 [uuid("97f7c4d4-547b-4a5f-8332-536430ad2e4d")]
287 interface IAMFilterData
: public IUnknown
289 STDMETHOD (ParseFilterData
) (BYTE
* rgbFilterData
, ULONG cb
, BYTE
** prgbRegFilter2
) PURE
;
290 STDMETHOD (CreateFilterData
) (REGFILTER2
* prf2
, BYTE
** prgbFilterData
, ULONG
* pcb
) PURE
;
293 void CFGFilterRegistry::ExtractFilterData(BYTE
* p
, UINT len
)
295 CComPtr
<IAMFilterData
> pFD
;
298 if(SUCCEEDED(pFD
.CoCreateInstance(CLSID_FilterMapper2
))
299 && SUCCEEDED(pFD
->ParseFilterData(p
, len
, (BYTE
**)&ptr
)))
301 REGFILTER2
* prf
= (REGFILTER2
*)*(DWORD
*)ptr
; // this is f*cked up
303 m_merit
.mid
= prf
->dwMerit
;
305 if(prf
->dwVersion
== 1)
307 for(UINT i
= 0; i
< prf
->cPins
; i
++)
309 if(prf
->rgPins
[i
].bOutput
)
312 for(UINT j
= 0; j
< prf
->rgPins
[i
].nMediaTypes
; j
++)
314 if(!prf
->rgPins
[i
].lpMediaType
[j
].clsMajorType
|| !prf
->rgPins
[i
].lpMediaType
[j
].clsMinorType
)
317 const REGPINTYPES
& rpt
= prf
->rgPins
[i
].lpMediaType
[j
];
318 AddType(*rpt
.clsMajorType
, *rpt
.clsMinorType
);
322 else if(prf
->dwVersion
== 2)
324 for(UINT i
= 0; i
< prf
->cPins2
; i
++)
326 if(prf
->rgPins2
[i
].dwFlags
®_PINFLAG_B_OUTPUT
)
329 for(UINT j
= 0; j
< prf
->rgPins2
[i
].nMediaTypes
; j
++)
331 if(!prf
->rgPins2
[i
].lpMediaType
[j
].clsMajorType
|| !prf
->rgPins2
[i
].lpMediaType
[j
].clsMinorType
)
334 const REGPINTYPES
& rpt
= prf
->rgPins2
[i
].lpMediaType
[j
];
335 AddType(*rpt
.clsMajorType
, *rpt
.clsMinorType
);
346 #define ChkLen(size) if(p - base + size > (int)len) return;
349 if(*(DWORD
*)p
!= 0x00000002) return; // only version 2 supported, no samples found for 1
353 m_merit
.mid
= *(DWORD
*)p
; p
+= 4;
358 DWORD nPins
= *(DWORD
*)p
; p
+= 8;
362 BYTE n
= *p
-0x30; p
++;
365 WORD pi
= *(WORD
*)p
; p
+= 2;
373 bool fOutput
= !!(*p
®_PINFLAG_B_OUTPUT
);
377 DWORD nTypes
= *(DWORD
*)p
; p
+= 12;
381 BYTE n
= *p
-0x30; p
++;
384 WORD ty
= *(WORD
*)p
; p
+= 2;
393 if(*(DWORD
*)p
< (p
-base
+8) || *(DWORD
*)p
>= len
394 || *(DWORD
*)(p
+4) < (p
-base
+8) || *(DWORD
*)(p
+4) >= len
)
400 GUID majortype
, subtype
;
401 memcpy(&majortype
, &base
[*(DWORD
*)p
], sizeof(GUID
)); p
+= 4;
402 if(!fOutput
) AddType(majortype
, subtype
);
414 CFGFilterFile::CFGFilterFile(const CLSID
& clsid
, CString path
, CStringW name
, UINT64 merit
)
415 : CFGFilter(clsid
, name
, merit
)
421 HRESULT
CFGFilterFile::Create(IBaseFilter
** ppBF
, CInterfaceList
<IUnknown
, &IID_IUnknown
>& pUnks
)
423 CheckPointer(ppBF
, E_POINTER
);
425 return LoadExternalFilter(m_path
, m_clsid
, ppBF
);
429 // CFGFilterVideoRenderer
432 CFGFilterVideoRenderer::CFGFilterVideoRenderer(HWND hWnd
, const CLSID
& clsid
, CStringW name
, UINT64 merit
)
433 : CFGFilter(clsid
, name
, merit
)
436 AddType(MEDIATYPE_Video
, MEDIASUBTYPE_NULL
);
439 HRESULT
CFGFilterVideoRenderer::Create(IBaseFilter
** ppBF
, CInterfaceList
<IUnknown
, &IID_IUnknown
>& pUnks
)
441 CheckPointer(ppBF
, E_POINTER
);
445 CComPtr
<ISubPicAllocatorPresenter
> pCAP
;
447 if(m_clsid
== CLSID_VMR7AllocatorPresenter
448 || m_clsid
== CLSID_VMR9AllocatorPresenter
449 || m_clsid
== CLSID_DXRAllocatorPresenter
)
451 if(SUCCEEDED(CreateAP7(m_clsid
, m_hWnd
, &pCAP
))
452 || SUCCEEDED(CreateAP9(m_clsid
, m_hWnd
, &pCAP
)))
454 CComPtr
<IUnknown
> pRenderer
;
455 if(SUCCEEDED(hr
= pCAP
->CreateRenderer(&pRenderer
)))
457 *ppBF
= CComQIPtr
<IBaseFilter
>(pRenderer
).Detach();
464 CComPtr
<IBaseFilter
> pBF
;
465 if(SUCCEEDED(pBF
.CoCreateInstance(m_clsid
)))
467 BeginEnumPins(pBF
, pEP
, pPin
)
469 if(CComQIPtr
<IMixerPinConfig
, &IID_IMixerPinConfig
> pMPC
= pPin
)
477 *ppBF
= pBF
.Detach();
481 if(!*ppBF
) hr
= E_FAIL
;
490 CFGFilterList::CFGFilterList()
494 CFGFilterList::~CFGFilterList()
499 void CFGFilterList::RemoveAll()
501 while(!m_filters
.IsEmpty())
503 const filter_t
& f
= m_filters
.RemoveHead();
504 if(f
.autodelete
) delete f
.pFGF
;
507 m_sortedfilters
.RemoveAll();
510 void CFGFilterList::Insert(CFGFilter
* pFGF
, int group
, bool exactmatch
, bool autodelete
)
512 if(CFGFilterRegistry
* f1r
= dynamic_cast<CFGFilterRegistry
*>(pFGF
))
514 POSITION pos
= m_filters
.GetHeadPosition();
517 filter_t
& f2
= m_filters
.GetNext(pos
);
519 if(group
!= f2
.group
) continue;
521 if(CFGFilterRegistry
* f2r
= dynamic_cast<CFGFilterRegistry
*>(f2
.pFGF
))
523 if(f1r
->GetMoniker() && f2r
->GetMoniker() && S_OK
== f1r
->GetMoniker()->IsEqual(f2r
->GetMoniker())
524 || f1r
->GetCLSID() != GUID_NULL
&& f1r
->GetCLSID() == f2r
->GetCLSID())
526 TRACE(_T("FGM: Inserting %d %d %016I64x '%s' NOT!\n"),
527 group
, exactmatch
, pFGF
->GetMerit(),
528 pFGF
->GetName().IsEmpty() ? CStringFromGUID(pFGF
->GetCLSID()) : CString(pFGF
->GetName()));
530 if(autodelete
) delete pFGF
;
537 POSITION pos
= m_filters
.GetHeadPosition();
540 if(m_filters
.GetNext(pos
).pFGF
== pFGF
)
542 TRACE(_T("FGM: Inserting %d %d %016I64x '%s' DUP!\n"),
543 group
, exactmatch
, pFGF
->GetMerit(),
544 pFGF
->GetName().IsEmpty() ? CStringFromGUID(pFGF
->GetCLSID()) : CString(pFGF
->GetName()));
546 if(autodelete
) delete pFGF
;
551 TRACE(_T("FGM: Inserting %d %d %016I64x '%s'\n"),
552 group
, exactmatch
, pFGF
->GetMerit(),
553 pFGF
->GetName().IsEmpty() ? CStringFromGUID(pFGF
->GetCLSID()) : CString(pFGF
->GetName()));
555 filter_t f
= {m_filters
.GetCount(), pFGF
, group
, exactmatch
, autodelete
};
556 m_filters
.AddTail(f
);
558 m_sortedfilters
.RemoveAll();
561 POSITION
CFGFilterList::GetHeadPosition()
563 if(m_sortedfilters
.IsEmpty())
565 CAtlArray
<filter_t
> sort
;
566 sort
.SetCount(m_filters
.GetCount());
567 POSITION pos
= m_filters
.GetHeadPosition();
568 for(int i
= 0; pos
; i
++) sort
[i
] = m_filters
.GetNext(pos
);
569 qsort(&sort
[0], sort
.GetCount(), sizeof(sort
[0]), filter_cmp
);
570 for(size_t i
= 0; i
< sort
.GetCount(); i
++)
571 if(sort
[i
].pFGF
->GetMerit() >= MERIT64_DO_USE
)
572 m_sortedfilters
.AddTail(sort
[i
].pFGF
);
575 TRACE(_T("FGM: Sorting filters\n"));
577 POSITION pos
= m_sortedfilters
.GetHeadPosition();
580 CFGFilter
* pFGF
= m_sortedfilters
.GetNext(pos
);
581 TRACE(_T("FGM: - %016I64x '%s'\n"), pFGF
->GetMerit(), pFGF
->GetName().IsEmpty() ? CStringFromGUID(pFGF
->GetCLSID()) : CString(pFGF
->GetName()));
584 return m_sortedfilters
.GetHeadPosition();
587 CFGFilter
* CFGFilterList::GetNext(POSITION
& pos
)
589 return m_sortedfilters
.GetNext(pos
);
592 int CFGFilterList::filter_cmp(const void* a
, const void* b
)
594 filter_t
* fa
= (filter_t
*)a
;
595 filter_t
* fb
= (filter_t
*)b
;
597 if(fa
->group
< fb
->group
) return -1;
598 if(fa
->group
> fb
->group
) return +1;
600 if(fa
->pFGF
->GetCLSID() == fb
->pFGF
->GetCLSID())
602 CFGFilterFile
* fgfa
= dynamic_cast<CFGFilterFile
*>(fa
->pFGF
);
603 CFGFilterFile
* fgfb
= dynamic_cast<CFGFilterFile
*>(fb
->pFGF
);
605 if(fgfa
&& !fgfb
) return -1;
606 if(!fgfa
&& fgfb
) return +1;
609 if(fa
->pFGF
->GetMerit() > fb
->pFGF
->GetMerit()) return -1;
610 if(fa
->pFGF
->GetMerit() < fb
->pFGF
->GetMerit()) return +1;
612 if(fa
->exactmatch
&& !fb
->exactmatch
) return -1;
613 if(!fa
->exactmatch
&& fb
->exactmatch
) return +1;
615 if(fa
->index
< fb
->index
) return -1;
616 if(fa
->index
> fb
->index
) return +1;