// // NonDelegatingQueryInterface // // This function is overwritten to expose IMediaPosition and IMediaSelection // Note that only one output stream can be allowed to expose this to avoid // conflicts, the other pins will just return E_NOINTERFACE and therefore // appear as non seekable streams. We have a LONG value that if exchanged to // produce a TRUE means that we have the honor. If it exchanges to FALSE then // someone is already in. If we do get it and error occurs then we reset it // to TRUE so someone else can get it. // STDMETHODIMP CTeeOutputPin::NonDelegatingQueryInterface(REFIID riid, void **ppv) { CheckPointer(ppv,E_POINTER); ASSERT(ppv); *ppv = NULL; HRESULT hr = NOERROR; // See what interface the caller is interested in. if(riid == IID_IMediaPosition || riid == IID_IMediaSeeking) { if(m_pPosition) { if(m_bHoldsSeek == FALSE) return E_NOINTERFACE; return m_pPosition->QueryInterface(riid, ppv); } } else { return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv); } CAutoLock lock_it(m_pLock); ASSERT(m_pPosition == NULL); IUnknown *pMediaPosition = NULL; // Try to create a seeking implementation if(InterlockedExchange(&m_pTee->m_lCanSeek, FALSE) == FALSE) return E_NOINTERFACE; // Create implementation of this dynamically as sometimes we may never // try and seek. The helper object implements IMediaPosition and also // the IMediaSelection control interface and simply takes the calls // normally from the downstream filter and passes them upstream hr = CreatePosPassThru(GetOwner(), FALSE, (IPin *)&m_pTee->m_Input, &pMediaPosition); if(pMediaPosition == NULL) { InterlockedExchange(&m_pTee->m_lCanSeek, TRUE); return E_OUTOFMEMORY; } if(FAILED(hr)) { InterlockedExchange(&m_pTee->m_lCanSeek, TRUE); pMediaPosition->Release(); return hr; } m_pPosition = pMediaPosition; m_bHoldsSeek = TRUE; return NonDelegatingQueryInterface(riid, ppv); } // NonDelegatingQueryInterface
HRESULT VMRSurfaceAllocator::QueryInterface( REFIID iid, PVOID *pvInterface ) { return NonDelegatingQueryInterface( iid, pvInterface ); }