StreamDriveThru.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 "streamdrivethru.h"
00024 #include "..\..\..\DSUtil\DSUtil.h"
00025 
00026 #ifdef REGISTER_FILTER
00027 
00028 const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
00029 {
00030         {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL},
00031 };
00032 
00033 const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
00034 {
00035         {&MEDIATYPE_Stream, &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(CStreamDriveThruFilter), L"StreamDriveThru", MERIT_DO_NOT_USE, countof(sudpPins), sudpPins}
00047 };
00048 
00049 CFactoryTemplate g_Templates[] =
00050 {
00051         {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CStreamDriveThruFilter>, 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 // CStreamDriveThruFilter
00077 //
00078 
00079 CStreamDriveThruFilter::CStreamDriveThruFilter(LPUNKNOWN pUnk, HRESULT* phr)
00080         : CBaseFilter(NAME("CStreamDriveThruFilter"), pUnk, &m_csLock, __uuidof(this))
00081         , m_position(0)
00082 {
00083         if(phr) *phr = S_OK;
00084 
00085         m_pInput = new CStreamDriveThruInputPin(NAME("CStreamDriveThruInputPin"), this, &m_csLock, phr);
00086         m_pOutput = new CStreamDriveThruOutputPin(NAME("CStreamDriveThruOutputPin"), this, &m_csLock, phr);
00087 
00088         CAMThread::Create();
00089 }
00090 
00091 CStreamDriveThruFilter::~CStreamDriveThruFilter()
00092 {
00093         CAutoLock csAutoLock(&m_csLock);
00094 
00095         CAMThread::CallWorker(CMD_EXIT);
00096         CAMThread::Close();
00097 
00098         delete m_pInput;
00099         delete m_pOutput;
00100 }
00101 
00102 STDMETHODIMP CStreamDriveThruFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00103 {
00104         CheckPointer(ppv, E_POINTER);
00105 
00106         return 
00107                 QI(IMediaSeeking)
00108                 __super::NonDelegatingQueryInterface(riid, ppv);
00109 }
00110 
00111 #define PACKETSIZE 65536
00112 
00113 DWORD CStreamDriveThruFilter::ThreadProc()
00114 {
00115         while(1)
00116         {
00117                 DWORD cmd = GetRequest();
00118 
00119                 switch(cmd)
00120                 {
00121                 default:
00122                 case CMD_EXIT: 
00123                         Reply(S_OK);
00124                         return 0;
00125                 case CMD_STOP:
00126                         Reply(S_OK);
00127                         break;
00128                 case CMD_PAUSE:
00129                         Reply(S_OK);
00130                         break;
00131                 case CMD_RUN:
00132                         Reply(S_OK);
00133 
00134                         do
00135                         {
00136                                 CComPtr<IAsyncReader> pAsyncReader;
00137                                 CComPtr<IStream> pStream;
00138 
00139                                 if(!m_pInput || !m_pInput->IsConnected() || FAILED(m_pInput->GetAsyncReader(&pAsyncReader))
00140                                 || !m_pOutput || !m_pOutput->IsConnected() || FAILED(m_pOutput->GetStream(&pStream)))
00141                                         break;
00142 
00143                                 LARGE_INTEGER li = {0};
00144                                 ULARGE_INTEGER uli = {0};
00145 
00146                                 if(FAILED(pStream->Seek(li, STREAM_SEEK_SET, NULL))
00147                                 || FAILED(pStream->SetSize(uli)))
00148                                         break;
00149 
00150                                 if(CComQIPtr<IFileSinkFilter2> pFSF = GetFilterFromPin(m_pOutput->GetConnected()))
00151                                 {
00152                                         pFSF->SetMode(AM_FILE_OVERWRITE);
00153 
00154                                         LPOLESTR pfn;
00155                                         if(SUCCEEDED(pFSF->GetCurFile(&pfn, NULL)))
00156                                         {
00157                                                 pFSF->SetFileName(pfn, NULL);
00158                                                 CoTaskMemFree(pfn);
00159                                         }
00160                                 }
00161 
00162                                 m_position = 0;
00163                                 BYTE buff[PACKETSIZE];
00164 
00165                                 do
00166                                 {
00167                                         while(!CheckRequest(&cmd))
00168                                         {
00169                                                 CAutoLock csAutoLock(&m_csLock);
00170 
00171                                                 LONGLONG total = 0, available = 0;
00172                                                 if(FAILED(pAsyncReader->Length(&total, &available)) || m_position >= total)
00173                                                 {
00174                                                         cmd = CMD_STOP;
00175                                                         break;
00176                                                 }
00177 
00178                                                 LONG size = (LONG)min(PACKETSIZE, total - m_position);
00179                                                 if(FAILED(pAsyncReader->SyncRead(m_position, size, buff)))
00180                                                 {
00181                                                         cmd = CMD_STOP;
00182                                                         break;
00183                                                 }
00184 
00185                                                 ULONG written = 0;
00186                                                 if(FAILED(pStream->Write(buff, (ULONG)size, &written)) || (ULONG)size != written)
00187                                                 {
00188                                                         cmd = CMD_STOP;
00189                                                         break;
00190                                                 }
00191 
00192                                                 m_position += size;
00193                                         }
00194 
00195                                         if(cmd == CMD_PAUSE)
00196                                         {
00197                                                 Reply(S_OK); // reply to CMD_PAUSE
00198 
00199                                                 while(!CheckRequest(&cmd))
00200                                                         Sleep(50);
00201 
00202                                                 Reply(S_OK); // reply to something
00203                                         }
00204                                 }
00205                                 while(cmd == CMD_RUN);
00206 
00207                                 uli.QuadPart = m_position;
00208                                 pStream->SetSize(uli);
00209 
00210                                 if(CComPtr<IPin> pPin = m_pOutput->GetConnected())
00211                                         pPin->EndOfStream();
00212                         }
00213                         while(false);
00214 
00215                         break;
00216                 }
00217         }
00218 
00219         return 0;
00220 }
00221 
00222 int CStreamDriveThruFilter::GetPinCount()
00223 {
00224         return 2;
00225 }
00226 
00227 CBasePin* CStreamDriveThruFilter::GetPin(int n)
00228 {
00229     CAutoLock csAutoLock(&m_csLock);
00230 
00231         if(n == 0) return m_pInput;
00232         else if(n == 1) return m_pOutput;
00233 
00234     return NULL;
00235 }
00236 
00237 STDMETHODIMP CStreamDriveThruFilter::Stop()
00238 {
00239         HRESULT hr;
00240         
00241         if(FAILED(hr = __super::Stop()))
00242                 return hr;
00243 
00244         CallWorker(CMD_STOP);
00245 
00246         return S_OK;
00247 }
00248 
00249 STDMETHODIMP CStreamDriveThruFilter::Pause()
00250 {
00251         HRESULT hr;
00252         
00253         if(FAILED(hr = __super::Pause()))
00254                 return hr;
00255 
00256         CallWorker(CMD_PAUSE);
00257 
00258         return S_OK;
00259 }
00260 
00261 STDMETHODIMP CStreamDriveThruFilter::Run(REFERENCE_TIME tStart)
00262 {
00263         HRESULT hr;
00264         
00265         if(FAILED(hr = __super::Run(tStart)))
00266                 return hr;
00267 
00268         CallWorker(CMD_RUN);
00269 
00270         return S_OK;
00271 }
00272 
00273 // IMediaSeeking
00274 
00275 STDMETHODIMP CStreamDriveThruFilter::GetCapabilities(DWORD* pCapabilities)
00276 {
00277         return pCapabilities ? *pCapabilities = AM_SEEKING_CanGetCurrentPos|AM_SEEKING_CanGetStopPos|AM_SEEKING_CanGetDuration, S_OK : E_POINTER;
00278 }
00279 STDMETHODIMP CStreamDriveThruFilter::CheckCapabilities(DWORD* pCapabilities)
00280 {
00281         CheckPointer(pCapabilities, E_POINTER);
00282 
00283         if(*pCapabilities == 0) return S_OK;
00284 
00285         DWORD caps;
00286         GetCapabilities(&caps);
00287 
00288         DWORD caps2 = caps & *pCapabilities;
00289 
00290         return caps2 == 0 ? E_FAIL : caps2 == *pCapabilities ? S_OK : S_FALSE;
00291 }
00292 STDMETHODIMP CStreamDriveThruFilter::IsFormatSupported(const GUID* pFormat)
00293 {
00294         return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
00295 }
00296 STDMETHODIMP CStreamDriveThruFilter::QueryPreferredFormat(GUID* pFormat)
00297 {
00298         return GetTimeFormat(pFormat);
00299 }
00300 STDMETHODIMP CStreamDriveThruFilter::GetTimeFormat(GUID* pFormat)
00301 {
00302         return pFormat ? *pFormat = TIME_FORMAT_MEDIA_TIME, S_OK : E_POINTER;
00303 }
00304 STDMETHODIMP CStreamDriveThruFilter::IsUsingTimeFormat(const GUID* pFormat)
00305 {
00306         return IsFormatSupported(pFormat);
00307 }
00308 STDMETHODIMP CStreamDriveThruFilter::SetTimeFormat(const GUID* pFormat)
00309 {
00310         return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG;
00311 }
00312 STDMETHODIMP CStreamDriveThruFilter::GetDuration(LONGLONG* pDuration)
00313 {
00314         CheckPointer(pDuration, E_POINTER);
00315         CheckPointer(m_pInput, VFW_E_NOT_CONNECTED);
00316 
00317         if(CComQIPtr<IAsyncReader> pAsyncReader = m_pInput->GetConnected())
00318         {
00319                 LONGLONG total, available;
00320                 if(SUCCEEDED(pAsyncReader->Length(&total, &available)))
00321                 {
00322                         *pDuration = total;
00323                         return S_OK;
00324                 }
00325         }
00326 
00327         return E_NOINTERFACE;
00328 }
00329 STDMETHODIMP CStreamDriveThruFilter::GetStopPosition(LONGLONG* pStop)
00330 {
00331         return GetDuration(pStop);
00332 }
00333 STDMETHODIMP CStreamDriveThruFilter::GetCurrentPosition(LONGLONG* pCurrent)
00334 {
00335         return pCurrent ? *pCurrent = m_position, S_OK : E_POINTER;
00336 }
00337 STDMETHODIMP CStreamDriveThruFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) {return E_NOTIMPL;}
00338 STDMETHODIMP CStreamDriveThruFilter::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags) {return E_NOTIMPL;}
00339 STDMETHODIMP CStreamDriveThruFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop) {return E_NOTIMPL;}
00340 STDMETHODIMP CStreamDriveThruFilter::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest) {return E_NOTIMPL;}
00341 STDMETHODIMP CStreamDriveThruFilter::SetRate(double dRate) {return E_NOTIMPL;}
00342 STDMETHODIMP CStreamDriveThruFilter::GetRate(double* pdRate) {return E_NOTIMPL;}
00343 STDMETHODIMP CStreamDriveThruFilter::GetPreroll(LONGLONG* pllPreroll)
00344 {
00345         return pllPreroll ? *pllPreroll = 0, S_OK : E_POINTER;
00346 }
00347 
00348 //
00349 // CStreamDriveThruInputPin
00350 //
00351 
00352 CStreamDriveThruInputPin::CStreamDriveThruInputPin(TCHAR* pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
00353         : CBasePin(pName, pFilter, pLock, phr, L"Input", PINDIR_INPUT)
00354 {
00355 }
00356 
00357 CStreamDriveThruInputPin::~CStreamDriveThruInputPin()
00358 {
00359 }
00360 
00361 HRESULT CStreamDriveThruInputPin::GetAsyncReader(IAsyncReader** ppAsyncReader)
00362 {
00363         CheckPointer(ppAsyncReader, E_POINTER);
00364 
00365         *ppAsyncReader = NULL;
00366 
00367         CheckPointer(m_pAsyncReader, VFW_E_NOT_CONNECTED);
00368 
00369         (*ppAsyncReader = m_pAsyncReader)->AddRef();
00370 
00371         return S_OK;
00372 }
00373 
00374 STDMETHODIMP CStreamDriveThruInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00375 {
00376         CheckPointer(ppv, E_POINTER);
00377 
00378         return 
00379                 __super::NonDelegatingQueryInterface(riid, ppv);
00380 }
00381 
00382 HRESULT CStreamDriveThruInputPin::CheckMediaType(const CMediaType* pmt)
00383 {
00384         return pmt->majortype == MEDIATYPE_Stream
00385                 ? S_OK
00386                 : E_INVALIDARG;
00387 }
00388 
00389 HRESULT CStreamDriveThruInputPin::CheckConnect(IPin* pPin)
00390 {
00391         HRESULT hr;
00392 
00393         if(FAILED(hr = __super::CheckConnect(pPin)))
00394                 return hr;
00395 
00396         if(!CComQIPtr<IAsyncReader>(pPin))
00397                 return E_NOINTERFACE;
00398 
00399         return S_OK;
00400 }
00401 
00402 HRESULT CStreamDriveThruInputPin::BreakConnect()
00403 {
00404         HRESULT hr;
00405 
00406         if(FAILED(hr = __super::BreakConnect()))
00407                 return hr;
00408 
00409         m_pAsyncReader.Release();
00410 
00411         return S_OK;
00412 }
00413 
00414 HRESULT CStreamDriveThruInputPin::CompleteConnect(IPin* pPin)
00415 {
00416         HRESULT hr;
00417 
00418         if(FAILED(hr = __super::CompleteConnect(pPin)))
00419                 return hr;
00420 
00421         CheckPointer(pPin, E_POINTER);
00422         m_pAsyncReader = pPin;
00423         CheckPointer(m_pAsyncReader, E_NOINTERFACE);
00424 
00425         return S_OK;
00426 }
00427 
00428 STDMETHODIMP CStreamDriveThruInputPin::BeginFlush()
00429 {
00430         return E_UNEXPECTED;
00431 }
00432 
00433 STDMETHODIMP CStreamDriveThruInputPin::EndFlush()
00434 {
00435         return E_UNEXPECTED;
00436 }
00437 
00438 //
00439 // CStreamDriveThruOutputPin
00440 //
00441 
00442 CStreamDriveThruOutputPin::CStreamDriveThruOutputPin(TCHAR* pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
00443         : CBaseOutputPin(pName, pFilter, pLock, phr, L"Output")
00444 {
00445 }
00446 
00447 CStreamDriveThruOutputPin::~CStreamDriveThruOutputPin()
00448 {
00449 }
00450 
00451 HRESULT CStreamDriveThruOutputPin::GetStream(IStream** ppStream)
00452 {
00453         CheckPointer(ppStream, E_POINTER);
00454 
00455         *ppStream = NULL;
00456 
00457         CheckPointer(m_pStream, VFW_E_NOT_CONNECTED);
00458 
00459         (*ppStream = m_pStream)->AddRef();
00460 
00461         return S_OK;
00462 }
00463 
00464 STDMETHODIMP CStreamDriveThruOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00465 {
00466         CheckPointer(ppv, E_POINTER);
00467 
00468         return 
00469                 __super::NonDelegatingQueryInterface(riid, ppv);
00470 }
00471 
00472 HRESULT CStreamDriveThruOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
00473 {
00474     ASSERT(pAlloc);
00475     ASSERT(pProperties);
00476 
00477     HRESULT hr = NOERROR;
00478 
00479         pProperties->cBuffers = 1;
00480         pProperties->cbBuffer = PACKETSIZE;
00481 
00482     ALLOCATOR_PROPERTIES Actual;
00483     if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) return hr;
00484 
00485     if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL;
00486     ASSERT(Actual.cBuffers == pProperties->cBuffers);
00487 
00488     return NOERROR;
00489 }
00490 
00491 HRESULT CStreamDriveThruOutputPin::CheckMediaType(const CMediaType* pmt)
00492 {
00493         return pmt->majortype == MEDIATYPE_Stream
00494                 ? S_OK
00495                 : E_INVALIDARG;
00496 }
00497 
00498 HRESULT CStreamDriveThruOutputPin::GetMediaType(int iPosition, CMediaType* pmt)
00499 {
00500     CAutoLock cAutoLock(m_pLock);
00501 
00502         if(iPosition < 0) return E_INVALIDARG;
00503         if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
00504 
00505         pmt->majortype = MEDIATYPE_Stream;
00506         pmt->subtype = GUID_NULL;
00507         pmt->formattype = GUID_NULL;
00508         pmt->SetSampleSize(PACKETSIZE);
00509 
00510         return S_OK;
00511 }
00512 
00513 HRESULT CStreamDriveThruOutputPin::CheckConnect(IPin* pPin)
00514 {
00515         HRESULT hr;
00516 
00517         if(FAILED(hr = __super::CheckConnect(pPin)))
00518                 return hr;
00519 
00520         if(!CComQIPtr<IStream>(pPin))
00521                 return E_NOINTERFACE;
00522 
00523         return S_OK;
00524 }
00525 
00526 HRESULT CStreamDriveThruOutputPin::BreakConnect()
00527 {
00528         HRESULT hr;
00529 
00530         if(FAILED(hr = __super::BreakConnect()))
00531                 return hr;
00532 
00533         m_pStream.Release();
00534 
00535         return S_OK;
00536 }
00537 
00538 HRESULT CStreamDriveThruOutputPin::CompleteConnect(IPin* pPin)
00539 {
00540         HRESULT hr;
00541 
00542         if(FAILED(hr = __super::CompleteConnect(pPin)))
00543                 return hr;
00544 
00545         CheckPointer(pPin, E_POINTER);
00546         m_pStream = pPin;
00547         CheckPointer(m_pStream, E_NOINTERFACE);
00548 
00549         return S_OK;
00550 }
00551 
00552 STDMETHODIMP CStreamDriveThruOutputPin::BeginFlush()
00553 {
00554         return E_UNEXPECTED;
00555 }
00556 
00557 STDMETHODIMP CStreamDriveThruOutputPin::EndFlush()
00558 {
00559         return E_UNEXPECTED;
00560 }
00561 
00562 STDMETHODIMP CStreamDriveThruOutputPin::Notify(IBaseFilter* pSender, Quality q)
00563 {
00564         return E_NOTIMPL;
00565 }

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