Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

442 lines
15 KiB

// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved.
// Media type stuff
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt);
void WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource);
void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt);
void WINAPI InitMediaType(AM_MEDIA_TYPE *mt);
/* Base class objects for ActiveMovie in ATL */
/* Allocators */
//=====================================================================
//=====================================================================
// Memory allocators
//
// the shared memory transport between pins requires the input pin
// to provide a memory allocator that can provide sample objects. A
// sample object supports the IMediaSample interface.
//
// CAMBaseAllocator handles the management of free and busy samples. It
// allocates CAMMediaSample objects. CAMBaseAllocator is an abstract class:
// in particular it has no method of initializing the list of free
// samples. CAMMemAllocator is derived from CAMBaseAllocator and initializes
// the list of samples using memory from the standard IMalloc interface.
//
// If you want your buffers to live in some special area of memory,
// derive your allocator object from CAMBaseAllocator. If you derive your
// IMemInputPin interface object from CAMBaseMemInputPin, you will get
// CAMMemAllocator-based allocation etc for free and will just need to
// supply the Receive handling, and media type / format negotiation.
//=====================================================================
//=====================================================================
//
// The inhertiance tree for allocators and samples looks like
//
// CAMImplMediaSample<_S, _A>
//
// CAMImplMediaSample< CMediaSample< _A >, _A >
// |
// V
// CAMMediaSample<_A>
//
//
// CAMBaseAllocator<_A, _S>
//
// CAMBaseAllocator< CAMMemAllocator, CAMMediaSample< CAMMemAllocator > > >
// |
// V
// CAMMemAllocator
//=====================================================================
//=====================================================================
// Defines CAMMediaSample
//
// an object of this class supports IMediaSample and represents a buffer
// for media data with some associated properties. Releasing it returns
// it to a freelist managed by a CAMBaseAllocator derived object.
//=====================================================================
//=====================================================================
template <class _S, class _A>
class CAMMediaSampleImpl : public IMediaSample2 // The interface we support
{
protected:
friend class _A;
/* Values for dwFlags - these are used for backward compatiblity
only now - use AM_SAMPLE_xxx
*/
enum { Sample_SyncPoint = 0x01, /* Is this a sync point */
Sample_Preroll = 0x02, /* Is this a preroll sample */
Sample_Discontinuity = 0x04, /* Set if start of new segment */
Sample_TypeChanged = 0x08, /* Has the type changed */
Sample_TimeValid = 0x10, /* Set if time is valid */
Sample_MediaTimeValid = 0x20, /* Is the media time valid */
Sample_TimeDiscontinuity = 0x40, /* Time discontinuity */
Sample_StopValid = 0x100, /* Stop time valid */
Sample_ValidFlags = 0x1FF
};
/* Properties, the media sample class can be a container for a format
change in which case we take a copy of a type through the SetMediaType
interface function and then return it when GetMediaType is called. As
we do no internal processing on it we leave it as a pointer */
DWORD m_dwFlags; /* Flags for this sample */
/* Type specific flags are packed
into the top word
*/
DWORD m_dwTypeSpecificFlags; /* Media type specific flags */
LPBYTE m_pBuffer; /* Pointer to the complete buffer */
LONG m_lActual; /* Length of data in this sample */
LONG m_cbBuffer; /* Size of the buffer */
_A *m_pAllocator; /* The allocator who owns us */
REFERENCE_TIME m_Start; /* Start sample time */
REFERENCE_TIME m_End; /* End sample time */
LONGLONG m_MediaStart; /* Real media start position */
LONG m_MediaEnd; /* A difference to get the end */
AM_MEDIA_TYPE *m_pMediaType; /* Media type change data */
public:
LONG m_cRef; /* Reference count */
_S *m_pNext; /* Chaining in free list */
public:
CAMMediaSampleImpl();
~CAMMediaSampleImpl()
{
if (m_pMediaType) {
DeleteMediaType(m_pMediaType);
}
}
/* Note the media sample does not delegate to its owner */
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
void Init(_A *pAllocator)
{
m_pAllocator = pAllocator;
}
// set the buffer pointer and length. Used by allocators that
// want variable sized pointers or pointers into already-read data.
// This is only available through a CAMMediaSampleImpl* not an IMediaSample*
// and so cannot be changed by clients.
HRESULT SetPointer(BYTE * ptr, LONG cBytes)
{
m_pBuffer = ptr; // new buffer area (could be null)
m_cbBuffer = cBytes; // length of buffer
m_lActual = cBytes; // length of data in buffer (assume full)
return S_OK;
}
// Get me a read/write pointer to this buffer's memory.
STDMETHODIMP GetPointer(BYTE ** ppBuffer);
STDMETHODIMP_(LONG) GetSize(void);
// get the stream time at which this sample should start and finish.
STDMETHODIMP GetTime(
REFERENCE_TIME * pTimeStart, // put time here
REFERENCE_TIME * pTimeEnd
);
// Set the stream time at which this sample should start and finish.
STDMETHODIMP SetTime(
REFERENCE_TIME * pTimeStart, // put time here
REFERENCE_TIME * pTimeEnd
);
STDMETHODIMP IsSyncPoint(void);
STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint);
STDMETHODIMP IsPreroll(void);
STDMETHODIMP SetPreroll(BOOL bIsPreroll);
STDMETHODIMP_(LONG) GetActualDataLength(void);
STDMETHODIMP SetActualDataLength(LONG lActual);
// these allow for limited format changes in band
STDMETHODIMP GetMediaType(AM_MEDIA_TYPE **ppMediaType);
STDMETHODIMP SetMediaType(AM_MEDIA_TYPE *pMediaType);
// returns S_OK if there is a discontinuity in the data (this same is
// not a continuation of the previous stream of data
// - there has been a seek).
STDMETHODIMP IsDiscontinuity(void);
// set the discontinuity property - TRUE if this sample is not a
// continuation, but a new sample after a seek.
STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity);
// get the media times for this sample
STDMETHODIMP GetMediaTime(
LONGLONG * pTimeStart,
LONGLONG * pTimeEnd
);
// Set the media times for this sample
STDMETHODIMP SetMediaTime(
LONGLONG * pTimeStart,
LONGLONG * pTimeEnd
);
// Set and get properties (IMediaSample2)
STDMETHODIMP GetProperties(
DWORD cbProperties,
BYTE * pbProperties
);
STDMETHODIMP SetProperties(
DWORD cbProperties,
const BYTE * pbProperties
);
};
//=====================================================================
//=====================================================================
// Defines CAMBaseAllocator
//
// Abstract base class that manages a list of media samples
//
// This class provides support for getting buffers from the free list,
// including handling of commit and (asynchronous) decommit.
//
// Derive from this class and override the Alloc and Free functions to
// allocate your CAMMediaSampleImpl (or derived) objects and add them to the
// free list, preparing them as necessary.
//=====================================================================
//=====================================================================
template <class _A, class _S>
class CAMBaseAllocator :
public CComObjectRoot,
public IMemAllocator // The interface we support
{
protected:
CCritSec m_Lock;
friend class _A;
typedef CAMBaseAllocator<_A, _S> _BaseAllocator;
class CSampleList;
friend class CSampleList;
/* Hack to get at protected member in _S */
static _S *
&NextSample(_S *pSample)
{
return pSample->m_pNext;
}
/* Mini list class for the free list */
class CSampleList
{
public:
CSampleList() : m_List(NULL), m_nOnList(0) {};
#ifdef DEBUG
~CSampleList()
{
_ASSERTE(m_nOnList == 0);
};
#endif
_S *Head() const { return m_List; };
_S *Next(_S *pSample) const { return NextSample(pSample); };
int GetCount() const { return m_nOnList; };
void Add(_S *pSample)
{
_ASSERTE(pSample != NULL);
NextSample(pSample) = m_List;
m_List = pSample;
m_nOnList++;
};
_S *RemoveHead()
{
_S *pSample = m_List;
if (pSample != NULL) {
m_List = NextSample(m_List);
m_nOnList--;
}
return pSample;
};
void Remove(_S *pSample);
public:
_S *m_List;
int m_nOnList;
};
protected:
CSampleList m_lFree; // Free list
/* Note to overriders of CAMBaseAllocator.
We use a lazy signalling mechanism for waiting for samples.
This means we don't call the OS if no waits occur.
In order to implement this:
1. When a new sample is added to m_lFree call NotifySample() which
calls ReleaseSemaphore on m_hSem with a count of m_lWaiting and
sets m_lWaiting to 0.
This must all be done holding the allocator's critical section.
2. When waiting for a sample call SetWaiting() which increments
m_lWaiting BEFORE leaving the allocator's critical section.
3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE)
having left the allocator's critical section. The effect of
this is to remove 1 from the semaphore's count. You MUST call
this once having incremented m_lWaiting.
The following are then true when the critical section is not held :
(let nWaiting = number about to wait or waiting)
(1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0)
(2) m_lWaiting + Semaphore count == nWaiting
We would deadlock if
nWaiting != 0 &&
m_lFree.GetCount() != 0 &&
Semaphore count == 0
But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so
from (2) Semaphore count == nWaiting (which is non-0) so the
deadlock can't happen.
*/
HANDLE m_hSem; // For signalling
long m_lWaiting; // Waiting for a free element
long m_lCount; // how many buffers we have agreed to provide
long m_lAllocated; // how many buffers are currently allocated
long m_lSize; // agreed size of each buffer
long m_lAlignment; // agreed alignment
long m_lPrefix; // agreed prefix (preceeds GetPointer() value)
BOOL m_bChanged; // Have the buffer requirements changed
// if true, we are decommitted and can't allocate memory
BOOL m_bCommitted;
// if true, the decommit has happened, but we haven't called Free yet
// as there are still outstanding buffers
BOOL m_bDecommitInProgress;
// override to free the memory when decommit completes
// - we actually do nothing, and save the memory until deletion.
virtual void Free(void) = 0;
// override to allocate the memory when commit called
virtual HRESULT Alloc(void);
public:
CAMBaseAllocator();
~CAMBaseAllocator();
HRESULT FinalConstruct();
BEGIN_COM_MAP(CAMBaseAllocator)
COM_INTERFACE_ENTRY(IMemAllocator)
END_COM_MAP()
STDMETHODIMP SetProperties(
ALLOCATOR_PROPERTIES* pRequest,
ALLOCATOR_PROPERTIES* pActual);
// return the properties actually being used on this allocator
STDMETHODIMP GetProperties(
ALLOCATOR_PROPERTIES* pProps);
// override Commit to allocate memory. We handle the GetBuffer
//state changes
STDMETHODIMP Commit();
// override this to handle the memory freeing. We handle any outstanding
// GetBuffer calls
STDMETHODIMP Decommit();
// get container for a sample. Blocking, synchronous call to get the
// next free buffer (as represented by an IMediaSample interface).
// on return, the time etc properties will be invalid, but the buffer
// pointer and size will be correct. The two time parameters are
// optional and either may be NULL, they may alternatively be set to
// the start and end times the sample will have attached to it
// bPrevFramesSkipped is not used (used only by the video renderer's
// allocator where it affects quality management in direct draw).
STDMETHODIMP GetBuffer(IMediaSample **ppBuffer,
REFERENCE_TIME * pStartTime,
REFERENCE_TIME * pEndTime,
DWORD dwFlags);
// final release of a _SampleClass will call this
STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer);
// obsolete:: virtual void PutOnFreeList(_SampleClass * pSample);
// Notify that a sample is available
void NotifySample();
// Notify that we're waiting for a sample
void SetWaiting() { m_lWaiting++; };
};
template < class _A >
class CAMMediaSample : public CAMMediaSampleImpl< CAMMediaSample<_A>, _A >
{
public:
CAMMediaSample() {}
};
//=====================================================================
//=====================================================================
// Defines CAMMemAllocator
//
// this is an allocator based on CAMBaseAllocator that allocates sample
// buffers in main memory (from 'new'). You must call SetProperties
// before calling Commit.
//
// we don't free the memory when going into Decommit state. The simplest
// way to implement this without complicating CAMBaseAllocator is to
// have a Free() function, called to go into decommit state, that does
// nothing and a ReallyFree function called from our destructor that
// actually frees the memory.
//=====================================================================
//=====================================================================
class CAMMemAllocator :
public CAMBaseAllocator< CAMMemAllocator,
CAMMediaSample<CAMMemAllocator> >
{
protected:
LPBYTE m_pBuffer; // combined memory for all buffers
// override to free the memory when decommit completes
// - we actually do nothing, and save the memory until deletion.
void Free(void);
// called from the destructor (and from Alloc if changing size/count) to
// actually free up the memory
void ReallyFree(void);
// overriden to allocate the memory when commit called
HRESULT Alloc(void);
public:
STDMETHODIMP SetProperties(
ALLOCATOR_PROPERTIES* pRequest,
ALLOCATOR_PROPERTIES* pActual);
CAMMemAllocator();
~CAMMemAllocator();
};