Support unrar64.dll
[xy_vsfilter.git] / src / apps / mplayerc / FGFilter.cpp
blob1ebae6cdcd68fd19c04770089931847035933ac8
1 /*
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)
8 * any later version.
9 *
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
22 #include "stdafx.h"
23 #include "FGFilter.h"
24 #include "..\..\DSUtil\DSUtil.h"
25 #include "DX7AllocatorPresenter.h"
26 #include "DX9AllocatorPresenter.h"
27 #include "..\..\..\include\moreuuids.h"
30 // CFGFilter
33 CFGFilter::CFGFilter(const CLSID& clsid, CStringW name, UINT64 merit)
34 : m_clsid(clsid)
35 , m_name(name)
37 m_merit.val = merit;
40 const CAtlList<GUID>& CFGFilter::GetTypes() const
42 return m_types;
45 void CFGFilter::SetTypes(const CAtlList<GUID>& types)
47 m_types.RemoveAll();
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();
60 while(pos)
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)
68 if(fExactMatch)
70 if(majortype == types[i] && majortype != GUID_NULL
71 && subtype == types[i+1] && subtype != GUID_NULL)
72 return true;
74 else
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]))
78 return true;
83 return false;
87 // CFGFilterRegistry
90 CFGFilterRegistry::CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit)
91 : CFGFilter(GUID_NULL, L"", merit)
92 , m_pMoniker(pMoniker)
94 if(!m_pMoniker) return;
96 LPOLESTR str = NULL;
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)))
104 CComVariant var;
105 if(SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
107 m_name = var.bstrVal;
108 var.Clear();
111 if(SUCCEEDED(pPB->Read(CComBSTR(_T("CLSID")), &var, NULL)))
113 CLSIDFromString(var.bstrVal, &m_clsid);
114 var.Clear();
117 if(SUCCEEDED(pPB->Read(CComBSTR(_T("FilterData")), &var, NULL)))
119 BSTR* pstr;
120 if(SUCCEEDED(SafeArrayAccessData(var.parray, (void**)&pstr)))
122 ExtractFilterData((BYTE*)pstr, var.parray->cbElements*(var.parray->rgsabound[0].cElements));
123 SafeArrayUnaccessData(var.parray);
126 var.Clear();
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);
142 ULONG chEaten;
143 if(S_OK != MkParseDisplayName(pBC, CComBSTR(m_DisplayName), &chEaten, &m_pMoniker))
144 return;
146 CComPtr<IPropertyBag> pPB;
147 if(SUCCEEDED(m_pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPB)))
149 CComVariant var;
150 if(SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
152 m_name = var.bstrVal;
153 var.Clear();
156 if(SUCCEEDED(pPB->Read(CComBSTR(_T("CLSID")), &var, NULL)))
158 CLSIDFromString(var.bstrVal, &m_clsid);
159 var.Clear();
162 if(SUCCEEDED(pPB->Read(CComBSTR(_T("FilterData")), &var, NULL)))
164 BSTR* pstr;
165 if(SUCCEEDED(SafeArrayAccessData(var.parray, (void**)&pstr)))
167 ExtractFilterData((BYTE*)pstr, var.parray->cbElements*(var.parray->rgsabound[0].cElements));
168 SafeArrayUnaccessData(var.parray);
171 var.Clear();
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);
185 CRegKey key;
187 if(ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + guid, KEY_READ))
189 ULONG nChars = 0;
190 if(ERROR_SUCCESS == key.QueryStringValue(NULL, NULL, &nChars))
192 CString name;
193 if(ERROR_SUCCESS == key.QueryStringValue(NULL, name.GetBuffer(nChars), &nChars))
195 name.ReleaseBuffer(nChars);
196 m_name = name;
200 key.Close();
203 CRegKey catkey;
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...
211 FILETIME ft;
212 TCHAR buff[256];
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))
218 TCHAR clsid[256];
219 len = countof(clsid);
220 if(ERROR_SUCCESS == key.QueryStringValue(_T("CLSID"), clsid, &len) && GUIDFromCString(clsid) == m_clsid)
221 break;
223 key.Close();
228 if(key)
230 ULONG nChars = 0;
231 if(ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), NULL, &nChars))
233 CString name;
234 if(ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), name.GetBuffer(nChars), &nChars))
236 name.ReleaseBuffer(nChars);
237 m_name = name;
241 ULONG nBytes = 0;
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);
251 key.Close();
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);
262 HRESULT hr = E_FAIL;
264 if(m_pMoniker)
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)))
276 return E_FAIL;
278 *ppBF = pBF.Detach();
280 hr = S_OK;
283 return hr;
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;
296 BYTE* ptr = NULL;
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)
310 continue;
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)
315 break;
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&REG_PINFLAG_B_OUTPUT)
327 continue;
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)
332 break;
334 const REGPINTYPES& rpt = prf->rgPins2[i].lpMediaType[j];
335 AddType(*rpt.clsMajorType, *rpt.clsMinorType);
340 CoTaskMemFree(prf);
342 else
344 BYTE* base = p;
346 #define ChkLen(size) if(p - base + size > (int)len) return;
348 ChkLen(4)
349 if(*(DWORD*)p != 0x00000002) return; // only version 2 supported, no samples found for 1
350 p += 4;
352 ChkLen(4)
353 m_merit.mid = *(DWORD*)p; p += 4;
355 m_types.RemoveAll();
357 ChkLen(8)
358 DWORD nPins = *(DWORD*)p; p += 8;
359 while(nPins-- > 0)
361 ChkLen(1)
362 BYTE n = *p-0x30; p++;
364 ChkLen(2)
365 WORD pi = *(WORD*)p; p += 2;
366 ASSERT(pi == 'ip');
368 ChkLen(1)
369 BYTE x33 = *p; p++;
370 ASSERT(x33 == 0x33);
372 ChkLen(8)
373 bool fOutput = !!(*p&REG_PINFLAG_B_OUTPUT);
374 p += 8;
376 ChkLen(12)
377 DWORD nTypes = *(DWORD*)p; p += 12;
378 while(nTypes-- > 0)
380 ChkLen(1)
381 BYTE n = *p-0x30; p++;
383 ChkLen(2)
384 WORD ty = *(WORD*)p; p += 2;
385 ASSERT(ty == 'yt');
387 ChkLen(5)
388 BYTE x33 = *p; p++;
389 ASSERT(x33 == 0x33);
390 p += 4;
392 ChkLen(8)
393 if(*(DWORD*)p < (p-base+8) || *(DWORD*)p >= len
394 || *(DWORD*)(p+4) < (p-base+8) || *(DWORD*)(p+4) >= len)
396 p += 8;
397 continue;
400 GUID majortype, subtype;
401 memcpy(&majortype, &base[*(DWORD*)p], sizeof(GUID)); p += 4;
402 if(!fOutput) AddType(majortype, subtype);
406 #undef ChkLen
411 // CFGFilterFile
414 CFGFilterFile::CFGFilterFile(const CLSID& clsid, CString path, CStringW name, UINT64 merit)
415 : CFGFilter(clsid, name, merit)
416 , m_path(path)
417 , m_hInst(NULL)
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)
434 , m_hWnd(hWnd)
436 AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL);
439 HRESULT CFGFilterVideoRenderer::Create(IBaseFilter** ppBF, CInterfaceList<IUnknown, &IID_IUnknown>& pUnks)
441 CheckPointer(ppBF, E_POINTER);
443 HRESULT hr = S_OK;
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();
458 pUnks.AddTail(pCAP);
462 else
464 CComPtr<IBaseFilter> pBF;
465 if(SUCCEEDED(pBF.CoCreateInstance(m_clsid)))
467 BeginEnumPins(pBF, pEP, pPin)
469 if(CComQIPtr<IMixerPinConfig, &IID_IMixerPinConfig> pMPC = pPin)
471 pUnks.AddTail(pMPC);
472 break;
475 EndEnumPins
477 *ppBF = pBF.Detach();
481 if(!*ppBF) hr = E_FAIL;
483 return hr;
487 // CFGFilterList
490 CFGFilterList::CFGFilterList()
494 CFGFilterList::~CFGFilterList()
496 RemoveAll();
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();
515 while(pos)
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;
531 return;
537 POSITION pos = m_filters.GetHeadPosition();
538 while(pos)
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;
547 return;
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();
578 while(pos)
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;
618 return 0;