/* * $Id$ * * (C) 2003-2006 Gabest * (C) 2006-2010 see AUTHORS * * This file is part of mplayerc. * * Mplayerc is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Mplayerc is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "stdafx.h" #include "FGFilter.h" #include "MainFrm.h" #include "../../DSUtil/DSUtil.h" #include "AllocatorCommon7.h" #include "AllocatorCommon.h" #include "SyncAllocatorPresenter.h" #include // // CFGFilter // CFGFilter::CFGFilter(const CLSID& clsid, CStringW name, UINT64 merit) : m_clsid(clsid) , m_name(name) { m_merit.val = merit; } const CAtlList& CFGFilter::GetTypes() const { return m_types; } void CFGFilter::SetTypes(const CAtlList& types) { m_types.RemoveAll(); m_types.AddTailList(&types); } void CFGFilter::AddType(const GUID& majortype, const GUID& subtype) { m_types.AddTail(majortype); m_types.AddTail(subtype); } bool CFGFilter::CheckTypes(const CAtlArray& types, bool fExactMatch) { POSITION pos = m_types.GetHeadPosition(); while(pos) { const GUID& majortype = m_types.GetNext(pos); if(!pos) { ASSERT(0); break; } const GUID& subtype = m_types.GetNext(pos); for(int i = 0, len = types.GetCount() & ~1; i < len; i += 2) { if(fExactMatch) { if(majortype == types[i] && majortype != GUID_NULL && subtype == types[i+1] && subtype != GUID_NULL) return true; } else { if((majortype == GUID_NULL || types[i] == GUID_NULL || majortype == types[i]) && (subtype == GUID_NULL || types[i+1] == GUID_NULL || subtype == types[i+1])) return true; } } } return false; } // // CFGFilterRegistry // CFGFilterRegistry::CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit) : CFGFilter(GUID_NULL, L"", merit) , m_pMoniker(pMoniker) { if(!m_pMoniker) return; LPOLESTR str = NULL; if(FAILED(m_pMoniker->GetDisplayName(0, 0, &str))) return; m_DisplayName = m_name = str; CoTaskMemFree(str), str = NULL; CComPtr pPB; if(SUCCEEDED(m_pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPB))) { CComVariant var; if(SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) { m_name = var.bstrVal; var.Clear(); } if(SUCCEEDED(pPB->Read(CComBSTR(_T("CLSID")), &var, NULL))) { CLSIDFromString(var.bstrVal, &m_clsid); var.Clear(); } if(SUCCEEDED(pPB->Read(CComBSTR(_T("FilterData")), &var, NULL))) { BSTR* pstr; if(SUCCEEDED(SafeArrayAccessData(var.parray, (void**)&pstr))) { ExtractFilterData((BYTE*)pstr, var.parray->cbElements*(var.parray->rgsabound[0].cElements)); SafeArrayUnaccessData(var.parray); } var.Clear(); } } if(merit != MERIT64_DO_USE) m_merit.val = merit; } CFGFilterRegistry::CFGFilterRegistry(CStringW DisplayName, UINT64 merit) : CFGFilter(GUID_NULL, L"", merit) , m_DisplayName(DisplayName) { if(m_DisplayName.IsEmpty()) return; CComPtr pBC; CreateBindCtx(0, &pBC); ULONG chEaten; if(S_OK != MkParseDisplayName(pBC, CComBSTR(m_DisplayName), &chEaten, &m_pMoniker)) return; CComPtr pPB; if(SUCCEEDED(m_pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPB))) { CComVariant var; if(SUCCEEDED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL))) { m_name = var.bstrVal; var.Clear(); } if(SUCCEEDED(pPB->Read(CComBSTR(_T("CLSID")), &var, NULL))) { CLSIDFromString(var.bstrVal, &m_clsid); var.Clear(); } if(SUCCEEDED(pPB->Read(CComBSTR(_T("FilterData")), &var, NULL))) { BSTR* pstr; if(SUCCEEDED(SafeArrayAccessData(var.parray, (void**)&pstr))) { ExtractFilterData((BYTE*)pstr, var.parray->cbElements*(var.parray->rgsabound[0].cElements)); SafeArrayUnaccessData(var.parray); } var.Clear(); } } if(merit != MERIT64_DO_USE) m_merit.val = merit; } CFGFilterRegistry::CFGFilterRegistry(const CLSID& clsid, UINT64 merit) : CFGFilter(clsid, L"", merit) { if(m_clsid == GUID_NULL) return; CString guid = CStringFromGUID(m_clsid); CRegKey key; if(ERROR_SUCCESS == key.Open(HKEY_CLASSES_ROOT, _T("CLSID\\") + guid, KEY_READ)) { ULONG nChars = 0; if(ERROR_SUCCESS == key.QueryStringValue(NULL, NULL, &nChars)) { CString name; if(ERROR_SUCCESS == key.QueryStringValue(NULL, name.GetBuffer(nChars), &nChars)) { name.ReleaseBuffer(nChars); m_name = name; } } key.Close(); } CRegKey catkey; if(ERROR_SUCCESS == catkey.Open(HKEY_CLASSES_ROOT, _T("CLSID\\{083863F1-70DE-11d0-BD40-00A0C911CE86}\\Instance"), KEY_READ)) { if(ERROR_SUCCESS != key.Open(catkey, guid, KEY_READ)) { // illiminable pack uses the name of the filter and not the clsid, have to enum all keys to find it... FILETIME ft; TCHAR buff[256]; DWORD len = countof(buff); for(DWORD i = 0; ERROR_SUCCESS == catkey.EnumKey(i, buff, &len, &ft); i++, len = countof(buff)) { if(ERROR_SUCCESS == key.Open(catkey, buff, KEY_READ)) { TCHAR clsid[256]; len = countof(clsid); if(ERROR_SUCCESS == key.QueryStringValue(_T("CLSID"), clsid, &len) && GUIDFromCString(clsid) == m_clsid) break; key.Close(); } } } if(key) { ULONG nChars = 0; if(ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), NULL, &nChars)) { CString name; if(ERROR_SUCCESS == key.QueryStringValue(_T("FriendlyName"), name.GetBuffer(nChars), &nChars)) { name.ReleaseBuffer(nChars); m_name = name; } } ULONG nBytes = 0; if(ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), NULL, &nBytes)) { CAutoVectorPtr buff; if(buff.Allocate(nBytes) && ERROR_SUCCESS == key.QueryBinaryValue(_T("FilterData"), buff, &nBytes)) { ExtractFilterData(buff, nBytes); } } key.Close(); } } if(merit != MERIT64_DO_USE) m_merit.val = merit; } HRESULT CFGFilterRegistry::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) { CheckPointer(ppBF, E_POINTER); HRESULT hr = E_FAIL; if(m_pMoniker) { if(SUCCEEDED(hr = m_pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)ppBF))) { m_clsid = ::GetCLSID(*ppBF); } } else if(m_clsid != GUID_NULL) { CComQIPtr pBF; if(FAILED(pBF.CoCreateInstance(m_clsid))) return E_FAIL; *ppBF = pBF.Detach(); hr = S_OK; } return hr; }; interface __declspec(uuid("97f7c4d4-547b-4a5f-8332-536430ad2e4d")) IAMFilterData : public IUnknown { STDMETHOD (ParseFilterData) (BYTE* rgbFilterData, ULONG cb, BYTE** prgbRegFilter2) PURE; STDMETHOD (CreateFilterData) (REGFILTER2* prf2, BYTE** prgbFilterData, ULONG* pcb) PURE; }; void CFGFilterRegistry::ExtractFilterData(BYTE* p, UINT len) { CComPtr pFD; BYTE* ptr = NULL; if(SUCCEEDED(pFD.CoCreateInstance(CLSID_FilterMapper2)) && SUCCEEDED(pFD->ParseFilterData(p, len, (BYTE**)&ptr))) { REGFILTER2* prf = (REGFILTER2*)*(WPARAM*)ptr; // this is f*cked up m_merit.mid = prf->dwMerit; if(prf->dwVersion == 1) { for(UINT i = 0; i < prf->cPins; i++) { if(prf->rgPins[i].bOutput) continue; for(UINT j = 0; j < prf->rgPins[i].nMediaTypes; j++) { if(!prf->rgPins[i].lpMediaType[j].clsMajorType || !prf->rgPins[i].lpMediaType[j].clsMinorType) break; const REGPINTYPES& rpt = prf->rgPins[i].lpMediaType[j]; AddType(*rpt.clsMajorType, *rpt.clsMinorType); } } } else if(prf->dwVersion == 2) { for(UINT i = 0; i < prf->cPins2; i++) { if(prf->rgPins2[i].dwFlags®_PINFLAG_B_OUTPUT) continue; for(UINT j = 0; j < prf->rgPins2[i].nMediaTypes; j++) { if(!prf->rgPins2[i].lpMediaType[j].clsMajorType || !prf->rgPins2[i].lpMediaType[j].clsMinorType) break; const REGPINTYPES& rpt = prf->rgPins2[i].lpMediaType[j]; AddType(*rpt.clsMajorType, *rpt.clsMinorType); } } } CoTaskMemFree(prf); } else { BYTE* base = p; #define ChkLen(size) if(p - base + size > (int)len) return; ChkLen(4) if(*(DWORD*)p != 0x00000002) return; // only version 2 supported, no samples found for 1 p += 4; ChkLen(4) m_merit.mid = *(DWORD*)p; p += 4; m_types.RemoveAll(); ChkLen(8) DWORD nPins = *(DWORD*)p; p += 8; while(nPins-- > 0) { ChkLen(1) BYTE n = *p-0x30; p++; UNUSED_ALWAYS(n); ChkLen(2) WORD pi = *(WORD*)p; p += 2; ASSERT(pi == 'ip'); ChkLen(1) BYTE x33 = *p; p++; ASSERT(x33 == 0x33); ChkLen(8) bool fOutput = !!(*p®_PINFLAG_B_OUTPUT); p += 8; ChkLen(12) DWORD nTypes = *(DWORD*)p; p += 12; while(nTypes-- > 0) { ChkLen(1) BYTE n = *p-0x30; p++; UNUSED_ALWAYS(n); ChkLen(2) WORD ty = *(WORD*)p; p += 2; ASSERT(ty == 'yt'); ChkLen(5) BYTE x33 = *p; p++; ASSERT(x33 == 0x33); p += 4; ChkLen(8) if(*(DWORD*)p < (p-base+8) || *(DWORD*)p >= len || *(DWORD*)(p+4) < (p-base+8) || *(DWORD*)(p+4) >= len) { p += 8; continue; } GUID majortype, subtype; memcpy(&majortype, &base[*(DWORD*)p], sizeof(GUID)); p += 4; if(!fOutput) AddType(majortype, subtype); } } #undef ChkLen } } // // CFGFilterFile // CFGFilterFile::CFGFilterFile(const CLSID& clsid, CString path, CStringW name, UINT64 merit) : CFGFilter(clsid, name, merit) , m_path(path) , m_hInst(NULL) { } HRESULT CFGFilterFile::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) { CheckPointer(ppBF, E_POINTER); return LoadExternalFilter(m_path, m_clsid, ppBF); } // // CFGFilterVideoRenderer // CFGFilterVideoRenderer::CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, CStringW name, UINT64 merit) : CFGFilter(clsid, name, merit) , m_hWnd(hWnd) { AddType(MEDIATYPE_Video, MEDIASUBTYPE_NULL); } HRESULT CFGFilterVideoRenderer::Create(IBaseFilter** ppBF, CInterfaceList& pUnks) { TRACE("--> CFGFilterVideoRenderer::Create on thread: %d\n", GetCurrentThreadId()); CheckPointer(ppBF, E_POINTER); HRESULT hr = S_OK; CComPtr pCAP; if(m_clsid == CLSID_VMR7AllocatorPresenter || m_clsid == CLSID_VMR9AllocatorPresenter || m_clsid == CLSID_DXRAllocatorPresenter || m_clsid == CLSID_madVRAllocatorPresenter || m_clsid == CLSID_EVRAllocatorPresenter || m_clsid == CLSID_SyncAllocatorPresenter) { bool bFullscreen = (AfxGetApp()->m_pMainWnd != NULL) && (((CMainFrame*)AfxGetApp()->m_pMainWnd)->IsD3DFullScreenMode()); if(SUCCEEDED(CreateAP7(m_clsid, m_hWnd, &pCAP)) || SUCCEEDED(CreateAP9(m_clsid, m_hWnd, bFullscreen, &pCAP)) || SUCCEEDED(CreateEVR(m_clsid, m_hWnd, bFullscreen, &pCAP)) || SUCCEEDED(CreateSyncRenderer(m_clsid, m_hWnd, bFullscreen, &pCAP))) { CComPtr pRenderer; if(SUCCEEDED(hr = pCAP->CreateRenderer(&pRenderer))) { *ppBF = CComQIPtr(pRenderer).Detach(); pUnks.AddTail(pCAP); } } } else { CComPtr pBF; if(SUCCEEDED(pBF.CoCreateInstance(m_clsid))) { BeginEnumPins(pBF, pEP, pPin) { if(CComQIPtr pMPC = pPin) { pUnks.AddTail(pMPC); break; } } EndEnumPins; *ppBF = pBF.Detach(); } } if(!*ppBF) hr = E_FAIL; return hr; } // // CFGFilterList // CFGFilterList::CFGFilterList() { } CFGFilterList::~CFGFilterList() { RemoveAll(); } void CFGFilterList::RemoveAll() { while(!m_filters.IsEmpty()) { const filter_t& f = m_filters.RemoveHead(); if(f.autodelete) delete f.pFGF; } m_sortedfilters.RemoveAll(); } void CFGFilterList::Insert(CFGFilter* pFGF, int group, bool exactmatch, bool autodelete) { if(CFGFilterRegistry* f1r = dynamic_cast(pFGF)) { POSITION pos = m_filters.GetHeadPosition(); while(pos) { filter_t& f2 = m_filters.GetNext(pos); if(group != f2.group) continue; if(CFGFilterRegistry* f2r = dynamic_cast(f2.pFGF)) { if(f1r->GetMoniker() && f2r->GetMoniker() && S_OK == f1r->GetMoniker()->IsEqual(f2r->GetMoniker()) || f1r->GetCLSID() != GUID_NULL && f1r->GetCLSID() == f2r->GetCLSID()) { TRACE(_T("FGM: Inserting %d %d %016I64x '%s' NOT!\n"), group, exactmatch, pFGF->GetMerit(), pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()) : CString(pFGF->GetName())); if(autodelete) delete pFGF; return; } } } } POSITION pos = m_filters.GetHeadPosition(); while(pos) { if(m_filters.GetNext(pos).pFGF == pFGF) { TRACE(_T("FGM: Inserting %d %d %016I64x '%s' DUP!\n"), group, exactmatch, pFGF->GetMerit(), pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()) : CString(pFGF->GetName())); if(autodelete) delete pFGF; return; } } TRACE(_T("FGM: Inserting %d %d %016I64x '%s'\n"), group, exactmatch, pFGF->GetMerit(), pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()) : CString(pFGF->GetName())); filter_t f = {m_filters.GetCount(), pFGF, group, exactmatch, autodelete}; m_filters.AddTail(f); m_sortedfilters.RemoveAll(); } POSITION CFGFilterList::GetHeadPosition() { if(m_sortedfilters.IsEmpty()) { CAtlArray sort; sort.SetCount(m_filters.GetCount()); POSITION pos = m_filters.GetHeadPosition(); for(int i = 0; pos; i++) sort[i] = m_filters.GetNext(pos); qsort(&sort[0], sort.GetCount(), sizeof(sort[0]), filter_cmp); for(size_t i = 0; i < sort.GetCount(); i++) if(sort[i].pFGF->GetMerit() >= MERIT64_DO_USE) m_sortedfilters.AddTail(sort[i].pFGF); } TRACE(_T("FGM: Sorting filters\n")); POSITION pos = m_sortedfilters.GetHeadPosition(); while(pos) { CFGFilter* pFGF = m_sortedfilters.GetNext(pos); TRACE(_T("FGM: - %016I64x '%s'\n"), pFGF->GetMerit(), pFGF->GetName().IsEmpty() ? CStringFromGUID(pFGF->GetCLSID()) : CString(pFGF->GetName())); } return m_sortedfilters.GetHeadPosition(); } CFGFilter* CFGFilterList::GetNext(POSITION& pos) { return m_sortedfilters.GetNext(pos); } int CFGFilterList::filter_cmp(const void* a, const void* b) { filter_t* fa = (filter_t*)a; filter_t* fb = (filter_t*)b; if(fa->group < fb->group) return -1; if(fa->group > fb->group) return +1; if(fa->pFGF->GetCLSID() == fb->pFGF->GetCLSID()) { CFGFilterFile* fgfa = dynamic_cast(fa->pFGF); CFGFilterFile* fgfb = dynamic_cast(fb->pFGF); if(fgfa && !fgfb) return -1; if(!fgfa && fgfb) return +1; } if(fa->pFGF->GetMerit() > fb->pFGF->GetMerit()) return -1; if(fa->pFGF->GetMerit() < fb->pFGF->GetMerit()) return +1; if(fa->exactmatch && !fb->exactmatch) return -1; if(!fa->exactmatch && fb->exactmatch) return +1; if(fa->index < fb->index) return -1; if(fa->index > fb->index) return +1; return 0; }