1 ///////////////////////////////////////////////////////////////////////////////
2 // $Source: x:/prj/tech/libsrc/actmovie/RCS/amalloc.h $
4 // $Date: 1996/09/18 11:32:12 $
7 // Active Movie related allocation code cribbed from Microsoft
23 ///////////////////////////////////////////////////////////////////////////////
27 // the shared memory transport between pins requires the input pin
28 // to provide a memory allocator that can provide sample objects. A
29 // sample object supports the IMediaSample interface.
31 // cBaseAllocator handles the management of free and busy samples. It
32 // allocates cMediaSample objects. cBaseAllocator is an abstract class:
33 // in particular it has no method of initializing the list of free
34 // samples. cMemAllocator is derived from cBaseAllocator and initializes
35 // the list of samples using memory from the standard IMalloc interface.
37 // If you want your buffers to live in some special area of memory,
38 // derive your allocator object from cBaseAllocator. If you derive your
39 // IMemInputPin interface object from cBaseMemInputPin, you will get
40 // cMemAllocator-based allocation etc for free and will just need to
41 // supply the Receive handling, and media type / format negotiation.
44 ///////////////////////////////////////////////////////////////////////////////
46 // CLASS: cMediaSample
48 // an object of this class supports IMediaSample and represents a buffer
49 // for media data with some associated properties. Releasing it returns
50 // it to a freelist managed by a cBaseAllocator derived object.
53 class cMediaSample
: public IMediaSample
57 cMediaSample(char * pName
, cBaseAllocator
* pAllocator
, HRESULT
* phr
,
58 BYTE
* pBuffer
= NULL
, long length
= 0);
60 virtual ~cMediaSample();
63 DECLARE_UNAGGREGATABLE();
66 // set the buffer pointer and length. Used by allocators that
67 // want variable sized pointers or pointers into already-read data.
68 // This is only available through a cMediaSample* not an IMediaSample*
69 // and so cannot be changed by clients.
70 HRESULT
SetPointer(BYTE
* ptr
, long cBytes
);
72 // Get me a read/write pointer to this buffer's memory.
73 STDMETHOD (GetPointer
)(BYTE
** ppBuffer
);
75 STDMETHOD_(long, GetSize
)(void);
77 // get the stream time at which this sample should start and finish.
78 STDMETHOD (GetTime
)(REFERENCE_TIME
* pTimeStart
, REFERENCE_TIME
* pTimeEnd
);
80 // Set the stream time at which this sample should start and finish.
81 STDMETHOD (SetTime
)(REFERENCE_TIME
* pTimeStart
, REFERENCE_TIME
* pTimeEnd
);
82 STDMETHOD (IsSyncPoint
)(void);
83 STDMETHOD (SetSyncPoint
)(BOOL bIsSyncPoint
);
84 STDMETHOD (IsPreroll
)(void);
85 STDMETHOD (SetPreroll
)(BOOL bIsPreroll
);
87 STDMETHOD_(long, GetActualDataLength
)(void);
88 STDMETHOD (SetActualDataLength
)(long lActual
);
90 // these allow for limited format changes in band
91 STDMETHOD (GetMediaType
)(AM_MEDIA_TYPE
** ppMediaType
);
92 STDMETHOD (SetMediaType
)(AM_MEDIA_TYPE
* pMediaType
);
94 // returns S_OK if there is a discontinuity in the data (this same is
95 // not a continuation of the previous stream of data
96 // - there has been a seek).
97 STDMETHOD (IsDiscontinuity
)(void);
99 // set the discontinuity property - TRUE if this sample is not a
100 // continuation, but a new sample after a seek.
101 STDMETHOD (SetDiscontinuity
)(BOOL bDiscontinuity
);
103 // get the media times for this sample
104 STDMETHOD (GetMediaTime
)(LONGLONG
* pTimeStart
, LONGLONG
* pTimeEnd
);
106 // Set the media times for this sample
107 STDMETHOD (SetMediaTime
)(LONGLONG
* pTimeStart
, LONGLONG
* pTimeEnd
);
111 friend class cBaseAllocator
;
113 /* Values for dwFlags */
116 Sample_SyncPoint
= 0x01, /* Is this a sync point */
117 Sample_Preroll
= 0x02, /* Is this a preroll sample */
118 Sample_Discontinuity
= 0x04, /* Set if start of new segment */
119 Sample_TypeChanged
= 0x08, /* Has the type changed */
120 Sample_TimeValid
= 0x10, /* Set if time is valid */
121 Sample_MediaTimeValid
= 0x20 /* Is the media time valid */
124 /* Properties, the media sample class can be a container for a format change in which case we take a copy of a type
125 through the SetMediaType interface function and then return it when GetMediaType is called. As we do no internal
126 processing on it we leave it as a pointer */
128 REFERENCE_TIME m_Start
; // Start sample time
129 REFERENCE_TIME m_End
; // End sample time
130 LONGLONG m_MediaStart
; // Real media start position
131 long m_MediaEnd
; // A difference to get the end
132 DWORD m_dwFlags
; // Flags for this sample
133 BYTE
* m_pBuffer
; // Pointer to the complete buffer
134 long m_cbBuffer
; // Size of the buffer
135 long m_lActual
; // Length of data in this sample
136 AM_MEDIA_TYPE
* m_pMediaType
; // Media type change data
137 cMediaSample
* m_pNext
; // Chaining in free list
139 cBaseAllocator
* m_pAllocator
; /* The allocator who owns us */
143 ///////////////////////////////////////////////////////////////////////////////
145 // CLASS: cBitmapSample
148 class cBitmapSample
: public cMediaSample
151 grs_bitmap
*m_pBitmap
;
156 cBaseAllocator
*pAllocator
,
161 grs_bitmap
*GetBitmap();
164 ///////////////////////////////////////////////////////////////////////////////
166 // CLASS: cBitmapSample
169 class cDDSample
: public cMediaSample
172 LPDIRECTDRAWSURFACE m_pDDSurface
;
173 IDirectDrawSurface
*m_pIDDSurface
;
174 LPDDSURFACEDESC m_pDDSurfaceDesc
;
179 cBaseAllocator
*pAllocator
,
181 LPDIRECTDRAWSURFACE pDDSurface
,
182 IDirectDrawSurface
*pIDDSurface
,
183 LPDDSURFACEDESC pDDSurfaceDesc
,
186 LPDIRECTDRAWSURFACE
GetDDSurface();
187 IDirectDrawSurface
*GetIDDSurface();
188 LPDDSURFACEDESC
GetDDSurfaceDesc();
191 ///////////////////////////////////////////////////////////////////////////////
193 // CLASS: cBaseAllocator
195 // Abstract base class that manages a list of media samples
197 // This class provides support for getting buffers from the free list,
198 // including handling of commit and (asynchronous) decommit.
200 // Derive from this class and override the Alloc and Free functions to
201 // allocate your cMediaSample (or derived) objects and add them to the
202 // free list, preparing them as necessary.
205 class cBaseAllocator
: public IMemAllocator
208 cBaseAllocator(char *, LPUNKNOWN
, HRESULT
*, BOOL bEvent
= TRUE
);
209 virtual ~ cBaseAllocator();
212 DECLARE_UNAGGREGATABLE();
215 STDMETHOD (SetProperties
)(ALLOCATOR_PROPERTIES
* pRequest
, ALLOCATOR_PROPERTIES
* pActual
);
217 // return the properties actually being used on this allocator
218 STDMETHOD (GetProperties
)(ALLOCATOR_PROPERTIES
* pProps
);
220 // override Commit to allocate memory. We handle the GetBuffer
222 STDMETHOD (Commit
)();
224 // override this to handle the memory freeing. We handle any outstanding
226 STDMETHOD (Decommit
)();
228 // get container for a sample. Blocking, synchronous call to get the
229 // next free buffer (as represented by an IMediaSample interface).
230 // on return, the time etc properties will be invalid, but the buffer
231 // pointer and size will be correct. The two time parameters are
232 // optional and either may be NULL, they may alternatively be set to
233 // the start and end times the sample will have attached to it
234 // bPrevFramesSkipped is not used (used only by the video renderer's
235 // allocator where it affects quality management in direct draw).
236 STDMETHOD (GetBuffer
)(IMediaSample
** ppBuffer
,
237 REFERENCE_TIME
* pStartTime
,
238 REFERENCE_TIME
* pEndTime
,
241 // final release of a cMediaSample will call this
242 STDMETHOD (ReleaseBuffer
)(IMediaSample
* pBuffer
);
244 // Notify that a sample is available
247 // Notify that we're waiting for a sample
258 friend class cSampleList
;
260 /* Hack to get at protected member in cMediaSample */
261 static cMediaSample
*&NextSample(cMediaSample
* pSample
)
263 return pSample
->m_pNext
;
266 /* Mini list class for the free list */
273 ~cSampleList() { Assert_(m_nOnList
== 0); }
274 cMediaSample
* Head() const { return m_List
; }
275 cMediaSample
* Next(cMediaSample
* pSample
) const { return cBaseAllocator::NextSample(pSample
); }
276 int GetCount() const { return m_nOnList
; };
278 void Add(cMediaSample
* pSample
)
280 Assert_(pSample
!= NULL
);
281 cBaseAllocator::NextSample(pSample
) = m_List
;
286 cMediaSample
*RemoveHead()
288 cMediaSample
*pSample
= m_List
;
291 m_List
= cBaseAllocator::NextSample(m_List
);
297 void Remove(cMediaSample
* pSample
);
299 cMediaSample
* m_List
;
303 cSampleList m_lFree
; // Free list
305 /* Note to overriders of cBaseAllocator.
307 We use a lazy signalling mechanism for waiting for samples. This means we don't call the OS if no waits occur.
309 In order to implement this:
311 1. When a new sample is added to m_lFree call NotifySample() which calls ReleaseSemaphore on m_hSem with a count of
312 m_lWaiting and sets m_lWaiting to 0. This must all be done holding the allocator's critical section.
314 2. When waiting for a sample call SetWait() which increments m_lWaiting BEFORE leaving the allocator's critical section.
316 3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE) having left the allocator's critical section. The
317 effect of this is to remove 1 from the semaphore's count. You MUST call this once having incremented m_lWaiting.
319 The following are then true when the critical section is not held : (let nWaiting = number about to wait or waiting)
321 (1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0) (2) m_lWaiting + Semaphore count == nWaiting
323 We would deadlock if nWaiting != 0 && m_lFree.GetCount() != 0 && Semaphore count == 0
325 But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so from (2) Semaphore count == nWaiting (which is non-0) so
326 the deadlock can't happen. */
328 HANDLE m_hSem
; // For signalling
329 long m_lWaiting
; // Waiting for a free element
330 long m_lCount
; // how many buffers we have agreed to provide
331 long m_lAllocated
; // how many buffers are currently allocated
332 long m_lSize
; // agreed size of each buffer
333 long m_lAlignment
; // agreed alignment
334 long m_lPrefix
; // agreed prefix (preceeds GetPointer() value)
335 BOOL m_bChanged
; // Have the buffer requirements changed
337 // if true, we are decommitted and can't allocate memory
340 // if true, the decommit has happened, but we haven't called Free yet
341 // as there are still outstanding buffers
342 BOOL m_bDecommitInProgress
;
344 // called to decommit the memory when the last buffer is freed
345 // pure virtual - need to override this
346 virtual void Free(void) = 0;
348 // override to allocate the memory when commit called
349 virtual HRESULT
Alloc(void);
354 ///////////////////////////////////////////////////////////////////////////////
356 // CLASS: cMemAllocator
358 // this is an allocator based on cBaseAllocator that allocates sample
359 // buffers in main memory (from 'new'). You must call SetProperties
360 // before calling Commit.
362 // we don't free the memory when going into Decommit state. The simplest
363 // way to implement this without complicating cBaseAllocator is to
364 // have a Free() function, called to go into decommit state, that does
365 // nothing and a ReallyFree function called from our destructor that
366 // actually frees the memory.
368 class cMemAllocator
: public cBaseAllocator
371 cMemAllocator(char *, LPUNKNOWN
, HRESULT
*);
375 STDMETHOD (SetProperties
)(ALLOCATOR_PROPERTIES
* pRequest
,
376 ALLOCATOR_PROPERTIES
* pActual
);
378 // override to free the memory when decommit completes
379 // - we actually do nothing, and save the memory until deletion.
382 // called from the destructor (and from Alloc if changing size/count) to
383 // actually free up the memory
384 void ReallyFree(void);
386 // overriden to allocate the memory when commit called
390 BYTE
* m_pBuffer
; // combined memory for all buffers
394 #endif /* !__AMALLOC_H */