//-------------------------------------------------------------------------
//
// 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 ;
}