//------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // The use and distribution terms for this software are covered by the // Microsoft Limited Public License (Ms-LPL) // which can be found in the file MS-LPL.txt at the root of this distribution. // By using this software in any fashion, you are agreeing to be bound by // the terms of this license. // // The software is licensed “as-is.” // // You must not remove this notice, or any other, from this software. // // // // Demux code for Windows CE // //------------------------------------------------------------------------- //====================================================================== // Demux code for Windows CE //====================================================================== #include "precomp.h" #include // for ksmedia.h #include // for bdamedia.h #include // for KSDATAFORMAT_TYPE_MPEG2_SECTIONS #include "mp2demux.h" #include "tsstats.h" #include "mp2seek.h" #include "pin_out.h" #include "bufsrc.h" // --------------------------------------------------------------------------- // CMediaSampleCopyBuffer // --------------------------------------------------------------------------- CMediaSampleCopyBuffer::CMediaSampleCopyBuffer ( IN CMPEG2DemuxOutputPin * pPin, IN BOOL fReportDiscontinuities, IN BOOL fSetSyncPoints, IN CRefCountedCritSec * pMapperLock, IN HKEY hkeyRoot, // don't copy and use beyond constructor IN DWORD dwPIDTag, IN CMpeg2Stats * pStats ) : CBufferSource (TRUE, // copy pStats, TRUE), // report stats m_pOutputPin (pPin), m_fReportDiscontinuities (fReportDiscontinuities), m_fSetSyncPoints (fSetSyncPoints), m_dwPIDTag (dwPIDTag), m_fTagPID (FALSE), m_pMapperLock (pMapperLock) { CMediaType mt ; TRACE_ENTER_1 (TEXT ("CMediaSampleCopyBuffer::CMediaSampleCopyBuffer (%08xh)"), pPin) ; TRACE_CONSTRUCTOR (TEXT ("CMediaSampleCopyBuffer")) ; ASSERT (m_pOutputPin) ; ASSERT (hkeyRoot) ; ASSERT (m_pMapperLock) ; m_pMapperLock -> AddRef () ; ASSERT (m_pOutputPin) ; m_pOutputPin -> AddRef () ; // if the pin's media type is MEDIATYPE_MPEG2_PSI, we'll need to tag // all the media samples with the PID ZeroMemory (& mt, sizeof mt) ; if (SUCCEEDED (m_pOutputPin -> GetMediaType (0, & mt))) { // tag the media samples with the PID if it's PSI m_fTagPID = (mt.majortype == KSDATAFORMAT_TYPE_MPEG2_SECTIONS ? TRUE : FALSE) ; } } CMediaSampleCopyBuffer::~CMediaSampleCopyBuffer ( ) { TRACE_ENTER_0 (TEXT ("CMediaSampleCopyBuffer::~CMediaSampleCopyBuffer ()")) ; TRACE_DESTRUCTOR (TEXT ("CMediaSampleCopyBuffer")) ; m_pMapperLock -> Release () ; ASSERT (m_pOutputPin) ; m_pOutputPin -> Release () ; } HRESULT CMediaSampleCopyBuffer::GetCopyBuffer ( OUT DWORD_PTR * pdwContext, OUT BYTE ** ppbBuffer, IN OUT int * piBufferLength ) { HRESULT hr ; IMediaSample * pIMediaSample ; AM_SAMPLE2_PROPERTIES Prop2 ; IMediaSample2 * pIMediaSample2 ; ASSERT (pdwContext) ; ASSERT (ppbBuffer) ; ASSERT (piBufferLength) ; TRACE_ENTER_3 (TEXT ("CMediaSampleCopyBuffer::GetCopyBuffer (%08xh, %08xh, %08xh)"), pdwContext, ppbBuffer, * piBufferLength) ; if (m_pOutputPin -> m_pAllocator == NULL) { TRACE_0 (LOG_DEMUX_MEDIA_SAMPLES, 3, TEXT ("CMediaSampleCopyBuffer::GetCopyBuffer () : failed because there is no allocator")) ; TRACE_ERROR_0 (TEXT ("CMediaSampleCopyBuffer::GetCopyBuffer () : failed because there is no allocator")) ; return E_FAIL ; } hr = m_pOutputPin -> m_pAllocator -> GetBuffer ( & pIMediaSample, NULL, NULL, FALSE // XXXX: need to set this correctly ) ; NE_SPEW (hr, S_OK, TEXT ("CMediaSampleCopyBuffer::GetCopyBuffer () : m_pAllocator -> GetBuffer () call failed")) ; if (SUCCEEDED (hr)) { // if a PID was specified, we put it in all the media samples' AM_SAMPLE2_PROPERTIES.dwTypeSpecificFlags if (m_fTagPID) { hr = pIMediaSample -> QueryInterface (IID_IMediaSample2, (void **) & pIMediaSample2) ; if (FAILED (hr)) { TRACE_ERROR_1 (TEXT ("CMediaSampleCopyBuffer::GetCopyBuffer () : QI for IMediaSample2 failed"), hr) ; pIMediaSample -> Release () ; return hr ; } hr = pIMediaSample2 -> GetProperties ( sizeof Prop2, (BYTE *) & Prop2 ) ; NE_SPEW (hr, S_OK, TEXT ("CMediaSampleCopyBuffer::GetCopyBuffer () : GetProperties () call failed")) ; if (SUCCEEDED (hr)) { ASSERT (VALID_PID (m_dwPIDTag)) ; // don't overwrite any dwTypeSpecificFlags that may already exist Prop2.dwTypeSpecificFlags = (Prop2.dwTypeSpecificFlags & 0xffffe) | (m_dwPIDTag & 0x1fff) ; hr = pIMediaSample2 -> SetProperties ( sizeof Prop2, (BYTE *) & Prop2 ) ; } pIMediaSample2 -> Release () ; if (FAILED (hr)) { TRACE_ERROR_1 (TEXT ("CMediaSampleCopyBuffer::GetCopyBuffer () : failed to Get/Set properties; hr = %08xh"), hr) ; pIMediaSample -> Release () ; return hr ; } TRACE_1 (LOG_DEMUX_MEDIA_SAMPLES, 4, TEXT ("CMediaSampleCopyBuffer::GetCopyBuffer () : tagged with PID %04xh"), m_dwPIDTag) ; } // all has succeeded; set the object's properties * pdwContext = (DWORD_PTR) pIMediaSample ; // context pIMediaSample -> GetPointer (ppbBuffer) ; // actual pointer ASSERT (ppbBuffer) ; * piBufferLength = pIMediaSample -> GetSize () ; // size TRACE_1 (LOG_DEMUX_MEDIA_SAMPLES, 4, TEXT ("CMediaSampleCopyBuffer::GetCopyBuffer () : buffer obtained successfully; %u bytes"), * piBufferLength) ; } return hr ; } HRESULT CMediaSampleCopyBuffer::CompleteCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN REFERENCE_TIME * pStartTime, // media sample start IN REFERENCE_TIME * pStopTime, // media sample stop IN CTStickyVal * pReset ) { HRESULT hr ; IMediaSample * pIMediaSample ; TRACE_ENTER_3 (TEXT ("CMediaSampleCopyBuffer::CompleteCopyBuffer (%08xh, %08xh, %08xh)"), dwContext, pbBuffer, iBufferLength) ; ASSERT (m_pOutputPin) ; ASSERT (dwContext) ; ASSERT (pbBuffer) ; pIMediaSample = reinterpret_cast (dwContext) ; ASSERT (pIMediaSample) ; hr = pIMediaSample -> SetActualDataLength (iBufferLength) ; if (SUCCEEDED (hr)) { // and set the start/stop time if (pStartTime && pStopTime) { hr = pIMediaSample -> SetTime (pStartTime, pStopTime) ; if (SUCCEEDED (hr)) { pIMediaSample -> SetSyncPoint (m_fSetSyncPoints) ; m_pStats -> Global_SyncPoint (m_fSetSyncPoints) ; } else { goto cleanup ; } } // m_fReportDiscontinuity is configurable because some decoders don't handle // discontinuities well; m_fReportDiscontinuities is a setting that can set // via registry setting pIMediaSample -> SetDiscontinuity (fDiscontinuity && m_fReportDiscontinuities) ; TRACE_1 (LOG_DEMUX_MEDIA_SAMPLES, 4, TEXT ("CMediaSampleCopyBuffer::CompleteCopyBuffer () - fDiscontinuity = %s"), fDiscontinuity ? TEXT ("TRUE") : TEXT ("FALSE")) ; // it's possible while we relinquish the lock that the parser gets // flushed and releases its ref on the lock; consequently, we // ref it locally before aquiring the lock & release when we are // done with it pIMediaSample -> AddRef () ; m_pMapperLock -> Unlock () ; hr = m_pOutputPin -> SendSample (pIMediaSample) ; // send pIMediaSample -> Release () ; // we are done m_pMapperLock -> Lock () ; TRACE_2 (LOG_DEMUX_MEDIA_SAMPLES, 2, TEXT("Media Sample delivered to output pin; %08xh, %u bytes"), pIMediaSample, pIMediaSample -> GetActualDataLength ()) ; } cleanup : return hr ; } HRESULT CMediaSampleCopyBuffer::ReleaseCopyBuffer ( IN DWORD_PTR dwContext, IN BYTE * pbBuffer, IN int iBufferLength ) { TRACE_ENTER_3 (TEXT ("CMediaSampleCopyBuffer::ReleaseCopyBuffer (%08xh, %08xh, %08xh)"), dwContext, pbBuffer, iBufferLength) ; if (dwContext) { ((IMediaSample *) (dwContext)) -> Release () ; } return S_OK ; } // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // CMediaSampleWrapper // --------------------------------------------------------------------------- CMediaSampleWrapper::CMediaSampleWrapper ( IN CMediaSampleWrapperPool * pMSPool ) : m_pMSPool (pMSPool), m_lRef (1), m_pCoreIMediaSample (NULL), m_dwFlags (0), m_dwTypeSpecificFlags (0), m_pbPayload (NULL), m_lActual (0), m_rtStart (0), m_rtEnd (0), m_llMediaStart (0), m_llMediaEnd (0), m_pMediaType (NULL), m_dwStreamId (0) { ASSERT (m_pMSPool) ; } CMediaSampleWrapper::~CMediaSampleWrapper ( ) { ASSERT (m_pMediaType == NULL) ; } HRESULT CMediaSampleWrapper::GetMSProperties ( IN IMediaSample * pIMS, OUT LONGLONG * pllMediaStart, OUT LONGLONG * pllMediaEnd, OUT REFERENCE_TIME * prtStart, OUT REFERENCE_TIME * prtEnd, OUT DWORD * pdwFlags ) { AM_MEDIA_TYPE * pmt ; HRESULT hr ; ASSERT (pIMS) ; ASSERT (pdwFlags) ; // reset * pdwFlags = 0 ; // -------------------------------------------------------------------- // what we don't support // BUGBUG // in-band format changes -- when do they apply ?? pmt = NULL ; hr = pIMS -> GetMediaType (& pmt) ; if (hr != S_FALSE) { ASSERT (pmt) ; DeleteMediaType (pmt) ; return E_FAIL ; } // -------------------------------------------------------------------- // what we do support // flip the bits for the toggle properties (* pdwFlags) |= (pIMS -> IsSyncPoint () == S_OK ? SAMPLE_SYNCPOINT : 0) ; (* pdwFlags) |= (pIMS -> IsPreroll () == S_OK ? SAMPLE_PREROLL : 0) ; (* pdwFlags) |= (pIMS -> IsDiscontinuity () == S_OK ? SAMPLE_DISCONTINUITY : 0) ; // BUGBUG // media times .. how do we timeshift these .. ? hr = pIMS -> GetMediaTime (pllMediaStart, pllMediaEnd) ; if (hr == NOERROR) { (* pdwFlags) |= SAMPLE_MEDIATIMEVALID ; } // presentation times; these will be skewed on the way out hr = pIMS -> GetTime (prtStart, prtEnd) ; if (hr != VFW_E_SAMPLE_TIME_NOT_SET) { (* pdwFlags) |= (SAMPLE_TIMEVALID | (hr == NOERROR ? SAMPLE_STOPVALID : 0)) ; } return S_OK ; } // ------------------------------------------------------------------- // init void CMediaSampleWrapper::ResetMS_ ( ) { // the flags m_dwFlags = 0x00000000 ; // the media type, if it is set if (m_pMediaType != NULL) { DeleteMediaType (m_pMediaType) ; m_pMediaType = NULL ; } } HRESULT CMediaSampleWrapper::Init ( IN IMediaSample * pIMS, IN BYTE * pbPayload, IN int iPayloadLength ) { ASSERT (pIMS) ; ASSERT (m_pCoreIMediaSample == NULL) ; m_pCoreIMediaSample = pIMS ; m_pCoreIMediaSample -> AddRef () ; m_pbPayload = pbPayload ; m_lActual = iPayloadLength ; return S_OK ; } // ------------------------------------------------------------------- // IUnknown methods STDMETHODIMP CMediaSampleWrapper::QueryInterface ( IN REFIID riid, OUT void ** ppv ) { if (ppv == NULL) { return E_INVALIDARG ; } if (riid == IID_IUnknown || riid == IID_IMediaSample || riid == IID_IMediaSample2) { * ppv = reinterpret_cast (this) ; } else { return E_NOINTERFACE ; } (reinterpret_cast (* ppv)) -> AddRef () ; return S_OK ; } STDMETHODIMP_(ULONG) CMediaSampleWrapper::AddRef ( ) { return InterlockedIncrement (& m_lRef) ; } STDMETHODIMP_(ULONG) CMediaSampleWrapper::Release ( ) { LONG lRef ; lRef = InterlockedDecrement (& m_lRef) ; if (lRef == 0) { delete this ; return 0 ; } else if (lRef == 1) { ASSERT (m_pCoreIMediaSample != NULL) ; m_pCoreIMediaSample -> Release () ; m_pCoreIMediaSample = NULL ; ResetMS_ () ; m_pMSPool -> RecycleMS (this) ; return 0 ; } return lRef ; } // ------------------------------------------------------------------- // IMediaSample // get me a read/write pointer to this buffer's memory. I will actually // want to use sizeUsed bytes. STDMETHODIMP CMediaSampleWrapper::GetPointer ( OUT BYTE ** ppBuffer ) { if (ppBuffer == NULL) { return E_POINTER ; } * ppBuffer = m_pbPayload ; return S_OK ; } // return the size in bytes of the buffer data area STDMETHODIMP_(LONG) CMediaSampleWrapper::GetSize ( ) { return m_lActual ; } // get the stream time at which this sample should start and finish. STDMETHODIMP CMediaSampleWrapper::GetTime ( OUT REFERENCE_TIME * pTimeStart, // put time here OUT REFERENCE_TIME * pTimeEnd ) { HRESULT hr ; if ((m_dwFlags & SAMPLE_TIMEVALID) == 0) { return VFW_E_SAMPLE_TIME_NOT_SET ; } if (pTimeStart == NULL || pTimeEnd == NULL) { return E_POINTER ; } // start time is there; maybe stop time * pTimeStart = m_rtStart ; // do we have a stop time ? if ((m_dwFlags & SAMPLE_STOPVALID) != 0) { * pTimeEnd = m_rtEnd ; hr = S_OK ; } else { // apparently this breaks older stuff if we don't do this .. * pTimeEnd = m_rtStart + 1 ; hr = VFW_S_NO_STOP_TIME ; } return hr ; } // Set the stream time at which this sample should start and finish. // pTimeStart==pTimeEnd==NULL will invalidate the time stamps in // this sample STDMETHODIMP CMediaSampleWrapper::SetTime ( IN REFERENCE_TIME * pTimeStart, // put time here IN REFERENCE_TIME * pTimeEnd ) { // caller wishes to explicitely clear the time if (pTimeStart == NULL) { // clear the flags m_dwFlags &= ~(SAMPLE_TIMEVALID | SAMPLE_STOPVALID) ; return S_OK ; } // we have been given a start time m_dwFlags |= SAMPLE_TIMEVALID ; m_rtStart = * pTimeStart ; // do we have a stop time ? if (pTimeEnd != NULL) { m_dwFlags |= SAMPLE_STOPVALID ; m_rtEnd = * pTimeEnd ; } else { // clear the stop time valid flag m_dwFlags &= ~SAMPLE_STOPVALID ; } return S_OK ; } // sync-point property. If true, then the beginning of this // sample is a sync-point. (note that if AM_MEDIA_TYPE.bTemporalCompression // is false then all samples are sync points). A filter can start // a stream at any sync point. S_FALSE if not sync-point, S_OK if true. STDMETHODIMP CMediaSampleWrapper::IsSyncPoint ( ) { return (m_dwFlags & SAMPLE_SYNCPOINT) ? S_OK : S_FALSE ; } STDMETHODIMP CMediaSampleWrapper::SetSyncPoint ( IN BOOL bIsSyncPoint ) { if (bIsSyncPoint) { m_dwFlags |= SAMPLE_SYNCPOINT ; } else { m_dwFlags &= ~SAMPLE_SYNCPOINT ; } return S_OK ; } // preroll property. If true, this sample is for preroll only and // shouldn't be displayed. STDMETHODIMP CMediaSampleWrapper::IsPreroll ( ) { return (m_dwFlags & SAMPLE_PREROLL) ? S_OK : S_FALSE ; } STDMETHODIMP CMediaSampleWrapper::SetPreroll ( BOOL bIsPreroll ) { if (bIsPreroll) { m_dwFlags |= SAMPLE_PREROLL ; } else { m_dwFlags &= ~SAMPLE_PREROLL ; } return S_OK ; } STDMETHODIMP_(LONG) CMediaSampleWrapper::GetActualDataLength ( ) { return m_lActual ; } STDMETHODIMP CMediaSampleWrapper::SetActualDataLength ( IN long lActual ) { if (lActual > m_lActual) { return VFW_E_BUFFER_OVERFLOW ; } m_lActual = lActual ; return S_OK ; } // these allow for limited format changes in band - if no format change // has been made when you receive a sample GetMediaType will return S_FALSE STDMETHODIMP CMediaSampleWrapper::GetMediaType ( AM_MEDIA_TYPE ** ppMediaType ) { if (ppMediaType == NULL) { return E_POINTER ; } if ((m_dwFlags & SAMPLE_TYPECHANGED) == 0) { ASSERT (m_pMediaType == NULL) ; * ppMediaType = NULL ; return S_FALSE ; } ASSERT (m_pMediaType != NULL) ; * ppMediaType = CreateMediaType (m_pMediaType) ; if (* ppMediaType) { return E_OUTOFMEMORY ; } return S_OK ; } STDMETHODIMP CMediaSampleWrapper::SetMediaType ( AM_MEDIA_TYPE * pMediaType ) { if (m_pMediaType != NULL) { DeleteMediaType (m_pMediaType) ; m_pMediaType = NULL ; } // explicitely being cleared if (pMediaType == NULL) { m_dwFlags &= ~SAMPLE_TYPECHANGED ; return S_OK ; } m_pMediaType = CreateMediaType (pMediaType) ; if (m_pMediaType == NULL) { m_dwFlags &= ~SAMPLE_TYPECHANGED ; return E_OUTOFMEMORY ; } m_dwFlags |= SAMPLE_TYPECHANGED ; return S_OK ; } // returns S_OK if there is a discontinuity in the data (this frame is // not a continuation of the previous stream of data // - there has been a seek or some dropped samples). STDMETHODIMP CMediaSampleWrapper::IsDiscontinuity ( ) { return (m_dwFlags & SAMPLE_DISCONTINUITY) ? S_OK : S_FALSE ; } // set the discontinuity property - TRUE if this sample is not a // continuation, but a new sample after a seek or a dropped sample. STDMETHODIMP CMediaSampleWrapper::SetDiscontinuity ( BOOL bDiscontinuity ) { if (bDiscontinuity) { m_dwFlags |= SAMPLE_DISCONTINUITY ; } else { m_dwFlags &= ~SAMPLE_DISCONTINUITY ; } return S_OK ; } // get the media times for this sample STDMETHODIMP CMediaSampleWrapper::GetMediaTime ( OUT LONGLONG * pTimeStart, OUT LONGLONG * pTimeEnd ) { if ((m_dwFlags & SAMPLE_MEDIATIMEVALID) == 0) { return VFW_E_MEDIA_TIME_NOT_SET ; } if (pTimeStart == NULL || pTimeEnd == NULL) { return E_POINTER ; } *pTimeStart = m_llMediaStart ; *pTimeEnd = m_llMediaEnd ; return S_OK ; } // Set the media times for this sample // pTimeStart==pTimeEnd==NULL will invalidate the media time stamps in // this sample STDMETHODIMP CMediaSampleWrapper::SetMediaTime ( IN LONGLONG * pTimeStart, IN LONGLONG * pTimeEnd ) { // caller is explicitely clearing the media time if (pTimeStart == NULL) { // toggle the bit OFF m_dwFlags &= ~SAMPLE_MEDIATIMEVALID ; return S_OK ; } if (pTimeEnd == NULL) { return E_POINTER ; } // toggle the bit ON m_dwFlags |= SAMPLE_MEDIATIMEVALID ; // and save the times m_rtStart = * pTimeStart ; m_rtEnd = * pTimeEnd ; return S_OK ; } // ------------------------------------------------------------------- // IMediaSample methods // Set and get properties (IMediaSample2) STDMETHODIMP CMediaSampleWrapper::GetProperties ( IN DWORD cbProperties, OUT BYTE * pbProperties ) { AM_SAMPLE2_PROPERTIES Props ; HRESULT hr ; hr = S_OK ; if (cbProperties > 0) { if (pbProperties) { Props.cbData = MIN (cbProperties, sizeof Props) ; Props.dwSampleFlags = m_dwFlags & ~SAMPLE_VALIDFLAGS ; Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags ; Props.pbBuffer = m_pbPayload ; Props.cbBuffer = m_lActual ; // same as actual Props.lActual = m_lActual ; Props.tStart = m_rtStart ; Props.tStop = m_rtEnd ; Props.dwStreamId = m_dwStreamId ; if (m_dwFlags & AM_SAMPLE_TYPECHANGED) { Props.pMediaType = m_pMediaType ; } else { Props.pMediaType = NULL ; } CopyMemory ( pbProperties, & Props, Props.cbData ) ; } else { hr = E_POINTER ; } } return hr ; } STDMETHODIMP CMediaSampleWrapper::SetProperties ( IN DWORD cbProperties, IN const BYTE * pbProperties ) { return E_NOTIMPL ; } // --------------------------------------------------------------------------- // CMediaSampleWrapperPool // --------------------------------------------------------------------------- CMediaSampleWrapperPool::CMediaSampleWrapperPool ( IN CMPEG2DemuxOutputPin * pOutputPin, IN BOOL fReportDiscontinuities, IN BOOL fSetSyncPoints, IN CRefCountedCritSec * pMapperLock, IN DWORD dwMaxPoolSize, IN HKEY hkeyRoot, // don't use after constructor ! IN CMpeg2Stats * pStats, OUT HRESULT * phr ) : CBufferSource (FALSE, // not a copy buffer source pStats, // stats TRUE), // and report 'em m_hWait (NULL), m_dwActualPoolSize (0), m_dwMaxPoolSize (dwMaxPoolSize), m_fCancelWait (FALSE), m_pOutputPin (pOutputPin), m_fReportDiscontinuities (fReportDiscontinuities), m_fSetSyncPoints (fSetSyncPoints), m_pMapperLock (pMapperLock) { DWORD dw ; ASSERT (m_dwMaxPoolSize > 0) ; InitializeListHead (& m_leMSPool) ; InitializeCriticalSection (& m_crt) ; ASSERT (m_pMapperLock) ; m_pMapperLock -> AddRef () ; // our ref to the pin ASSERT (m_pOutputPin) ; m_pOutputPin -> AddRef () ; // because the pool contains no media samples, we initialize this // event to be non-signaled m_hWait = CreateEvent (NULL, TRUE, FALSE, NULL) ; if (m_hWait == NULL) { dw = GetLastError () ; * phr = HRESULT_FROM_WIN32 (dw) ; return ; } // success (* phr) = S_OK ; } CMediaSampleWrapperPool::~CMediaSampleWrapperPool ( ) { DWORD i ; LIST_ENTRY * pListEntry ; CMediaSampleWrapper * pMS ; for (i = 0; i < m_dwActualPoolSize; i++) { ASSERT (!IsListEmpty (& m_leMSPool)) ; pListEntry = RemoveHeadList (& m_leMSPool) ; pMS = CONTAINING_RECORD (pListEntry, CMediaSampleWrapper, m_ListEntry) ; delete pMS ; } ASSERT (IsListEmpty (& m_leMSPool)) ; m_pMapperLock -> Release () ; m_pOutputPin -> Release () ; CLOSE_RESET_HANDLE (m_hWait) ; DeleteCriticalSection (& m_crt) ; } void CMediaSampleWrapperPool::RecycleMS ( IN CMediaSampleWrapper * pMS ) { ASSERT (pMS) ; Lock_ () ; SetEvent (m_hWait) ; InsertHeadList (& m_leMSPool, & pMS -> m_ListEntry) ; // media sample's ref wraps to this Release () ; Unlock_ () ; } HRESULT CMediaSampleWrapperPool::GetMediaSampleWrapper_ ( IN IMediaSample * pIMS, IN BYTE * pbPayload, IN int iPayloadLength, OUT CMediaSampleWrapper ** ppMS ) { CMediaSampleWrapper * pMS ; LIST_ENTRY * pListEntry ; HRESULT hr ; DWORD dw ; // PREFIX (* ppMS) = NULL ; Lock_ () ; for (;;) { // make sure we have not been cancelled in the meantime if (m_fCancelWait) { hr = m_hrRet ; m_fCancelWait = FALSE ; Unlock_ () ; return hr ; } if (!IsListEmpty (& m_leMSPool)) { // if there are media samples, don't wait break ; } else if (m_dwActualPoolSize < m_dwMaxPoolSize) { // we have room for more allocations; do so now pMS = new CMediaSampleWrapper (this) ; if (pMS == NULL) { Unlock_ () ; return E_OUTOFMEMORY ; } m_dwActualPoolSize++ ; InsertHeadList (& m_leMSPool, & pMS -> m_ListEntry) ; // media sample ref: keep the ref of 1 (allocation) as the list's // there's 1 in the list; old on to the lock break ; } // no media samples are available; we need to block // explicitely reset ResetEvent (m_hWait) ; Unlock_ () ; dw = WaitForSingleObject ( m_hWait, INFINITE ) ; Lock_ () ; //if (dw == WAIT_TIMEOUT) { // Unlock_ () ; // return HRESULT_FROM_WIN32 (WAIT_TIMEOUT) ; //} } // if blocked media sample requests are being failed, m_fCancelWait // will be TRUE if (!m_fCancelWait) { ASSERT (!IsListEmpty (& m_leMSPool)) ; pListEntry = RemoveHeadList (& m_leMSPool) ; pMS = CONTAINING_RECORD (pListEntry, CMediaSampleWrapper, m_ListEntry) ; // media sample's ref on this AddRef () ; // we have the media sample and have addref'd the filter, so we can // now release the lock Unlock_ () ; // caller's ref ASSERT (pMS) ; pMS -> AddRef () ; // media sample pMS -> Init ( pIMS, pbPayload, iPayloadLength ) ; (* ppMS) = pMS ; return S_OK ; } else { Unlock_ () ; ASSERT (FAILED (m_hrRet)) ; return m_hrRet ; } } HRESULT CMediaSampleWrapperPool::WrapAndComplete ( IN IMediaSample * pIMediaSample, // wrap this IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN REFERENCE_TIME * pStartTime, // media sample start IN REFERENCE_TIME * pStopTime, // media sample stop IN CTStickyVal * pReset ) { HRESULT hr ; CMediaSampleWrapper * pMSWrapper ; TRACE_ENTER_6 (TEXT ("CMediaSampleWrapperPool::WrapAndComplete (%08xh, %08xh, %08xh, %08xh, %I64d, %I64d)"), pIMediaSample, pbBuffer, iBufferLength, fDiscontinuity, (* pStartTime), (* pStopTime)) ; hr = GetMediaSampleWrapper_ ( pIMediaSample, pbBuffer, iBufferLength, & pMSWrapper ) ; if (SUCCEEDED (hr)) { if (pMSWrapper) { hr = pMSWrapper -> SetTime ( pStartTime, pStopTime ) ; if (SUCCEEDED (hr)) { pMSWrapper -> SetDiscontinuity (fDiscontinuity && m_fReportDiscontinuities) ; pMSWrapper -> SetSyncPoint (m_fSetSyncPoints) ; // don't hold the mapper lock across the call m_pMapperLock -> Unlock () ; hr = m_pOutputPin -> SendSample (pMSWrapper) ; m_pMapperLock -> Lock () ; } pMSWrapper -> Release () ; } else { hr = E_UNEXPECTED ; } } return hr ; } HRESULT CMediaSampleWrapperPool::WrapAndComplete ( IN IMediaSample * pIMediaSample, // wrap this IN BYTE * pbBuffer, IN int iBufferLength, IN BOOL fDiscontinuity, IN CTStickyVal * pReset ) { HRESULT hr ; CMediaSampleWrapper * pMSWrapper ; TRACE_ENTER_4 (TEXT ("CMediaSampleWrapperPool::WrapAndComplete (%08xh, %08xh, %08xh, %08xh)"), pIMediaSample, pbBuffer, iBufferLength, fDiscontinuity) ; hr = GetMediaSampleWrapper_ ( pIMediaSample, pbBuffer, iBufferLength, & pMSWrapper ) ; if (SUCCEEDED (hr)) { if (pMSWrapper) { pMSWrapper -> SetDiscontinuity ( m_fReportDiscontinuities && fDiscontinuity ) ; m_pMapperLock -> Unlock () ; hr = m_pOutputPin -> SendSample (pMSWrapper) ; m_pMapperLock -> Lock () ; pMSWrapper -> Release () ; } else { hr = E_UNEXPECTED ; } } return hr ; }