00001
00002
00003
00004
00005
00006 #include <streams.h>
00007
00008 STDAPI CreateMemoryAllocator(IMemAllocator **ppAllocator)
00009 {
00010 return CoCreateInstance(CLSID_MemoryAllocator,
00011 0,
00012 CLSCTX_INPROC_SERVER,
00013 IID_IMemAllocator,
00014 (void **)ppAllocator);
00015 }
00016
00017 STDAPI CreatePosPassThru(
00018 LPUNKNOWN pAgg,
00019 BOOL bRenderer,
00020 IPin *pPin,
00021 IUnknown **ppPassThru
00022 )
00023 {
00024 *ppPassThru = NULL;
00025 IUnknown *pUnkSeek;
00026 HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru,
00027 pAgg,
00028 CLSCTX_INPROC_SERVER,
00029 IID_IUnknown,
00030 (void **)&pUnkSeek
00031 );
00032 if (FAILED(hr)) {
00033 return hr;
00034 }
00035
00036 ISeekingPassThru *pPassThru;
00037 hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru);
00038 if (FAILED(hr)) {
00039 pUnkSeek->Release();
00040 return hr;
00041 }
00042 hr = pPassThru->Init(bRenderer, pPin);
00043 pPassThru->Release();
00044 if (FAILED(hr)) {
00045 pUnkSeek->Release();
00046 return hr;
00047 }
00048 *ppPassThru = pUnkSeek;
00049 return S_OK;
00050 }
00051
00052 #define CONNECT_TRACE_LEVEL 3
00053
00054 CBaseMediaFilter::CBaseMediaFilter(const TCHAR *pName,
00055 LPUNKNOWN pUnk,
00056 CCritSec *pLock,
00057 REFCLSID clsid) :
00058 CUnknown(pName, pUnk),
00059 m_pLock(pLock),
00060 m_clsid(clsid),
00061 m_State(State_Stopped),
00062 m_pClock(NULL)
00063 {
00064 }
00065
00066 CBaseMediaFilter::~CBaseMediaFilter()
00067 {
00068
00069 if (m_pClock) {
00070 m_pClock->Release();
00071 m_pClock = NULL;
00072 }
00073 }
00074
00075 STDMETHODIMP
00076 CBaseMediaFilter::NonDelegatingQueryInterface(
00077 REFIID riid,
00078 void ** ppv)
00079 {
00080 if (riid == IID_IMediaFilter) {
00081 return GetInterface((IMediaFilter *) this, ppv);
00082 } else if (riid == IID_IPersist) {
00083 return GetInterface((IPersist *) this, ppv);
00084 } else {
00085 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
00086 }
00087 }
00088
00089 STDMETHODIMP
00090 CBaseMediaFilter::GetClassID(CLSID *pClsID)
00091 {
00092 CheckPointer(pClsID,E_POINTER);
00093 ValidateReadWritePtr(pClsID,sizeof(CLSID));
00094 *pClsID = m_clsid;
00095 return NOERROR;
00096 }
00097
00098 STDMETHODIMP
00099 CBaseMediaFilter::GetState(DWORD dwMSecs, FILTER_STATE *State)
00100 {
00101 UNREFERENCED_PARAMETER(dwMSecs);
00102 CheckPointer(State,E_POINTER);
00103 ValidateReadWritePtr(State,sizeof(FILTER_STATE));
00104
00105 *State = m_State;
00106 return S_OK;
00107 }
00108
00109 STDMETHODIMP
00110 CBaseMediaFilter::SetSyncSource(IReferenceClock *pClock)
00111 {
00112 CAutoLock cObjectLock(m_pLock);
00113
00114 if (pClock) {
00115 pClock->AddRef();
00116 }
00117
00118 if (m_pClock) {
00119 m_pClock->Release();
00120 }
00121
00122 m_pClock = pClock;
00123
00124 return NOERROR;
00125 }
00126
00127 STDMETHODIMP
00128 CBaseMediaFilter::GetSyncSource(IReferenceClock **pClock)
00129 {
00130 CheckPointer(pClock,E_POINTER);
00131 ValidateReadWritePtr(pClock,sizeof(IReferenceClock *));
00132 CAutoLock cObjectLock(m_pLock);
00133
00134 if (m_pClock) {
00135
00136 m_pClock->AddRef();
00137 }
00138 *pClock = (IReferenceClock*)m_pClock;
00139 return NOERROR;
00140 }
00141
00142 STDMETHODIMP
00143 CBaseMediaFilter::Stop()
00144 {
00145 CAutoLock cObjectLock(m_pLock);
00146
00147 m_State = State_Stopped;
00148 return S_OK;
00149 }
00150
00151 STDMETHODIMP
00152 CBaseMediaFilter::Pause()
00153 {
00154 CAutoLock cObjectLock(m_pLock);
00155
00156 m_State = State_Paused;
00157 return S_OK;
00158 }
00159
00160 STDMETHODIMP
00161 CBaseMediaFilter::Run(REFERENCE_TIME tStart)
00162 {
00163 CAutoLock cObjectLock(m_pLock);
00164
00165
00166 m_tStart = tStart;
00167
00168 if (m_State == State_Stopped){
00169 HRESULT hr = Pause();
00170
00171 if (FAILED(hr)) {
00172 return hr;
00173 }
00174 }
00175 m_State = State_Running;
00176 return S_OK;
00177 }
00178
00179 HRESULT
00180 CBaseMediaFilter::StreamTime(CRefTime& rtStream)
00181 {
00182
00183 if (m_pClock == NULL) {
00184 return VFW_E_NO_CLOCK;
00185 }
00186
00187 HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream);
00188 if (FAILED(hr)) {
00189 return hr;
00190 }
00191
00192 rtStream -= m_tStart;
00193
00194 return S_OK;
00195 }
00196
00197 STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid,
00198 void **ppv)
00199 {
00200
00201 if (riid == IID_IBaseFilter) {
00202 return GetInterface((IBaseFilter *) this, ppv);
00203 } else if (riid == IID_IMediaFilter) {
00204 return GetInterface((IMediaFilter *) this, ppv);
00205 } else if (riid == IID_IPersist) {
00206 return GetInterface((IPersist *) this, ppv);
00207 } else if (riid == IID_IAMovieSetup) {
00208 return GetInterface((IAMovieSetup *) this, ppv);
00209 } else {
00210 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
00211 }
00212 }
00213
00214 #ifdef DEBUG
00215 STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease()
00216 {
00217 if (m_cRef == 1) {
00218 KASSERT(m_pGraph == NULL);
00219 }
00220 return CUnknown::NonDelegatingRelease();
00221 }
00222 #endif
00223
00224 CBaseFilter::CBaseFilter(const TCHAR *pName,
00225 LPUNKNOWN pUnk,
00226 CCritSec *pLock,
00227 REFCLSID clsid) :
00228 CUnknown( pName, pUnk ),
00229 m_pLock(pLock),
00230 m_clsid(clsid),
00231 m_State(State_Stopped),
00232 m_pClock(NULL),
00233 m_pGraph(NULL),
00234 m_pSink(NULL),
00235 m_pName(NULL),
00236 m_PinVersion(1)
00237 {
00238
00239 ASSERT(pLock != NULL);
00240 }
00241
00242 CBaseFilter::CBaseFilter(TCHAR *pName,
00243 LPUNKNOWN pUnk,
00244 CCritSec *pLock,
00245 REFCLSID clsid,
00246 HRESULT *phr) :
00247 CUnknown( pName, pUnk ),
00248 m_pLock(pLock),
00249 m_clsid(clsid),
00250 m_State(State_Stopped),
00251 m_pClock(NULL),
00252 m_pGraph(NULL),
00253 m_pSink(NULL),
00254 m_pName(NULL),
00255 m_PinVersion(1)
00256 {
00257
00258 ASSERT(pLock != NULL);
00259 UNREFERENCED_PARAMETER(phr);
00260 }
00261
00262 #ifdef UNICODE
00263 CBaseFilter::CBaseFilter(const CHAR *pName,
00264 LPUNKNOWN pUnk,
00265 CCritSec *pLock,
00266 REFCLSID clsid) :
00267 CUnknown( pName, pUnk ),
00268 m_pLock(pLock),
00269 m_clsid(clsid),
00270 m_State(State_Stopped),
00271 m_pClock(NULL),
00272 m_pGraph(NULL),
00273 m_pSink(NULL),
00274 m_pName(NULL),
00275 m_PinVersion(1)
00276 {
00277
00278 ASSERT(pLock != NULL);
00279 }
00280 CBaseFilter::CBaseFilter(CHAR *pName,
00281 LPUNKNOWN pUnk,
00282 CCritSec *pLock,
00283 REFCLSID clsid,
00284 HRESULT *phr) :
00285 CUnknown( pName, pUnk ),
00286 m_pLock(pLock),
00287 m_clsid(clsid),
00288 m_State(State_Stopped),
00289 m_pClock(NULL),
00290 m_pGraph(NULL),
00291 m_pSink(NULL),
00292 m_pName(NULL),
00293 m_PinVersion(1)
00294 {
00295
00296 ASSERT(pLock != NULL);
00297 UNREFERENCED_PARAMETER(phr);
00298 }
00299 #endif
00300
00301 CBaseFilter::~CBaseFilter()
00302 {
00303 delete[] m_pName;
00304
00305 if (m_pClock) {
00306 m_pClock->Release();
00307 m_pClock = NULL;
00308 }
00309 }
00310
00311 STDMETHODIMP
00312 CBaseFilter::GetClassID(CLSID *pClsID)
00313 {
00314 CheckPointer(pClsID,E_POINTER);
00315 ValidateReadWritePtr(pClsID,sizeof(CLSID));
00316 *pClsID = m_clsid;
00317 return NOERROR;
00318 }
00319
00320 STDMETHODIMP
00321 CBaseFilter::GetState(DWORD dwMSecs, FILTER_STATE *State)
00322 {
00323 UNREFERENCED_PARAMETER(dwMSecs);
00324 CheckPointer(State,E_POINTER);
00325 ValidateReadWritePtr(State,sizeof(FILTER_STATE));
00326
00327 *State = m_State;
00328 return S_OK;
00329 }
00330
00331 STDMETHODIMP
00332 CBaseFilter::SetSyncSource(IReferenceClock *pClock)
00333 {
00334 CAutoLock cObjectLock(m_pLock);
00335
00336 if (pClock) {
00337 pClock->AddRef();
00338 }
00339
00340 if (m_pClock) {
00341 m_pClock->Release();
00342 }
00343
00344 m_pClock = pClock;
00345
00346 return NOERROR;
00347 }
00348
00349 STDMETHODIMP
00350 CBaseFilter::GetSyncSource(IReferenceClock **pClock)
00351 {
00352 CheckPointer(pClock,E_POINTER);
00353 ValidateReadWritePtr(pClock,sizeof(IReferenceClock *));
00354 CAutoLock cObjectLock(m_pLock);
00355
00356 if (m_pClock) {
00357
00358 m_pClock->AddRef();
00359 }
00360 *pClock = (IReferenceClock*)m_pClock;
00361 return NOERROR;
00362 }
00363
00364 STDMETHODIMP
00365 CBaseFilter::Stop()
00366 {
00367 CAutoLock cObjectLock(m_pLock);
00368 HRESULT hr = NOERROR;
00369
00370
00371 if (m_State != State_Stopped) {
00372 int cPins = GetPinCount();
00373 for (int c = 0; c < cPins; c++) {
00374
00375 CBasePin *pPin = GetPin(c);
00376
00377 if (pPin->IsConnected()) {
00378 HRESULT hrTmp = pPin->Inactive();
00379 if (FAILED(hrTmp) && SUCCEEDED(hr)) {
00380 hr = hrTmp;
00381 }
00382 }
00383 }
00384 }
00385
00386 m_State = State_Stopped;
00387 return hr;
00388 }
00389
00390 STDMETHODIMP
00391 CBaseFilter::Pause()
00392 {
00393 CAutoLock cObjectLock(m_pLock);
00394
00395 if (m_State == State_Stopped) {
00396 int cPins = GetPinCount();
00397 for (int c = 0; c < cPins; c++) {
00398
00399 CBasePin *pPin = GetPin(c);
00400
00401 if (pPin->IsConnected()) {
00402 HRESULT hr = pPin->Active();
00403 if (FAILED(hr)) {
00404 return hr;
00405 }
00406 }
00407 }
00408 }
00409
00410 m_State = State_Paused;
00411 return S_OK;
00412 }
00413
00414 STDMETHODIMP
00415 CBaseFilter::Run(REFERENCE_TIME tStart)
00416 {
00417 CAutoLock cObjectLock(m_pLock);
00418
00419 m_tStart = tStart;
00420
00421 if (m_State == State_Stopped){
00422 HRESULT hr = Pause();
00423
00424 if (FAILED(hr)) {
00425 return hr;
00426 }
00427 }
00428
00429 if (m_State != State_Running) {
00430 int cPins = GetPinCount();
00431 for (int c = 0; c < cPins; c++) {
00432
00433 CBasePin *pPin = GetPin(c);
00434
00435 if (pPin->IsConnected()) {
00436 HRESULT hr = pPin->Run(tStart);
00437 if (FAILED(hr)) {
00438 return hr;
00439 }
00440 }
00441 }
00442 }
00443
00444 m_State = State_Running;
00445 return S_OK;
00446 }
00447
00448 HRESULT
00449 CBaseFilter::StreamTime(CRefTime& rtStream)
00450 {
00451
00452 if (m_pClock == NULL) {
00453 return VFW_E_NO_CLOCK;
00454 }
00455
00456 HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream);
00457 if (FAILED(hr)) {
00458 return hr;
00459 }
00460
00461 rtStream -= m_tStart;
00462
00463 return S_OK;
00464 }
00465
00466 STDMETHODIMP
00467 CBaseFilter::EnumPins(IEnumPins **ppEnum)
00468 {
00469 CheckPointer(ppEnum,E_POINTER);
00470 ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *));
00471
00472 *ppEnum = new CEnumPins(this,
00473 NULL);
00474
00475 return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR;
00476 }
00477
00478 STDMETHODIMP
00479 CBaseFilter::FindPin(
00480 LPCWSTR Id,
00481 IPin ** ppPin
00482 )
00483 {
00484 CheckPointer(ppPin,E_POINTER);
00485 ValidateReadWritePtr(ppPin,sizeof(IPin *));
00486
00487 CAutoLock lck(m_pLock);
00488 int iCount = GetPinCount();
00489 for (int i = 0; i < iCount; i++) {
00490 CBasePin *pPin = GetPin(i);
00491 ASSERT(pPin != NULL);
00492
00493 if (0 == lstrcmpW(pPin->Name(), Id)) {
00494
00495 *ppPin = pPin;
00496 pPin->AddRef();
00497 return S_OK;
00498 }
00499 }
00500 *ppPin = NULL;
00501 return VFW_E_NOT_FOUND;
00502 }
00503
00504 STDMETHODIMP
00505 CBaseFilter::QueryFilterInfo(FILTER_INFO * pInfo)
00506 {
00507 CheckPointer(pInfo,E_POINTER);
00508 ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO));
00509
00510 if (m_pName) {
00511 lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR));
00512 } else {
00513 pInfo->achName[0] = L'\0';
00514 }
00515 pInfo->pGraph = m_pGraph;
00516 if (m_pGraph)
00517 m_pGraph->AddRef();
00518 return NOERROR;
00519 }
00520
00521 STDMETHODIMP
00522 CBaseFilter::JoinFilterGraph(
00523 IFilterGraph * pGraph,
00524 LPCWSTR pName)
00525 {
00526 CAutoLock cObjectLock(m_pLock);
00527
00528 m_pGraph = pGraph;
00529 if (m_pGraph) {
00530 HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink,
00531 (void**) &m_pSink);
00532 if (FAILED(hr)) {
00533 ASSERT(m_pSink == NULL);
00534 }
00535 else m_pSink->Release();
00536 } else {
00537
00538 m_pSink = NULL;
00539 }
00540
00541 if (m_pName) {
00542 delete[] m_pName;
00543 m_pName = NULL;
00544 }
00545
00546 if (pName) {
00547 DWORD nameLen = lstrlenW(pName)+1;
00548 m_pName = new WCHAR[nameLen];
00549 if (m_pName) {
00550 CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR));
00551 } else {
00552
00553 }
00554 }
00555
00556 return NOERROR;
00557 }
00558
00559 STDMETHODIMP
00560 CBaseFilter::QueryVendorInfo(
00561 LPWSTR* pVendorInfo)
00562 {
00563 UNREFERENCED_PARAMETER(pVendorInfo);
00564 return E_NOTIMPL;
00565 }
00566
00567 HRESULT
00568 CBaseFilter::NotifyEvent(
00569 long EventCode,
00570 LONG_PTR EventParam1,
00571 LONG_PTR EventParam2)
00572 {
00573
00574 IMediaEventSink *pSink = m_pSink;
00575 if (pSink) {
00576 if (EC_COMPLETE == EventCode) {
00577 EventParam2 = (LONG_PTR)(IBaseFilter*)this;
00578 }
00579
00580 return pSink->Notify(EventCode, EventParam1, EventParam2);
00581 } else {
00582 return E_NOTIMPL;
00583 }
00584 }
00585
00586 HRESULT
00587 CBaseFilter::ReconnectPin(
00588 IPin *pPin,
00589 AM_MEDIA_TYPE const *pmt
00590 )
00591 {
00592 IFilterGraph2 *pGraph2;
00593 if (m_pGraph != NULL) {
00594 HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2);
00595 if (SUCCEEDED(hr)) {
00596 hr = pGraph2->ReconnectEx(pPin, pmt);
00597 pGraph2->Release();
00598 return hr;
00599 } else {
00600 return m_pGraph->Reconnect(pPin);
00601 }
00602 } else {
00603 return E_NOINTERFACE;
00604 }
00605 }
00606
00607 LONG CBaseFilter::GetPinVersion()
00608 {
00609 return m_PinVersion;
00610 }
00611
00612 void CBaseFilter::IncrementPinVersion()
00613 {
00614 InterlockedIncrement(&m_PinVersion);
00615 }
00616
00617 STDMETHODIMP CBaseFilter::Register()
00618 {
00619
00620 LPAMOVIESETUP_FILTER psetupdata = GetSetupData();
00621
00622 if( NULL == psetupdata ) return S_FALSE;
00623
00624 HRESULT hr = CoInitialize( (LPVOID)NULL );
00625 ASSERT( SUCCEEDED(hr) );
00626
00627 IFilterMapper *pIFM;
00628 hr = CoCreateInstance( CLSID_FilterMapper
00629 , NULL
00630 , CLSCTX_INPROC_SERVER
00631 , IID_IFilterMapper
00632 , (void **)&pIFM );
00633 if( SUCCEEDED(hr) )
00634 {
00635 hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE );
00636 pIFM->Release();
00637 }
00638
00639 CoFreeUnusedLibraries();
00640 CoUninitialize();
00641
00642 return NOERROR;
00643 }
00644
00645 STDMETHODIMP CBaseFilter::Unregister()
00646 {
00647
00648 LPAMOVIESETUP_FILTER psetupdata = GetSetupData();
00649
00650 if( NULL == psetupdata ) return S_FALSE;
00651
00652 HRESULT hr = CoInitialize( (LPVOID)NULL );
00653 ASSERT( SUCCEEDED(hr) );
00654
00655 IFilterMapper *pIFM;
00656 hr = CoCreateInstance( CLSID_FilterMapper
00657 , NULL
00658 , CLSCTX_INPROC_SERVER
00659 , IID_IFilterMapper
00660 , (void **)&pIFM );
00661 if( SUCCEEDED(hr) )
00662 {
00663 hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE );
00664
00665 pIFM->Release();
00666 }
00667
00668 CoFreeUnusedLibraries();
00669 CoUninitialize();
00670
00671 if( 0x80070002 == hr)
00672 return NOERROR;
00673 else
00674 return hr;
00675 }
00676
00677 CEnumPins::CEnumPins(CBaseFilter *pFilter,
00678 CEnumPins *pEnumPins) :
00679 m_Position(0),
00680 m_PinCount(0),
00681 m_pFilter(pFilter),
00682 m_cRef(1),
00683 m_PinCache(NAME("Pin Cache"))
00684 {
00685
00686 #ifdef DEBUG
00687 m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0);
00688 #endif
00689
00690 ASSERT(pFilter != NULL);
00691
00692 m_pFilter->AddRef();
00693
00694 if (pEnumPins == NULL) {
00695 m_Version = m_pFilter->GetPinVersion();
00696 m_PinCount = m_pFilter->GetPinCount();
00697 } else {
00698 ASSERT(m_Position <= m_PinCount);
00699 m_Position = pEnumPins->m_Position;
00700 m_PinCount = pEnumPins->m_PinCount;
00701 m_Version = pEnumPins->m_Version;
00702 m_PinCache.AddTail(&(pEnumPins->m_PinCache));
00703 }
00704 }
00705
00706 CEnumPins::~CEnumPins()
00707 {
00708 m_pFilter->Release();
00709
00710 #ifdef DEBUG
00711 DbgRegisterObjectDestruction(m_dwCookie);
00712 #endif
00713 }
00714
00715 STDMETHODIMP
00716 CEnumPins::QueryInterface(REFIID riid,void **ppv)
00717 {
00718 CheckPointer(ppv, E_POINTER);
00719
00720 if (riid == IID_IEnumPins || riid == IID_IUnknown) {
00721 return GetInterface((IEnumPins *) this, ppv);
00722 } else {
00723 *ppv = NULL;
00724 return E_NOINTERFACE;
00725 }
00726 }
00727
00728 STDMETHODIMP_(ULONG)
00729 CEnumPins::AddRef()
00730 {
00731 return InterlockedIncrement(&m_cRef);
00732 }
00733
00734 STDMETHODIMP_(ULONG)
00735 CEnumPins::Release()
00736 {
00737 ULONG cRef = InterlockedDecrement(&m_cRef);
00738 if (cRef == 0) {
00739 delete this;
00740 }
00741 return cRef;
00742 }
00743
00744 STDMETHODIMP
00745 CEnumPins::Clone(IEnumPins **ppEnum)
00746 {
00747 CheckPointer(ppEnum,E_POINTER);
00748 ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *));
00749 HRESULT hr = NOERROR;
00750
00751
00752 if (AreWeOutOfSync() == TRUE) {
00753 *ppEnum = NULL;
00754 hr = VFW_E_ENUM_OUT_OF_SYNC;
00755 } else {
00756
00757 *ppEnum = new CEnumPins(m_pFilter,
00758 this);
00759 if (*ppEnum == NULL) {
00760 hr = E_OUTOFMEMORY;
00761 }
00762 }
00763 return hr;
00764 }
00765
00766 STDMETHODIMP
00767 CEnumPins::Next(ULONG cPins,
00768 IPin **ppPins,
00769 ULONG *pcFetched)
00770 {
00771 CheckPointer(ppPins,E_POINTER);
00772 ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *));
00773
00774 ASSERT(ppPins);
00775
00776 if (pcFetched!=NULL) {
00777 ValidateWritePtr(pcFetched, sizeof(ULONG));
00778 *pcFetched = 0;
00779 }
00780
00781 else if (cPins>1) {
00782 return E_INVALIDARG;
00783 }
00784 ULONG cFetched = 0;
00785
00786 if (AreWeOutOfSync() == TRUE) {
00787
00788 Refresh();
00789 }
00790
00791 int cRealPins = min(m_PinCount - m_Position, (int) cPins);
00792 if (cRealPins == 0) {
00793 return S_FALSE;
00794 }
00795
00796 while (cRealPins && (m_PinCount - m_Position)) {
00797
00798 CBasePin *pPin = m_pFilter->GetPin(m_Position++);
00799 if (pPin == NULL) {
00800
00801 ASSERT( cFetched==0 );
00802 return VFW_E_ENUM_OUT_OF_SYNC;
00803 }
00804
00805 if (0 == m_PinCache.Find(pPin))
00806 {
00807
00808 *ppPins = pPin;
00809 pPin->AddRef();
00810
00811 cFetched++;
00812 ppPins++;
00813
00814 m_PinCache.AddTail(pPin);
00815
00816 cRealPins--;
00817
00818 }
00819 }
00820
00821 if (pcFetched!=NULL) {
00822 *pcFetched = cFetched;
00823 }
00824
00825 return (cPins==cFetched ? NOERROR : S_FALSE);
00826 }
00827
00828 STDMETHODIMP
00829 CEnumPins::Skip(ULONG cPins)
00830 {
00831
00832 if (AreWeOutOfSync() == TRUE) {
00833 return VFW_E_ENUM_OUT_OF_SYNC;
00834 }
00835
00836 ULONG PinsLeft = m_PinCount - m_Position;
00837 if (cPins > PinsLeft) {
00838 return S_FALSE;
00839 }
00840 m_Position += cPins;
00841 return NOERROR;
00842 }
00843
00844 STDMETHODIMP
00845 CEnumPins::Reset()
00846 {
00847 m_Version = m_pFilter->GetPinVersion();
00848 m_PinCount = m_pFilter->GetPinCount();
00849
00850 m_Position = 0;
00851
00852
00853 m_PinCache.RemoveAll();
00854
00855 return S_OK;
00856 }
00857
00858 STDMETHODIMP
00859 CEnumPins::Refresh()
00860 {
00861 m_Version = m_pFilter->GetPinVersion();
00862 m_PinCount = m_pFilter->GetPinCount();
00863
00864 m_Position = 0;
00865 return S_OK;
00866 }
00867
00868 CEnumMediaTypes::CEnumMediaTypes(CBasePin *pPin,
00869 CEnumMediaTypes *pEnumMediaTypes) :
00870 m_Position(0),
00871 m_pPin(pPin),
00872 m_cRef(1)
00873 {
00874
00875 #ifdef DEBUG
00876 m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0);
00877 #endif
00878
00879 ASSERT(pPin != NULL);
00880
00881 m_pPin->AddRef();
00882
00883 if (pEnumMediaTypes == NULL) {
00884 m_Version = m_pPin->GetMediaTypeVersion();
00885 return;
00886 }
00887
00888 m_Position = pEnumMediaTypes->m_Position;
00889 m_Version = pEnumMediaTypes->m_Version;
00890 }
00891
00892 CEnumMediaTypes::~CEnumMediaTypes()
00893 {
00894 #ifdef DEBUG
00895 DbgRegisterObjectDestruction(m_dwCookie);
00896 #endif
00897 m_pPin->Release();
00898 }
00899
00900 STDMETHODIMP
00901 CEnumMediaTypes::QueryInterface(REFIID riid,void **ppv)
00902 {
00903 CheckPointer(ppv, E_POINTER);
00904
00905 if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) {
00906 return GetInterface((IEnumMediaTypes *) this, ppv);
00907 } else {
00908 *ppv = NULL;
00909 return E_NOINTERFACE;
00910 }
00911 }
00912
00913 STDMETHODIMP_(ULONG)
00914 CEnumMediaTypes::AddRef()
00915 {
00916 return InterlockedIncrement(&m_cRef);
00917 }
00918
00919 STDMETHODIMP_(ULONG)
00920 CEnumMediaTypes::Release()
00921 {
00922 ULONG cRef = InterlockedDecrement(&m_cRef);
00923 if (cRef == 0) {
00924 delete this;
00925 }
00926 return cRef;
00927 }
00928
00929 STDMETHODIMP
00930 CEnumMediaTypes::Clone(IEnumMediaTypes **ppEnum)
00931 {
00932 CheckPointer(ppEnum,E_POINTER);
00933 ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));
00934 HRESULT hr = NOERROR;
00935
00936
00937 if (AreWeOutOfSync() == TRUE) {
00938 *ppEnum = NULL;
00939 hr = VFW_E_ENUM_OUT_OF_SYNC;
00940 } else {
00941
00942 *ppEnum = new CEnumMediaTypes(m_pPin,
00943 this);
00944
00945 if (*ppEnum == NULL) {
00946 hr = E_OUTOFMEMORY;
00947 }
00948 }
00949 return hr;
00950 }
00951
00952 STDMETHODIMP
00953 CEnumMediaTypes::Next(ULONG cMediaTypes,
00954 AM_MEDIA_TYPE **ppMediaTypes,
00955 ULONG *pcFetched)
00956 {
00957 CheckPointer(ppMediaTypes,E_POINTER);
00958 ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *));
00959
00960 if (AreWeOutOfSync() == TRUE) {
00961 return VFW_E_ENUM_OUT_OF_SYNC;
00962 }
00963
00964 if (pcFetched!=NULL) {
00965 ValidateWritePtr(pcFetched, sizeof(ULONG));
00966 *pcFetched = 0;
00967 }
00968
00969 else if (cMediaTypes>1) {
00970 return E_INVALIDARG;
00971 }
00972 ULONG cFetched = 0;
00973
00974
00975
00976 while (cMediaTypes) {
00977
00978 CMediaType cmt;
00979
00980 HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt);
00981 if (S_OK != hr) {
00982 break;
00983 }
00984
00985 *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
00986 if (*ppMediaTypes == NULL) {
00987 break;
00988 }
00989
00990 **ppMediaTypes = (AM_MEDIA_TYPE)cmt;
00991
00992 cmt.pbFormat = NULL;
00993 cmt.cbFormat = NULL;
00994 cmt.pUnk = NULL;
00995
00996 ppMediaTypes++;
00997 cFetched++;
00998 cMediaTypes--;
00999 }
01000
01001 if (pcFetched!=NULL) {
01002 *pcFetched = cFetched;
01003 }
01004
01005 return ( cMediaTypes==0 ? NOERROR : S_FALSE );
01006 }
01007
01008 STDMETHODIMP
01009 CEnumMediaTypes::Skip(ULONG cMediaTypes)
01010 {
01011
01012 if (cMediaTypes == 0) {
01013 return S_OK;
01014 }
01015
01016 if (AreWeOutOfSync() == TRUE) {
01017 return VFW_E_ENUM_OUT_OF_SYNC;
01018 }
01019
01020 m_Position += cMediaTypes;
01021
01022 CMediaType cmt;
01023 return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE;
01024 }
01025
01026 STDMETHODIMP
01027 CEnumMediaTypes::Reset()
01028
01029 {
01030 m_Position = 0;
01031
01032 m_Version = m_pPin->GetMediaTypeVersion();
01033 return NOERROR;
01034 }
01035
01036 CBasePin::CBasePin(TCHAR *pObjectName,
01037 CBaseFilter *pFilter,
01038 CCritSec *pLock,
01039 HRESULT *phr,
01040 LPCWSTR pName,
01041 PIN_DIRECTION dir) :
01042 CUnknown( pObjectName, NULL ),
01043 m_pFilter(pFilter),
01044 m_pLock(pLock),
01045 m_pName(NULL),
01046 m_Connected(NULL),
01047 m_dir(dir),
01048 m_bRunTimeError(FALSE),
01049 m_pQSink(NULL),
01050 m_TypeVersion(1),
01051 m_tStart(),
01052 m_tStop(MAX_TIME),
01053 m_bCanReconnectWhenActive(false),
01054 m_bTryMyTypesFirst(false),
01055 m_dRate(1.0)
01056 {
01057
01058 ASSERT(pFilter != NULL);
01059 ASSERT(pLock != NULL);
01060
01061 if (pName) {
01062 DWORD nameLen = lstrlenW(pName)+1;
01063 m_pName = new WCHAR[nameLen];
01064 if (m_pName) {
01065 CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR));
01066 }
01067 }
01068
01069 #ifdef DEBUG
01070 m_cRef = 0;
01071 #endif
01072 }
01073
01074 #ifdef UNICODE
01075 CBasePin::CBasePin(CHAR *pObjectName,
01076 CBaseFilter *pFilter,
01077 CCritSec *pLock,
01078 HRESULT *phr,
01079 LPCWSTR pName,
01080 PIN_DIRECTION dir) :
01081 CUnknown( pObjectName, NULL ),
01082 m_pFilter(pFilter),
01083 m_pLock(pLock),
01084 m_pName(NULL),
01085 m_Connected(NULL),
01086 m_dir(dir),
01087 m_bRunTimeError(FALSE),
01088 m_pQSink(NULL),
01089 m_TypeVersion(1),
01090 m_tStart(),
01091 m_tStop(MAX_TIME),
01092 m_bCanReconnectWhenActive(false),
01093 m_bTryMyTypesFirst(false),
01094 m_dRate(1.0)
01095 {
01096
01097 ASSERT(pFilter != NULL);
01098 ASSERT(pLock != NULL);
01099
01100 if (pName) {
01101 DWORD nameLen = lstrlenW(pName)+1;
01102 m_pName = new WCHAR[nameLen];
01103 if (m_pName) {
01104 CopyMemory(m_pName, pName, nameLen*sizeof(WCHAR));
01105 }
01106 }
01107
01108 #ifdef DEBUG
01109 m_cRef = 0;
01110 #endif
01111 }
01112 #endif
01113
01114 CBasePin::~CBasePin()
01115 {
01116
01117 ASSERT(m_Connected == FALSE);
01118
01119 delete[] m_pName;
01120
01121 ASSERT(m_cRef == 0);
01122 }
01123
01124 STDMETHODIMP
01125 CBasePin::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
01126 {
01127
01128 if (riid == IID_IPin) {
01129 return GetInterface((IPin *) this, ppv);
01130 } else if (riid == IID_IQualityControl) {
01131 return GetInterface((IQualityControl *) this, ppv);
01132 } else {
01133 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
01134 }
01135 }
01136
01137 STDMETHODIMP_(ULONG)
01138 CBasePin::NonDelegatingAddRef()
01139 {
01140 ASSERT(InterlockedIncrement(&m_cRef) > 0);
01141 return m_pFilter->AddRef();
01142 }
01143
01144 STDMETHODIMP_(ULONG)
01145 CBasePin::NonDelegatingRelease()
01146 {
01147 ASSERT(InterlockedDecrement(&m_cRef) >= 0);
01148 return m_pFilter->Release();
01149 }
01150
01151 #ifdef DEBUG
01152 void
01153 CBasePin::DisplayPinInfo(IPin *pReceivePin)
01154 {
01155
01156 if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) {
01157 PIN_INFO ConnectPinInfo;
01158 PIN_INFO ReceivePinInfo;
01159
01160 if (FAILED(QueryPinInfo(&ConnectPinInfo))) {
01161 lstrcpyW(ConnectPinInfo.achName, L"Bad Pin");
01162 } else {
01163 QueryPinInfoReleaseFilter(ConnectPinInfo);
01164 }
01165
01166 if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) {
01167 lstrcpyW(ReceivePinInfo.achName, L"Bad Pin");
01168 } else {
01169 QueryPinInfoReleaseFilter(ReceivePinInfo);
01170 }
01171
01172 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :")));
01173 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ConnectPinInfo.achName));
01174 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" <%ls>"), ReceivePinInfo.achName));
01175 }
01176 }
01177 #endif
01178
01179 #ifdef DEBUG
01180 void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt)
01181 {
01182 UNREFERENCED_PARAMETER(pPin);
01183 if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) {
01184 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:")));
01185 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" major type: %hs"),
01186 GuidNames[*pmt->Type()]));
01187 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT(" sub type : %hs"),
01188 GuidNames[*pmt->Subtype()]));
01189 }
01190 }
01191 #endif
01192
01193 STDMETHODIMP
01194 CBasePin::Connect(
01195 IPin * pReceivePin,
01196 const AM_MEDIA_TYPE *pmt
01197 )
01198 {
01199 CheckPointer(pReceivePin,E_POINTER);
01200 ValidateReadPtr(pReceivePin,sizeof(IPin));
01201 CAutoLock cObjectLock(m_pLock);
01202 DisplayPinInfo(pReceivePin);
01203
01204 if (m_Connected) {
01205 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected")));
01206 return VFW_E_ALREADY_CONNECTED;
01207 }
01208
01209
01210 if (!IsStopped() && !m_bCanReconnectWhenActive) {
01211 return VFW_E_NOT_STOPPED;
01212 }
01213
01214 const CMediaType * ptype = (CMediaType*)pmt;
01215 HRESULT hr = AgreeMediaType(pReceivePin, ptype);
01216 if (FAILED(hr)) {
01217 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type")));
01218
01219 EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
01220
01221 return hr;
01222 }
01223
01224 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded")));
01225
01226 return NOERROR;
01227 }
01228
01229 HRESULT
01230 CBasePin::AttemptConnection(
01231 IPin* pReceivePin,
01232 const CMediaType* pmt
01233 )
01234 {
01235 HRESULT hr = CheckConnect(pReceivePin);
01236 if (FAILED(hr)) {
01237 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed")));
01238
01239 EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
01240
01241 return hr;
01242 }
01243
01244 DisplayTypeInfo(pReceivePin, pmt);
01245
01246 hr = CheckMediaType(pmt);
01247 if (hr == NOERROR) {
01248
01249 m_Connected = pReceivePin;
01250 m_Connected->AddRef();
01251 SetMediaType(pmt);
01252
01253 hr = pReceivePin->ReceiveConnection((IPin *)this, pmt);
01254 if (SUCCEEDED(hr)) {
01255
01256 hr = CompleteConnect(pReceivePin);
01257 if (SUCCEEDED(hr)) {
01258 return hr;
01259 } else {
01260 DbgLog((LOG_TRACE,
01261 CONNECT_TRACE_LEVEL,
01262 TEXT("Failed to complete connection")));
01263 pReceivePin->Disconnect();
01264 }
01265 }
01266 } else {
01267
01268 if (SUCCEEDED(hr) ||
01269 (hr == E_FAIL) ||
01270 (hr == E_INVALIDARG)) {
01271 hr = VFW_E_TYPE_NOT_ACCEPTED;
01272 }
01273 }
01274
01275 EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
01276
01277
01278 if (m_Connected) {
01279 m_Connected->Release();
01280 m_Connected = NULL;
01281 }
01282
01283 return hr;
01284 }
01285
01286 HRESULT CBasePin::TryMediaTypes(
01287 IPin *pReceivePin,
01288 const CMediaType *pmt,
01289 IEnumMediaTypes *pEnum)
01290 {
01291
01292
01293 HRESULT hr = pEnum->Reset();
01294 if (FAILED(hr)) {
01295 return hr;
01296 }
01297
01298 CMediaType *pMediaType = NULL;
01299 ULONG ulMediaCount = 0;
01300
01301
01302 HRESULT hrFailure = S_OK;
01303
01304 for (;;) {
01305
01306
01307
01308 hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount);
01309 if (hr != S_OK) {
01310 if (S_OK == hrFailure) {
01311 hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
01312 }
01313 return hrFailure;
01314 }
01315
01316 ASSERT(ulMediaCount == 1);
01317 ASSERT(pMediaType);
01318
01319
01320
01321 if ((pmt == NULL) ||
01322 pMediaType->MatchesPartial(pmt)) {
01323
01324 hr = AttemptConnection(pReceivePin, pMediaType);
01325
01326
01327 if (FAILED(hr) &&
01328 SUCCEEDED(hrFailure) &&
01329 (hr != E_FAIL) &&
01330 (hr != E_INVALIDARG) &&
01331 (hr != VFW_E_TYPE_NOT_ACCEPTED)) {
01332 hrFailure = hr;
01333 }
01334 } else {
01335 hr = VFW_E_NO_ACCEPTABLE_TYPES;
01336 }
01337
01338 DeleteMediaType(pMediaType);
01339
01340 if (S_OK == hr) {
01341 return hr;
01342 }
01343 }
01344 }
01345
01346 HRESULT CBasePin::AgreeMediaType(
01347 IPin *pReceivePin,
01348 const CMediaType *pmt)
01349 {
01350 ASSERT(pReceivePin);
01351 IEnumMediaTypes *pEnumMediaTypes = NULL;
01352
01353
01354 if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) {
01355
01356
01357
01358
01359
01360 return AttemptConnection(pReceivePin, pmt);
01361 }
01362
01363
01364
01365 HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
01366
01367 for (int i = 0; i < 2; i++) {
01368 HRESULT hr;
01369 if (i == (int)m_bTryMyTypesFirst) {
01370 hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes);
01371 } else {
01372 hr = EnumMediaTypes(&pEnumMediaTypes);
01373 }
01374 if (SUCCEEDED(hr)) {
01375 ASSERT(pEnumMediaTypes);
01376 hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes);
01377 pEnumMediaTypes->Release();
01378 if (SUCCEEDED(hr)) {
01379 return NOERROR;
01380 } else {
01381
01382 if ((hr != E_FAIL) &&
01383 (hr != E_INVALIDARG) &&
01384 (hr != VFW_E_TYPE_NOT_ACCEPTED)) {
01385 hrFailure = hr;
01386 }
01387 }
01388 }
01389 }
01390
01391 return hrFailure;
01392 }
01393
01394 HRESULT
01395 CBasePin::CompleteConnect(IPin *pReceivePin)
01396 {
01397 UNREFERENCED_PARAMETER(pReceivePin);
01398 return NOERROR;
01399 }
01400
01401 HRESULT
01402 CBasePin::SetMediaType(const CMediaType *pmt)
01403 {
01404 m_mt = *pmt;
01405 return NOERROR;
01406 }
01407
01408 HRESULT
01409 CBasePin::CheckConnect(IPin * pPin)
01410 {
01411
01412
01413 PIN_DIRECTION pd;
01414 pPin->QueryDirection(&pd);
01415
01416 ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT));
01417 ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT));
01418
01419
01420 if (pd == m_dir) {
01421 return VFW_E_INVALID_DIRECTION;
01422 }
01423 return NOERROR;
01424 }
01425
01426 HRESULT
01427 CBasePin::BreakConnect()
01428 {
01429 return NOERROR;
01430 }
01431
01432 STDMETHODIMP
01433 CBasePin::ReceiveConnection(
01434 IPin * pConnector,
01435 const AM_MEDIA_TYPE *pmt
01436 )
01437 {
01438 CheckPointer(pConnector,E_POINTER);
01439 CheckPointer(pmt,E_POINTER);
01440 ValidateReadPtr(pConnector,sizeof(IPin));
01441 ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE));
01442 CAutoLock cObjectLock(m_pLock);
01443
01444
01445 if (m_Connected) {
01446 return VFW_E_ALREADY_CONNECTED;
01447 }
01448
01449
01450 if (!IsStopped() && !m_bCanReconnectWhenActive) {
01451 return VFW_E_NOT_STOPPED;
01452 }
01453
01454 HRESULT hr = CheckConnect(pConnector);
01455 if (FAILED(hr)) {
01456
01457
01458 EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
01459
01460 return hr;
01461 }
01462
01463
01464
01465 CMediaType * pcmt = (CMediaType*) pmt;
01466 hr = CheckMediaType(pcmt);
01467 if (hr != NOERROR) {
01468
01469
01470
01471
01472 EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
01473
01474
01475
01476
01477 if (SUCCEEDED(hr) ||
01478 (hr == E_FAIL) ||
01479 (hr == E_INVALIDARG)) {
01480 hr = VFW_E_TYPE_NOT_ACCEPTED;
01481 }
01482
01483 return hr;
01484 }
01485
01486
01487
01488 m_Connected = pConnector;
01489 m_Connected->AddRef();
01490 SetMediaType(pcmt);
01491
01492 hr = CompleteConnect(pConnector);
01493 if (FAILED(hr)) {
01494 DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to complete connection")));
01495 m_Connected->Release();
01496 m_Connected = NULL;
01497
01498
01499
01500 EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
01501
01502 return hr;
01503 }
01504
01505 return NOERROR;
01506 }
01507
01508 STDMETHODIMP
01509 CBasePin::Disconnect()
01510 {
01511 CAutoLock cObjectLock(m_pLock);
01512
01513
01514 if (!IsStopped()) {
01515 return VFW_E_NOT_STOPPED;
01516 }
01517
01518 return DisconnectInternal();
01519 }
01520
01521 STDMETHODIMP
01522 CBasePin::DisconnectInternal()
01523 {
01524 ASSERT(CritCheckIn(m_pLock));
01525
01526 if (m_Connected) {
01527 HRESULT hr = BreakConnect();
01528 if( FAILED( hr ) ) {
01529
01530
01531 DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." );
01532 return hr;
01533 }
01534
01535 m_Connected->Release();
01536 m_Connected = NULL;
01537
01538 return S_OK;
01539 } else {
01540
01541
01542 return S_FALSE;
01543 }
01544 }
01545
01546 STDMETHODIMP
01547 CBasePin::ConnectedTo(
01548 IPin **ppPin
01549 )
01550 {
01551 CheckPointer(ppPin,E_POINTER);
01552 ValidateReadWritePtr(ppPin,sizeof(IPin *));
01553
01554
01555
01556
01557
01558 IPin *pPin = m_Connected;
01559 *ppPin = pPin;
01560 if (pPin != NULL) {
01561 pPin->AddRef();
01562 return S_OK;
01563 } else {
01564 ASSERT(*ppPin == NULL);
01565 return VFW_E_NOT_CONNECTED;
01566 }
01567 }
01568
01569 STDMETHODIMP
01570 CBasePin::ConnectionMediaType(
01571 AM_MEDIA_TYPE *pmt
01572 )
01573 {
01574 CheckPointer(pmt,E_POINTER);
01575 ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE));
01576 CAutoLock cObjectLock(m_pLock);
01577
01578
01579 if (IsConnected()) {
01580 CopyMediaType( pmt, &m_mt );
01581 return S_OK;
01582 } else {
01583 ((CMediaType *)pmt)->InitMediaType();
01584 return VFW_E_NOT_CONNECTED;
01585 }
01586 }
01587
01588 STDMETHODIMP
01589 CBasePin::QueryPinInfo(
01590 PIN_INFO * pInfo
01591 )
01592 {
01593 CheckPointer(pInfo,E_POINTER);
01594 ValidateReadWritePtr(pInfo,sizeof(PIN_INFO));
01595
01596 pInfo->pFilter = m_pFilter;
01597 if (m_pFilter) {
01598 m_pFilter->AddRef();
01599 }
01600
01601 if (m_pName) {
01602 lstrcpynW(pInfo->achName, m_pName, sizeof(pInfo->achName)/sizeof(WCHAR));
01603 } else {
01604 pInfo->achName[0] = L'\0';
01605 }
01606
01607 pInfo->dir = m_dir;
01608
01609 return NOERROR;
01610 }
01611
01612 STDMETHODIMP
01613 CBasePin::QueryDirection(
01614 PIN_DIRECTION * pPinDir
01615 )
01616 {
01617 CheckPointer(pPinDir,E_POINTER);
01618 ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION));
01619
01620 *pPinDir = m_dir;
01621 return NOERROR;
01622 }
01623
01624 STDMETHODIMP
01625 CBasePin::QueryId(
01626 LPWSTR * Id
01627 )
01628 {
01629
01630
01631
01632 return AMGetWideString(Name(), Id);
01633 }
01634
01635 STDMETHODIMP
01636 CBasePin::QueryAccept(
01637 const AM_MEDIA_TYPE *pmt
01638 )
01639 {
01640 CheckPointer(pmt,E_POINTER);
01641 ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE));
01642
01643
01644
01645 HRESULT hr = CheckMediaType((CMediaType*)pmt);
01646 if (FAILED(hr)) {
01647 return S_FALSE;
01648 }
01649
01650 return hr;
01651 }
01652
01653 STDMETHODIMP
01654 CBasePin::EnumMediaTypes(
01655 IEnumMediaTypes **ppEnum
01656 )
01657 {
01658 CheckPointer(ppEnum,E_POINTER);
01659 ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));
01660
01661
01662
01663 *ppEnum = new CEnumMediaTypes(this,
01664 NULL);
01665
01666 if (*ppEnum == NULL) {
01667 return E_OUTOFMEMORY;
01668 }
01669
01670 return NOERROR;
01671 }
01672
01673 HRESULT CBasePin::GetMediaType(int iPosition, CMediaType *pMediaType)
01674 {
01675 UNREFERENCED_PARAMETER(iPosition);
01676 UNREFERENCED_PARAMETER(pMediaType);
01677 return E_UNEXPECTED;
01678 }
01679
01680 LONG CBasePin::GetMediaTypeVersion()
01681 {
01682 return m_TypeVersion;
01683 }
01684
01685 void CBasePin::IncrementTypeVersion()
01686 {
01687 InterlockedIncrement(&m_TypeVersion);
01688 }
01689
01690 HRESULT
01691 CBasePin::Active(void)
01692 {
01693 return NOERROR;
01694 }
01695
01696 HRESULT
01697 CBasePin::Run(REFERENCE_TIME tStart)
01698 {
01699 UNREFERENCED_PARAMETER(tStart);
01700 return NOERROR;
01701 }
01702
01703 HRESULT
01704 CBasePin::Inactive(void)
01705 {
01706 m_bRunTimeError = FALSE;
01707 return NOERROR;
01708 }
01709
01710 STDMETHODIMP
01711 CBasePin::EndOfStream(void)
01712 {
01713 return S_OK;
01714 }
01715
01716 STDMETHODIMP
01717 CBasePin::SetSink(IQualityControl * piqc)
01718 {
01719 CAutoLock cObjectLock(m_pLock);
01720 if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl));
01721 m_pQSink = piqc;
01722 return NOERROR;
01723 }
01724
01725 STDMETHODIMP
01726 CBasePin::Notify(IBaseFilter * pSender, Quality q)
01727 {
01728 UNREFERENCED_PARAMETER(q);
01729 UNREFERENCED_PARAMETER(pSender);
01730 DbgBreak("IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)");
01731 return E_NOTIMPL;
01732 }
01733
01734 STDMETHODIMP
01735 CBasePin::NewSegment(
01736 REFERENCE_TIME tStart,
01737 REFERENCE_TIME tStop,
01738 double dRate)
01739 {
01740 m_tStart = tStart;
01741 m_tStop = tStop;
01742 m_dRate = dRate;
01743
01744 return S_OK;
01745 }
01746
01747 CBaseOutputPin::CBaseOutputPin(TCHAR *pObjectName,
01748 CBaseFilter *pFilter,
01749 CCritSec *pLock,
01750 HRESULT *phr,
01751 LPCWSTR pName) :
01752 CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT),
01753 m_pAllocator(NULL),
01754 m_pInputPin(NULL)
01755 {
01756 ASSERT(pFilter);
01757 }
01758
01759 #ifdef UNICODE
01760 CBaseOutputPin::CBaseOutputPin(CHAR *pObjectName,
01761 CBaseFilter *pFilter,
01762 CCritSec *pLock,
01763 HRESULT *phr,
01764 LPCWSTR pName) :
01765 CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT),
01766 m_pAllocator(NULL),
01767 m_pInputPin(NULL)
01768 {
01769 ASSERT(pFilter);
01770 }
01771 #endif
01772
01773 HRESULT
01774 CBaseOutputPin::CompleteConnect(IPin *pReceivePin)
01775 {
01776 UNREFERENCED_PARAMETER(pReceivePin);
01777 return DecideAllocator(m_pInputPin, &m_pAllocator);
01778 }
01779
01780 HRESULT
01781 CBaseOutputPin::CheckConnect(IPin * pPin)
01782 {
01783 HRESULT hr = CBasePin::CheckConnect(pPin);
01784 if (FAILED(hr)) {
01785 return hr;
01786 }
01787
01788
01789 hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin);
01790 if (FAILED(hr)) {
01791 return hr;
01792 }
01793 return NOERROR;
01794 }
01795
01796 HRESULT
01797 CBaseOutputPin::BreakConnect()
01798 {
01799
01800
01801 if (m_pAllocator) {
01802
01803
01804
01805 HRESULT hr = m_pAllocator->Decommit();
01806 if( FAILED( hr ) ) {
01807 return hr;
01808 }
01809
01810 m_pAllocator->Release();
01811 m_pAllocator = NULL;
01812 }
01813
01814
01815
01816 if (m_pInputPin) {
01817 m_pInputPin->Release();
01818 m_pInputPin = NULL;
01819 }
01820 return NOERROR;
01821 }
01822
01823 HRESULT
01824 CBaseOutputPin::InitAllocator(IMemAllocator **ppAlloc)
01825 {
01826 return CreateMemoryAllocator(ppAlloc);
01827 }
01828
01829 HRESULT
01830 CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc)
01831 {
01832 HRESULT hr = NOERROR;
01833 *ppAlloc = NULL;
01834
01835
01836
01837
01838
01839 ALLOCATOR_PROPERTIES prop;
01840 ZeroMemory(&prop, sizeof(prop));
01841
01842
01843
01844 pPin->GetAllocatorRequirements(&prop);
01845
01846
01847 if (prop.cbAlign == 0) {
01848 prop.cbAlign = 1;
01849 }
01850
01851
01852
01853 hr = pPin->GetAllocator(ppAlloc);
01854 if (SUCCEEDED(hr)) {
01855
01856 hr = DecideBufferSize(*ppAlloc, &prop);
01857 if (SUCCEEDED(hr)) {
01858 hr = pPin->NotifyAllocator(*ppAlloc, FALSE);
01859 if (SUCCEEDED(hr)) {
01860 return NOERROR;
01861 }
01862 }
01863 }
01864
01865
01866
01867 if (*ppAlloc) {
01868 (*ppAlloc)->Release();
01869 *ppAlloc = NULL;
01870 }
01871
01872
01873
01874 hr = InitAllocator(ppAlloc);
01875 if (SUCCEEDED(hr)) {
01876
01877
01878
01879
01880 hr = DecideBufferSize(*ppAlloc, &prop);
01881 if (SUCCEEDED(hr)) {
01882 hr = pPin->NotifyAllocator(*ppAlloc, FALSE);
01883 if (SUCCEEDED(hr)) {
01884 return NOERROR;
01885 }
01886 }
01887 }
01888
01889
01890
01891 if (*ppAlloc) {
01892 (*ppAlloc)->Release();
01893 *ppAlloc = NULL;
01894 }
01895 return hr;
01896 }
01897
01898 HRESULT
01899 CBaseOutputPin::GetDeliveryBuffer(IMediaSample ** ppSample,
01900 REFERENCE_TIME * pStartTime,
01901 REFERENCE_TIME * pEndTime,
01902 DWORD dwFlags)
01903 {
01904 if (m_pAllocator != NULL) {
01905 return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags);
01906 } else {
01907 return E_NOINTERFACE;
01908 }
01909 }
01910
01911 HRESULT
01912 CBaseOutputPin::Deliver(IMediaSample * pSample)
01913 {
01914 if (m_pInputPin == NULL) {
01915 return VFW_E_NOT_CONNECTED;
01916 }
01917
01918 return m_pInputPin->Receive(pSample);
01919 }
01920
01921 HRESULT
01922 CBaseOutputPin::DeliverEndOfStream(void)
01923 {
01924
01925 if (m_Connected == NULL) {
01926 return VFW_E_NOT_CONNECTED;
01927 }
01928 return m_Connected->EndOfStream();
01929 }
01930
01931 HRESULT
01932 CBaseOutputPin::Active(void)
01933 {
01934 if (m_pAllocator == NULL) {
01935 return VFW_E_NO_ALLOCATOR;
01936 }
01937 return m_pAllocator->Commit();
01938 }
01939
01940 HRESULT
01941 CBaseOutputPin::Inactive(void)
01942 {
01943 m_bRunTimeError = FALSE;
01944 if (m_pAllocator == NULL) {
01945 return VFW_E_NO_ALLOCATOR;
01946 }
01947 return m_pAllocator->Decommit();
01948 }
01949
01950 STDMETHODIMP
01951 CBaseOutputPin::EndOfStream(void)
01952 {
01953 return E_UNEXPECTED;
01954 }
01955
01956 STDMETHODIMP
01957 CBaseOutputPin::BeginFlush(void)
01958 {
01959 return E_UNEXPECTED;
01960 }
01961
01962 STDMETHODIMP
01963 CBaseOutputPin::EndFlush(void)
01964 {
01965 return E_UNEXPECTED;
01966 }
01967
01968 HRESULT
01969 CBaseOutputPin::DeliverBeginFlush(void)
01970 {
01971
01972 if (m_Connected == NULL) {
01973 return VFW_E_NOT_CONNECTED;
01974 }
01975 return m_Connected->BeginFlush();
01976 }
01977
01978 HRESULT
01979 CBaseOutputPin::DeliverEndFlush(void)
01980 {
01981
01982 if (m_Connected == NULL) {
01983 return VFW_E_NOT_CONNECTED;
01984 }
01985 return m_Connected->EndFlush();
01986 }
01987
01988 HRESULT
01989 CBaseOutputPin::DeliverNewSegment(
01990 REFERENCE_TIME tStart,
01991 REFERENCE_TIME tStop,
01992 double dRate)
01993 {
01994 if (m_Connected == NULL) {
01995 return VFW_E_NOT_CONNECTED;
01996 }
01997 return m_Connected->NewSegment(tStart, tStop, dRate);
01998 }
01999
02000 CBaseInputPin::CBaseInputPin(TCHAR *pObjectName,
02001 CBaseFilter *pFilter,
02002 CCritSec *pLock,
02003 HRESULT *phr,
02004 LPCWSTR pPinName) :
02005 CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT),
02006 m_pAllocator(NULL),
02007 m_bReadOnly(FALSE),
02008 m_bFlushing(FALSE)
02009 {
02010 ZeroMemory(&m_SampleProps, sizeof(m_SampleProps));
02011 }
02012
02013 #ifdef UNICODE
02014 CBaseInputPin::CBaseInputPin(CHAR *pObjectName,
02015 CBaseFilter *pFilter,
02016 CCritSec *pLock,
02017 HRESULT *phr,
02018 LPCWSTR pPinName) :
02019 CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT),
02020 m_pAllocator(NULL),
02021 m_bReadOnly(FALSE),
02022 m_bFlushing(FALSE)
02023 {
02024 ZeroMemory(&m_SampleProps, sizeof(m_SampleProps));
02025 }
02026 #endif
02027
02028 CBaseInputPin::~CBaseInputPin()
02029 {
02030 if (m_pAllocator != NULL) {
02031 m_pAllocator->Release();
02032 m_pAllocator = NULL;
02033 }
02034 }
02035
02036 STDMETHODIMP
02037 CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
02038 {
02039
02040
02041 if (riid == IID_IMemInputPin) {
02042 return GetInterface((IMemInputPin *) this, ppv);
02043 } else {
02044 return CBasePin::NonDelegatingQueryInterface(riid, ppv);
02045 }
02046 }
02047
02048 STDMETHODIMP
02049 CBaseInputPin::GetAllocator(
02050 IMemAllocator **ppAllocator)
02051 {
02052 CheckPointer(ppAllocator,E_POINTER);
02053 ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
02054 CAutoLock cObjectLock(m_pLock);
02055
02056 if (m_pAllocator == NULL) {
02057 HRESULT hr = CreateMemoryAllocator(&m_pAllocator);
02058 if (FAILED(hr)) {
02059 return hr;
02060 }
02061 }
02062 ASSERT(m_pAllocator != NULL);
02063 *ppAllocator = m_pAllocator;
02064 m_pAllocator->AddRef();
02065 return NOERROR;
02066 }
02067
02068 STDMETHODIMP
02069 CBaseInputPin::NotifyAllocator(
02070 IMemAllocator * pAllocator,
02071 BOOL bReadOnly)
02072 {
02073 CheckPointer(pAllocator,E_POINTER);
02074 ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
02075 CAutoLock cObjectLock(m_pLock);
02076
02077 IMemAllocator *pOldAllocator = m_pAllocator;
02078 pAllocator->AddRef();
02079 m_pAllocator = pAllocator;
02080
02081 if (pOldAllocator != NULL) {
02082 pOldAllocator->Release();
02083 }
02084
02085
02086
02087
02088 m_bReadOnly = (BYTE)bReadOnly;
02089 return NOERROR;
02090 }
02091
02092 HRESULT
02093 CBaseInputPin::BreakConnect()
02094 {
02095
02096 if (m_pAllocator) {
02097
02098
02099
02100 HRESULT hr = m_pAllocator->Decommit();
02101 if( FAILED( hr ) ) {
02102 return hr;
02103 }
02104
02105 m_pAllocator->Release();
02106 m_pAllocator = NULL;
02107 }
02108
02109 return S_OK;
02110 }
02111
02112 STDMETHODIMP
02113 CBaseInputPin::Receive(IMediaSample *pSample)
02114 {
02115 CheckPointer(pSample,E_POINTER);
02116 ValidateReadPtr(pSample,sizeof(IMediaSample));
02117 ASSERT(pSample);
02118
02119 HRESULT hr = CheckStreaming();
02120 if (S_OK != hr) {
02121 return hr;
02122 }
02123
02124
02125 IMediaSample2 *pSample2;
02126 if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) {
02127 hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps);
02128 pSample2->Release();
02129 if (FAILED(hr)) {
02130 return hr;
02131 }
02132 } else {
02133
02134 m_SampleProps.cbData = sizeof(m_SampleProps);
02135 m_SampleProps.dwTypeSpecificFlags = 0;
02136 m_SampleProps.dwStreamId = AM_STREAM_MEDIA;
02137 m_SampleProps.dwSampleFlags = 0;
02138 if (S_OK == pSample->IsDiscontinuity()) {
02139 m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
02140 }
02141 if (S_OK == pSample->IsPreroll()) {
02142 m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL;
02143 }
02144 if (S_OK == pSample->IsSyncPoint()) {
02145 m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
02146 }
02147 if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart,
02148 &m_SampleProps.tStop))) {
02149 m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID |
02150 AM_SAMPLE_STOPVALID;
02151 }
02152 if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) {
02153 m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED;
02154 }
02155 pSample->GetPointer(&m_SampleProps.pbBuffer);
02156 m_SampleProps.lActual = pSample->GetActualDataLength();
02157 m_SampleProps.cbBuffer = pSample->GetSize();
02158 }
02159
02160
02161
02162 if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) {
02163 return NOERROR;
02164 }
02165
02166
02167
02168
02169 hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType);
02170
02171 if (hr == NOERROR) {
02172 return NOERROR;
02173 }
02174
02175
02176
02177 m_bRunTimeError = TRUE;
02178 EndOfStream();
02179 m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0);
02180 return VFW_E_INVALIDMEDIATYPE;
02181 }
02182
02183 STDMETHODIMP
02184 CBaseInputPin::ReceiveMultiple (
02185 IMediaSample **pSamples,
02186 long nSamples,
02187 long *nSamplesProcessed)
02188 {
02189 CheckPointer(pSamples,E_POINTER);
02190 ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *));
02191
02192 HRESULT hr = S_OK;
02193 *nSamplesProcessed = 0;
02194 while (nSamples-- > 0) {
02195 hr = Receive(pSamples[*nSamplesProcessed]);
02196
02197
02198 if (hr != S_OK) {
02199 break;
02200 }
02201 (*nSamplesProcessed)++;
02202 }
02203 return hr;
02204 }
02205
02206 STDMETHODIMP
02207 CBaseInputPin::ReceiveCanBlock()
02208 {
02209
02210 int cPins = m_pFilter->GetPinCount();
02211 int cOutputPins = 0;
02212 for (int c = 0; c < cPins; c++) {
02213 CBasePin *pPin = m_pFilter->GetPin(c);
02214 PIN_DIRECTION pd;
02215 HRESULT hr = pPin->QueryDirection(&pd);
02216 if (FAILED(hr)) {
02217 return hr;
02218 }
02219
02220 if (pd == PINDIR_OUTPUT) {
02221
02222 IPin *pConnected;
02223 hr = pPin->ConnectedTo(&pConnected);
02224 if (SUCCEEDED(hr)) {
02225 ASSERT(pConnected != NULL);
02226 cOutputPins++;
02227 IMemInputPin *pInputPin;
02228 hr = pConnected->QueryInterface(
02229 IID_IMemInputPin,
02230 (void **)&pInputPin);
02231 pConnected->Release();
02232 if (SUCCEEDED(hr)) {
02233 hr = pInputPin->ReceiveCanBlock();
02234 pInputPin->Release();
02235 if (hr != S_FALSE) {
02236 return S_OK;
02237 }
02238 } else {
02239
02240 return S_OK;
02241 }
02242 }
02243 }
02244 }
02245 return cOutputPins == 0 ? S_OK : S_FALSE;
02246 }
02247
02248 STDMETHODIMP
02249 CBaseInputPin::BeginFlush(void)
02250 {
02251
02252
02253 CAutoLock lck(m_pLock);
02254
02255
02256
02257 ASSERT(!m_bFlushing);
02258
02259
02260 m_bFlushing = TRUE;
02261
02262
02263
02264 return S_OK;
02265 }
02266
02267 STDMETHODIMP
02268 CBaseInputPin::EndFlush(void)
02269 {
02270
02271
02272 CAutoLock lck(m_pLock);
02273
02274
02275 ASSERT(m_bFlushing);
02276
02277
02278
02279
02280
02281
02282 m_bFlushing = FALSE;
02283
02284
02285 m_bRunTimeError = FALSE;
02286
02287 return S_OK;
02288 }
02289
02290 STDMETHODIMP
02291 CBaseInputPin::Notify(IBaseFilter * pSender, Quality q)
02292 {
02293 UNREFERENCED_PARAMETER(q);
02294 CheckPointer(pSender,E_POINTER);
02295 ValidateReadPtr(pSender,sizeof(IBaseFilter));
02296 DbgBreak("IQuality::Notify called on an input pin");
02297 return NOERROR;
02298 }
02299
02300 HRESULT
02301 CBaseInputPin::Inactive(void)
02302 {
02303 m_bRunTimeError = FALSE;
02304 if (m_pAllocator == NULL) {
02305 return VFW_E_NO_ALLOCATOR;
02306 }
02307
02308 m_bFlushing = FALSE;
02309
02310 return m_pAllocator->Decommit();
02311 }
02312
02313 STDMETHODIMP
02314 CBaseInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES*pProps)
02315 {
02316 UNREFERENCED_PARAMETER(pProps);
02317 return E_NOTIMPL;
02318 }
02319
02320 HRESULT
02321 CBaseInputPin::CheckStreaming()
02322 {
02323
02324 ASSERT(IsConnected());
02325
02326
02327 if (IsStopped()) {
02328 return VFW_E_WRONG_STATE;
02329 }
02330 if (m_bFlushing) {
02331 return S_FALSE;
02332 }
02333 if (m_bRunTimeError) {
02334 return VFW_E_RUNTIME_ERROR;
02335 }
02336 return S_OK;
02337 }
02338
02339 HRESULT
02340 CBaseInputPin::PassNotify(Quality& q)
02341 {
02342
02343
02344
02345 DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform")));
02346 if (m_pQSink!=NULL) {
02347 return m_pQSink->Notify(m_pFilter, q);
02348 } else {
02349
02350 HRESULT hr;
02351 IQualityControl * pIQC;
02352
02353 hr = VFW_E_NOT_FOUND;
02354 if (m_Connected) {
02355 m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC);
02356
02357 if (pIQC!=NULL) {
02358 hr = pIQC->Notify(m_pFilter, q);
02359 pIQC->Release();
02360 }
02361 }
02362 return hr;
02363 }
02364
02365 }
02366
02367 CMediaSample::CMediaSample(TCHAR *pName,
02368 CBaseAllocator *pAllocator,
02369 HRESULT *phr,
02370 LPBYTE pBuffer,
02371 LONG length) :
02372 m_pBuffer(pBuffer),
02373 m_cbBuffer(length),
02374 m_lActual(length),
02375 m_pMediaType(NULL),
02376 m_dwFlags(0),
02377 m_cRef(0),
02378 m_dwTypeSpecificFlags(0),
02379 m_dwStreamId(AM_STREAM_MEDIA),
02380 m_pAllocator(pAllocator)
02381 {
02382
02383
02384
02385 ASSERT(pAllocator);
02386 }
02387
02388 #ifdef UNICODE
02389 CMediaSample::CMediaSample(CHAR *pName,
02390 CBaseAllocator *pAllocator,
02391 HRESULT *phr,
02392 LPBYTE pBuffer,
02393 LONG length) :
02394 m_pBuffer(pBuffer),
02395 m_cbBuffer(length),
02396 m_lActual(length),
02397 m_pMediaType(NULL),
02398 m_dwFlags(0),
02399 m_cRef(0),
02400 m_dwTypeSpecificFlags(0),
02401 m_dwStreamId(AM_STREAM_MEDIA),
02402 m_pAllocator(pAllocator)
02403 {
02404
02405
02406
02407 ASSERT(pAllocator);
02408 }
02409 #endif
02410
02411 CMediaSample::~CMediaSample()
02412 {
02413
02414 if (m_pMediaType) {
02415 DeleteMediaType(m_pMediaType);
02416 }
02417 }
02418
02419 STDMETHODIMP
02420 CMediaSample::QueryInterface(REFIID riid, void **ppv)
02421 {
02422 if (riid == IID_IMediaSample ||
02423 riid == IID_IMediaSample2 ||
02424 riid == IID_IUnknown) {
02425 return GetInterface((IMediaSample *) this, ppv);
02426 } else {
02427 return E_NOINTERFACE;
02428 }
02429 }
02430
02431 STDMETHODIMP_(ULONG)
02432 CMediaSample::AddRef()
02433 {
02434 return InterlockedIncrement(&m_cRef);
02435 }
02436
02437 STDMETHODIMP_(ULONG)
02438 CMediaSample::Release()
02439 {
02440
02441 LONG lRef;
02442 if (m_cRef == 1) {
02443 lRef = 0;
02444 m_cRef = 0;
02445 } else {
02446 lRef = InterlockedDecrement(&m_cRef);
02447 }
02448 ASSERT(lRef >= 0);
02449
02450 DbgLog((LOG_MEMORY,3,TEXT(" Unknown %X ref-- = %d"),
02451 this, m_cRef));
02452
02453
02454 if (lRef == 0) {
02455
02456 if (m_dwFlags & Sample_TypeChanged) {
02457 SetMediaType(NULL);
02458 }
02459 ASSERT(m_pMediaType == NULL);
02460 m_dwFlags = 0;
02461 m_dwTypeSpecificFlags = 0;
02462 m_dwStreamId = AM_STREAM_MEDIA;
02463
02464
02465
02466 m_pAllocator->ReleaseBuffer(this);
02467 }
02468 return (ULONG)lRef;
02469 }
02470
02471 HRESULT
02472 CMediaSample::SetPointer(BYTE * ptr, LONG cBytes)
02473 {
02474 m_pBuffer = ptr;
02475 m_cbBuffer = cBytes;
02476 m_lActual = cBytes;
02477
02478 return S_OK;
02479 }
02480
02481 STDMETHODIMP
02482 CMediaSample::GetPointer(BYTE ** ppBuffer)
02483 {
02484 ValidateReadWritePtr(ppBuffer,sizeof(BYTE *));
02485
02486
02487
02488 ASSERT(m_pBuffer);
02489
02490 *ppBuffer = m_pBuffer;
02491 return NOERROR;
02492 }
02493
02494 STDMETHODIMP_(LONG)
02495 CMediaSample::GetSize(void)
02496 {
02497 return m_cbBuffer;
02498 }
02499
02500 STDMETHODIMP
02501 CMediaSample::GetTime(
02502 REFERENCE_TIME * pTimeStart,
02503 REFERENCE_TIME * pTimeEnd
02504 )
02505 {
02506 ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME));
02507 ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME));
02508
02509 if (!(m_dwFlags & Sample_StopValid)) {
02510 if (!(m_dwFlags & Sample_TimeValid)) {
02511 return VFW_E_SAMPLE_TIME_NOT_SET;
02512 } else {
02513 *pTimeStart = m_Start;
02514
02515
02516 *pTimeEnd = m_Start + 1;
02517 return VFW_S_NO_STOP_TIME;
02518 }
02519 }
02520
02521 *pTimeStart = m_Start;
02522 *pTimeEnd = m_End;
02523 return NOERROR;
02524 }
02525
02526 STDMETHODIMP
02527 CMediaSample::SetTime(
02528 REFERENCE_TIME * pTimeStart,
02529 REFERENCE_TIME * pTimeEnd
02530 )
02531 {
02532 if (pTimeStart == NULL) {
02533 ASSERT(pTimeEnd == NULL);
02534 m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid);
02535 } else {
02536 if (pTimeEnd == NULL) {
02537 m_Start = *pTimeStart;
02538 m_dwFlags |= Sample_TimeValid;
02539 m_dwFlags &= ~Sample_StopValid;
02540 } else {
02541 ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME));
02542 ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME));
02543 ASSERT(*pTimeEnd >= *pTimeStart);
02544
02545 m_Start = *pTimeStart;
02546 m_End = *pTimeEnd;
02547 m_dwFlags |= Sample_TimeValid | Sample_StopValid;
02548 }
02549 }
02550 return NOERROR;
02551 }
02552
02553 STDMETHODIMP
02554 CMediaSample::GetMediaTime(
02555 LONGLONG * pTimeStart,
02556 LONGLONG * pTimeEnd
02557 )
02558 {
02559 ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG));
02560 ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG));
02561
02562 if (!(m_dwFlags & Sample_MediaTimeValid)) {
02563 return VFW_E_MEDIA_TIME_NOT_SET;
02564 }
02565
02566 *pTimeStart = m_MediaStart;
02567 *pTimeEnd = (m_MediaStart + m_MediaEnd);
02568 return NOERROR;
02569 }
02570
02571 STDMETHODIMP
02572 CMediaSample::SetMediaTime(
02573 LONGLONG * pTimeStart,
02574 LONGLONG * pTimeEnd
02575 )
02576 {
02577 if (pTimeStart == NULL) {
02578 ASSERT(pTimeEnd == NULL);
02579 m_dwFlags &= ~Sample_MediaTimeValid;
02580 } else {
02581 ValidateReadPtr(pTimeStart,sizeof(LONGLONG));
02582 ValidateReadPtr(pTimeEnd,sizeof(LONGLONG));
02583 ASSERT(*pTimeEnd >= *pTimeStart);
02584
02585 m_MediaStart = *pTimeStart;
02586 m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart);
02587 m_dwFlags |= Sample_MediaTimeValid;
02588 }
02589 return NOERROR;
02590 }
02591
02592 STDMETHODIMP
02593 CMediaSample::IsSyncPoint(void)
02594 {
02595 if (m_dwFlags & Sample_SyncPoint) {
02596 return S_OK;
02597 } else {
02598 return S_FALSE;
02599 }
02600 }
02601
02602 STDMETHODIMP
02603 CMediaSample::SetSyncPoint(BOOL bIsSyncPoint)
02604 {
02605 if (bIsSyncPoint) {
02606 m_dwFlags |= Sample_SyncPoint;
02607 } else {
02608 m_dwFlags &= ~Sample_SyncPoint;
02609 }
02610 return NOERROR;
02611 }
02612
02613 STDMETHODIMP
02614 CMediaSample::IsDiscontinuity(void)
02615 {
02616 if (m_dwFlags & Sample_Discontinuity) {
02617 return S_OK;
02618 } else {
02619 return S_FALSE;
02620 }
02621 }
02622
02623 STDMETHODIMP
02624 CMediaSample::SetDiscontinuity(BOOL bDiscont)
02625 {
02626
02627 if (bDiscont) {
02628 m_dwFlags |= Sample_Discontinuity;
02629 } else {
02630 m_dwFlags &= ~Sample_Discontinuity;
02631 }
02632 return S_OK;
02633 }
02634
02635 STDMETHODIMP
02636 CMediaSample::IsPreroll(void)
02637 {
02638 if (m_dwFlags & Sample_Preroll) {
02639 return S_OK;
02640 } else {
02641 return S_FALSE;
02642 }
02643 }
02644
02645 STDMETHODIMP
02646 CMediaSample::SetPreroll(BOOL bIsPreroll)
02647 {
02648 if (bIsPreroll) {
02649 m_dwFlags |= Sample_Preroll;
02650 } else {
02651 m_dwFlags &= ~Sample_Preroll;
02652 }
02653 return NOERROR;
02654 }
02655
02656 STDMETHODIMP_(LONG)
02657 CMediaSample::GetActualDataLength(void)
02658 {
02659 return m_lActual;
02660 }
02661
02662 STDMETHODIMP
02663 CMediaSample::SetActualDataLength(LONG lActual)
02664 {
02665 if (lActual > m_cbBuffer) {
02666 ASSERT(lActual <= GetSize());
02667 return VFW_E_BUFFER_OVERFLOW;
02668 }
02669 m_lActual = lActual;
02670 return NOERROR;
02671 }
02672
02673 STDMETHODIMP
02674 CMediaSample::GetMediaType(AM_MEDIA_TYPE **ppMediaType)
02675 {
02676 ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *));
02677 ASSERT(ppMediaType);
02678
02679
02680
02681 if (!(m_dwFlags & Sample_TypeChanged)) {
02682 ASSERT(m_pMediaType == NULL);
02683 *ppMediaType = NULL;
02684 return S_FALSE;
02685 }
02686
02687 ASSERT(m_pMediaType);
02688
02689
02690
02691 *ppMediaType = CreateMediaType(m_pMediaType);
02692 if (*ppMediaType == NULL) {
02693 return E_OUTOFMEMORY;
02694 }
02695 return NOERROR;
02696 }
02697
02698 STDMETHODIMP
02699 CMediaSample::SetMediaType(AM_MEDIA_TYPE *pMediaType)
02700 {
02701
02702
02703 if (m_pMediaType) {
02704 DeleteMediaType(m_pMediaType);
02705 m_pMediaType = NULL;
02706 }
02707
02708
02709
02710 if (pMediaType == NULL) {
02711 m_dwFlags &= ~Sample_TypeChanged;
02712 return NOERROR;
02713 }
02714
02715 ASSERT(pMediaType);
02716 ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE));
02717
02718
02719
02720 m_pMediaType = CreateMediaType(pMediaType);
02721 if (m_pMediaType == NULL) {
02722 m_dwFlags &= ~Sample_TypeChanged;
02723 return E_OUTOFMEMORY;
02724 }
02725
02726 m_dwFlags |= Sample_TypeChanged;
02727 return NOERROR;
02728 }
02729
02730 STDMETHODIMP CMediaSample::GetProperties(
02731 DWORD cbProperties,
02732 BYTE * pbProperties
02733 )
02734 {
02735 if (0 != cbProperties) {
02736 CheckPointer(pbProperties, E_POINTER);
02737
02738 AM_SAMPLE2_PROPERTIES Props;
02739 Props.cbData = min(cbProperties, sizeof(Props));
02740 Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid;
02741 Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags;
02742 Props.pbBuffer = m_pBuffer;
02743 Props.cbBuffer = m_cbBuffer;
02744 Props.lActual = m_lActual;
02745 Props.tStart = m_Start;
02746 Props.tStop = m_End;
02747 Props.dwStreamId = m_dwStreamId;
02748 if (m_dwFlags & AM_SAMPLE_TYPECHANGED) {
02749 Props.pMediaType = m_pMediaType;
02750 } else {
02751 Props.pMediaType = NULL;
02752 }
02753 CopyMemory(pbProperties, &Props, Props.cbData);
02754 }
02755 return S_OK;
02756 }
02757
02758 #define CONTAINS_FIELD(type, field, offset) \
02759 ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset)
02760
02761 HRESULT CMediaSample::SetProperties(
02762 DWORD cbProperties,
02763 const BYTE * pbProperties
02764 )
02765 {
02766
02767
02768 AM_MEDIA_TYPE *pMediaType = NULL;
02769
02770 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) {
02771 CheckPointer(pbProperties, E_POINTER);
02772 AM_SAMPLE2_PROPERTIES *pProps =
02773 (AM_SAMPLE2_PROPERTIES *)pbProperties;
02774
02775
02776 if (pProps->cbData < cbProperties) {
02777 cbProperties = pProps->cbData;
02778 }
02779
02780 if (cbProperties > sizeof(*pProps) ||
02781 pProps->cbData > sizeof(*pProps)) {
02782 return E_INVALIDARG;
02783 }
02784
02785 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) {
02786
02787 if (pProps->dwSampleFlags &
02788 (~Sample_ValidFlags | Sample_MediaTimeValid)) {
02789 return E_INVALIDARG;
02790 }
02791
02792 if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) &&
02793 !(m_dwFlags & AM_SAMPLE_TIMEVALID) &&
02794 !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) {
02795 return E_INVALIDARG;
02796 }
02797 }
02798
02799 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) {
02800
02801
02802 if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) {
02803 return E_INVALIDARG;
02804 }
02805 }
02806 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) {
02807
02808
02809 if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) {
02810 return E_INVALIDARG;
02811 }
02812 }
02813 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) &&
02814 CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) {
02815
02816
02817 if (pProps->cbBuffer < pProps->lActual) {
02818 return E_INVALIDARG;
02819 }
02820 }
02821
02822 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) {
02823
02824
02825 if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
02826 CheckPointer(pProps->pMediaType, E_POINTER);
02827 pMediaType = CreateMediaType(pProps->pMediaType);
02828 if (pMediaType == NULL) {
02829 return E_OUTOFMEMORY;
02830 }
02831 }
02832 }
02833
02834
02835 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) {
02836 m_dwStreamId = pProps->dwStreamId;
02837 }
02838 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) {
02839
02840 m_dwFlags = pProps->dwSampleFlags |
02841 (m_dwFlags & Sample_MediaTimeValid);
02842 m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
02843 } else {
02844 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) {
02845 m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
02846 }
02847 }
02848
02849 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) {
02850
02851 m_lActual = pProps->lActual;
02852 }
02853
02854 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) {
02855
02856
02857 m_End = pProps->tStop;
02858 }
02859 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) {
02860
02861
02862 m_Start = pProps->tStart;
02863 }
02864
02865 if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) {
02866
02867 if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
02868 if (m_pMediaType != NULL) {
02869 DeleteMediaType(m_pMediaType);
02870 }
02871 m_pMediaType = pMediaType;
02872 }
02873 }
02874
02875
02876 if (m_pMediaType) {
02877 m_dwFlags |= Sample_TypeChanged;
02878 } else {
02879 m_dwFlags &= ~Sample_TypeChanged;
02880 }
02881 }
02882
02883 return S_OK;
02884 }
02885
02886 CDynamicOutputPin::CDynamicOutputPin(
02887 TCHAR *pObjectName,
02888 CBaseFilter *pFilter,
02889 CCritSec *pLock,
02890 HRESULT *phr,
02891 LPCWSTR pName) :
02892 CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName),
02893 m_hStopEvent(NULL),
02894 m_pGraphConfig(NULL),
02895 m_bPinUsesReadOnlyAllocator(FALSE),
02896 m_BlockState(NOT_BLOCKED),
02897 m_hUnblockOutputPinEvent(NULL),
02898 m_hNotifyCallerPinBlockedEvent(NULL),
02899 m_dwBlockCallerThreadID(0),
02900 m_dwNumOutstandingOutputPinUsers(0)
02901 {
02902 HRESULT hr = Initialize();
02903 if( FAILED( hr ) ) {
02904 *phr = hr;
02905 return;
02906 }
02907 }
02908
02909 #ifdef UNICODE
02910 CDynamicOutputPin::CDynamicOutputPin(
02911 CHAR *pObjectName,
02912 CBaseFilter *pFilter,
02913 CCritSec *pLock,
02914 HRESULT *phr,
02915 LPCWSTR pName) :
02916 CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName),
02917 m_hStopEvent(NULL),
02918 m_pGraphConfig(NULL),
02919 m_bPinUsesReadOnlyAllocator(FALSE),
02920 m_BlockState(NOT_BLOCKED),
02921 m_hUnblockOutputPinEvent(NULL),
02922 m_hNotifyCallerPinBlockedEvent(NULL),
02923 m_dwBlockCallerThreadID(0),
02924 m_dwNumOutstandingOutputPinUsers(0)
02925 {
02926 HRESULT hr = Initialize();
02927 if( FAILED( hr ) ) {
02928 *phr = hr;
02929 return;
02930 }
02931 }
02932 #endif
02933
02934 CDynamicOutputPin::~CDynamicOutputPin()
02935 {
02936 if(NULL != m_hUnblockOutputPinEvent) {
02937
02938
02939 EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent));
02940 }
02941
02942 if(NULL != m_hNotifyCallerPinBlockedEvent) {
02943
02944
02945 EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent));
02946 }
02947 }
02948
02949 HRESULT CDynamicOutputPin::Initialize(void)
02950 {
02951 m_hUnblockOutputPinEvent = ::CreateEvent( NULL,
02952 TRUE,
02953 TRUE,
02954 NULL );
02955
02956
02957 if(NULL == m_hUnblockOutputPinEvent) {
02958 return AmGetLastErrorToHResult();
02959 }
02960
02961
02962 SetReconnectWhenActive(true);
02963
02964 return S_OK;
02965 }
02966
02967 STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv)
02968 {
02969 if(riid == IID_IPinFlowControl) {
02970 return GetInterface(static_cast<IPinFlowControl*>(this), ppv);
02971 } else {
02972 return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
02973 }
02974 }
02975
02976 STDMETHODIMP CDynamicOutputPin::Disconnect(void)
02977 {
02978 CAutoLock cObjectLock(m_pLock);
02979 return DisconnectInternal();
02980 }
02981
02982 STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent)
02983 {
02984 const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK;
02985
02986
02987 if(dwBlockFlags & ~VALID_FLAGS) {
02988 return E_INVALIDARG;
02989 }
02990
02991
02992 if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) {
02993 if( !::ResetEvent( hEvent ) ) {
02994 return AmGetLastErrorToHResult();
02995 }
02996 }
02997
02998
02999 if(0 == dwBlockFlags) {
03000
03001
03002
03003 if(NULL != hEvent) {
03004 return E_INVALIDARG;
03005 }
03006 }
03007
03008 #ifdef DEBUG
03009 AssertValid();
03010 #endif
03011
03012 HRESULT hr;
03013
03014 if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) {
03015
03016
03017 if(NULL == hEvent) {
03018 hr = SynchronousBlockOutputPin();
03019 } else {
03020 hr = AsynchronousBlockOutputPin(hEvent);
03021 }
03022 } else {
03023 hr = UnblockOutputPin();
03024 }
03025
03026 #ifdef DEBUG
03027 AssertValid();
03028 #endif
03029
03030 if(FAILED(hr)) {
03031 return hr;
03032 }
03033
03034 return S_OK;
03035 }
03036
03037 HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void)
03038 {
03039 HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL,
03040 FALSE,
03041 FALSE,
03042 NULL );
03043
03044
03045 if(NULL == hNotifyCallerPinBlockedEvent) {
03046 return AmGetLastErrorToHResult();
03047 }
03048
03049 HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent);
03050 if(FAILED(hr)) {
03051
03052
03053 EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent));
03054
03055 return hr;
03056 }
03057
03058 hr = WaitEvent(hNotifyCallerPinBlockedEvent);
03059
03060
03061
03062 EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent));
03063
03064 if(FAILED(hr)) {
03065 return hr;
03066 }
03067
03068 return S_OK;
03069 }
03070
03071 HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent)
03072 {
03073
03074
03075
03076 CAutoLock alBlockStateLock(&m_BlockStateLock);
03077
03078 if(NOT_BLOCKED != m_BlockState) {
03079 if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) {
03080 return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD;
03081 } else {
03082 return VFW_E_PIN_ALREADY_BLOCKED;
03083 }
03084 }
03085
03086 BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(),
03087 hNotifyCallerPinBlockedEvent,
03088 ::GetCurrentProcess(),
03089 &m_hNotifyCallerPinBlockedEvent,
03090 EVENT_MODIFY_STATE,
03091 FALSE,
03092 0 );
03093 if( !fSuccess ) {
03094 return AmGetLastErrorToHResult();
03095 }
03096
03097 m_BlockState = PENDING;
03098 m_dwBlockCallerThreadID = ::GetCurrentThreadId();
03099
03100
03101
03102
03103
03104
03105 if(!StreamingThreadUsingOutputPin()) {
03106
03107
03108 BlockOutputPin();
03109 }
03110
03111 return S_OK;
03112 }
03113
03114 void CDynamicOutputPin::BlockOutputPin(void)
03115 {
03116
03117
03118 ASSERT(CritCheckIn(&m_BlockStateLock));
03119
03120
03121
03122 ASSERT(!StreamingThreadUsingOutputPin());
03123
03124
03125
03126 EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent));
03127
03128
03129
03130 EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent));
03131 EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent));
03132
03133 m_BlockState = BLOCKED;
03134 m_hNotifyCallerPinBlockedEvent = NULL;
03135 }
03136
03137 HRESULT CDynamicOutputPin::UnblockOutputPin(void)
03138 {
03139
03140
03141
03142 CAutoLock alBlockStateLock(&m_BlockStateLock);
03143
03144 if(NOT_BLOCKED == m_BlockState) {
03145 return S_FALSE;
03146 }
03147
03148
03149
03150 EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent));
03151
03152
03153 if(NULL != m_hNotifyCallerPinBlockedEvent) {
03154
03155
03156 EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent));
03157 EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent));
03158 }
03159
03160 m_BlockState = NOT_BLOCKED;
03161 m_dwBlockCallerThreadID = 0;
03162 m_hNotifyCallerPinBlockedEvent = NULL;
03163
03164 return S_OK;
03165 }
03166
03167 HRESULT CDynamicOutputPin::StartUsingOutputPin(void)
03168 {
03169
03170
03171 ASSERT(CritCheckOut(&m_BlockStateLock));
03172
03173 CAutoLock alBlockStateLock(&m_BlockStateLock);
03174
03175 #ifdef DEBUG
03176 AssertValid();
03177 #endif
03178
03179
03180 while(BLOCKED == m_BlockState) {
03181 m_BlockStateLock.Unlock();
03182
03183
03184
03185 ASSERT(CritCheckOut( &m_BlockStateLock ));
03186
03187
03188
03189
03190
03191 const DWORD UNBLOCK = WAIT_OBJECT_0;
03192 const DWORD STOP = WAIT_OBJECT_0 + 1;
03193
03194 HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent };
03195 DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE);
03196
03197 DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE );
03198
03199 m_BlockStateLock.Lock();
03200
03201 #ifdef DEBUG
03202 AssertValid();
03203 #endif
03204
03205 switch( dwReturnValue ) {
03206 case UNBLOCK:
03207 break;
03208
03209 case STOP:
03210 return VFW_E_STATE_CHANGED;
03211
03212 case WAIT_FAILED:
03213 return AmGetLastErrorToHResult();
03214
03215 default:
03216 DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." );
03217 return E_UNEXPECTED;
03218 }
03219 }
03220
03221 m_dwNumOutstandingOutputPinUsers++;
03222
03223 #ifdef DEBUG
03224 AssertValid();
03225 #endif
03226
03227 return S_OK;
03228 }
03229
03230 void CDynamicOutputPin::StopUsingOutputPin(void)
03231 {
03232 CAutoLock alBlockStateLock(&m_BlockStateLock);
03233
03234 #ifdef DEBUG
03235 AssertValid();
03236 #endif
03237
03238 m_dwNumOutstandingOutputPinUsers--;
03239
03240 if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) {
03241 BlockOutputPin();
03242 }
03243
03244 #ifdef DEBUG
03245 AssertValid();
03246 #endif
03247 }
03248
03249 bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void)
03250 {
03251 CAutoLock alBlockStateLock(&m_BlockStateLock);
03252
03253 return (m_dwNumOutstandingOutputPinUsers > 0);
03254 }
03255
03256 void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent)
03257 {
03258
03259
03260
03261 m_pGraphConfig = pGraphConfig;
03262
03263 m_hStopEvent = hStopEvent;
03264 }
03265
03266 HRESULT CDynamicOutputPin::Active(void)
03267 {
03268
03269 if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) {
03270 DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them. );
03271 return E_FAIL;
03272 }
03273
03274
03275
03276
03277
03278 EXECUTE_ASSERT(ResetEvent(m_hStopEvent));
03279
03280 return CBaseOutputPin::Active();
03281 }
03282
03283 HRESULT CDynamicOutputPin::Inactive(void)
03284 {
03285
03286
03287
03288
03289 EXECUTE_ASSERT(SetEvent(m_hStopEvent));
03290
03291 return CBaseOutputPin::Inactive();
03292 }
03293
03294 HRESULT CDynamicOutputPin::DeliverBeginFlush(void)
03295 {
03296
03297
03298
03299
03300 EXECUTE_ASSERT(SetEvent(m_hStopEvent));
03301
03302 return CBaseOutputPin::DeliverBeginFlush();
03303 }
03304
03305 HRESULT CDynamicOutputPin::DeliverEndFlush(void)
03306 {
03307
03308
03309
03310
03311 EXECUTE_ASSERT(ResetEvent(m_hStopEvent));
03312
03313 return CBaseOutputPin::DeliverEndFlush();
03314 }
03315
03316 HRESULT CDynamicOutputPin::ChangeOutputFormat
03317 (
03318 const AM_MEDIA_TYPE *pmt,
03319 REFERENCE_TIME tSegmentStart,
03320 REFERENCE_TIME tSegmentStop,
03321 double dSegmentRate
03322 )
03323 {
03324
03325
03326 ASSERT(StreamingThreadUsingOutputPin());
03327
03328
03329 ASSERT(NULL != pmt);
03330
03331 CMediaType cmt(*pmt);
03332 HRESULT hr = ChangeMediaType(&cmt);
03333 if (FAILED(hr)) {
03334 return hr;
03335 }
03336
03337 hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate);
03338 if( FAILED( hr ) ) {
03339 return hr;
03340 }
03341
03342 return S_OK;
03343 }
03344
03345 HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt)
03346 {
03347
03348
03349 ASSERT(StreamingThreadUsingOutputPin());
03350
03351
03352 ASSERT(!IsStopped());
03353
03354 if(!IsConnected()) {
03355 return VFW_E_NOT_CONNECTED;
03356 }
03357
03358
03359 QzCComPtr<IPinConnection> pConnection;
03360
03361 m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection);
03362 if(pConnection != NULL) {
03363
03364 if(S_OK == pConnection->DynamicQueryAccept(pmt)) {
03365
03366 HRESULT hr = ChangeMediaTypeHelper(pmt);
03367 if(FAILED(hr)) {
03368 return hr;
03369 }
03370
03371 return S_OK;
03372 }
03373 }
03374
03375
03376 return DynamicReconnect(pmt);
03377 }
03378
03379 HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt)
03380 {
03381
03382
03383 ASSERT(StreamingThreadUsingOutputPin());
03384
03385 HRESULT hr = m_Connected->ReceiveConnection(this, pmt);
03386 if(FAILED(hr)) {
03387 return hr;
03388 }
03389
03390 hr = SetMediaType(pmt);
03391 if(FAILED(hr)) {
03392 return hr;
03393 }
03394
03395
03396 if(NULL != m_pInputPin) {
03397
03398
03399 ASSERT(::IsEqualObject(m_Connected, m_pInputPin));
03400
03401 ALLOCATOR_PROPERTIES apInputPinRequirements;
03402 apInputPinRequirements.cbAlign = 0;
03403 apInputPinRequirements.cbBuffer = 0;
03404 apInputPinRequirements.cbPrefix = 0;
03405 apInputPinRequirements.cBuffers = 0;
03406
03407 m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements);
03408
03409
03410 if(0 == apInputPinRequirements.cbAlign) {
03411 apInputPinRequirements.cbAlign = 1;
03412 }
03413
03414 hr = m_pAllocator->Decommit();
03415 if(FAILED(hr)) {
03416 return hr;
03417 }
03418
03419 hr = DecideBufferSize(m_pAllocator, &apInputPinRequirements);
03420 if(FAILED(hr)) {
03421 return hr;
03422 }
03423
03424 hr = m_pAllocator->Commit();
03425 if(FAILED(hr)) {
03426 return hr;
03427 }
03428
03429 hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator);
03430 if(FAILED(hr)) {
03431 return hr;
03432 }
03433 }
03434
03435 return S_OK;
03436 }
03437
03438 HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt )
03439 {
03440
03441
03442 ASSERT(StreamingThreadUsingOutputPin());
03443
03444 if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) {
03445 return E_FAIL;
03446 }
03447
03448 HRESULT hr = m_pGraphConfig->Reconnect(
03449 this,
03450 NULL,
03451 pmt,
03452 NULL,
03453 m_hStopEvent,
03454 AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS );
03455
03456 return hr;
03457 }
03458
03459 HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin)
03460 {
03461 HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin);
03462 if(SUCCEEDED(hr)) {
03463 if(!IsStopped() && m_pAllocator) {
03464 hr = m_pAllocator->Commit();
03465 ASSERT(hr != VFW_E_ALREADY_COMMITTED);
03466 }
03467 }
03468
03469 return hr;
03470 }
03471
03472 #ifdef DEBUG
03473 void CDynamicOutputPin::AssertValid(void)
03474 {
03475
03476
03477
03478
03479 ASSERT(NULL != m_hUnblockOutputPinEvent);
03480
03481
03482
03483 ASSERT(NULL != m_hStopEvent);
03484 ASSERT(NULL != m_pGraphConfig);
03485
03486
03487
03488 CAutoLock alBlockStateLock(&m_BlockStateLock);
03489
03490
03491 ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState));
03492
03493
03494
03495 ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) ||
03496 ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) );
03497
03498
03499
03500 ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState));
03501
03502
03503
03504 ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) ||
03505 ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) ||
03506 ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) );
03507 }
03508 #endif
03509
03510 HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent)
03511 {
03512 const DWORD EVENT_SIGNALED = WAIT_OBJECT_0;
03513
03514 DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE);
03515
03516 switch( dwReturnValue ) {
03517 case EVENT_SIGNALED:
03518 return S_OK;
03519
03520 case WAIT_FAILED:
03521 return AmGetLastErrorToHResult();
03522
03523 default:
03524 DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." );
03525 return E_UNEXPECTED;
03526 }
03527 }
03528
03529 CBaseAllocator::CBaseAllocator(TCHAR *pName,
03530 LPUNKNOWN pUnk,
03531 HRESULT *phr,
03532 BOOL bEvent,
03533 BOOL fEnableReleaseCallback
03534 ) :
03535 CUnknown(pName, pUnk),
03536 m_lAllocated(0),
03537 m_bChanged(FALSE),
03538 m_bCommitted(FALSE),
03539 m_bDecommitInProgress(FALSE),
03540 m_lSize(0),
03541 m_lCount(0),
03542 m_lAlignment(0),
03543 m_lPrefix(0),
03544 m_hSem(NULL),
03545 m_lWaiting(0),
03546 m_fEnableReleaseCallback(fEnableReleaseCallback),
03547 m_pNotify(NULL)
03548 {
03549
03550 if (bEvent) {
03551 m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
03552 if (m_hSem == NULL) {
03553 *phr = E_OUTOFMEMORY;
03554 return;
03555 }
03556 }
03557 }
03558
03559 #ifdef UNICODE
03560 CBaseAllocator::CBaseAllocator(CHAR *pName,
03561 LPUNKNOWN pUnk,
03562 HRESULT *phr,
03563 BOOL bEvent,
03564 BOOL fEnableReleaseCallback) :
03565 CUnknown(pName, pUnk),
03566 m_lAllocated(0),
03567 m_bChanged(FALSE),
03568 m_bCommitted(FALSE),
03569 m_bDecommitInProgress(FALSE),
03570 m_lSize(0),
03571 m_lCount(0),
03572 m_lAlignment(0),
03573 m_lPrefix(0),
03574 m_hSem(NULL),
03575 m_lWaiting(0),
03576 m_fEnableReleaseCallback(fEnableReleaseCallback),
03577 m_pNotify(NULL)
03578 {
03579
03580 if (bEvent) {
03581 m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
03582 if (m_hSem == NULL) {
03583 *phr = E_OUTOFMEMORY;
03584 return;
03585 }
03586 }
03587 }
03588 #endif
03589
03590 CBaseAllocator::~CBaseAllocator()
03591 {
03592
03593
03594
03595
03596
03597 ASSERT(!m_bCommitted);
03598 if (m_hSem != NULL) {
03599 EXECUTE_ASSERT(CloseHandle(m_hSem));
03600 }
03601 if (m_pNotify) {
03602 m_pNotify->Release();
03603 }
03604 }
03605
03606 STDMETHODIMP
03607 CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, void **ppv)
03608 {
03609
03610
03611 if (riid == IID_IMemAllocator ||
03612 riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) {
03613 return GetInterface((IMemAllocatorCallbackTemp *) this, ppv);
03614 } else {
03615 return CUnknown::NonDelegatingQueryInterface(riid, ppv);
03616 }
03617 }
03618
03619 STDMETHODIMP
03620 CBaseAllocator::SetProperties(
03621 ALLOCATOR_PROPERTIES* pRequest,
03622 ALLOCATOR_PROPERTIES* pActual)
03623 {
03624 CheckPointer(pRequest, E_POINTER);
03625 CheckPointer(pActual, E_POINTER);
03626 ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES));
03627 CAutoLock cObjectLock(this);
03628
03629 ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
03630
03631 ASSERT(pRequest->cbBuffer > 0);
03632
03633
03634 if (pRequest->cbAlign != 1) {
03635 DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"),
03636 pRequest->cbAlign));
03637 return VFW_E_BADALIGN;
03638 }
03639
03640
03641
03642 if (m_bCommitted) {
03643 return VFW_E_ALREADY_COMMITTED;
03644 }
03645
03646
03647
03648 if (m_lAllocated != m_lFree.GetCount()) {
03649 return VFW_E_BUFFERS_OUTSTANDING;
03650 }
03651
03652
03653
03654 pActual->cbBuffer = m_lSize = pRequest->cbBuffer;
03655 pActual->cBuffers = m_lCount = pRequest->cBuffers;
03656 pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
03657 pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
03658
03659 m_bChanged = TRUE;
03660 return NOERROR;
03661 }
03662
03663 STDMETHODIMP
03664 CBaseAllocator::GetProperties(
03665 ALLOCATOR_PROPERTIES * pActual)
03666 {
03667 CheckPointer(pActual,E_POINTER);
03668 ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES));
03669
03670 CAutoLock cObjectLock(this);
03671 pActual->cbBuffer = m_lSize;
03672 pActual->cBuffers = m_lCount;
03673 pActual->cbAlign = m_lAlignment;
03674 pActual->cbPrefix = m_lPrefix;
03675 return NOERROR;
03676 }
03677
03678 HRESULT CBaseAllocator::GetBuffer(IMediaSample **ppBuffer,
03679 REFERENCE_TIME *pStartTime,
03680 REFERENCE_TIME *pEndTime,
03681 DWORD dwFlags
03682 )
03683 {
03684 UNREFERENCED_PARAMETER(pStartTime);
03685 UNREFERENCED_PARAMETER(pEndTime);
03686 UNREFERENCED_PARAMETER(dwFlags);
03687 CMediaSample *pSample;
03688
03689 *ppBuffer = NULL;
03690 for (;;)
03691 {
03692 {
03693 CAutoLock cObjectLock(this);
03694
03695
03696 if (!m_bCommitted) {
03697 return VFW_E_NOT_COMMITTED;
03698 }
03699 pSample = (CMediaSample *) m_lFree.RemoveHead();
03700 if (pSample == NULL) {
03701 SetWaiting();
03702 }
03703 }
03704
03705
03706
03707 if (pSample) {
03708 break;
03709 }
03710 if (dwFlags & AM_GBF_NOWAIT) {
03711 return VFW_E_TIMEOUT;
03712 }
03713 ASSERT(m_hSem != NULL);
03714 WaitForSingleObject(m_hSem, INFINITE);
03715 }
03716
03717
03718
03719 ASSERT(pSample->m_cRef == 0);
03720 pSample->m_cRef = 1;
03721 *ppBuffer = pSample;
03722
03723 return NOERROR;
03724 }
03725
03726 STDMETHODIMP
03727 CBaseAllocator::ReleaseBuffer(IMediaSample * pSample)
03728 {
03729 CheckPointer(pSample,E_POINTER);
03730 ValidateReadPtr(pSample,sizeof(IMediaSample));
03731
03732 BOOL bRelease = FALSE;
03733 {
03734 CAutoLock cal(this);
03735
03736
03737
03738 m_lFree.Add((CMediaSample *)pSample);
03739 if (m_lWaiting != 0) {
03740 NotifySample();
03741 }
03742
03743
03744
03745
03746 LONG l1 = m_lFree.GetCount();
03747 if (m_bDecommitInProgress && (l1 == m_lAllocated)) {
03748 Free();
03749 m_bDecommitInProgress = FALSE;
03750 bRelease = TRUE;
03751 }
03752 }
03753
03754 if (m_pNotify) {
03755
03756 ASSERT(m_fEnableReleaseCallback);
03757
03758
03759
03760
03761
03762 m_pNotify->NotifyRelease();
03763 }
03764
03765
03766
03767 if (bRelease) {
03768 Release();
03769 }
03770 return NOERROR;
03771 }
03772
03773 STDMETHODIMP
03774 CBaseAllocator::SetNotify(
03775 IMemAllocatorNotifyCallbackTemp* pNotify
03776 )
03777 {
03778 ASSERT(m_fEnableReleaseCallback);
03779 CAutoLock lck(this);
03780 if (pNotify) {
03781 pNotify->AddRef();
03782 }
03783 if (m_pNotify) {
03784 m_pNotify->Release();
03785 }
03786 m_pNotify = pNotify;
03787 return S_OK;
03788 }
03789
03790 STDMETHODIMP
03791 CBaseAllocator::GetFreeCount(
03792 LONG* plBuffersFree
03793 )
03794 {
03795 ASSERT(m_fEnableReleaseCallback);
03796 CAutoLock cObjectLock(this);
03797 *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount();
03798 return NOERROR;
03799 }
03800
03801 void
03802 CBaseAllocator::NotifySample()
03803 {
03804 if (m_lWaiting != 0) {
03805 ASSERT(m_hSem != NULL);
03806 ReleaseSemaphore(m_hSem, m_lWaiting, 0);
03807 m_lWaiting = 0;
03808 }
03809 }
03810
03811 STDMETHODIMP
03812 CBaseAllocator::Commit()
03813 {
03814
03815 CAutoLock cObjectLock(this);
03816
03817
03818 if (m_bCommitted) {
03819 return NOERROR;
03820 }
03821
03822
03823
03824 m_bCommitted = TRUE;
03825
03826
03827 if (m_bDecommitInProgress) {
03828 m_bDecommitInProgress = FALSE;
03829
03830
03831
03832
03833
03834 return NOERROR;
03835 }
03836
03837 DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize));
03838
03839
03840 HRESULT hr = Alloc();
03841 if (FAILED(hr)) {
03842 m_bCommitted = FALSE;
03843 return hr;
03844 }
03845 AddRef();
03846 return NOERROR;
03847 }
03848
03849 STDMETHODIMP
03850 CBaseAllocator::Decommit()
03851 {
03852 BOOL bRelease = FALSE;
03853 {
03854
03855 CAutoLock cObjectLock(this);
03856 if (m_bCommitted == FALSE) {
03857 if (m_bDecommitInProgress == FALSE) {
03858 return NOERROR;
03859 }
03860 }
03861
03862
03863 m_bCommitted = FALSE;
03864
03865
03866 if (m_lFree.GetCount() < m_lAllocated) {
03867
03868 m_bDecommitInProgress = TRUE;
03869 } else {
03870 m_bDecommitInProgress = FALSE;
03871
03872
03873
03874
03875 Free();
03876 bRelease = TRUE;
03877 }
03878
03879
03880
03881 NotifySample();
03882 }
03883
03884 if (bRelease) {
03885 Release();
03886 }
03887 return NOERROR;
03888 }
03889
03890 HRESULT
03891 CBaseAllocator::Alloc(void)
03892 {
03893
03894 if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) {
03895 return VFW_E_SIZENOTSET;
03896 }
03897
03898
03899 ASSERT(m_lFree.GetCount() == m_lAllocated);
03900
03901
03902 if (m_bChanged == FALSE) {
03903 return S_FALSE;
03904 }
03905
03906 return NOERROR;
03907 }
03908
03909 void
03910 CBaseAllocator::CSampleList::Remove(CMediaSample * pSample)
03911 {
03912 CMediaSample **pSearch;
03913 for (pSearch = &m_List;
03914 *pSearch != NULL;
03915 pSearch = &(CBaseAllocator::NextSample(*pSearch))) {
03916 if (*pSearch == pSample) {
03917 *pSearch = CBaseAllocator::NextSample(pSample);
03918 CBaseAllocator::NextSample(pSample) = NULL;
03919 m_nOnList--;
03920 return;
03921 }
03922 }
03923 DbgBreak("Couldn't find sample in list");
03924 }
03925
03926 CUnknown *CMemAllocator::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
03927 {
03928 CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr);
03929 return pUnkRet;
03930 }
03931
03932 CMemAllocator::CMemAllocator(
03933 TCHAR *pName,
03934 LPUNKNOWN pUnk,
03935 HRESULT *phr)
03936 : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE),
03937 m_pBuffer(NULL)
03938 {
03939 }
03940
03941 #ifdef UNICODE
03942 CMemAllocator::CMemAllocator(
03943 CHAR *pName,
03944 LPUNKNOWN pUnk,
03945 HRESULT *phr)
03946 : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE),
03947 m_pBuffer(NULL)
03948 {
03949 }
03950 #endif
03951
03952 STDMETHODIMP
03953 CMemAllocator::SetProperties(
03954 ALLOCATOR_PROPERTIES* pRequest,
03955 ALLOCATOR_PROPERTIES* pActual)
03956 {
03957 CheckPointer(pActual,E_POINTER);
03958 ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES));
03959 CAutoLock cObjectLock(this);
03960
03961 ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
03962
03963 ASSERT(pRequest->cbBuffer > 0);
03964
03965 SYSTEM_INFO SysInfo;
03966 GetSystemInfo(&SysInfo);
03967
03968
03969 if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) {
03970 DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"),
03971 pRequest->cbAlign));
03972 }
03973
03974 if (pRequest->cbAlign == 0 ||
03975 (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) {
03976 DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"),
03977 pRequest->cbAlign, SysInfo.dwAllocationGranularity));
03978 return VFW_E_BADALIGN;
03979 }
03980
03981
03982
03983 if (m_bCommitted == TRUE) {
03984 return VFW_E_ALREADY_COMMITTED;
03985 }
03986
03987
03988
03989 if (m_lFree.GetCount() < m_lAllocated) {
03990 return VFW_E_BUFFERS_OUTSTANDING;
03991 }
03992
03993
03994
03995
03996
03997 LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix;
03998 LONG lRemainder = lSize % pRequest->cbAlign;
03999 if (lRemainder != 0) {
04000 lSize = lSize - lRemainder + pRequest->cbAlign;
04001 }
04002 pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix);
04003
04004 pActual->cBuffers = m_lCount = pRequest->cBuffers;
04005 pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
04006 pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
04007
04008 m_bChanged = TRUE;
04009 return NOERROR;
04010 }
04011
04012 HRESULT
04013 CMemAllocator::Alloc(void)
04014 {
04015 CAutoLock lck(this);
04016
04017
04018 HRESULT hr = CBaseAllocator::Alloc();
04019 if (FAILED(hr)) {
04020 return hr;
04021 }
04022
04023
04024 if (hr == S_FALSE) {
04025 ASSERT(m_pBuffer);
04026 return NOERROR;
04027 }
04028 ASSERT(hr == S_OK);
04029
04030
04031 if (m_pBuffer) {
04032 ReallyFree();
04033 }
04034
04035
04036 LONG lAlignedSize = m_lSize + m_lPrefix;
04037 if (m_lAlignment > 1) {
04038 LONG lRemainder = lAlignedSize % m_lAlignment;
04039 if (lRemainder != 0) {
04040 lAlignedSize += (m_lAlignment - lRemainder);
04041 }
04042 }
04043
04044
04045 ASSERT(lAlignedSize % m_lAlignment == 0);
04046
04047 m_pBuffer = (PBYTE)VirtualAlloc(NULL,
04048 m_lCount * lAlignedSize,
04049 MEM_COMMIT,
04050 PAGE_READWRITE);
04051
04052 if (m_pBuffer == NULL) {
04053 return E_OUTOFMEMORY;
04054 }
04055
04056 LPBYTE pNext = m_pBuffer;
04057 CMediaSample *pSample;
04058
04059 ASSERT(m_lAllocated == 0);
04060
04061
04062
04063
04064
04065 for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) {
04066
04067 pSample = new CMediaSample(
04068 NAME("Default memory media sample"),
04069 this,
04070 &hr,
04071 pNext + m_lPrefix,
04072 m_lSize);
04073
04074 ASSERT(SUCCEEDED(hr));
04075 if (pSample == NULL) {
04076 return E_OUTOFMEMORY;
04077 }
04078
04079
04080 m_lFree.Add(pSample);
04081 }
04082
04083 m_bChanged = FALSE;
04084 return NOERROR;
04085 }
04086
04087 void
04088 CMemAllocator::Free(void)
04089 {
04090 return;
04091 }
04092
04093 void
04094 CMemAllocator::ReallyFree(void)
04095 {
04096
04097
04098 ASSERT(m_lAllocated == m_lFree.GetCount());
04099
04100
04101
04102 CMediaSample *pSample;
04103 for (;;) {
04104 pSample = m_lFree.RemoveHead();
04105 if (pSample != NULL) {
04106 delete pSample;
04107 } else {
04108 break;
04109 }
04110 }
04111
04112 m_lAllocated = 0;
04113
04114
04115 if (m_pBuffer) {
04116 EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE));
04117 m_pBuffer = NULL;
04118 }
04119 }
04120
04121 CMemAllocator::~CMemAllocator()
04122 {
04123 Decommit();
04124 ReallyFree();
04125 }
04126
04127 STDAPI
04128 AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata
04129 , IFilterMapper * pIFM
04130 , BOOL bRegister )
04131 {
04132 DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter")));
04133
04134
04135
04136 if( NULL == psetupdata ) return S_FALSE;
04137
04138
04139
04140
04141
04142 DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter")));
04143 HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) );
04144
04145 if( bRegister )
04146 {
04147
04148
04149 DbgLog((LOG_TRACE, 3, TEXT("= = register filter")));
04150 hr = pIFM->RegisterFilter( *(psetupdata->clsID)
04151 , psetupdata->strName
04152 , psetupdata->dwMerit );
04153 if( SUCCEEDED(hr) )
04154 {
04155
04156
04157 DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins")));
04158 for( UINT m1=0; m1 < psetupdata->nPins; m1++ )
04159 {
04160 hr = pIFM->RegisterPin( *(psetupdata->clsID)
04161 , psetupdata->lpPin[m1].strName
04162 , psetupdata->lpPin[m1].bRendered
04163 , psetupdata->lpPin[m1].bOutput
04164 , psetupdata->lpPin[m1].bZero
04165 , psetupdata->lpPin[m1].bMany
04166 , *(psetupdata->lpPin[m1].clsConnectsToFilter)
04167 , psetupdata->lpPin[m1].strConnectsToPin );
04168
04169 if( SUCCEEDED(hr) )
04170 {
04171
04172
04173 DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types")));
04174 for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ )
04175 {
04176 hr = pIFM->RegisterPinType( *(psetupdata->clsID)
04177 , psetupdata->lpPin[m1].strName
04178 , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType)
04179 , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) );
04180 if( FAILED(hr) ) break;
04181 }
04182 if( FAILED(hr) ) break;
04183 }
04184 if( FAILED(hr) ) break;
04185 }
04186 }
04187 }
04188
04189
04190 if( 0x80070002 == hr)
04191 return NOERROR;
04192 else
04193 return hr;
04194 }
04195
04196 #pragma warning(disable:4514)
04197