00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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);
00071 }
00072
00073 #endif
00074
00075
00076
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);
00198
00199 while(!CheckRequest(&cmd))
00200 Sleep(50);
00201
00202 Reply(S_OK);
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
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
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
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 }