blob: 14f17cd4288ffb2d710cf45fe095762c58f864f8 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001//------------------------------------------------------------------------------
2// File: AMFilter.h
3//
4// Desc: DirectShow base classes - efines class hierarchy for streams
5// architecture.
6//
7// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8//------------------------------------------------------------------------------
9
10
11#ifndef __FILTER__
12#define __FILTER__
13
14/* The following classes are declared in this header: */
15
16class CBaseMediaFilter; // IMediaFilter support
17class CBaseFilter; // IBaseFilter,IMediaFilter support
18class CBasePin; // Abstract base class for IPin interface
19class CEnumPins; // Enumerate input and output pins
20class CEnumMediaTypes; // Enumerate the pin's preferred formats
21class CBaseOutputPin; // Adds data provider member functions
22class CBaseInputPin; // Implements IMemInputPin interface
23class CMediaSample; // Basic transport unit for IMemInputPin
24class CBaseAllocator; // General list guff for most allocators
25class CMemAllocator; // Implements memory buffer allocation
26
27
28//=====================================================================
29//=====================================================================
30//
31// QueryFilterInfo and QueryPinInfo AddRef the interface pointers
32// they return. You can use the macro below to release the interface.
33//
34//=====================================================================
35//=====================================================================
36
37#define QueryFilterInfoReleaseGraph(fi) if ((fi).pGraph) (fi).pGraph->Release();
38
39#define QueryPinInfoReleaseFilter(pi) if ((pi).pFilter) (pi).pFilter->Release();
40
41//=====================================================================
42//=====================================================================
43// Defines CBaseMediaFilter
44//
45// Abstract base class implementing IMediaFilter.
46//
47// Typically you will derive your filter from CBaseFilter rather than
48// this, unless you are implementing an object such as a plug-in
49// distributor that needs to support IMediaFilter but not IBaseFilter.
50//
51// Note that IMediaFilter is derived from IPersist to allow query of
52// class id.
53//=====================================================================
54//=====================================================================
55
56class AM_NOVTABLE CBaseMediaFilter : public CUnknown,
57 public IMediaFilter
58{
59
60protected:
61
62 FILTER_STATE m_State; // current state: running, paused
63 IReferenceClock *m_pClock; // this filter's reference clock
64 // note: all filters in a filter graph use the same clock
65
66 // offset from stream time to reference time
67 CRefTime m_tStart;
68
69 CLSID m_clsid; // This filters clsid
70 // used for serialization
71 CCritSec *m_pLock; // Object we use for locking
72
73public:
74
75 CBaseMediaFilter(
76 __in_opt LPCTSTR pName,
77 __inout_opt LPUNKNOWN pUnk,
78 __in CCritSec *pLock,
79 REFCLSID clsid);
80
81 virtual ~CBaseMediaFilter();
82
83 DECLARE_IUNKNOWN
84
85 // override this to say what interfaces we support where
86 STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv);
87
88 //
89 // --- IPersist method ---
90 //
91
92 STDMETHODIMP GetClassID(__out CLSID *pClsID);
93
94 // --- IMediaFilter methods ---
95
96 STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State);
97
98 STDMETHODIMP SetSyncSource(__inout_opt IReferenceClock *pClock);
99
100 STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock);
101
102 // default implementation of Stop and Pause just record the
103 // state. Override to activate or de-activate your filter.
104 // Note that Run when called from Stopped state will call Pause
105 // to ensure activation, so if you are a source or transform
106 // you will probably not need to override Run.
107 STDMETHODIMP Stop();
108 STDMETHODIMP Pause();
109
110
111 // the start parameter is the difference to be added to the
112 // sample's stream time to get the reference time for
113 // its presentation
114 STDMETHODIMP Run(REFERENCE_TIME tStart);
115
116 // --- helper methods ---
117
118 // return the current stream time - ie find out what
119 // stream time should be appearing now
120 virtual HRESULT StreamTime(CRefTime& rtStream);
121
122 // Is the filter currently active? (running or paused)
123 BOOL IsActive() {
124 CAutoLock cObjectLock(m_pLock);
125 return ((m_State == State_Paused) || (m_State == State_Running));
126 };
127};
128
129//=====================================================================
130//=====================================================================
131// Defines CBaseFilter
132//
133// An abstract class providing basic IBaseFilter support for pin
134// enumeration and filter information reading.
135//
136// We cannot derive from CBaseMediaFilter since methods in IMediaFilter
137// are also in IBaseFilter and would be ambiguous. Since much of the code
138// assumes that they derive from a class that has m_State and other state
139// directly available, we duplicate code from CBaseMediaFilter rather than
140// having a member variable.
141//
142// Derive your filter from this, or from a derived object such as
143// CTransformFilter.
144//=====================================================================
145//=====================================================================
146
147
148class AM_NOVTABLE CBaseFilter : public CUnknown, // Handles an IUnknown
149 public IBaseFilter, // The Filter Interface
150 public IAMovieSetup // For un/registration
151{
152
153friend class CBasePin;
154
155protected:
156 FILTER_STATE m_State; // current state: running, paused
157 IReferenceClock *m_pClock; // this graph's ref clock
158 CRefTime m_tStart; // offset from stream time to reference time
159 CLSID m_clsid; // This filters clsid
160 // used for serialization
161 CCritSec *m_pLock; // Object we use for locking
162
163 WCHAR *m_pName; // Full filter name
164 IFilterGraph *m_pGraph; // Graph we belong to
165 IMediaEventSink *m_pSink; // Called with notify events
166 LONG m_PinVersion; // Current pin version
167
168public:
169
170 CBaseFilter(
171 __in_opt LPCTSTR pName, // Object description
172 __inout_opt LPUNKNOWN pUnk, // IUnknown of delegating object
173 __in CCritSec *pLock, // Object who maintains lock
174 REFCLSID clsid); // The clsid to be used to serialize this filter
175
176 CBaseFilter(
177 __in_opt LPCTSTR pName, // Object description
178 __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object
179 __in CCritSec *pLock, // Object who maintains lock
180 REFCLSID clsid, // The clsid to be used to serialize this filter
181 __inout HRESULT *phr); // General OLE return code
182#ifdef UNICODE
183 CBaseFilter(
184 __in_opt LPCSTR pName, // Object description
185 __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object
186 __in CCritSec *pLock, // Object who maintains lock
187 REFCLSID clsid); // The clsid to be used to serialize this filter
188
189 CBaseFilter(
190 __in_opt LPCSTR pName, // Object description
191 __in_opt LPUNKNOWN pUnk, // IUnknown of delegating object
192 __in CCritSec *pLock, // Object who maintains lock
193 REFCLSID clsid, // The clsid to be used to serialize this filter
194 __inout HRESULT *phr); // General OLE return code
195#endif
196 ~CBaseFilter();
197
198 DECLARE_IUNKNOWN
199
200 // override this to say what interfaces we support where
201 STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv);
202#ifdef DEBUG
203 STDMETHODIMP_(ULONG) NonDelegatingRelease();
204#endif
205
206 //
207 // --- IPersist method ---
208 //
209
210 STDMETHODIMP GetClassID(__out CLSID *pClsID);
211
212 // --- IMediaFilter methods ---
213
214 STDMETHODIMP GetState(DWORD dwMSecs, __out FILTER_STATE *State);
215
216 STDMETHODIMP SetSyncSource(__in_opt IReferenceClock *pClock);
217
218 STDMETHODIMP GetSyncSource(__deref_out_opt IReferenceClock **pClock);
219
220
221 // override Stop and Pause so we can activate the pins.
222 // Note that Run will call Pause first if activation needed.
223 // Override these if you want to activate your filter rather than
224 // your pins.
225 STDMETHODIMP Stop();
226 STDMETHODIMP Pause();
227
228 // the start parameter is the difference to be added to the
229 // sample's stream time to get the reference time for
230 // its presentation
231 STDMETHODIMP Run(REFERENCE_TIME tStart);
232
233 // --- helper methods ---
234
235 // return the current stream time - ie find out what
236 // stream time should be appearing now
237 virtual HRESULT StreamTime(CRefTime& rtStream);
238
239 // Is the filter currently active?
240 BOOL IsActive() {
241 CAutoLock cObjectLock(m_pLock);
242 return ((m_State == State_Paused) || (m_State == State_Running));
243 };
244
245 // Is this filter stopped (without locking)
246 BOOL IsStopped() {
247 return (m_State == State_Stopped);
248 };
249
250 //
251 // --- IBaseFilter methods ---
252 //
253
254 // pin enumerator
255 STDMETHODIMP EnumPins(
256 __deref_out IEnumPins ** ppEnum);
257
258
259 // default behaviour of FindPin assumes pin ids are their names
260 STDMETHODIMP FindPin(
261 LPCWSTR Id,
262 __deref_out IPin ** ppPin
263 );
264
265 STDMETHODIMP QueryFilterInfo(
266 __out FILTER_INFO * pInfo);
267
268 STDMETHODIMP JoinFilterGraph(
269 __inout_opt IFilterGraph * pGraph,
270 __in_opt LPCWSTR pName);
271
272 // return a Vendor information string. Optional - may return E_NOTIMPL.
273 // memory returned should be freed using CoTaskMemFree
274 // default implementation returns E_NOTIMPL
275 STDMETHODIMP QueryVendorInfo(
276 __deref_out LPWSTR* pVendorInfo
277 );
278
279 // --- helper methods ---
280
281 // send an event notification to the filter graph if we know about it.
282 // returns S_OK if delivered, S_FALSE if the filter graph does not sink
283 // events, or an error otherwise.
284 HRESULT NotifyEvent(
285 long EventCode,
286 LONG_PTR EventParam1,
287 LONG_PTR EventParam2);
288
289 // return the filter graph we belong to
290 __out_opt IFilterGraph *GetFilterGraph() {
291 return m_pGraph;
292 }
293
294 // Request reconnect
295 // pPin is the pin to reconnect
296 // pmt is the type to reconnect with - can be NULL
297 // Calls ReconnectEx on the filter graph
298 HRESULT ReconnectPin(IPin *pPin, __in_opt AM_MEDIA_TYPE const *pmt);
299
300 // find out the current pin version (used by enumerators)
301 virtual LONG GetPinVersion();
302 void IncrementPinVersion();
303
304 // you need to supply these to access the pins from the enumerator
305 // and for default Stop and Pause/Run activation.
306 virtual int GetPinCount() PURE;
307 virtual CBasePin *GetPin(int n) PURE;
308
309 // --- IAMovieSetup methods ---
310
311 STDMETHODIMP Register(); // ask filter to register itself
312 STDMETHODIMP Unregister(); // and unregister itself
313
314 // --- setup helper methods ---
315 // (override to return filters setup data)
316
317 virtual __out_opt LPAMOVIESETUP_FILTER GetSetupData(){ return NULL; }
318
319};
320
321
322//=====================================================================
323//=====================================================================
324// Defines CBasePin
325//
326// Abstract class that supports the basics of IPin
327//=====================================================================
328//=====================================================================
329
330class AM_NOVTABLE CBasePin : public CUnknown, public IPin, public IQualityControl
331{
332
333protected:
334
335 WCHAR * m_pName; // This pin's name
336 IPin *m_Connected; // Pin we have connected to
337 PIN_DIRECTION m_dir; // Direction of this pin
338 CCritSec *m_pLock; // Object we use for locking
339 bool m_bRunTimeError; // Run time error generated
340 bool m_bCanReconnectWhenActive; // OK to reconnect when active
341 bool m_bTryMyTypesFirst; // When connecting enumerate
342 // this pin's types first
343 CBaseFilter *m_pFilter; // Filter we were created by
344 IQualityControl *m_pQSink; // Target for Quality messages
345 LONG m_TypeVersion; // Holds current type version
346 CMediaType m_mt; // Media type of connection
347
348 CRefTime m_tStart; // time from NewSegment call
349 CRefTime m_tStop; // time from NewSegment
350 double m_dRate; // rate from NewSegment
351
352#ifdef DEBUG
353 LONG m_cRef; // Ref count tracing
354#endif
355
356 // displays pin connection information
357
358#ifdef DEBUG
359 void DisplayPinInfo(IPin *pReceivePin);
360 void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt);
361#else
362 void DisplayPinInfo(IPin *pReceivePin) {};
363 void DisplayTypeInfo(IPin *pPin, const CMediaType *pmt) {};
364#endif
365
366 // used to agree a media type for a pin connection
367
368 // given a specific media type, attempt a connection (includes
369 // checking that the type is acceptable to this pin)
370 HRESULT
371 AttemptConnection(
372 IPin* pReceivePin, // connect to this pin
373 const CMediaType* pmt // using this type
374 );
375
376 // try all the media types in this enumerator - for each that
377 // we accept, try to connect using ReceiveConnection.
378 HRESULT TryMediaTypes(
379 IPin *pReceivePin, // connect to this pin
380 __in_opt const CMediaType *pmt, // proposed type from Connect
381 IEnumMediaTypes *pEnum); // try this enumerator
382
383 // establish a connection with a suitable mediatype. Needs to
384 // propose a media type if the pmt pointer is null or partially
385 // specified - use TryMediaTypes on both our and then the other pin's
386 // enumerator until we find one that works.
387 HRESULT AgreeMediaType(
388 IPin *pReceivePin, // connect to this pin
389 const CMediaType *pmt); // proposed type from Connect
390
391public:
392
393 CBasePin(
394 __in_opt LPCTSTR pObjectName, // Object description
395 __in CBaseFilter *pFilter, // Owning filter who knows about pins
396 __in CCritSec *pLock, // Object who implements the lock
397 __inout HRESULT *phr, // General OLE return code
398 __in_opt LPCWSTR pName, // Pin name for us
399 PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT
400#ifdef UNICODE
401 CBasePin(
402 __in_opt LPCSTR pObjectName, // Object description
403 __in CBaseFilter *pFilter, // Owning filter who knows about pins
404 __in CCritSec *pLock, // Object who implements the lock
405 __inout HRESULT *phr, // General OLE return code
406 __in_opt LPCWSTR pName, // Pin name for us
407 PIN_DIRECTION dir); // Either PINDIR_INPUT or PINDIR_OUTPUT
408#endif
409 virtual ~CBasePin();
410
411 DECLARE_IUNKNOWN
412
413 STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv);
414 STDMETHODIMP_(ULONG) NonDelegatingRelease();
415 STDMETHODIMP_(ULONG) NonDelegatingAddRef();
416
417 // --- IPin methods ---
418
419 // take lead role in establishing a connection. Media type pointer
420 // may be null, or may point to partially-specified mediatype
421 // (subtype or format type may be GUID_NULL).
422 STDMETHODIMP Connect(
423 IPin * pReceivePin,
424 __in_opt const AM_MEDIA_TYPE *pmt // optional media type
425 );
426
427 // (passive) accept a connection from another pin
428 STDMETHODIMP ReceiveConnection(
429 IPin * pConnector, // this is the initiating connecting pin
430 const AM_MEDIA_TYPE *pmt // this is the media type we will exchange
431 );
432
433 STDMETHODIMP Disconnect();
434
435 STDMETHODIMP ConnectedTo(__deref_out IPin **pPin);
436
437 STDMETHODIMP ConnectionMediaType(__out AM_MEDIA_TYPE *pmt);
438
439 STDMETHODIMP QueryPinInfo(
440 __out PIN_INFO * pInfo
441 );
442
443 STDMETHODIMP QueryDirection(
444 __out PIN_DIRECTION * pPinDir
445 );
446
447 STDMETHODIMP QueryId(
448 __deref_out LPWSTR * Id
449 );
450
451 // does the pin support this media type
452 STDMETHODIMP QueryAccept(
453 const AM_MEDIA_TYPE *pmt
454 );
455
456 // return an enumerator for this pins preferred media types
457 STDMETHODIMP EnumMediaTypes(
458 __deref_out IEnumMediaTypes **ppEnum
459 );
460
461 // return an array of IPin* - the pins that this pin internally connects to
462 // All pins put in the array must be AddReffed (but no others)
463 // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE
464 // Default: return E_NOTIMPL
465 // The filter graph will interpret NOT_IMPL as any input pin connects to
466 // all visible output pins and vice versa.
467 // apPin can be NULL if nPin==0 (not otherwise).
468 STDMETHODIMP QueryInternalConnections(
469 __out_ecount_part(*nPin,*nPin) IPin* *apPin, // array of IPin*
470 __inout ULONG *nPin // on input, the number of slots
471 // on output the number of pins
472 ) { return E_NOTIMPL; }
473
474 // Called when no more data will be sent
475 STDMETHODIMP EndOfStream(void);
476
477 // Begin/EndFlush still PURE
478
479 // NewSegment notifies of the start/stop/rate applying to the data
480 // about to be received. Default implementation records data and
481 // returns S_OK.
482 // Override this to pass downstream.
483 STDMETHODIMP NewSegment(
484 REFERENCE_TIME tStart,
485 REFERENCE_TIME tStop,
486 double dRate);
487
488 //================================================================================
489 // IQualityControl methods
490 //================================================================================
491
492 STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
493
494 STDMETHODIMP SetSink(IQualityControl * piqc);
495
496 // --- helper methods ---
497
498 // Returns true if the pin is connected. false otherwise.
499 BOOL IsConnected(void) {return (m_Connected != NULL); };
500 // Return the pin this is connected to (if any)
501 IPin * GetConnected() { return m_Connected; };
502
503 // Check if our filter is currently stopped
504 BOOL IsStopped() {
505 return (m_pFilter->m_State == State_Stopped);
506 };
507
508 // find out the current type version (used by enumerators)
509 virtual LONG GetMediaTypeVersion();
510 void IncrementTypeVersion();
511
512 // switch the pin to active (paused or running) mode
513 // not an error to call this if already active
514 virtual HRESULT Active(void);
515
516 // switch the pin to inactive state - may already be inactive
517 virtual HRESULT Inactive(void);
518
519 // Notify of Run() from filter
520 virtual HRESULT Run(REFERENCE_TIME tStart);
521
522 // check if the pin can support this specific proposed type and format
523 virtual HRESULT CheckMediaType(const CMediaType *) PURE;
524
525 // set the connection to use this format (previously agreed)
526 virtual HRESULT SetMediaType(const CMediaType *);
527
528 // check that the connection is ok before verifying it
529 // can be overridden eg to check what interfaces will be supported.
530 virtual HRESULT CheckConnect(IPin *);
531
532 // Set and release resources required for a connection
533 virtual HRESULT BreakConnect();
534 virtual HRESULT CompleteConnect(IPin *pReceivePin);
535
536 // returns the preferred formats for a pin
537 virtual HRESULT GetMediaType(int iPosition, __inout CMediaType *pMediaType);
538
539 // access to NewSegment values
540 REFERENCE_TIME CurrentStopTime() {
541 return m_tStop;
542 }
543 REFERENCE_TIME CurrentStartTime() {
544 return m_tStart;
545 }
546 double CurrentRate() {
547 return m_dRate;
548 }
549
550 // Access name
551 LPWSTR Name() { return m_pName; };
552
553 // Can reconnectwhen active?
554 void SetReconnectWhenActive(bool bCanReconnect)
555 {
556 m_bCanReconnectWhenActive = bCanReconnect;
557 }
558
559 bool CanReconnectWhenActive()
560 {
561 return m_bCanReconnectWhenActive;
562 }
563
564protected:
565 STDMETHODIMP DisconnectInternal();
566};
567
568
569//=====================================================================
570//=====================================================================
571// Defines CEnumPins
572//
573// Pin enumerator class that works by calling CBaseFilter. This interface
574// is provided by CBaseFilter::EnumPins and calls GetPinCount() and
575// GetPin() to enumerate existing pins. Needs to be a separate object so
576// that it can be cloned (creating an existing object at the same
577// position in the enumeration)
578//
579//=====================================================================
580//=====================================================================
581
582class CEnumPins : public IEnumPins // The interface we support
583{
584 int m_Position; // Current ordinal position
585 int m_PinCount; // Number of pins available
586 CBaseFilter *m_pFilter; // The filter who owns us
587 LONG m_Version; // Pin version information
588 LONG m_cRef;
589
590 typedef CGenericList<CBasePin> CPinList;
591
592 CPinList m_PinCache; // These pointers have not been AddRef'ed and
593 // so they should not be dereferenced. They are
594 // merely kept to ID which pins have been enumerated.
595
596#ifdef DEBUG
597 DWORD m_dwCookie;
598#endif
599
600 /* If while we are retrieving a pin for example from the filter an error
601 occurs we assume that our internal state is stale with respect to the
602 filter (someone may have deleted all the pins). We can check before
603 starting whether or not the operation is likely to fail by asking the
604 filter what it's current version number is. If the filter has not
605 overriden the GetPinVersion method then this will always match */
606
607 BOOL AreWeOutOfSync() {
608 return (m_pFilter->GetPinVersion() == m_Version ? FALSE : TRUE);
609 };
610
611 /* This method performs the same operations as Reset, except is does not clear
612 the cache of pins already enumerated. */
613
614 STDMETHODIMP Refresh();
615
616public:
617
618 CEnumPins(
619 __in CBaseFilter *pFilter,
620 __in_opt CEnumPins *pEnumPins);
621
622 virtual ~CEnumPins();
623
624 // IUnknown
625 STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv);
626 STDMETHODIMP_(ULONG) AddRef();
627 STDMETHODIMP_(ULONG) Release();
628
629 // IEnumPins
630 STDMETHODIMP Next(
631 ULONG cPins, // place this many pins...
632 __out_ecount(cPins) IPin ** ppPins, // ...in this array of IPin*
633 __out_opt ULONG * pcFetched // actual count passed returned here
634 );
635
636 STDMETHODIMP Skip(ULONG cPins);
637 STDMETHODIMP Reset();
638 STDMETHODIMP Clone(__deref_out IEnumPins **ppEnum);
639
640
641};
642
643
644//=====================================================================
645//=====================================================================
646// Defines CEnumMediaTypes
647//
648// Enumerates the preferred formats for input and output pins
649//=====================================================================
650//=====================================================================
651
652class CEnumMediaTypes : public IEnumMediaTypes // The interface we support
653{
654 int m_Position; // Current ordinal position
655 CBasePin *m_pPin; // The pin who owns us
656 LONG m_Version; // Media type version value
657 LONG m_cRef;
658#ifdef DEBUG
659 DWORD m_dwCookie;
660#endif
661
662 /* The media types a filter supports can be quite dynamic so we add to
663 the general IEnumXXXX interface the ability to be signaled when they
664 change via an event handle the connected filter supplies. Until the
665 Reset method is called after the state changes all further calls to
666 the enumerator (except Reset) will return E_UNEXPECTED error code */
667
668 BOOL AreWeOutOfSync() {
669 return (m_pPin->GetMediaTypeVersion() == m_Version ? FALSE : TRUE);
670 };
671
672public:
673
674 CEnumMediaTypes(
675 __in CBasePin *pPin,
676 __in_opt CEnumMediaTypes *pEnumMediaTypes);
677
678 virtual ~CEnumMediaTypes();
679
680 // IUnknown
681 STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv);
682 STDMETHODIMP_(ULONG) AddRef();
683 STDMETHODIMP_(ULONG) Release();
684
685 // IEnumMediaTypes
686 STDMETHODIMP Next(
687 ULONG cMediaTypes, // place this many pins...
688 __out_ecount(cMediaTypes) AM_MEDIA_TYPE ** ppMediaTypes, // ...in this array
689 __out_opt ULONG * pcFetched // actual count passed
690 );
691
692 STDMETHODIMP Skip(ULONG cMediaTypes);
693 STDMETHODIMP Reset();
694 STDMETHODIMP Clone(__deref_out IEnumMediaTypes **ppEnum);
695};
696
697
698
699
700//=====================================================================
701//=====================================================================
702// Defines CBaseOutputPin
703//
704// class derived from CBasePin that can pass buffers to a connected pin
705// that supports IMemInputPin. Supports IPin.
706//
707// Derive your output pin from this.
708//
709//=====================================================================
710//=====================================================================
711
712class AM_NOVTABLE CBaseOutputPin : public CBasePin
713{
714
715protected:
716
717 IMemAllocator *m_pAllocator;
718 IMemInputPin *m_pInputPin; // interface on the downstreaminput pin
719 // set up in CheckConnect when we connect.
720
721public:
722
723 CBaseOutputPin(
724 __in_opt LPCTSTR pObjectName,
725 __in CBaseFilter *pFilter,
726 __in CCritSec *pLock,
727 __inout HRESULT *phr,
728 __in_opt LPCWSTR pName);
729#ifdef UNICODE
730 CBaseOutputPin(
731 __in_opt LPCSTR pObjectName,
732 __in CBaseFilter *pFilter,
733 __in CCritSec *pLock,
734 __inout HRESULT *phr,
735 __in_opt LPCWSTR pName);
736#endif
737 // override CompleteConnect() so we can negotiate an allocator
738 virtual HRESULT CompleteConnect(IPin *pReceivePin);
739
740 // negotiate the allocator and its buffer size/count and other properties
741 // Calls DecideBufferSize to set properties
742 virtual HRESULT DecideAllocator(IMemInputPin * pPin, __deref_out IMemAllocator ** pAlloc);
743
744 // override this to set the buffer size and count. Return an error
745 // if the size/count is not to your liking.
746 // The allocator properties passed in are those requested by the
747 // input pin - use eg the alignment and prefix members if you have
748 // no preference on these.
749 virtual HRESULT DecideBufferSize(
750 IMemAllocator * pAlloc,
751 __inout ALLOCATOR_PROPERTIES * ppropInputRequest
752 ) PURE;
753
754 // returns an empty sample buffer from the allocator
755 virtual HRESULT GetDeliveryBuffer(__deref_out IMediaSample ** ppSample,
756 __in_opt REFERENCE_TIME * pStartTime,
757 __in_opt REFERENCE_TIME * pEndTime,
758 DWORD dwFlags);
759
760 // deliver a filled-in sample to the connected input pin
761 // note - you need to release it after calling this. The receiving
762 // pin will addref the sample if it needs to hold it beyond the
763 // call.
764 virtual HRESULT Deliver(IMediaSample *);
765
766 // override this to control the connection
767 virtual HRESULT InitAllocator(__deref_out IMemAllocator **ppAlloc);
768 HRESULT CheckConnect(IPin *pPin);
769 HRESULT BreakConnect();
770
771 // override to call Commit and Decommit
772 HRESULT Active(void);
773 HRESULT Inactive(void);
774
775 // we have a default handling of EndOfStream which is to return
776 // an error, since this should be called on input pins only
777 STDMETHODIMP EndOfStream(void);
778
779 // called from elsewhere in our filter to pass EOS downstream to
780 // our connected input pin
781 virtual HRESULT DeliverEndOfStream(void);
782
783 // same for Begin/EndFlush - we handle Begin/EndFlush since it
784 // is an error on an output pin, and we have Deliver methods to
785 // call the methods on the connected pin
786 STDMETHODIMP BeginFlush(void);
787 STDMETHODIMP EndFlush(void);
788 virtual HRESULT DeliverBeginFlush(void);
789 virtual HRESULT DeliverEndFlush(void);
790
791 // deliver NewSegment to connected pin - you will need to
792 // override this if you queue any data in your output pin.
793 virtual HRESULT DeliverNewSegment(
794 REFERENCE_TIME tStart,
795 REFERENCE_TIME tStop,
796 double dRate);
797
798 //================================================================================
799 // IQualityControl methods
800 //================================================================================
801
802 // All inherited from CBasePin and not overridden here.
803 // STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
804 // STDMETHODIMP SetSink(IQualityControl * piqc);
805};
806
807
808//=====================================================================
809//=====================================================================
810// Defines CBaseInputPin
811//
812// derive your standard input pin from this.
813// you need to supply GetMediaType and CheckConnect etc (see CBasePin),
814// and you need to supply Receive to do something more useful.
815//
816//=====================================================================
817//=====================================================================
818
819class AM_NOVTABLE CBaseInputPin : public CBasePin,
820 public IMemInputPin
821{
822
823protected:
824
825 IMemAllocator *m_pAllocator; // Default memory allocator
826
827 // allocator is read-only, so received samples
828 // cannot be modified (probably only relevant to in-place
829 // transforms
830 BYTE m_bReadOnly;
831
832 // in flushing state (between BeginFlush and EndFlush)
833 // if TRUE, all Receives are returned with S_FALSE
834 BYTE m_bFlushing;
835
836 // Sample properties - initalized in Receive
837 AM_SAMPLE2_PROPERTIES m_SampleProps;
838
839public:
840
841 CBaseInputPin(
842 __in_opt LPCTSTR pObjectName,
843 __in CBaseFilter *pFilter,
844 __in CCritSec *pLock,
845 __inout HRESULT *phr,
846 __in_opt LPCWSTR pName);
847#ifdef UNICODE
848 CBaseInputPin(
849 __in_opt LPCSTR pObjectName,
850 __in CBaseFilter *pFilter,
851 __in CCritSec *pLock,
852 __inout HRESULT *phr,
853 __in_opt LPCWSTR pName);
854#endif
855 virtual ~CBaseInputPin();
856
857 DECLARE_IUNKNOWN
858
859 // override this to publicise our interfaces
860 STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv);
861
862 // return the allocator interface that this input pin
863 // would like the output pin to use
864 STDMETHODIMP GetAllocator(__deref_out IMemAllocator ** ppAllocator);
865
866 // tell the input pin which allocator the output pin is actually
867 // going to use.
868 STDMETHODIMP NotifyAllocator(
869 IMemAllocator * pAllocator,
870 BOOL bReadOnly);
871
872 // do something with this media sample
873 STDMETHODIMP Receive(IMediaSample *pSample);
874
875 // do something with these media samples
876 STDMETHODIMP ReceiveMultiple (
877 __in_ecount(nSamples) IMediaSample **pSamples,
878 long nSamples,
879 __out long *nSamplesProcessed);
880
881 // See if Receive() blocks
882 STDMETHODIMP ReceiveCanBlock();
883
884 // Default handling for BeginFlush - call at the beginning
885 // of your implementation (makes sure that all Receive calls
886 // fail). After calling this, you need to free any queued data
887 // and then call downstream.
888 STDMETHODIMP BeginFlush(void);
889
890 // default handling for EndFlush - call at end of your implementation
891 // - before calling this, ensure that there is no queued data and no thread
892 // pushing any more without a further receive, then call downstream,
893 // then call this method to clear the m_bFlushing flag and re-enable
894 // receives
895 STDMETHODIMP EndFlush(void);
896
897 // this method is optional (can return E_NOTIMPL).
898 // default implementation returns E_NOTIMPL. Override if you have
899 // specific alignment or prefix needs, but could use an upstream
900 // allocator
901 STDMETHODIMP GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps);
902
903 // Release the pin's allocator.
904 HRESULT BreakConnect();
905
906 // helper method to check the read-only flag
907 BOOL IsReadOnly() {
908 return m_bReadOnly;
909 };
910
911 // helper method to see if we are flushing
912 BOOL IsFlushing() {
913 return m_bFlushing;
914 };
915
916 // Override this for checking whether it's OK to process samples
917 // Also call this from EndOfStream.
918 virtual HRESULT CheckStreaming();
919
920 // Pass a Quality notification on to the appropriate sink
921 HRESULT PassNotify(Quality& q);
922
923
924 //================================================================================
925 // IQualityControl methods (from CBasePin)
926 //================================================================================
927
928 STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
929
930 // no need to override:
931 // STDMETHODIMP SetSink(IQualityControl * piqc);
932
933
934 // switch the pin to inactive state - may already be inactive
935 virtual HRESULT Inactive(void);
936
937 // Return sample properties pointer
938 AM_SAMPLE2_PROPERTIES * SampleProps() {
939 ASSERT(m_SampleProps.cbData != 0);
940 return &m_SampleProps;
941 }
942
943};
944
945///////////////////////////////////////////////////////////////////////////
946// CDynamicOutputPin
947//
948
949class CDynamicOutputPin : public CBaseOutputPin,
950 public IPinFlowControl
951{
952public:
953#ifdef UNICODE
954 CDynamicOutputPin(
955 __in_opt LPCSTR pObjectName,
956 __in CBaseFilter *pFilter,
957 __in CCritSec *pLock,
958 __inout HRESULT *phr,
959 __in_opt LPCWSTR pName);
960#endif
961
962 CDynamicOutputPin(
963 __in_opt LPCTSTR pObjectName,
964 __in CBaseFilter *pFilter,
965 __in CCritSec *pLock,
966 __inout HRESULT *phr,
967 __in_opt LPCWSTR pName);
968
969 ~CDynamicOutputPin();
970
971 // IUnknown Methods
972 DECLARE_IUNKNOWN
973 STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv);
974
975 // IPin Methods
976 STDMETHODIMP Disconnect(void);
977
978 // IPinFlowControl Methods
979 STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent);
980
981 // Set graph config info
982 void SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent);
983
984 #ifdef DEBUG
985 virtual HRESULT Deliver(IMediaSample *pSample);
986 virtual HRESULT DeliverEndOfStream(void);
987 virtual HRESULT DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
988 #endif // DEBUG
989
990 HRESULT DeliverBeginFlush(void);
991 HRESULT DeliverEndFlush(void);
992
993 HRESULT Inactive(void);
994 HRESULT Active(void);
995 virtual HRESULT CompleteConnect(IPin *pReceivePin);
996
997 virtual HRESULT StartUsingOutputPin(void);
998 virtual void StopUsingOutputPin(void);
999 virtual bool StreamingThreadUsingOutputPin(void);
1000
1001 HRESULT ChangeOutputFormat
1002 (
1003 const AM_MEDIA_TYPE *pmt,
1004 REFERENCE_TIME tSegmentStart,
1005 REFERENCE_TIME tSegmentStop,
1006 double dSegmentRate
1007 );
1008 HRESULT ChangeMediaType(const CMediaType *pmt);
1009 HRESULT DynamicReconnect(const CMediaType *pmt);
1010
1011protected:
1012 HRESULT SynchronousBlockOutputPin(void);
1013 HRESULT AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent);
1014 HRESULT UnblockOutputPin(void);
1015
1016 void BlockOutputPin(void);
1017 void ResetBlockState(void);
1018
1019 static HRESULT WaitEvent(HANDLE hEvent);
1020
1021 enum BLOCK_STATE
1022 {
1023 NOT_BLOCKED,
1024 PENDING,
1025 BLOCKED
1026 };
1027
1028 // This lock should be held when the following class members are
1029 // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState,
1030 // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers.
1031 CCritSec m_BlockStateLock;
1032
1033 // This event should be signaled when the output pin is
1034 // not blocked. This is a manual reset event. For more
1035 // information on events, see the documentation for
1036 // CreateEvent() in the Windows SDK.
1037 HANDLE m_hUnblockOutputPinEvent;
1038
1039 // This event will be signaled when block operation succeedes or
1040 // when the user cancels the block operation. The block operation
1041 // can be canceled by calling IPinFlowControl2::Block( 0, NULL )
1042 // while the block operation is pending.
1043 HANDLE m_hNotifyCallerPinBlockedEvent;
1044
1045 // The state of the current block operation.
1046 BLOCK_STATE m_BlockState;
1047
1048 // The ID of the thread which last called IPinFlowControl::Block().
1049 // For more information on thread IDs, see the documentation for
1050 // GetCurrentThreadID() in the Windows SDK.
1051 DWORD m_dwBlockCallerThreadID;
1052
1053 // The number of times StartUsingOutputPin() has been sucessfully
1054 // called and a corresponding call to StopUsingOutputPin() has not
1055 // been made. When this variable is greater than 0, the streaming
1056 // thread is calling IPin::NewSegment(), IPin::EndOfStream(),
1057 // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple(). The
1058 // streaming thread could also be calling: DynamicReconnect(),
1059 // ChangeMediaType() or ChangeOutputFormat(). The output pin cannot
1060 // be blocked while the output pin is being used.
1061 DWORD m_dwNumOutstandingOutputPinUsers;
1062
1063 // This event should be set when the IMediaFilter::Stop() is called.
1064 // This is a manual reset event. It is also set when the output pin
1065 // delivers a flush to the connected input pin.
1066 HANDLE m_hStopEvent;
1067 IGraphConfig* m_pGraphConfig;
1068
1069 // TRUE if the output pin's allocator's samples are read only.
1070 // Otherwise FALSE. For more information, see the documentation
1071 // for IMemInputPin::NotifyAllocator().
1072 BOOL m_bPinUsesReadOnlyAllocator;
1073
1074private:
1075 HRESULT Initialize(void);
1076 HRESULT ChangeMediaTypeHelper(const CMediaType *pmt);
1077
1078 #ifdef DEBUG
1079 void AssertValid(void);
1080 #endif // DEBUG
1081};
1082
1083class CAutoUsingOutputPin
1084{
1085public:
1086 CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr );
1087 ~CAutoUsingOutputPin();
1088
1089private:
1090 CDynamicOutputPin* m_pOutputPin;
1091};
1092
1093inline CAutoUsingOutputPin::CAutoUsingOutputPin( __in CDynamicOutputPin* pOutputPin, __inout HRESULT* phr ) :
1094 m_pOutputPin(NULL)
1095{
1096 // The caller should always pass in valid pointers.
1097 ASSERT( NULL != pOutputPin );
1098 ASSERT( NULL != phr );
1099
1100 // Make sure the user initialized phr.
1101 ASSERT( S_OK == *phr );
1102
1103 HRESULT hr = pOutputPin->StartUsingOutputPin();
1104 if( FAILED( hr ) )
1105 {
1106 *phr = hr;
1107 return;
1108 }
1109
1110 m_pOutputPin = pOutputPin;
1111}
1112
1113inline CAutoUsingOutputPin::~CAutoUsingOutputPin()
1114{
1115 if( NULL != m_pOutputPin )
1116 {
1117 m_pOutputPin->StopUsingOutputPin();
1118 }
1119}
1120
1121#ifdef DEBUG
1122
1123inline HRESULT CDynamicOutputPin::Deliver(IMediaSample *pSample)
1124{
1125 // The caller should call StartUsingOutputPin() before calling this
1126 // method.
1127 ASSERT(StreamingThreadUsingOutputPin());
1128
1129 return CBaseOutputPin::Deliver(pSample);
1130}
1131
1132inline HRESULT CDynamicOutputPin::DeliverEndOfStream(void)
1133{
1134 // The caller should call StartUsingOutputPin() before calling this
1135 // method.
1136 ASSERT( StreamingThreadUsingOutputPin() );
1137
1138 return CBaseOutputPin::DeliverEndOfStream();
1139}
1140
1141inline HRESULT CDynamicOutputPin::DeliverNewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1142{
1143 // The caller should call StartUsingOutputPin() before calling this
1144 // method.
1145 ASSERT(StreamingThreadUsingOutputPin());
1146
1147 return CBaseOutputPin::DeliverNewSegment(tStart, tStop, dRate);
1148}
1149
1150#endif // DEBUG
1151
1152//=====================================================================
1153//=====================================================================
1154// Memory allocators
1155//
1156// the shared memory transport between pins requires the input pin
1157// to provide a memory allocator that can provide sample objects. A
1158// sample object supports the IMediaSample interface.
1159//
1160// CBaseAllocator handles the management of free and busy samples. It
1161// allocates CMediaSample objects. CBaseAllocator is an abstract class:
1162// in particular it has no method of initializing the list of free
1163// samples. CMemAllocator is derived from CBaseAllocator and initializes
1164// the list of samples using memory from the standard IMalloc interface.
1165//
1166// If you want your buffers to live in some special area of memory,
1167// derive your allocator object from CBaseAllocator. If you derive your
1168// IMemInputPin interface object from CBaseMemInputPin, you will get
1169// CMemAllocator-based allocation etc for free and will just need to
1170// supply the Receive handling, and media type / format negotiation.
1171//=====================================================================
1172//=====================================================================
1173
1174
1175//=====================================================================
1176//=====================================================================
1177// Defines CMediaSample
1178//
1179// an object of this class supports IMediaSample and represents a buffer
1180// for media data with some associated properties. Releasing it returns
1181// it to a freelist managed by a CBaseAllocator derived object.
1182//=====================================================================
1183//=====================================================================
1184
1185class CMediaSample : public IMediaSample2 // The interface we support
1186{
1187
1188protected:
1189
1190 friend class CBaseAllocator;
1191
1192 /* Values for dwFlags - these are used for backward compatiblity
1193 only now - use AM_SAMPLE_xxx
1194 */
1195 enum { Sample_SyncPoint = 0x01, /* Is this a sync point */
1196 Sample_Preroll = 0x02, /* Is this a preroll sample */
1197 Sample_Discontinuity = 0x04, /* Set if start of new segment */
1198 Sample_TypeChanged = 0x08, /* Has the type changed */
1199 Sample_TimeValid = 0x10, /* Set if time is valid */
1200 Sample_MediaTimeValid = 0x20, /* Is the media time valid */
1201 Sample_TimeDiscontinuity = 0x40, /* Time discontinuity */
1202 Sample_StopValid = 0x100, /* Stop time valid */
1203 Sample_ValidFlags = 0x1FF
1204 };
1205
1206 /* Properties, the media sample class can be a container for a format
1207 change in which case we take a copy of a type through the SetMediaType
1208 interface function and then return it when GetMediaType is called. As
1209 we do no internal processing on it we leave it as a pointer */
1210
1211 DWORD m_dwFlags; /* Flags for this sample */
1212 /* Type specific flags are packed
1213 into the top word
1214 */
1215 DWORD m_dwTypeSpecificFlags; /* Media type specific flags */
1216 __field_ecount_opt(m_cbBuffer) LPBYTE m_pBuffer; /* Pointer to the complete buffer */
1217 LONG m_lActual; /* Length of data in this sample */
1218 LONG m_cbBuffer; /* Size of the buffer */
1219 CBaseAllocator *m_pAllocator; /* The allocator who owns us */
1220 CMediaSample *m_pNext; /* Chaining in free list */
1221 REFERENCE_TIME m_Start; /* Start sample time */
1222 REFERENCE_TIME m_End; /* End sample time */
1223 LONGLONG m_MediaStart; /* Real media start position */
1224 LONG m_MediaEnd; /* A difference to get the end */
1225 AM_MEDIA_TYPE *m_pMediaType; /* Media type change data */
1226 DWORD m_dwStreamId; /* Stream id */
1227public:
1228 LONG m_cRef; /* Reference count */
1229
1230
1231public:
1232
1233 CMediaSample(
1234 __in_opt LPCTSTR pName,
1235 __in_opt CBaseAllocator *pAllocator,
1236 __inout_opt HRESULT *phr,
1237 __in_bcount_opt(length) LPBYTE pBuffer = NULL,
1238 LONG length = 0);
1239#ifdef UNICODE
1240 CMediaSample(
1241 __in_opt LPCSTR pName,
1242 __in_opt CBaseAllocator *pAllocator,
1243 __inout_opt HRESULT *phr,
1244 __in_bcount_opt(length) LPBYTE pBuffer = NULL,
1245 LONG length = 0);
1246#endif
1247
1248 virtual ~CMediaSample();
1249
1250 /* Note the media sample does not delegate to its owner */
1251
1252 STDMETHODIMP QueryInterface(REFIID riid, __deref_out void **ppv);
1253 STDMETHODIMP_(ULONG) AddRef();
1254 STDMETHODIMP_(ULONG) Release();
1255
1256 // set the buffer pointer and length. Used by allocators that
1257 // want variable sized pointers or pointers into already-read data.
1258 // This is only available through a CMediaSample* not an IMediaSample*
1259 // and so cannot be changed by clients.
1260 HRESULT SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes);
1261
1262 // Get me a read/write pointer to this buffer's memory.
1263 STDMETHODIMP GetPointer(__deref_out BYTE ** ppBuffer);
1264
1265 STDMETHODIMP_(LONG) GetSize(void);
1266
1267 // get the stream time at which this sample should start and finish.
1268 STDMETHODIMP GetTime(
1269 __out REFERENCE_TIME * pTimeStart, // put time here
1270 __out REFERENCE_TIME * pTimeEnd
1271 );
1272
1273 // Set the stream time at which this sample should start and finish.
1274 STDMETHODIMP SetTime(
1275 __in_opt REFERENCE_TIME * pTimeStart, // put time here
1276 __in_opt REFERENCE_TIME * pTimeEnd
1277 );
1278 STDMETHODIMP IsSyncPoint(void);
1279 STDMETHODIMP SetSyncPoint(BOOL bIsSyncPoint);
1280 STDMETHODIMP IsPreroll(void);
1281 STDMETHODIMP SetPreroll(BOOL bIsPreroll);
1282
1283 STDMETHODIMP_(LONG) GetActualDataLength(void);
1284 STDMETHODIMP SetActualDataLength(LONG lActual);
1285
1286 // these allow for limited format changes in band
1287
1288 STDMETHODIMP GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType);
1289 STDMETHODIMP SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType);
1290
1291 // returns S_OK if there is a discontinuity in the data (this same is
1292 // not a continuation of the previous stream of data
1293 // - there has been a seek).
1294 STDMETHODIMP IsDiscontinuity(void);
1295 // set the discontinuity property - TRUE if this sample is not a
1296 // continuation, but a new sample after a seek.
1297 STDMETHODIMP SetDiscontinuity(BOOL bDiscontinuity);
1298
1299 // get the media times for this sample
1300 STDMETHODIMP GetMediaTime(
1301 __out LONGLONG * pTimeStart,
1302 __out LONGLONG * pTimeEnd
1303 );
1304
1305 // Set the media times for this sample
1306 STDMETHODIMP SetMediaTime(
1307 __in_opt LONGLONG * pTimeStart,
1308 __in_opt LONGLONG * pTimeEnd
1309 );
1310
1311 // Set and get properties (IMediaSample2)
1312 STDMETHODIMP GetProperties(
1313 DWORD cbProperties,
1314 __out_bcount(cbProperties) BYTE * pbProperties
1315 );
1316
1317 STDMETHODIMP SetProperties(
1318 DWORD cbProperties,
1319 __in_bcount(cbProperties) const BYTE * pbProperties
1320 );
1321};
1322
1323
1324//=====================================================================
1325//=====================================================================
1326// Defines CBaseAllocator
1327//
1328// Abstract base class that manages a list of media samples
1329//
1330// This class provides support for getting buffers from the free list,
1331// including handling of commit and (asynchronous) decommit.
1332//
1333// Derive from this class and override the Alloc and Free functions to
1334// allocate your CMediaSample (or derived) objects and add them to the
1335// free list, preparing them as necessary.
1336//=====================================================================
1337//=====================================================================
1338
1339class AM_NOVTABLE CBaseAllocator : public CUnknown,// A non delegating IUnknown
1340 public IMemAllocatorCallbackTemp, // The interface we support
1341 public CCritSec // Provides object locking
1342{
1343 class CSampleList;
1344 friend class CSampleList;
1345
1346 /* Trick to get at protected member in CMediaSample */
1347 static CMediaSample * &NextSample(__in CMediaSample *pSample)
1348 {
1349 return pSample->m_pNext;
1350 };
1351
1352 /* Mini list class for the free list */
1353 class CSampleList
1354 {
1355 public:
1356 CSampleList() : m_List(NULL), m_nOnList(0) {};
1357#ifdef DEBUG
1358 ~CSampleList()
1359 {
1360 ASSERT(m_nOnList == 0);
1361 };
1362#endif
1363 CMediaSample *Head() const { return m_List; };
1364 CMediaSample *Next(__in CMediaSample *pSample) const { return CBaseAllocator::NextSample(pSample); };
1365 int GetCount() const { return m_nOnList; };
1366 void Add(__inout CMediaSample *pSample)
1367 {
1368 ASSERT(pSample != NULL);
1369 CBaseAllocator::NextSample(pSample) = m_List;
1370 m_List = pSample;
1371 m_nOnList++;
1372 };
1373 CMediaSample *RemoveHead()
1374 {
1375 CMediaSample *pSample = m_List;
1376 if (pSample != NULL) {
1377 m_List = CBaseAllocator::NextSample(m_List);
1378 m_nOnList--;
1379 }
1380 return pSample;
1381 };
1382 void Remove(__inout CMediaSample *pSample);
1383
1384 public:
1385 CMediaSample *m_List;
1386 int m_nOnList;
1387 };
1388protected:
1389
1390 CSampleList m_lFree; // Free list
1391
1392 /* Note to overriders of CBaseAllocator.
1393
1394 We use a lazy signalling mechanism for waiting for samples.
1395 This means we don't call the OS if no waits occur.
1396
1397 In order to implement this:
1398
1399 1. When a new sample is added to m_lFree call NotifySample() which
1400 calls ReleaseSemaphore on m_hSem with a count of m_lWaiting and
1401 sets m_lWaiting to 0.
1402 This must all be done holding the allocator's critical section.
1403
1404 2. When waiting for a sample call SetWaiting() which increments
1405 m_lWaiting BEFORE leaving the allocator's critical section.
1406
1407 3. Actually wait by calling WaitForSingleObject(m_hSem, INFINITE)
1408 having left the allocator's critical section. The effect of
1409 this is to remove 1 from the semaphore's count. You MUST call
1410 this once having incremented m_lWaiting.
1411
1412 The following are then true when the critical section is not held :
1413 (let nWaiting = number about to wait or waiting)
1414
1415 (1) if (m_lFree.GetCount() != 0) then (m_lWaiting == 0)
1416 (2) m_lWaiting + Semaphore count == nWaiting
1417
1418 We would deadlock if
1419 nWaiting != 0 &&
1420 m_lFree.GetCount() != 0 &&
1421 Semaphore count == 0
1422
1423 But from (1) if m_lFree.GetCount() != 0 then m_lWaiting == 0 so
1424 from (2) Semaphore count == nWaiting (which is non-0) so the
1425 deadlock can't happen.
1426 */
1427
1428 HANDLE m_hSem; // For signalling
1429 long m_lWaiting; // Waiting for a free element
1430 long m_lCount; // how many buffers we have agreed to provide
1431 long m_lAllocated; // how many buffers are currently allocated
1432 long m_lSize; // agreed size of each buffer
1433 long m_lAlignment; // agreed alignment
1434 long m_lPrefix; // agreed prefix (preceeds GetPointer() value)
1435 BOOL m_bChanged; // Have the buffer requirements changed
1436
1437 // if true, we are decommitted and can't allocate memory
1438 BOOL m_bCommitted;
1439 // if true, the decommit has happened, but we haven't called Free yet
1440 // as there are still outstanding buffers
1441 BOOL m_bDecommitInProgress;
1442
1443 // Notification interface
1444 IMemAllocatorNotifyCallbackTemp *m_pNotify;
1445
1446 BOOL m_fEnableReleaseCallback;
1447
1448 // called to decommit the memory when the last buffer is freed
1449 // pure virtual - need to override this
1450 virtual void Free(void) PURE;
1451
1452 // override to allocate the memory when commit called
1453 virtual HRESULT Alloc(void);
1454
1455public:
1456
1457 CBaseAllocator(
1458 __in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *,
1459 BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE);
1460#ifdef UNICODE
1461 CBaseAllocator(
1462 __in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *,
1463 BOOL bEvent = TRUE, BOOL fEnableReleaseCallback = FALSE);
1464#endif
1465 virtual ~CBaseAllocator();
1466
1467 DECLARE_IUNKNOWN
1468
1469 // override this to publicise our interfaces
1470 STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv);
1471
1472 STDMETHODIMP SetProperties(
1473 __in ALLOCATOR_PROPERTIES* pRequest,
1474 __out ALLOCATOR_PROPERTIES* pActual);
1475
1476 // return the properties actually being used on this allocator
1477 STDMETHODIMP GetProperties(
1478 __out ALLOCATOR_PROPERTIES* pProps);
1479
1480 // override Commit to allocate memory. We handle the GetBuffer
1481 //state changes
1482 STDMETHODIMP Commit();
1483
1484 // override this to handle the memory freeing. We handle any outstanding
1485 // GetBuffer calls
1486 STDMETHODIMP Decommit();
1487
1488 // get container for a sample. Blocking, synchronous call to get the
1489 // next free buffer (as represented by an IMediaSample interface).
1490 // on return, the time etc properties will be invalid, but the buffer
1491 // pointer and size will be correct. The two time parameters are
1492 // optional and either may be NULL, they may alternatively be set to
1493 // the start and end times the sample will have attached to it
1494 // bPrevFramesSkipped is not used (used only by the video renderer's
1495 // allocator where it affects quality management in direct draw).
1496
1497 STDMETHODIMP GetBuffer(__deref_out IMediaSample **ppBuffer,
1498 __in_opt REFERENCE_TIME * pStartTime,
1499 __in_opt REFERENCE_TIME * pEndTime,
1500 DWORD dwFlags);
1501
1502 // final release of a CMediaSample will call this
1503 STDMETHODIMP ReleaseBuffer(IMediaSample *pBuffer);
1504 // obsolete:: virtual void PutOnFreeList(CMediaSample * pSample);
1505
1506 STDMETHODIMP SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify);
1507
1508 STDMETHODIMP GetFreeCount(__out LONG *plBuffersFree);
1509
1510 // Notify that a sample is available
1511 void NotifySample();
1512
1513 // Notify that we're waiting for a sample
1514 void SetWaiting() { m_lWaiting++; };
1515};
1516
1517
1518//=====================================================================
1519//=====================================================================
1520// Defines CMemAllocator
1521//
1522// this is an allocator based on CBaseAllocator that allocates sample
1523// buffers in main memory (from 'new'). You must call SetProperties
1524// before calling Commit.
1525//
1526// we don't free the memory when going into Decommit state. The simplest
1527// way to implement this without complicating CBaseAllocator is to
1528// have a Free() function, called to go into decommit state, that does
1529// nothing and a ReallyFree function called from our destructor that
1530// actually frees the memory.
1531//=====================================================================
1532//=====================================================================
1533
1534// Make me one from quartz.dll
1535STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator);
1536
1537class CMemAllocator : public CBaseAllocator
1538{
1539
1540protected:
1541
1542 LPBYTE m_pBuffer; // combined memory for all buffers
1543
1544 // override to free the memory when decommit completes
1545 // - we actually do nothing, and save the memory until deletion.
1546 void Free(void);
1547
1548 // called from the destructor (and from Alloc if changing size/count) to
1549 // actually free up the memory
1550 void ReallyFree(void);
1551
1552 // overriden to allocate the memory when commit called
1553 HRESULT Alloc(void);
1554
1555public:
1556 /* This goes in the factory template table to create new instances */
1557 static CUnknown *CreateInstance(__inout_opt LPUNKNOWN, __inout HRESULT *);
1558
1559 STDMETHODIMP SetProperties(
1560 __in ALLOCATOR_PROPERTIES* pRequest,
1561 __out ALLOCATOR_PROPERTIES* pActual);
1562
1563 CMemAllocator(__in_opt LPCTSTR , __inout_opt LPUNKNOWN, __inout HRESULT *);
1564#ifdef UNICODE
1565 CMemAllocator(__in_opt LPCSTR , __inout_opt LPUNKNOWN, __inout HRESULT *);
1566#endif
1567 ~CMemAllocator();
1568};
1569
1570// helper used by IAMovieSetup implementation
1571STDAPI
1572AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata
1573 , IFilterMapper * pIFM
1574 , BOOL bRegister );
1575
1576
1577///////////////////////////////////////////////////////////////////////////
1578// ------------------------------------------------------------------------
1579// ------------------------------------------------------------------------
1580// ------------------------------------------------------------------------
1581// ------------------------------------------------------------------------
1582///////////////////////////////////////////////////////////////////////////
1583
1584#endif /* __FILTER__ */
1585
1586
1587