asyncrdr.cpp

00001 //------------------------------------------------------------------------------
00002 // File: AsyncRdr.cpp
00003 //
00004 // Desc: DirectShow sample code - base library with I/O functionality.
00005 //       This file implements I/O source filter methods and output pin 
00006 //       methods for CAsyncReader and CAsyncOutputPin.
00007 //
00008 // Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
00009 //------------------------------------------------------------------------------
00010 
00011 
00012 #include "stdafx.h"
00013 #include "asyncio.h"
00014 #include "asyncrdr.h"
00015 
00016 // --- CAsyncOutputPin implementation ---
00017 
00018 CAsyncOutputPin::CAsyncOutputPin(
00019     HRESULT * phr,
00020     CAsyncReader *pReader,
00021     CAsyncIo *pIo,
00022     CCritSec * pLock)
00023   : CBasePin(
00024         NAME("Async output pin"),
00025         pReader,
00026         pLock,
00027         phr,
00028         L"Output",
00029         PINDIR_OUTPUT),
00030     m_pReader(pReader),
00031     m_pIo(pIo)
00032 {
00033 }
00034 
00035 CAsyncOutputPin::~CAsyncOutputPin()
00036 {
00037 }
00038 
00039 STDMETHODIMP
00040 CAsyncOutputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00041 {
00042     CheckPointer(ppv,E_POINTER);
00043 
00044     if (riid == IID_IAsyncReader) {
00045         m_bQueriedForAsyncReader = TRUE;
00046         return GetInterface((IAsyncReader*) this, ppv);
00047     } else {
00048         return CBasePin::NonDelegatingQueryInterface(riid, ppv);
00049     }
00050 }
00051 
00052 HRESULT
00053 CAsyncOutputPin::GetMediaType(int iPosition, CMediaType *pMediaType)
00054 {
00055     if (iPosition < 0) {
00056         return E_INVALIDARG;
00057     }
00058     if (iPosition > 0) {
00059         return VFW_S_NO_MORE_ITEMS;
00060     }
00061 
00062     *pMediaType = *m_pReader->LoadType();
00063     return S_OK;
00064 }
00065 
00066 HRESULT
00067 CAsyncOutputPin::CheckMediaType(const CMediaType* pType)
00068 {
00069     CAutoLock lck(m_pLock);
00070 
00071     /*  We treat MEDIASUBTYPE_NULL subtype as a wild card */
00072     if ((m_pReader->LoadType()->majortype == pType->majortype) &&
00073         (m_pReader->LoadType()->subtype == MEDIASUBTYPE_NULL ||
00074          m_pReader->LoadType()->subtype == pType->subtype)) {
00075             return S_OK;
00076     }
00077     return S_FALSE;
00078 }
00079 
00080 HRESULT
00081 CAsyncOutputPin::InitAllocator(IMemAllocator **ppAlloc)
00082 {
00083     HRESULT hr = NOERROR;
00084     *ppAlloc = NULL;
00085     CMemAllocator *pMemObject = NULL;
00086 
00087     /* Create a default memory allocator */
00088     pMemObject = new CMemAllocator(NAME("Base memory allocator"),NULL, &hr);
00089     if (pMemObject == NULL) {
00090         return E_OUTOFMEMORY;
00091     }
00092 
00093     if (FAILED(hr)) {
00094             delete pMemObject;
00095             return hr;
00096     }
00097 
00098     /* Get a reference counted IID_IMemAllocator interface */
00099     hr = pMemObject->QueryInterface(IID_IMemAllocator,(void **)ppAlloc);
00100     if (FAILED(hr)) {
00101             delete pMemObject;
00102             return E_NOINTERFACE;
00103     }
00104 
00105     ASSERT(*ppAlloc != NULL);
00106     return NOERROR;
00107 }
00108 
00109 // we need to return an addrefed allocator, even if it is the preferred
00110 // one, since he doesn't know whether it is the preferred one or not.
00111 STDMETHODIMP
00112 CAsyncOutputPin::RequestAllocator(
00113     IMemAllocator* pPreferred,
00114     ALLOCATOR_PROPERTIES* pProps,
00115     IMemAllocator ** ppActual)
00116 {
00117     // we care about alignment but nothing else
00118     if (!pProps->cbAlign || !m_pIo->IsAligned(pProps->cbAlign)) {
00119        m_pIo->Alignment(&pProps->cbAlign);
00120     }
00121 
00122     ALLOCATOR_PROPERTIES Actual;
00123     HRESULT hr;
00124 
00125     if (pPreferred) {
00126             hr = pPreferred->SetProperties(pProps, &Actual);
00127             if (SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) {
00128             pPreferred->AddRef();
00129             *ppActual = pPreferred;
00130             return S_OK;
00131         }
00132     }
00133 
00134     // create our own allocator
00135     IMemAllocator* pAlloc;
00136     hr = InitAllocator(&pAlloc);
00137     if (FAILED(hr)) {
00138         return hr;
00139     }
00140 
00141     //...and see if we can make it suitable
00142     hr = pAlloc->SetProperties(pProps, &Actual);
00143     if (SUCCEEDED(hr) && m_pIo->IsAligned(Actual.cbAlign)) {
00144         // we need to release our refcount on pAlloc, and addref
00145         // it to pass a refcount to the caller - this is a net nothing.
00146         *ppActual = pAlloc;
00147         return S_OK;
00148     }
00149 
00150     // failed to find a suitable allocator
00151     pAlloc->Release();
00152 
00153     // if we failed because of the IsAligned test, the error code will
00154     // not be failure
00155     if (SUCCEEDED(hr)) {
00156         hr = VFW_E_BADALIGN;
00157     }
00158     return hr;
00159 }
00160 
00161 
00162 // queue an aligned read request. call WaitForNext to get
00163 // completion.
00164 STDMETHODIMP
00165 CAsyncOutputPin::Request(
00166     IMediaSample* pSample,
00167     DWORD dwUser)               // user context
00168 {
00169     REFERENCE_TIME tStart, tStop;
00170     HRESULT hr = pSample->GetTime(&tStart, &tStop);
00171     if (FAILED(hr)) {
00172         return hr;
00173     }
00174 
00175     LONGLONG llPos = tStart / UNITS;
00176     LONG lLength = (LONG) ((tStop - tStart) / UNITS);
00177     LONGLONG llTotal;
00178     LONGLONG llAvailable;
00179 
00180     hr = m_pIo->Length(&llTotal, &llAvailable);
00181     if (llPos + lLength > llTotal) {
00182 
00183         // the end needs to be aligned, but may have been aligned
00184         // on a coarser alignment.
00185         LONG lAlign;
00186         m_pIo->Alignment(&lAlign);
00187         llTotal = (llTotal + lAlign -1) & ~(lAlign-1);
00188 
00189         if (llPos + lLength > llTotal) {
00190             lLength = (LONG) (llTotal - llPos);
00191 
00192             // must be reducing this!
00193             ASSERT((llTotal * UNITS) <= tStop);
00194             tStop = llTotal * UNITS;
00195             pSample->SetTime(&tStart, &tStop);
00196         }
00197     }
00198 
00199 
00200     BYTE* pBuffer;
00201     hr = pSample->GetPointer(&pBuffer);
00202     if (FAILED(hr)) {
00203         return hr;
00204     }
00205 
00206     return m_pIo->Request(
00207                         llPos,
00208                         lLength,
00209             TRUE,
00210                         pBuffer,
00211                         (LPVOID)pSample,
00212                         dwUser);
00213 }
00214 
00215 // sync-aligned request. just like a request/waitfornext pair.
00216 STDMETHODIMP
00217 CAsyncOutputPin::SyncReadAligned(
00218                   IMediaSample* pSample)
00219 {
00220     REFERENCE_TIME tStart, tStop;
00221     HRESULT hr = pSample->GetTime(&tStart, &tStop);
00222     if (FAILED(hr)) {
00223         return hr;
00224     }
00225 
00226     LONGLONG llPos = tStart / UNITS;
00227     LONG lLength = (LONG) ((tStop - tStart) / UNITS);
00228     LONGLONG llTotal;
00229     LONGLONG llAvailable;
00230 
00231     hr = m_pIo->Length(&llTotal, &llAvailable);
00232     if (llPos + lLength > llTotal) {
00233 
00234         // the end needs to be aligned, but may have been aligned
00235         // on a coarser alignment.
00236         LONG lAlign;
00237         m_pIo->Alignment(&lAlign);
00238         llTotal = (llTotal + lAlign -1) & ~(lAlign-1);
00239 
00240         if (llPos + lLength > llTotal) {
00241             lLength = (LONG) (llTotal - llPos);
00242 
00243             // must be reducing this!
00244             ASSERT((llTotal * UNITS) <= tStop);
00245             tStop = llTotal * UNITS;
00246             pSample->SetTime(&tStart, &tStop);
00247         }
00248     }
00249 
00250 
00251     BYTE* pBuffer;
00252     hr = pSample->GetPointer(&pBuffer);
00253     if (FAILED(hr)) {
00254         return hr;
00255     }
00256 
00257     LONG cbActual;
00258     hr = m_pIo->SyncReadAligned(
00259                         llPos,
00260                         lLength,
00261                         pBuffer,
00262             &cbActual,
00263             pSample
00264             );
00265 
00266     pSample->SetActualDataLength(cbActual);
00267     return hr;
00268 }
00269 
00270 
00271 //
00272 // collect the next ready sample
00273 STDMETHODIMP
00274 CAsyncOutputPin::WaitForNext(
00275     DWORD dwTimeout,
00276     IMediaSample** ppSample,  // completed sample
00277     DWORD * pdwUser)            // user context
00278 {
00279     LONG cbActual;
00280     IMediaSample* pSample;
00281 
00282     HRESULT hr =  m_pIo->WaitForNext(
00283                             dwTimeout,
00284                             (LPVOID*) &pSample,
00285                             pdwUser,
00286                 &cbActual
00287                 );
00288 
00289     if (SUCCEEDED(hr)) {
00290         pSample->SetActualDataLength(cbActual);
00291     }
00292 
00293     *ppSample = pSample;
00294     return hr;
00295 }
00296 
00297 
00298 //
00299 // synchronous read that need not be aligned.
00300 STDMETHODIMP
00301 CAsyncOutputPin::SyncRead(
00302     LONGLONG llPosition,        // absolute Io position
00303     LONG lLength,               // nr bytes required
00304     BYTE* pBuffer)              // write data here
00305 {
00306     return m_pIo->SyncRead(llPosition, lLength, pBuffer);
00307 }
00308 
00309 // return the length of the file, and the length currently
00310 // available locally. We only support locally accessible files,
00311 // so they are always the same
00312 STDMETHODIMP
00313 CAsyncOutputPin::Length(
00314     LONGLONG* pTotal,
00315     LONGLONG* pAvailable)
00316 {
00317     HRESULT hr = m_pIo->Length(pTotal, pAvailable);
00318     return hr;
00319 }
00320 
00321 STDMETHODIMP
00322 CAsyncOutputPin::BeginFlush(void)
00323 {
00324     return m_pIo->BeginFlush();
00325 }
00326 
00327 STDMETHODIMP
00328 CAsyncOutputPin::EndFlush(void)
00329 {
00330     return m_pIo->EndFlush();
00331 }
00332 
00333 
00334 STDMETHODIMP
00335 CAsyncOutputPin::Connect(
00336     IPin * pReceivePin,
00337     const AM_MEDIA_TYPE *pmt   // optional media type
00338 )
00339 {
00340     return m_pReader->Connect(pReceivePin, pmt);
00341 }
00342 
00343 
00344 // --- CAsyncReader implementation ---
00345 
00346 #pragma warning(disable:4355)
00347 
00348 CAsyncReader::CAsyncReader(
00349     TCHAR *pName,
00350     LPUNKNOWN pUnk,
00351     CAsyncStream *pStream,
00352     HRESULT *phr,
00353         const CLSID& clsid)
00354   : CBaseFilter(
00355         pName,
00356             pUnk,
00357             &m_csFilter,
00358             clsid,
00359         NULL
00360         ),
00361     m_OutputPin(
00362         phr,
00363         this,
00364         &m_Io,
00365         &m_csFilter),
00366     m_Io(pStream)
00367 {
00368 }
00369 
00370 CAsyncReader::~CAsyncReader()
00371 {
00372 }
00373 
00374 STDMETHODIMP CAsyncReader::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00375 {
00376     CheckPointer(ppv, E_POINTER);
00377 
00378         return 
00379                 (riid == __uuidof(IAMFilterMiscFlags)) ? GetInterface((IAMFilterMiscFlags*)this, ppv) :
00380                 __super::NonDelegatingQueryInterface(riid, ppv);
00381 }
00382 
00383 // IAMFilterMiscFlags
00384 
00385 ULONG CAsyncReader::GetMiscFlags()
00386 {
00387         return AM_FILTER_MISC_FLAGS_IS_SOURCE;
00388 }
00389 
00390 
00391 int
00392 CAsyncReader::GetPinCount()
00393 {
00394     return 1;
00395 }
00396 
00397 CBasePin *
00398 CAsyncReader::GetPin(int n)
00399 {
00400     if ((GetPinCount() > 0) && (n == 0)) {
00401         return &m_OutputPin;
00402     } else {
00403         return NULL;
00404     }
00405 }
00406 
00407 

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