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 }

Generated on Tue Dec 13 14:47:26 2005 for guliverkli by  doxygen 1.4.5