- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# BufferFilter.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    00019  *
    00020  */
    00021
    00022 #include "stdafx.h"
    00023 #include "bufferfilter.h"
    00024 #include "..\..\..\DSUtil\DSUtil.h"
    00025
    00026 #ifdef REGISTER_FILTER
    00027
    00028 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
    00029 {
    00030         {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL},
    00031 };
    00032
    00033 const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
    00034 {
    00035         {&MEDIATYPE_NULL, &MEDIASUBTYPE_NULL},
    00036 };
    00037
    00038 const AMOVIESETUP_PIN sudpPins[] =
    00039 {
    00040     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
    00041     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut}
    00042 };
    00043
    00044 const AMOVIESETUP_FILTER sudFilter[] =
    00045 {
    00046         {&__uuidof(CBufferFilter), L"Buffer Filter", MERIT_DO_NOT_USE, countof(sudpPins), sudpPins}
    00047 };
    00048
    00049 CFactoryTemplate g_Templates[] =
    00050 {
    00051         {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CBufferFilter>, NULL, &sudFilter[0]}
    00052 };
    00053
    00054 int g_cTemplates = countof(g_Templates);
    00055
    00056 STDAPI DllRegisterServer()
    00057 {
    00058         return AMovieDllRegisterServer2(TRUE);
    00059 }
    00060
    00061 STDAPI DllUnregisterServer()
    00062 {
    00063         return AMovieDllRegisterServer2(FALSE);
    00064 }
    00065
    00066 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
    00067
    00068 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
    00069 {
    00070     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
    00071 }
    00072
    00073 #endif
    00074
    00075 //
    00076 // CBufferFilter
    00077 //
    00078
    00079 CBufferFilter::CBufferFilter(LPUNKNOWN lpunk, HRESULT* phr)
    00080         : CTransformFilter(NAME("CBufferFilter"), lpunk, __uuidof(this))
    00081         , m_nSamplesToBuffer(2)
    00082 {
    00083         HRESULT hr = S_OK;
    00084
    00085         do
    00086         {
    00087                 if(!(m_pInput = new CTransformInputPin(NAME("Transform input pin"), this, &hr, L"In"))) hr = E_OUTOFMEMORY;
    00088                 if(FAILED(hr)) break;
    00089
    00090                 if(!(m_pOutput = new CBufferFilterOutputPin(this, &hr))) hr = E_OUTOFMEMORY;
    00091                 if(FAILED(hr)) {delete m_pInput, m_pInput = NULL; break;}
    00092         }
    00093         while(false);
    00094
    00095         if(phr) *phr = hr;
    00096 }
    00097
    00098 CBufferFilter::~CBufferFilter()
    00099 {
    00100 }
    00101
    00102 STDMETHODIMP CBufferFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00103 {
    00104         return
    00105                 QI(IBufferFilter)
    00106                 __super::NonDelegatingQueryInterface(riid, ppv);
    00107 }
    00108
    00109 // IBufferFilter
    00110
    00111 STDMETHODIMP CBufferFilter::SetBuffers(int nBuffers)
    00112 {
    00113         if(!m_pOutput)
    00114                 return E_FAIL;
    00115
    00116         if(m_pOutput->IsConnected()) // TODO: allow "on-the-fly" changes
    00117                 return VFW_E_ALREADY_CONNECTED;
    00118
    00119         m_nSamplesToBuffer = nBuffers;
    00120
    00121         return S_OK;
    00122 }
    00123
    00124 STDMETHODIMP_(int) CBufferFilter::GetBuffers()
    00125 {
    00126         return(m_nSamplesToBuffer);
    00127 }
    00128
    00129 STDMETHODIMP_(int) CBufferFilter::GetFreeBuffers()
    00130 {
    00131         CBufferFilterOutputPin* pPin = (CBufferFilterOutputPin*)m_pOutput;
    00132         return(pPin && pPin->m_pOutputQueue ? (m_nSamplesToBuffer - pPin->m_pOutputQueue->GetQueueCount()) : 0);
    00133 }
    00134
    00135 STDMETHODIMP CBufferFilter::SetPriority(DWORD dwPriority)
    00136 {
    00137         CBufferFilterOutputPin* pPin = (CBufferFilterOutputPin*)m_pOutput;
    00138         return(pPin && pPin->m_pOutputQueue ? (pPin->m_pOutputQueue->SetPriority(dwPriority) ? S_OK : E_FAIL) : E_UNEXPECTED);
    00139 }
    00140
    00141 //
    00142
    00143 HRESULT CBufferFilter::Receive(IMediaSample* pSample)
    00144 {
    00145         /*  Check for other streams and pass them on */
    00146         AM_SAMPLE2_PROPERTIES* const pProps = m_pInput->SampleProps();
    00147         if(pProps->dwStreamId != AM_STREAM_MEDIA)
    00148                 return m_pOutput->Deliver(pSample);
    00149
    00150         HRESULT hr;
    00151         ASSERT(pSample);
    00152         IMediaSample* pOutSample;
    00153
    00154         ASSERT(m_pOutput != NULL);
    00155
    00156         // Set up the output sample
    00157         hr = InitializeOutputSample(pSample, &pOutSample);
    00158
    00159         if(FAILED(hr))
    00160                 return hr;
    00161
    00162         // Start timing the transform (if PERF is defined)
    00163         MSR_START(m_idTransform);
    00164
    00165         // have the derived class transform the data
    00166
    00167         hr = Transform(pSample, pOutSample);
    00168
    00169         // Stop the clock and log it (if PERF is defined)
    00170         MSR_STOP(m_idTransform);
    00171
    00172         if(FAILED(hr)) {
    00173                 DbgLog((LOG_TRACE,1,TEXT("Error from transform")));
    00174         }
    00175         else {
    00176                 // the Transform() function can return S_FALSE to indicate that the
    00177                 // sample should not be delivered; we only deliver the sample if it's
    00178                 // really S_OK (same as NOERROR, of course.)
    00179                 if(hr == NOERROR) {
    00180                         hr = m_pOutput->Deliver(pOutSample);
    00181                         m_bSampleSkipped = FALSE;   // last thing no longer dropped
    00182                 }
    00183                 else {
    00184                         // S_FALSE returned from Transform is a PRIVATE agreement
    00185                         // We should return NOERROR from Receive() in this cause because returning S_FALSE
    00186                         // from Receive() means that this is the end of the stream and no more data should
    00187                         // be sent.
    00188                         if(S_FALSE == hr) {
    00189
    00190                                 //  Release the sample before calling notify to avoid
    00191                                 //  deadlocks if the sample holds a lock on the system
    00192                                 //  such as DirectDraw buffers do
    00193                                 pOutSample->Release();
    00194                                 m_bSampleSkipped = TRUE;
    00195                                 if(!m_bQualityChanged) {
    00196                                         NotifyEvent(EC_QUALITY_CHANGE,0,0);
    00197                                         m_bQualityChanged = TRUE;
    00198                                 }
    00199                                 return NOERROR;
    00200                         }
    00201                 }
    00202         }
    00203
    00204         // release the output buffer. If the connected pin still needs it,
    00205         // it will have addrefed it itself.
    00206         pOutSample->Release();
    00207
    00208         return hr;
    00209 }
    00210
    00211 HRESULT CBufferFilter::Transform(IMediaSample* pIn, IMediaSample* pOut)
    00212 {
    00213         BYTE* pDataIn = NULL;
    00214         BYTE* pDataOut = NULL;
    00215
    00216         pIn->GetPointer(&pDataIn);
    00217         pOut->GetPointer(&pDataOut);
    00218
    00219         long len = pIn->GetActualDataLength();
    00220         long size = pOut->GetSize();
    00221
    00222         if(!pDataIn || !pDataOut || len > size || len <= 0) return S_FALSE;
    00223
    00224         memcpy(pDataOut, pDataIn, min(len, size));
    00225
    00226         pOut->SetActualDataLength(min(len, size));
    00227
    00228         return S_OK;
    00229 }
    00230
    00231 HRESULT CBufferFilter::CheckInputType(const CMediaType* mtIn)
    00232 {
    00233         return S_OK;
    00234 }
    00235
    00236 HRESULT CBufferFilter::CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut)
    00237 {
    00238         return mtIn->MatchesPartial(mtOut) ? S_OK : VFW_E_TYPE_NOT_ACCEPTED;
    00239 }
    00240
    00241 HRESULT CBufferFilter::DecideBufferSize(IMemAllocator* pAllocator, ALLOCATOR_PROPERTIES* pProperties)
    00242 {
    00243         if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
    00244
    00245         CComPtr<IMemAllocator> pAllocatorIn;
    00246         m_pInput->GetAllocator(&pAllocatorIn);
    00247         if(!pAllocatorIn) return E_UNEXPECTED;
    00248
    00249         pAllocatorIn->GetProperties(pProperties);
    00250
    00251         pProperties->cBuffers = max(m_nSamplesToBuffer, pProperties->cBuffers);
    00252
    00253         HRESULT hr;
    00254         ALLOCATOR_PROPERTIES Actual;
    00255     if(FAILED(hr = pAllocator->SetProperties(pProperties, &Actual)))
    00256                 return hr;
    00257
    00258     return(pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer
    00259                 ? E_FAIL
    00260                 : NOERROR);
    00261 }
    00262
    00263 HRESULT CBufferFilter::GetMediaType(int iPosition, CMediaType* pMediaType)
    00264 {
    00265     if(m_pInput->IsConnected() == FALSE) return E_UNEXPECTED;
    00266
    00267         // TODO: offer all input types from upstream and allow reconnection at least in stopped state
    00268         if(iPosition < 0) return E_INVALIDARG;
    00269     if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
    00270
    00271         CopyMediaType(pMediaType, &m_pInput->CurrentMediaType());
    00272
    00273         return S_OK;
    00274 }
    00275
    00276 HRESULT CBufferFilter::StopStreaming()
    00277 {
    00278         CBufferFilterOutputPin* pPin = (CBufferFilterOutputPin*)m_pOutput;
    00279         if(m_pInput && pPin && pPin->m_pOutputQueue)
    00280         {
    00281                 while(!m_pInput->IsFlushing() && pPin->m_pOutputQueue->GetQueueCount() > 0)
    00282                         Sleep(50);
    00283         }
    00284
    00285         return __super::StopStreaming();
    00286 }
    00287
    00288 //
    00289 // CBufferFilterOutputPin
    00290 //
    00291
    00292 CBufferFilterOutputPin::CBufferFilterOutputPin(CTransformFilter* pFilter, HRESULT* phr)
    00293         : CTransformOutputPin(NAME("CBufferFilterOutputPin"), pFilter, phr, L"Out")
    00294 {
    00295 }
    00296
    00297 HRESULT CBufferFilterOutputPin::Active()
    00298 {
    00299         CAutoLock lock_it(m_pLock);
    00300
    00301         if(m_Connected && !m_pOutputQueue)
    00302         {
    00303                 HRESULT hr = NOERROR;
    00304
    00305                 m_pOutputQueue.Attach(new CBufferFilterOutputQueue(m_Connected, &hr));
    00306                 if(!m_pOutputQueue) hr = E_OUTOFMEMORY;
    00307
    00308                 if(FAILED(hr))
    00309                 {
    00310                         m_pOutputQueue.Free();
    00311                         return hr;
    00312                 }
    00313         }
    00314
    00315         return __super::Active();
    00316 }
    00317
    00318 HRESULT CBufferFilterOutputPin::Inactive()
    00319 {
    00320         CAutoLock lock_it(m_pLock);
    00321         m_pOutputQueue.Free();
    00322         return __super::Inactive();
    00323 }
    00324
    00325 HRESULT CBufferFilterOutputPin::Deliver(IMediaSample* pMediaSample)
    00326 {
    00327         if(!m_pOutputQueue) return NOERROR;
    00328         pMediaSample->AddRef();
    00329         return m_pOutputQueue->Receive(pMediaSample);
    00330 }
    00331
    00332 #define CallQueue(call) \
    00333                 if(!m_pOutputQueue) return NOERROR; \
    00334                 m_pOutputQueue->##call; \
    00335                 return NOERROR; \
    00336
    00337 HRESULT CBufferFilterOutputPin::DeliverEndOfStream()
    00338 {
    00339         CallQueue(EOS());
    00340 }
    00341
    00342 HRESULT CBufferFilterOutputPin::DeliverBeginFlush()
    00343 {
    00344         CallQueue(BeginFlush());
    00345 }
    00346
    00347 HRESULT CBufferFilterOutputPin::DeliverEndFlush()
    00348 {
    00349         CallQueue(EndFlush());
    00350 }
    00351
    00352 HRESULT CBufferFilterOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
    00353 {
    00354         CallQueue(NewSegment(tStart, tStop, dRate));
    00355 }