- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# 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 }