~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/third_party/BaseClasses/amfilter.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//------------------------------------------------------------------------------
2
 
// File: AMFilter.cpp
3
 
//
4
 
// Desc: DirectShow base classes - implements class hierarchy for streams
5
 
//       architecture.
6
 
//
7
 
// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
8
 
//------------------------------------------------------------------------------
9
 
 
10
 
 
11
 
//=====================================================================
12
 
//=====================================================================
13
 
// The following classes are declared in this header:
14
 
//
15
 
//
16
 
// CBaseMediaFilter            Basic IMediaFilter support (abstract class)
17
 
// CBaseFilter                 Support for IBaseFilter (incl. IMediaFilter)
18
 
// CEnumPins                   Enumerate input and output pins
19
 
// CEnumMediaTypes             Enumerate the preferred pin formats
20
 
// CBasePin                    Abstract base class for IPin interface
21
 
//    CBaseOutputPin           Adds data provider member functions
22
 
//    CBaseInputPin            Implements IMemInputPin interface
23
 
// CMediaSample                Basic transport unit for IMemInputPin
24
 
// CBaseAllocator              General list guff for most allocators
25
 
//    CMemAllocator            Implements memory buffer allocation
26
 
//
27
 
//=====================================================================
28
 
//=====================================================================
29
 
 
30
 
#include <pjmedia-videodev/config.h>
31
 
 
32
 
#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
33
 
 
34
 
#include <streams.h>
35
 
#include <strsafe.h>
36
 
 
37
 
#ifdef DXMPERF
38
 
#include "dxmperf.h"
39
 
#endif // DXMPERF
40
 
 
41
 
 
42
 
//=====================================================================
43
 
// Helpers
44
 
//=====================================================================
45
 
STDAPI CreateMemoryAllocator(__deref_out IMemAllocator **ppAllocator)
46
 
{
47
 
    return CoCreateInstance(CLSID_MemoryAllocator,
48
 
                            0,
49
 
                            CLSCTX_INPROC_SERVER,
50
 
                            IID_IMemAllocator,
51
 
                            (void **)ppAllocator);
52
 
}
53
 
 
54
 
//  Put this one here rather than in ctlutil.cpp to avoid linking
55
 
//  anything brought in by ctlutil.cpp
56
 
STDAPI CreatePosPassThru(
57
 
    __in_opt LPUNKNOWN pAgg,
58
 
    BOOL bRenderer,
59
 
    IPin *pPin,
60
 
    __deref_out IUnknown **ppPassThru
61
 
)
62
 
{
63
 
    *ppPassThru = NULL;
64
 
    IUnknown *pUnkSeek;
65
 
    HRESULT hr = CoCreateInstance(CLSID_SeekingPassThru,
66
 
                                  pAgg,
67
 
                                  CLSCTX_INPROC_SERVER,
68
 
                                  IID_IUnknown,
69
 
                                  (void **)&pUnkSeek
70
 
                                 );
71
 
    if (FAILED(hr)) {
72
 
        return hr;
73
 
    }
74
 
 
75
 
    ISeekingPassThru *pPassThru;
76
 
    hr = pUnkSeek->QueryInterface(IID_ISeekingPassThru, (void**)&pPassThru);
77
 
    if (FAILED(hr)) {
78
 
        pUnkSeek->Release();
79
 
        return hr;
80
 
    }
81
 
    hr = pPassThru->Init(bRenderer, pPin);
82
 
    pPassThru->Release();
83
 
    if (FAILED(hr)) {
84
 
        pUnkSeek->Release();
85
 
        return hr;
86
 
    }
87
 
    *ppPassThru = pUnkSeek;
88
 
    return S_OK;
89
 
}
90
 
 
91
 
 
92
 
 
93
 
#define CONNECT_TRACE_LEVEL 3
94
 
 
95
 
//=====================================================================
96
 
//=====================================================================
97
 
// Implements CBaseMediaFilter
98
 
//=====================================================================
99
 
//=====================================================================
100
 
 
101
 
 
102
 
/* Constructor */
103
 
 
104
 
CBaseMediaFilter::CBaseMediaFilter(__in_opt LPCTSTR pName,
105
 
                   __inout_opt LPUNKNOWN    pUnk,
106
 
                   __in CCritSec *pLock,
107
 
                   REFCLSID clsid) :
108
 
    CUnknown(pName, pUnk),
109
 
    m_pLock(pLock),
110
 
    m_clsid(clsid),
111
 
    m_State(State_Stopped),
112
 
    m_pClock(NULL)
113
 
{
114
 
}
115
 
 
116
 
 
117
 
/* Destructor */
118
 
 
119
 
CBaseMediaFilter::~CBaseMediaFilter()
120
 
{
121
 
    // must be stopped, but can't call Stop here since
122
 
    // our critsec has been destroyed.
123
 
 
124
 
    /* Release any clock we were using */
125
 
 
126
 
    if (m_pClock) {
127
 
        m_pClock->Release();
128
 
        m_pClock = NULL;
129
 
    }
130
 
}
131
 
 
132
 
 
133
 
/* Override this to say what interfaces we support and where */
134
 
 
135
 
STDMETHODIMP
136
 
CBaseMediaFilter::NonDelegatingQueryInterface(
137
 
    REFIID riid,
138
 
    __deref_out void ** ppv)
139
 
{
140
 
    if (riid == IID_IMediaFilter) {
141
 
        return GetInterface((IMediaFilter *) this, ppv);
142
 
    } else if (riid == IID_IPersist) {
143
 
        return GetInterface((IPersist *) this, ppv);
144
 
    } else {
145
 
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
146
 
    }
147
 
}
148
 
 
149
 
/* Return the filter's clsid */
150
 
STDMETHODIMP
151
 
CBaseMediaFilter::GetClassID(__out CLSID *pClsID)
152
 
{
153
 
    CheckPointer(pClsID,E_POINTER);
154
 
    ValidateReadWritePtr(pClsID,sizeof(CLSID));
155
 
    *pClsID = m_clsid;
156
 
    return NOERROR;
157
 
}
158
 
 
159
 
/* Override this if your state changes are not done synchronously */
160
 
 
161
 
STDMETHODIMP
162
 
CBaseMediaFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State)
163
 
{
164
 
    UNREFERENCED_PARAMETER(dwMSecs);
165
 
    CheckPointer(State,E_POINTER);
166
 
    ValidateReadWritePtr(State,sizeof(FILTER_STATE));
167
 
 
168
 
    *State = m_State;
169
 
    return S_OK;
170
 
}
171
 
 
172
 
 
173
 
/* Set the clock we will use for synchronisation */
174
 
 
175
 
STDMETHODIMP
176
 
CBaseMediaFilter::SetSyncSource(__inout_opt IReferenceClock *pClock)
177
 
{
178
 
    CAutoLock cObjectLock(m_pLock);
179
 
 
180
 
    // Ensure the new one does not go away - even if the same as the old
181
 
    if (pClock) {
182
 
        pClock->AddRef();
183
 
    }
184
 
 
185
 
    // if we have a clock, release it
186
 
    if (m_pClock) {
187
 
        m_pClock->Release();
188
 
    }
189
 
 
190
 
    // Set the new reference clock (might be NULL)
191
 
    // Should we query it to ensure it is a clock?  Consider for a debug build.
192
 
    m_pClock = pClock;
193
 
 
194
 
    return NOERROR;
195
 
}
196
 
 
197
 
/* Return the clock we are using for synchronisation */
198
 
STDMETHODIMP
199
 
CBaseMediaFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock)
200
 
{
201
 
    CheckPointer(pClock,E_POINTER);
202
 
    ValidateReadWritePtr(pClock,sizeof(IReferenceClock *));
203
 
    CAutoLock cObjectLock(m_pLock);
204
 
 
205
 
    if (m_pClock) {
206
 
        // returning an interface... addref it...
207
 
        m_pClock->AddRef();
208
 
    }
209
 
    *pClock = (IReferenceClock*)m_pClock;
210
 
    return NOERROR;
211
 
}
212
 
 
213
 
 
214
 
/* Put the filter into a stopped state */
215
 
 
216
 
STDMETHODIMP
217
 
CBaseMediaFilter::Stop()
218
 
{
219
 
    CAutoLock cObjectLock(m_pLock);
220
 
 
221
 
    m_State = State_Stopped;
222
 
    return S_OK;
223
 
}
224
 
 
225
 
 
226
 
/* Put the filter into a paused state */
227
 
 
228
 
STDMETHODIMP
229
 
CBaseMediaFilter::Pause()
230
 
{
231
 
    CAutoLock cObjectLock(m_pLock);
232
 
 
233
 
    m_State = State_Paused;
234
 
    return S_OK;
235
 
}
236
 
 
237
 
 
238
 
// Put the filter into a running state.
239
 
 
240
 
// The time parameter is the offset to be added to the samples'
241
 
// stream time to get the reference time at which they should be presented.
242
 
//
243
 
// you can either add these two and compare it against the reference clock,
244
 
// or you can call CBaseMediaFilter::StreamTime and compare that against
245
 
// the sample timestamp.
246
 
 
247
 
STDMETHODIMP
248
 
CBaseMediaFilter::Run(REFERENCE_TIME tStart)
249
 
{
250
 
    CAutoLock cObjectLock(m_pLock);
251
 
 
252
 
    // remember the stream time offset
253
 
    m_tStart = tStart;
254
 
 
255
 
    if (m_State == State_Stopped){
256
 
        HRESULT hr = Pause();
257
 
 
258
 
        if (FAILED(hr)) {
259
 
            return hr;
260
 
        }
261
 
    }
262
 
    m_State = State_Running;
263
 
    return S_OK;
264
 
}
265
 
 
266
 
 
267
 
//
268
 
// return the current stream time - samples with start timestamps of this
269
 
// time or before should be rendered by now
270
 
HRESULT
271
 
CBaseMediaFilter::StreamTime(CRefTime& rtStream)
272
 
{
273
 
    // Caller must lock for synchronization
274
 
    // We can't grab the filter lock because we want to be able to call
275
 
    // this from worker threads without deadlocking
276
 
 
277
 
    if (m_pClock == NULL) {
278
 
        return VFW_E_NO_CLOCK;
279
 
    }
280
 
 
281
 
    // get the current reference time
282
 
    HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream);
283
 
    if (FAILED(hr)) {
284
 
        return hr;
285
 
    }
286
 
 
287
 
    // subtract the stream offset to get stream time
288
 
    rtStream -= m_tStart;
289
 
 
290
 
    return S_OK;
291
 
}
292
 
 
293
 
 
294
 
//=====================================================================
295
 
//=====================================================================
296
 
// Implements CBaseFilter
297
 
//=====================================================================
298
 
//=====================================================================
299
 
 
300
 
 
301
 
/* Override this to say what interfaces we support and where */
302
 
 
303
 
STDMETHODIMP CBaseFilter::NonDelegatingQueryInterface(REFIID riid,
304
 
                                                      __deref_out void **ppv)
305
 
{
306
 
    /* Do we have this interface */
307
 
 
308
 
    if (riid == IID_IBaseFilter) {
309
 
        return GetInterface((IBaseFilter *) this, ppv);
310
 
    } else if (riid == IID_IMediaFilter) {
311
 
        return GetInterface((IMediaFilter *) this, ppv);
312
 
    } else if (riid == IID_IPersist) {
313
 
        return GetInterface((IPersist *) this, ppv);
314
 
    } else if (riid == IID_IAMovieSetup) {
315
 
        return GetInterface((IAMovieSetup *) this, ppv);
316
 
    } else {
317
 
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
318
 
    }
319
 
}
320
 
 
321
 
#ifdef DEBUG
322
 
STDMETHODIMP_(ULONG) CBaseFilter::NonDelegatingRelease()
323
 
{
324
 
    if (m_cRef == 1) {
325
 
        KASSERT(m_pGraph == NULL);
326
 
    }
327
 
    return CUnknown::NonDelegatingRelease();
328
 
}
329
 
#endif
330
 
 
331
 
 
332
 
/* Constructor */
333
 
 
334
 
CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName,
335
 
             __inout_opt LPUNKNOWN  pUnk,
336
 
             __in CCritSec   *pLock,
337
 
             REFCLSID   clsid) :
338
 
    CUnknown( pName, pUnk ),
339
 
    m_pLock(pLock),
340
 
    m_clsid(clsid),
341
 
    m_State(State_Stopped),
342
 
    m_pClock(NULL),
343
 
    m_pGraph(NULL),
344
 
    m_pSink(NULL),
345
 
    m_pName(NULL),
346
 
    m_PinVersion(1)
347
 
{
348
 
#ifdef DXMPERF
349
 
    PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this );
350
 
#endif // DXMPERF
351
 
 
352
 
    ASSERT(pLock != NULL);
353
 
}
354
 
 
355
 
/* Passes in a redundant HRESULT argument */
356
 
 
357
 
CBaseFilter::CBaseFilter(__in_opt LPCTSTR pName,
358
 
                         __in_opt LPUNKNOWN  pUnk,
359
 
                         __in CCritSec  *pLock,
360
 
                         REFCLSID   clsid,
361
 
                         __inout HRESULT   *phr) :
362
 
    CUnknown( pName, pUnk ),
363
 
    m_pLock(pLock),
364
 
    m_clsid(clsid),
365
 
    m_State(State_Stopped),
366
 
    m_pClock(NULL),
367
 
    m_pGraph(NULL),
368
 
    m_pSink(NULL),
369
 
    m_pName(NULL),
370
 
    m_PinVersion(1)
371
 
{
372
 
#ifdef DXMPERF
373
 
    PERFLOG_CTOR( pName ? pName : L"CBaseFilter", (IBaseFilter *) this );
374
 
#endif // DXMPERF
375
 
 
376
 
    ASSERT(pLock != NULL);
377
 
    UNREFERENCED_PARAMETER(phr);
378
 
}
379
 
 
380
 
#ifdef UNICODE
381
 
CBaseFilter::CBaseFilter(__in_opt LPCSTR pName,
382
 
             __in_opt LPUNKNOWN  pUnk,
383
 
             __in CCritSec   *pLock,
384
 
             REFCLSID   clsid) :
385
 
    CUnknown( pName, pUnk ),
386
 
    m_pLock(pLock),
387
 
    m_clsid(clsid),
388
 
    m_State(State_Stopped),
389
 
    m_pClock(NULL),
390
 
    m_pGraph(NULL),
391
 
    m_pSink(NULL),
392
 
    m_pName(NULL),
393
 
    m_PinVersion(1)
394
 
{
395
 
#ifdef DXMPERF
396
 
    PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this );
397
 
#endif // DXMPERF
398
 
 
399
 
    ASSERT(pLock != NULL);
400
 
}
401
 
CBaseFilter::CBaseFilter(__in_opt LPCSTR pName,
402
 
                         __in_opt LPUNKNOWN  pUnk,
403
 
                         __in CCritSec  *pLock,
404
 
                         REFCLSID   clsid,
405
 
                         __inout HRESULT   *phr) :
406
 
    CUnknown( pName, pUnk ),
407
 
    m_pLock(pLock),
408
 
    m_clsid(clsid),
409
 
    m_State(State_Stopped),
410
 
    m_pClock(NULL),
411
 
    m_pGraph(NULL),
412
 
    m_pSink(NULL),
413
 
    m_pName(NULL),
414
 
    m_PinVersion(1)
415
 
{
416
 
#ifdef DXMPERF
417
 
    PERFLOG_CTOR( L"CBaseFilter", (IBaseFilter *) this );
418
 
#endif // DXMPERF
419
 
 
420
 
    ASSERT(pLock != NULL);
421
 
    UNREFERENCED_PARAMETER(phr);
422
 
}
423
 
#endif
424
 
 
425
 
/* Destructor */
426
 
 
427
 
CBaseFilter::~CBaseFilter()
428
 
{
429
 
#ifdef DXMPERF
430
 
    PERFLOG_DTOR( L"CBaseFilter", (IBaseFilter *) this );
431
 
#endif // DXMPERF
432
 
 
433
 
    // NOTE we do NOT hold references on the filtergraph for m_pGraph or m_pSink
434
 
    // When we did we had the circular reference problem.  Nothing would go away.
435
 
 
436
 
    delete[] m_pName;
437
 
 
438
 
    // must be stopped, but can't call Stop here since
439
 
    // our critsec has been destroyed.
440
 
 
441
 
    /* Release any clock we were using */
442
 
    if (m_pClock) {
443
 
        m_pClock->Release();
444
 
        m_pClock = NULL;
445
 
    }
446
 
}
447
 
 
448
 
/* Return the filter's clsid */
449
 
STDMETHODIMP
450
 
CBaseFilter::GetClassID(__out CLSID *pClsID)
451
 
{
452
 
    CheckPointer(pClsID,E_POINTER);
453
 
    ValidateReadWritePtr(pClsID,sizeof(CLSID));
454
 
    *pClsID = m_clsid;
455
 
    return NOERROR;
456
 
}
457
 
 
458
 
/* Override this if your state changes are not done synchronously */
459
 
STDMETHODIMP
460
 
CBaseFilter::GetState(DWORD dwMSecs, __out FILTER_STATE *State)
461
 
{
462
 
    UNREFERENCED_PARAMETER(dwMSecs);
463
 
    CheckPointer(State,E_POINTER);
464
 
    ValidateReadWritePtr(State,sizeof(FILTER_STATE));
465
 
 
466
 
    *State = m_State;
467
 
    return S_OK;
468
 
}
469
 
 
470
 
 
471
 
/* Set the clock we will use for synchronisation */
472
 
 
473
 
STDMETHODIMP
474
 
CBaseFilter::SetSyncSource(__in_opt IReferenceClock *pClock)
475
 
{
476
 
    CAutoLock cObjectLock(m_pLock);
477
 
 
478
 
    // Ensure the new one does not go away - even if the same as the old
479
 
    if (pClock) {
480
 
        pClock->AddRef();
481
 
    }
482
 
 
483
 
    // if we have a clock, release it
484
 
    if (m_pClock) {
485
 
        m_pClock->Release();
486
 
    }
487
 
 
488
 
    // Set the new reference clock (might be NULL)
489
 
    // Should we query it to ensure it is a clock?  Consider for a debug build.
490
 
    m_pClock = pClock;
491
 
 
492
 
    return NOERROR;
493
 
}
494
 
 
495
 
/* Return the clock we are using for synchronisation */
496
 
STDMETHODIMP
497
 
CBaseFilter::GetSyncSource(__deref_out_opt IReferenceClock **pClock)
498
 
{
499
 
    CheckPointer(pClock,E_POINTER);
500
 
    ValidateReadWritePtr(pClock,sizeof(IReferenceClock *));
501
 
    CAutoLock cObjectLock(m_pLock);
502
 
 
503
 
    if (m_pClock) {
504
 
        // returning an interface... addref it...
505
 
        m_pClock->AddRef();
506
 
    }
507
 
    *pClock = (IReferenceClock*)m_pClock;
508
 
    return NOERROR;
509
 
}
510
 
 
511
 
 
512
 
 
513
 
// override CBaseMediaFilter Stop method, to deactivate any pins this
514
 
// filter has.
515
 
STDMETHODIMP
516
 
CBaseFilter::Stop()
517
 
{
518
 
    CAutoLock cObjectLock(m_pLock);
519
 
    HRESULT hr = NOERROR;
520
 
 
521
 
    // notify all pins of the state change
522
 
    if (m_State != State_Stopped) {
523
 
        int cPins = GetPinCount();
524
 
        for (int c = 0; c < cPins; c++) {
525
 
 
526
 
            CBasePin *pPin = GetPin(c);
527
 
            if (NULL == pPin) {
528
 
                break;
529
 
            }
530
 
 
531
 
            // Disconnected pins are not activated - this saves pins worrying
532
 
            // about this state themselves. We ignore the return code to make
533
 
            // sure everyone is inactivated regardless. The base input pin
534
 
            // class can return an error if it has no allocator but Stop can
535
 
            // be used to resync the graph state after something has gone bad
536
 
 
537
 
            if (pPin->IsConnected()) {
538
 
                HRESULT hrTmp = pPin->Inactive();
539
 
                if (FAILED(hrTmp) && SUCCEEDED(hr)) {
540
 
                    hr = hrTmp;
541
 
                }
542
 
            }
543
 
        }
544
 
    }
545
 
 
546
 
#ifdef DXMPERF
547
 
    PERFLOG_STOP( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State );
548
 
#endif // DXMPERF
549
 
 
550
 
    m_State = State_Stopped;
551
 
    return hr;
552
 
}
553
 
 
554
 
 
555
 
// override CBaseMediaFilter Pause method to activate any pins
556
 
// this filter has (also called from Run)
557
 
 
558
 
STDMETHODIMP
559
 
CBaseFilter::Pause()
560
 
{
561
 
    CAutoLock cObjectLock(m_pLock);
562
 
 
563
 
    // notify all pins of the change to active state
564
 
    if (m_State == State_Stopped) {
565
 
        int cPins = GetPinCount();
566
 
        for (int c = 0; c < cPins; c++) {
567
 
 
568
 
            CBasePin *pPin = GetPin(c);
569
 
            if (NULL == pPin) {
570
 
                break;
571
 
            }
572
 
 
573
 
            // Disconnected pins are not activated - this saves pins
574
 
            // worrying about this state themselves
575
 
 
576
 
            if (pPin->IsConnected()) {
577
 
                HRESULT hr = pPin->Active();
578
 
                if (FAILED(hr)) {
579
 
                    return hr;
580
 
                }
581
 
            }
582
 
        }
583
 
    }
584
 
 
585
 
 
586
 
#ifdef DXMPERF
587
 
    PERFLOG_PAUSE( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, m_State );
588
 
#endif // DXMPERF
589
 
 
590
 
    m_State = State_Paused;
591
 
    return S_OK;
592
 
}
593
 
 
594
 
// Put the filter into a running state.
595
 
 
596
 
// The time parameter is the offset to be added to the samples'
597
 
// stream time to get the reference time at which they should be presented.
598
 
//
599
 
// you can either add these two and compare it against the reference clock,
600
 
// or you can call CBaseFilter::StreamTime and compare that against
601
 
// the sample timestamp.
602
 
 
603
 
STDMETHODIMP
604
 
CBaseFilter::Run(REFERENCE_TIME tStart)
605
 
{
606
 
    CAutoLock cObjectLock(m_pLock);
607
 
 
608
 
    // remember the stream time offset
609
 
    m_tStart = tStart;
610
 
 
611
 
    if (m_State == State_Stopped){
612
 
    HRESULT hr = Pause();
613
 
 
614
 
    if (FAILED(hr)) {
615
 
        return hr;
616
 
    }
617
 
    }
618
 
    // notify all pins of the change to active state
619
 
    if (m_State != State_Running) {
620
 
        int cPins = GetPinCount();
621
 
        for (int c = 0; c < cPins; c++) {
622
 
 
623
 
            CBasePin *pPin = GetPin(c);
624
 
            if (NULL == pPin) {
625
 
                break;
626
 
            }
627
 
 
628
 
            // Disconnected pins are not activated - this saves pins
629
 
            // worrying about this state themselves
630
 
 
631
 
            if (pPin->IsConnected()) {
632
 
                HRESULT hr = pPin->Run(tStart);
633
 
                if (FAILED(hr)) {
634
 
                    return hr;
635
 
                }
636
 
            }
637
 
        }
638
 
    }
639
 
 
640
 
#ifdef DXMPERF
641
 
    PERFLOG_RUN( m_pName ? m_pName : L"CBaseFilter", (IBaseFilter *) this, tStart, m_State );
642
 
#endif // DXMPERF
643
 
 
644
 
    m_State = State_Running;
645
 
    return S_OK;
646
 
}
647
 
 
648
 
//
649
 
// return the current stream time - samples with start timestamps of this
650
 
// time or before should be rendered by now
651
 
HRESULT
652
 
CBaseFilter::StreamTime(CRefTime& rtStream)
653
 
{
654
 
    // Caller must lock for synchronization
655
 
    // We can't grab the filter lock because we want to be able to call
656
 
    // this from worker threads without deadlocking
657
 
 
658
 
    if (m_pClock == NULL) {
659
 
        return VFW_E_NO_CLOCK;
660
 
    }
661
 
 
662
 
    // get the current reference time
663
 
    HRESULT hr = m_pClock->GetTime((REFERENCE_TIME*)&rtStream);
664
 
    if (FAILED(hr)) {
665
 
        return hr;
666
 
    }
667
 
 
668
 
    // subtract the stream offset to get stream time
669
 
    rtStream -= m_tStart;
670
 
 
671
 
    return S_OK;
672
 
}
673
 
 
674
 
 
675
 
/* Create an enumerator for the pins attached to this filter */
676
 
 
677
 
STDMETHODIMP
678
 
CBaseFilter::EnumPins(__deref_out IEnumPins **ppEnum)
679
 
{
680
 
    CheckPointer(ppEnum,E_POINTER);
681
 
    ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *));
682
 
 
683
 
    /* Create a new ref counted enumerator */
684
 
 
685
 
    *ppEnum = new CEnumPins(this,
686
 
                        NULL);
687
 
 
688
 
    return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR;
689
 
}
690
 
 
691
 
 
692
 
// default behaviour of FindPin is to assume pins are named
693
 
// by their pin names
694
 
STDMETHODIMP
695
 
CBaseFilter::FindPin(
696
 
    LPCWSTR Id,
697
 
    __deref_out IPin ** ppPin
698
 
)
699
 
{
700
 
    CheckPointer(ppPin,E_POINTER);
701
 
    ValidateReadWritePtr(ppPin,sizeof(IPin *));
702
 
 
703
 
    //  We're going to search the pin list so maintain integrity
704
 
    CAutoLock lck(m_pLock);
705
 
    int iCount = GetPinCount();
706
 
    for (int i = 0; i < iCount; i++) {
707
 
        CBasePin *pPin = GetPin(i);
708
 
        if (NULL == pPin) {
709
 
            break;
710
 
        }
711
 
 
712
 
        if (0 == lstrcmpW(pPin->Name(), Id)) {
713
 
            //  Found one that matches
714
 
            //
715
 
            //  AddRef() and return it
716
 
            *ppPin = pPin;
717
 
            pPin->AddRef();
718
 
            return S_OK;
719
 
        }
720
 
    }
721
 
    *ppPin = NULL;
722
 
    return VFW_E_NOT_FOUND;
723
 
}
724
 
 
725
 
/* Return information about this filter */
726
 
 
727
 
STDMETHODIMP
728
 
CBaseFilter::QueryFilterInfo(__out FILTER_INFO * pInfo)
729
 
{
730
 
    CheckPointer(pInfo,E_POINTER);
731
 
    ValidateReadWritePtr(pInfo,sizeof(FILTER_INFO));
732
 
 
733
 
    if (m_pName) {
734
 
        (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName);
735
 
    } else {
736
 
        pInfo->achName[0] = L'\0';
737
 
    }
738
 
    pInfo->pGraph = m_pGraph;
739
 
    if (m_pGraph)
740
 
        m_pGraph->AddRef();
741
 
    return NOERROR;
742
 
}
743
 
 
744
 
 
745
 
/* Provide the filter with a filter graph */
746
 
 
747
 
STDMETHODIMP
748
 
CBaseFilter::JoinFilterGraph(
749
 
    __inout_opt IFilterGraph * pGraph,
750
 
    __in_opt LPCWSTR pName)
751
 
{
752
 
    CAutoLock cObjectLock(m_pLock);
753
 
 
754
 
    // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink)
755
 
 
756
 
    m_pGraph = pGraph;
757
 
    if (m_pGraph) {
758
 
        HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEventSink,
759
 
                        (void**) &m_pSink);
760
 
        if (FAILED(hr)) {
761
 
            ASSERT(m_pSink == NULL);
762
 
        }
763
 
        else m_pSink->Release();        // we do NOT keep a reference on it.
764
 
    } else {
765
 
        // if graph pointer is null, then we should
766
 
        // also release the IMediaEventSink on the same object - we don't
767
 
        // refcount it, so just set it to null
768
 
        m_pSink = NULL;
769
 
    }
770
 
 
771
 
 
772
 
    if (m_pName) {
773
 
        delete[] m_pName;
774
 
        m_pName = NULL;
775
 
    }
776
 
 
777
 
    if (pName) {
778
 
        size_t namelen;
779
 
        HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &namelen);
780
 
        if (FAILED(hr)) {
781
 
            return hr;
782
 
        }
783
 
        m_pName = new WCHAR[namelen + 1];
784
 
        if (m_pName) {
785
 
            (void)StringCchCopyW(m_pName, namelen + 1, pName);
786
 
        } else {
787
 
            return E_OUTOFMEMORY;
788
 
        }
789
 
    }
790
 
 
791
 
#ifdef DXMPERF
792
 
    PERFLOG_JOINGRAPH( m_pName ? m_pName : L"CBaseFilter",(IBaseFilter *) this, pGraph );
793
 
#endif // DXMPERF
794
 
 
795
 
    return NOERROR;
796
 
}
797
 
 
798
 
 
799
 
// return a Vendor information string. Optional - may return E_NOTIMPL.
800
 
// memory returned should be freed using CoTaskMemFree
801
 
// default implementation returns E_NOTIMPL
802
 
STDMETHODIMP
803
 
CBaseFilter::QueryVendorInfo(
804
 
    __deref_out LPWSTR* pVendorInfo)
805
 
{
806
 
    UNREFERENCED_PARAMETER(pVendorInfo);
807
 
    return E_NOTIMPL;
808
 
}
809
 
 
810
 
 
811
 
// send an event notification to the filter graph if we know about it.
812
 
// returns S_OK if delivered, S_FALSE if the filter graph does not sink
813
 
// events, or an error otherwise.
814
 
HRESULT
815
 
CBaseFilter::NotifyEvent(
816
 
    long EventCode,
817
 
    LONG_PTR EventParam1,
818
 
    LONG_PTR EventParam2)
819
 
{
820
 
    // Snapshot so we don't have to lock up
821
 
    IMediaEventSink *pSink = m_pSink;
822
 
    if (pSink) {
823
 
        if (EC_COMPLETE == EventCode) {
824
 
            EventParam2 = (LONG_PTR)(IBaseFilter*)this;
825
 
        }
826
 
 
827
 
        return pSink->Notify(EventCode, EventParam1, EventParam2);
828
 
    } else {
829
 
        return E_NOTIMPL;
830
 
    }
831
 
}
832
 
 
833
 
// Request reconnect
834
 
// pPin is the pin to reconnect
835
 
// pmt is the type to reconnect with - can be NULL
836
 
// Calls ReconnectEx on the filter graph
837
 
HRESULT
838
 
CBaseFilter::ReconnectPin(
839
 
    IPin *pPin,
840
 
    __in_opt AM_MEDIA_TYPE const *pmt
841
 
)
842
 
{
843
 
    IFilterGraph2 *pGraph2;
844
 
    if (m_pGraph != NULL) {
845
 
        HRESULT hr = m_pGraph->QueryInterface(IID_IFilterGraph2, (void **)&pGraph2);
846
 
        if (SUCCEEDED(hr)) {
847
 
            hr = pGraph2->ReconnectEx(pPin, pmt);
848
 
            pGraph2->Release();
849
 
            return hr;
850
 
        } else {
851
 
            return m_pGraph->Reconnect(pPin);
852
 
        }
853
 
    } else {
854
 
        return E_NOINTERFACE;
855
 
    }
856
 
}
857
 
 
858
 
 
859
 
 
860
 
/* This is the same idea as the media type version does for type enumeration
861
 
   on pins but for the list of pins available. So if the list of pins you
862
 
   provide changes dynamically then either override this virtual function
863
 
   to provide the version number, or more simply call IncrementPinVersion */
864
 
 
865
 
LONG CBaseFilter::GetPinVersion()
866
 
{
867
 
    return m_PinVersion;
868
 
}
869
 
 
870
 
 
871
 
/* Increment the current pin version cookie */
872
 
 
873
 
void CBaseFilter::IncrementPinVersion()
874
 
{
875
 
    InterlockedIncrement(&m_PinVersion);
876
 
}
877
 
 
878
 
/* register filter */
879
 
 
880
 
STDMETHODIMP CBaseFilter::Register()
881
 
{
882
 
    // get setup data, if it exists
883
 
    //
884
 
    LPAMOVIESETUP_FILTER psetupdata = GetSetupData();
885
 
 
886
 
    // check we've got data
887
 
    //
888
 
    if( NULL == psetupdata ) return S_FALSE;
889
 
 
890
 
    // init is ref counted so call just in case
891
 
    // we're being called cold.
892
 
    //
893
 
    HRESULT hr = CoInitialize( (LPVOID)NULL );
894
 
    ASSERT( SUCCEEDED(hr) );
895
 
 
896
 
    // get hold of IFilterMapper
897
 
    //
898
 
    IFilterMapper *pIFM;
899
 
    hr = CoCreateInstance( CLSID_FilterMapper
900
 
                             , NULL
901
 
                             , CLSCTX_INPROC_SERVER
902
 
                             , IID_IFilterMapper
903
 
                             , (void **)&pIFM       );
904
 
    if( SUCCEEDED(hr) )
905
 
    {
906
 
        hr = AMovieSetupRegisterFilter( psetupdata, pIFM, TRUE );
907
 
        pIFM->Release();
908
 
    }
909
 
 
910
 
    // and clear up
911
 
    //
912
 
    CoFreeUnusedLibraries();
913
 
    CoUninitialize();
914
 
 
915
 
    return NOERROR;
916
 
}
917
 
 
918
 
 
919
 
/* unregister filter */
920
 
 
921
 
STDMETHODIMP CBaseFilter::Unregister()
922
 
{
923
 
    // get setup data, if it exists
924
 
    //
925
 
    LPAMOVIESETUP_FILTER psetupdata = GetSetupData();
926
 
 
927
 
    // check we've got data
928
 
    //
929
 
    if( NULL == psetupdata ) return S_FALSE;
930
 
 
931
 
    // OLE init is ref counted so call
932
 
    // just in case we're being called cold.
933
 
    //
934
 
    HRESULT hr = CoInitialize( (LPVOID)NULL );
935
 
    ASSERT( SUCCEEDED(hr) );
936
 
 
937
 
    // get hold of IFilterMapper
938
 
    //
939
 
    IFilterMapper *pIFM;
940
 
    hr = CoCreateInstance( CLSID_FilterMapper
941
 
                             , NULL
942
 
                             , CLSCTX_INPROC_SERVER
943
 
                             , IID_IFilterMapper
944
 
                             , (void **)&pIFM       );
945
 
    if( SUCCEEDED(hr) )
946
 
    {
947
 
        hr = AMovieSetupRegisterFilter( psetupdata, pIFM, FALSE );
948
 
 
949
 
        // release interface
950
 
        //
951
 
        pIFM->Release();
952
 
    }
953
 
 
954
 
    // clear up
955
 
    //
956
 
    CoFreeUnusedLibraries();
957
 
    CoUninitialize();
958
 
 
959
 
    // handle one acceptable "error" - that
960
 
    // of filter not being registered!
961
 
    // (couldn't find a suitable #define'd
962
 
    // name for the error!)
963
 
    //
964
 
    if( 0x80070002 == hr)
965
 
      return NOERROR;
966
 
    else
967
 
      return hr;
968
 
}
969
 
 
970
 
 
971
 
//=====================================================================
972
 
//=====================================================================
973
 
// Implements CEnumPins
974
 
//=====================================================================
975
 
//=====================================================================
976
 
 
977
 
 
978
 
CEnumPins::CEnumPins(__in CBaseFilter *pFilter,
979
 
                     __in_opt CEnumPins *pEnumPins) :
980
 
    m_Position(0),
981
 
    m_PinCount(0),
982
 
    m_pFilter(pFilter),
983
 
    m_cRef(1),               // Already ref counted
984
 
    m_PinCache(NAME("Pin Cache"))
985
 
{
986
 
 
987
 
#ifdef DEBUG
988
 
    m_dwCookie = DbgRegisterObjectCreation("CEnumPins", 0);
989
 
#endif
990
 
 
991
 
    /* We must be owned by a filter derived from CBaseFilter */
992
 
 
993
 
    ASSERT(pFilter != NULL);
994
 
 
995
 
    /* Hold a reference count on our filter */
996
 
    m_pFilter->AddRef();
997
 
 
998
 
    /* Are we creating a new enumerator */
999
 
 
1000
 
    if (pEnumPins == NULL) {
1001
 
        m_Version = m_pFilter->GetPinVersion();
1002
 
        m_PinCount = m_pFilter->GetPinCount();
1003
 
    } else {
1004
 
        ASSERT(m_Position <= m_PinCount);
1005
 
        m_Position = pEnumPins->m_Position;
1006
 
        m_PinCount = pEnumPins->m_PinCount;
1007
 
        m_Version = pEnumPins->m_Version;
1008
 
        m_PinCache.AddTail(&(pEnumPins->m_PinCache));
1009
 
    }
1010
 
}
1011
 
 
1012
 
 
1013
 
/* Destructor releases the reference count on our filter NOTE since we hold
1014
 
   a reference count on the filter who created us we know it is safe to
1015
 
   release it, no access can be made to it afterwards though as we have just
1016
 
   caused the last reference count to go and the object to be deleted */
1017
 
 
1018
 
CEnumPins::~CEnumPins()
1019
 
{
1020
 
    m_pFilter->Release();
1021
 
 
1022
 
#ifdef DEBUG
1023
 
    DbgRegisterObjectDestruction(m_dwCookie);
1024
 
#endif
1025
 
}
1026
 
 
1027
 
 
1028
 
/* Override this to say what interfaces we support where */
1029
 
 
1030
 
STDMETHODIMP
1031
 
CEnumPins::QueryInterface(REFIID riid, __deref_out void **ppv)
1032
 
{
1033
 
    CheckPointer(ppv, E_POINTER);
1034
 
 
1035
 
    /* Do we have this interface */
1036
 
 
1037
 
    if (riid == IID_IEnumPins || riid == IID_IUnknown) {
1038
 
        return GetInterface((IEnumPins *) this, ppv);
1039
 
    } else {
1040
 
        *ppv = NULL;
1041
 
        return E_NOINTERFACE;
1042
 
    }
1043
 
}
1044
 
 
1045
 
STDMETHODIMP_(ULONG)
1046
 
CEnumPins::AddRef()
1047
 
{
1048
 
    return InterlockedIncrement(&m_cRef);
1049
 
}
1050
 
 
1051
 
STDMETHODIMP_(ULONG)
1052
 
CEnumPins::Release()
1053
 
{
1054
 
    ULONG cRef = InterlockedDecrement(&m_cRef);
1055
 
    if (cRef == 0) {
1056
 
        delete this;
1057
 
    }
1058
 
    return cRef;
1059
 
}
1060
 
 
1061
 
/* One of an enumerator's basic member functions allows us to create a cloned
1062
 
   interface that initially has the same state. Since we are taking a snapshot
1063
 
   of an object (current position and all) we must lock access at the start */
1064
 
 
1065
 
STDMETHODIMP
1066
 
CEnumPins::Clone(__deref_out IEnumPins **ppEnum)
1067
 
{
1068
 
    CheckPointer(ppEnum,E_POINTER);
1069
 
    ValidateReadWritePtr(ppEnum,sizeof(IEnumPins *));
1070
 
    HRESULT hr = NOERROR;
1071
 
 
1072
 
    /* Check we are still in sync with the filter */
1073
 
    if (AreWeOutOfSync() == TRUE) {
1074
 
        *ppEnum = NULL;
1075
 
        hr =  VFW_E_ENUM_OUT_OF_SYNC;
1076
 
    } else {
1077
 
        *ppEnum = new CEnumPins(m_pFilter,
1078
 
                                this);
1079
 
        if (*ppEnum == NULL) {
1080
 
            hr = E_OUTOFMEMORY;
1081
 
        }
1082
 
    }
1083
 
    return hr;
1084
 
}
1085
 
 
1086
 
 
1087
 
/* Return the next pin after the current position */
1088
 
 
1089
 
STDMETHODIMP
1090
 
CEnumPins::Next(ULONG cPins,        // place this many pins...
1091
 
        __out_ecount(cPins) IPin **ppPins,      // ...in this array
1092
 
        __out_opt ULONG *pcFetched)   // actual count passed returned here
1093
 
{
1094
 
    CheckPointer(ppPins,E_POINTER);
1095
 
    ValidateReadWritePtr(ppPins,cPins * sizeof(IPin *));
1096
 
 
1097
 
    ASSERT(ppPins);
1098
 
 
1099
 
    if (pcFetched!=NULL) {
1100
 
        ValidateWritePtr(pcFetched, sizeof(ULONG));
1101
 
        *pcFetched = 0;           // default unless we succeed
1102
 
    }
1103
 
    // now check that the parameter is valid
1104
 
    else if (cPins>1) {   // pcFetched == NULL
1105
 
        return E_INVALIDARG;
1106
 
    }
1107
 
    ULONG cFetched = 0;           // increment as we get each one.
1108
 
 
1109
 
    /* Check we are still in sync with the filter */
1110
 
    if (AreWeOutOfSync() == TRUE) {
1111
 
        // If we are out of sync, we should refresh the enumerator.
1112
 
        // This will reset the position and update the other members, but
1113
 
        // will not clear cache of pins we have already returned.
1114
 
        Refresh();
1115
 
    }
1116
 
 
1117
 
    /* Return each pin interface NOTE GetPin returns CBasePin * not addrefed
1118
 
       so we must QI for the IPin (which increments its reference count)
1119
 
       If while we are retrieving a pin from the filter an error occurs we
1120
 
       assume that our internal state is stale with respect to the filter
1121
 
       (for example someone has deleted a pin) so we
1122
 
       return VFW_E_ENUM_OUT_OF_SYNC                            */
1123
 
 
1124
 
    while (cFetched < cPins && m_PinCount > m_Position) {
1125
 
 
1126
 
        /* Get the next pin object from the filter */
1127
 
 
1128
 
        CBasePin *pPin = m_pFilter->GetPin(m_Position++);
1129
 
        if (pPin == NULL) {
1130
 
            // If this happend, and it's not the first time through, then we've got a problem,
1131
 
            // since we should really go back and release the iPins, which we have previously
1132
 
            // AddRef'ed.
1133
 
            ASSERT( cFetched==0 );
1134
 
            return VFW_E_ENUM_OUT_OF_SYNC;
1135
 
        }
1136
 
 
1137
 
        /* We only want to return this pin, if it is not in our cache */
1138
 
        if (0 == m_PinCache.Find(pPin))
1139
 
        {
1140
 
            /* From the object get an IPin interface */
1141
 
 
1142
 
            *ppPins = pPin;
1143
 
            pPin->AddRef();
1144
 
 
1145
 
            cFetched++;
1146
 
            ppPins++;
1147
 
 
1148
 
            m_PinCache.AddTail(pPin);
1149
 
        }
1150
 
    }
1151
 
 
1152
 
    if (pcFetched!=NULL) {
1153
 
        *pcFetched = cFetched;
1154
 
    }
1155
 
 
1156
 
    return (cPins==cFetched ? NOERROR : S_FALSE);
1157
 
}
1158
 
 
1159
 
 
1160
 
/* Skip over one or more entries in the enumerator */
1161
 
 
1162
 
STDMETHODIMP
1163
 
CEnumPins::Skip(ULONG cPins)
1164
 
{
1165
 
    /* Check we are still in sync with the filter */
1166
 
    if (AreWeOutOfSync() == TRUE) {
1167
 
        return VFW_E_ENUM_OUT_OF_SYNC;
1168
 
    }
1169
 
 
1170
 
    /* Work out how many pins are left to skip over */
1171
 
    /* We could position at the end if we are asked to skip too many... */
1172
 
    /* ..which would match the base implementation for CEnumMediaTypes::Skip */
1173
 
 
1174
 
    ULONG PinsLeft = m_PinCount - m_Position;
1175
 
    if (cPins > PinsLeft) {
1176
 
        return S_FALSE;
1177
 
    }
1178
 
    m_Position += cPins;
1179
 
    return NOERROR;
1180
 
}
1181
 
 
1182
 
 
1183
 
/* Set the current position back to the start */
1184
 
/* Reset has 4 simple steps:
1185
 
 *
1186
 
 * Set position to head of list
1187
 
 * Sync enumerator with object being enumerated
1188
 
 * Clear the cache of pins already returned
1189
 
 * return S_OK
1190
 
 */
1191
 
 
1192
 
STDMETHODIMP
1193
 
CEnumPins::Reset()
1194
 
{
1195
 
    m_Version = m_pFilter->GetPinVersion();
1196
 
    m_PinCount = m_pFilter->GetPinCount();
1197
 
 
1198
 
    m_Position = 0;
1199
 
 
1200
 
    // Clear the cache
1201
 
    m_PinCache.RemoveAll();
1202
 
 
1203
 
    return S_OK;
1204
 
}
1205
 
 
1206
 
 
1207
 
/* Set the current position back to the start */
1208
 
/* Refresh has 3 simple steps:
1209
 
 *
1210
 
 * Set position to head of list
1211
 
 * Sync enumerator with object being enumerated
1212
 
 * return S_OK
1213
 
 */
1214
 
 
1215
 
STDMETHODIMP
1216
 
CEnumPins::Refresh()
1217
 
{
1218
 
    m_Version = m_pFilter->GetPinVersion();
1219
 
    m_PinCount = m_pFilter->GetPinCount();
1220
 
 
1221
 
    m_Position = 0;
1222
 
    return S_OK;
1223
 
}
1224
 
 
1225
 
 
1226
 
//=====================================================================
1227
 
//=====================================================================
1228
 
// Implements CEnumMediaTypes
1229
 
//=====================================================================
1230
 
//=====================================================================
1231
 
 
1232
 
 
1233
 
CEnumMediaTypes::CEnumMediaTypes(__in CBasePin *pPin,
1234
 
                                 __in_opt CEnumMediaTypes *pEnumMediaTypes) :
1235
 
    m_Position(0),
1236
 
    m_pPin(pPin),
1237
 
    m_cRef(1)
1238
 
{
1239
 
 
1240
 
#ifdef DEBUG
1241
 
    m_dwCookie = DbgRegisterObjectCreation("CEnumMediaTypes", 0);
1242
 
#endif
1243
 
 
1244
 
    /* We must be owned by a pin derived from CBasePin */
1245
 
 
1246
 
    ASSERT(pPin != NULL);
1247
 
 
1248
 
    /* Hold a reference count on our pin */
1249
 
    m_pPin->AddRef();
1250
 
 
1251
 
    /* Are we creating a new enumerator */
1252
 
 
1253
 
    if (pEnumMediaTypes == NULL) {
1254
 
        m_Version = m_pPin->GetMediaTypeVersion();
1255
 
        return;
1256
 
    }
1257
 
 
1258
 
    m_Position = pEnumMediaTypes->m_Position;
1259
 
    m_Version = pEnumMediaTypes->m_Version;
1260
 
}
1261
 
 
1262
 
 
1263
 
/* Destructor releases the reference count on our base pin. NOTE since we hold
1264
 
   a reference count on the pin who created us we know it is safe to release
1265
 
   it, no access can be made to it afterwards though as we might have just
1266
 
   caused the last reference count to go and the object to be deleted */
1267
 
 
1268
 
CEnumMediaTypes::~CEnumMediaTypes()
1269
 
{
1270
 
#ifdef DEBUG
1271
 
    DbgRegisterObjectDestruction(m_dwCookie);
1272
 
#endif
1273
 
    m_pPin->Release();
1274
 
}
1275
 
 
1276
 
 
1277
 
/* Override this to say what interfaces we support where */
1278
 
 
1279
 
STDMETHODIMP
1280
 
CEnumMediaTypes::QueryInterface(REFIID riid, __deref_out void **ppv)
1281
 
{
1282
 
    CheckPointer(ppv, E_POINTER);
1283
 
 
1284
 
    /* Do we have this interface */
1285
 
 
1286
 
    if (riid == IID_IEnumMediaTypes || riid == IID_IUnknown) {
1287
 
        return GetInterface((IEnumMediaTypes *) this, ppv);
1288
 
    } else {
1289
 
        *ppv = NULL;
1290
 
        return E_NOINTERFACE;
1291
 
    }
1292
 
}
1293
 
 
1294
 
STDMETHODIMP_(ULONG)
1295
 
CEnumMediaTypes::AddRef()
1296
 
{
1297
 
    return InterlockedIncrement(&m_cRef);
1298
 
}
1299
 
 
1300
 
STDMETHODIMP_(ULONG)
1301
 
CEnumMediaTypes::Release()
1302
 
{
1303
 
    ULONG cRef = InterlockedDecrement(&m_cRef);
1304
 
    if (cRef == 0) {
1305
 
        delete this;
1306
 
    }
1307
 
    return cRef;
1308
 
}
1309
 
 
1310
 
/* One of an enumerator's basic member functions allows us to create a cloned
1311
 
   interface that initially has the same state. Since we are taking a snapshot
1312
 
   of an object (current position and all) we must lock access at the start */
1313
 
 
1314
 
STDMETHODIMP
1315
 
CEnumMediaTypes::Clone(__deref_out IEnumMediaTypes **ppEnum)
1316
 
{
1317
 
    CheckPointer(ppEnum,E_POINTER);
1318
 
    ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));
1319
 
    HRESULT hr = NOERROR;
1320
 
 
1321
 
    /* Check we are still in sync with the pin */
1322
 
    if (AreWeOutOfSync() == TRUE) {
1323
 
        *ppEnum = NULL;
1324
 
        hr = VFW_E_ENUM_OUT_OF_SYNC;
1325
 
    } else {
1326
 
 
1327
 
        *ppEnum = new CEnumMediaTypes(m_pPin,
1328
 
                                      this);
1329
 
 
1330
 
        if (*ppEnum == NULL) {
1331
 
            hr =  E_OUTOFMEMORY;
1332
 
        }
1333
 
    }
1334
 
    return hr;
1335
 
}
1336
 
 
1337
 
 
1338
 
/* Enumerate the next pin(s) after the current position. The client using this
1339
 
   interface passes in a pointer to an array of pointers each of which will
1340
 
   be filled in with a pointer to a fully initialised media type format
1341
 
   Return NOERROR if it all works,
1342
 
          S_FALSE if fewer than cMediaTypes were enumerated.
1343
 
          VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by
1344
 
                                 state changes in the filter
1345
 
   The actual count always correctly reflects the number of types in the array.
1346
 
*/
1347
 
 
1348
 
STDMETHODIMP
1349
 
CEnumMediaTypes::Next(ULONG cMediaTypes,          // place this many types...
1350
 
                      __out_ecount(cMediaTypes) AM_MEDIA_TYPE **ppMediaTypes,   // ...in this array
1351
 
                      __out ULONG *pcFetched)           // actual count passed
1352
 
{
1353
 
    CheckPointer(ppMediaTypes,E_POINTER);
1354
 
    ValidateReadWritePtr(ppMediaTypes,cMediaTypes * sizeof(AM_MEDIA_TYPE *));
1355
 
    /* Check we are still in sync with the pin */
1356
 
    if (AreWeOutOfSync() == TRUE) {
1357
 
        return VFW_E_ENUM_OUT_OF_SYNC;
1358
 
    }
1359
 
 
1360
 
    if (pcFetched!=NULL) {
1361
 
        ValidateWritePtr(pcFetched, sizeof(ULONG));
1362
 
        *pcFetched = 0;           // default unless we succeed
1363
 
    }
1364
 
    // now check that the parameter is valid
1365
 
    else if (cMediaTypes>1) {     // pcFetched == NULL
1366
 
        return E_INVALIDARG;
1367
 
    }
1368
 
    ULONG cFetched = 0;           // increment as we get each one.
1369
 
 
1370
 
    /* Return each media type by asking the filter for them in turn - If we
1371
 
       have an error code retured to us while we are retrieving a media type
1372
 
       we assume that our internal state is stale with respect to the filter
1373
 
       (for example the window size changing) so we return
1374
 
       VFW_E_ENUM_OUT_OF_SYNC */
1375
 
 
1376
 
    while (cMediaTypes) {
1377
 
 
1378
 
        CMediaType cmt;
1379
 
 
1380
 
        HRESULT hr = m_pPin->GetMediaType(m_Position++, &cmt);
1381
 
        if (S_OK != hr) {
1382
 
            break;
1383
 
        }
1384
 
 
1385
 
        /* We now have a CMediaType object that contains the next media type
1386
 
           but when we assign it to the array position we CANNOT just assign
1387
 
           the AM_MEDIA_TYPE structure because as soon as the object goes out of
1388
 
           scope it will delete the memory we have just copied. The function
1389
 
           we use is CreateMediaType which allocates a task memory block */
1390
 
 
1391
 
        /*  Transfer across the format block manually to save an allocate
1392
 
            and free on the format block and generally go faster */
1393
 
 
1394
 
        *ppMediaTypes = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
1395
 
        if (*ppMediaTypes == NULL) {
1396
 
            break;
1397
 
        }
1398
 
 
1399
 
        /*  Do a regular copy */
1400
 
        **ppMediaTypes = cmt;
1401
 
 
1402
 
        /*  Make sure the destructor doesn't free these */
1403
 
        cmt.pbFormat = NULL;
1404
 
        cmt.cbFormat = NULL;
1405
 
        cmt.pUnk     = NULL;
1406
 
 
1407
 
 
1408
 
        ppMediaTypes++;
1409
 
        cFetched++;
1410
 
        cMediaTypes--;
1411
 
    }
1412
 
 
1413
 
    if (pcFetched!=NULL) {
1414
 
        *pcFetched = cFetched;
1415
 
    }
1416
 
 
1417
 
    return ( cMediaTypes==0 ? NOERROR : S_FALSE );
1418
 
}
1419
 
 
1420
 
 
1421
 
/* Skip over one or more entries in the enumerator */
1422
 
 
1423
 
STDMETHODIMP
1424
 
CEnumMediaTypes::Skip(ULONG cMediaTypes)
1425
 
{
1426
 
    //  If we're skipping 0 elements we're guaranteed to skip the
1427
 
    //  correct number of elements
1428
 
    if (cMediaTypes == 0) {
1429
 
        return S_OK;
1430
 
    }
1431
 
 
1432
 
    /* Check we are still in sync with the pin */
1433
 
    if (AreWeOutOfSync() == TRUE) {
1434
 
        return VFW_E_ENUM_OUT_OF_SYNC;
1435
 
    }
1436
 
 
1437
 
    m_Position += cMediaTypes;
1438
 
 
1439
 
    /*  See if we're over the end */
1440
 
    CMediaType cmt;
1441
 
    return S_OK == m_pPin->GetMediaType(m_Position - 1, &cmt) ? S_OK : S_FALSE;
1442
 
}
1443
 
 
1444
 
 
1445
 
/* Set the current position back to the start */
1446
 
/* Reset has 3 simple steps:
1447
 
 *
1448
 
 * set position to head of list
1449
 
 * sync enumerator with object being enumerated
1450
 
 * return S_OK
1451
 
 */
1452
 
 
1453
 
STDMETHODIMP
1454
 
CEnumMediaTypes::Reset()
1455
 
 
1456
 
{
1457
 
    m_Position = 0;
1458
 
 
1459
 
    // Bring the enumerator back into step with the current state.  This
1460
 
    // may be a noop but ensures that the enumerator will be valid on the
1461
 
    // next call.
1462
 
    m_Version = m_pPin->GetMediaTypeVersion();
1463
 
    return NOERROR;
1464
 
}
1465
 
 
1466
 
 
1467
 
//=====================================================================
1468
 
//=====================================================================
1469
 
// Implements CBasePin
1470
 
//=====================================================================
1471
 
//=====================================================================
1472
 
 
1473
 
 
1474
 
/* NOTE The implementation of this class calls the CUnknown constructor with
1475
 
   a NULL outer unknown pointer. This has the effect of making us a self
1476
 
   contained class, ie any QueryInterface, AddRef or Release calls will be
1477
 
   routed to the class's NonDelegatingUnknown methods. You will typically
1478
 
   find that the classes that do this then override one or more of these
1479
 
   virtual functions to provide more specialised behaviour. A good example
1480
 
   of this is where a class wants to keep the QueryInterface internal but
1481
 
   still wants its lifetime controlled by the external object */
1482
 
 
1483
 
/* Constructor */
1484
 
 
1485
 
CBasePin::CBasePin(__in_opt LPCTSTR pObjectName,
1486
 
           __in CBaseFilter *pFilter,
1487
 
           __in CCritSec *pLock,
1488
 
           __inout HRESULT *phr,
1489
 
           __in_opt LPCWSTR pName,
1490
 
           PIN_DIRECTION dir) :
1491
 
    CUnknown( pObjectName, NULL ),
1492
 
    m_pFilter(pFilter),
1493
 
    m_pLock(pLock),
1494
 
    m_pName(NULL),
1495
 
    m_Connected(NULL),
1496
 
    m_dir(dir),
1497
 
    m_bRunTimeError(FALSE),
1498
 
    m_pQSink(NULL),
1499
 
    m_TypeVersion(1),
1500
 
    m_tStart(),
1501
 
    m_tStop(MAX_TIME),
1502
 
    m_bCanReconnectWhenActive(false),
1503
 
    m_bTryMyTypesFirst(false),
1504
 
    m_dRate(1.0)
1505
 
{
1506
 
    /*  WARNING - pFilter is often not a properly constituted object at
1507
 
        this state (in particular QueryInterface may not work) - this
1508
 
        is because its owner is often its containing object and we
1509
 
        have been called from the containing object's constructor so
1510
 
        the filter's owner has not yet had its CUnknown constructor
1511
 
        called
1512
 
    */
1513
 
#ifdef DXMPERF
1514
 
    PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this );
1515
 
#endif // DXMPERF
1516
 
 
1517
 
    ASSERT(pFilter != NULL);
1518
 
    ASSERT(pLock != NULL);
1519
 
 
1520
 
    if (pName) {
1521
 
        size_t cchName;
1522
 
        HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName);
1523
 
        if (SUCCEEDED(hr)) {
1524
 
            m_pName = new WCHAR[cchName + 1];
1525
 
            if (m_pName) {
1526
 
                (void)StringCchCopyW(m_pName, cchName + 1, pName);
1527
 
            }
1528
 
        }
1529
 
    }
1530
 
 
1531
 
#ifdef DEBUG
1532
 
    m_cRef = 0;
1533
 
#endif
1534
 
}
1535
 
 
1536
 
#ifdef UNICODE
1537
 
CBasePin::CBasePin(__in_opt LPCSTR pObjectName,
1538
 
           __in CBaseFilter *pFilter,
1539
 
           __in CCritSec *pLock,
1540
 
           __inout HRESULT *phr,
1541
 
           __in_opt LPCWSTR pName,
1542
 
           PIN_DIRECTION dir) :
1543
 
    CUnknown( pObjectName, NULL ),
1544
 
    m_pFilter(pFilter),
1545
 
    m_pLock(pLock),
1546
 
    m_pName(NULL),
1547
 
    m_Connected(NULL),
1548
 
    m_dir(dir),
1549
 
    m_bRunTimeError(FALSE),
1550
 
    m_pQSink(NULL),
1551
 
    m_TypeVersion(1),
1552
 
    m_tStart(),
1553
 
    m_tStop(MAX_TIME),
1554
 
    m_bCanReconnectWhenActive(false),
1555
 
    m_bTryMyTypesFirst(false),
1556
 
    m_dRate(1.0)
1557
 
{
1558
 
    /*  WARNING - pFilter is often not a properly constituted object at
1559
 
        this state (in particular QueryInterface may not work) - this
1560
 
        is because its owner is often its containing object and we
1561
 
        have been called from the containing object's constructor so
1562
 
        the filter's owner has not yet had its CUnknown constructor
1563
 
        called
1564
 
    */
1565
 
#ifdef DXMPERF
1566
 
    PERFLOG_CTOR( pName ? pName : L"CBasePin", (IPin *) this );
1567
 
#endif // DXMPERF
1568
 
 
1569
 
    ASSERT(pFilter != NULL);
1570
 
    ASSERT(pLock != NULL);
1571
 
 
1572
 
    if (pName) {
1573
 
        size_t cchName;
1574
 
        HRESULT hr = StringCchLengthW(pName, STRSAFE_MAX_CCH, &cchName);
1575
 
        if (SUCCEEDED(hr)) {
1576
 
            m_pName = new WCHAR[cchName + 1];
1577
 
            if (m_pName) {
1578
 
                (void)StringCchCopyW(m_pName, cchName + 1, pName);
1579
 
            }
1580
 
        }
1581
 
    }
1582
 
 
1583
 
 
1584
 
#ifdef DEBUG
1585
 
    m_cRef = 0;
1586
 
#endif
1587
 
}
1588
 
#endif
1589
 
 
1590
 
/* Destructor since a connected pin holds a reference count on us there is
1591
 
   no way that we can be deleted unless we are not currently connected */
1592
 
 
1593
 
CBasePin::~CBasePin()
1594
 
{
1595
 
#ifdef DXMPERF
1596
 
    PERFLOG_DTOR( m_pName ? m_pName : L"CBasePin", (IPin *) this );
1597
 
#endif // DXMPERF
1598
 
 
1599
 
    //  We don't call disconnect because if the filter is going away
1600
 
    //  all the pins must have a reference count of zero so they must
1601
 
    //  have been disconnected anyway - (but check the assumption)
1602
 
    ASSERT(m_Connected == FALSE);
1603
 
 
1604
 
    delete[] m_pName;
1605
 
 
1606
 
    // check the internal reference count is consistent
1607
 
    ASSERT(m_cRef == 0);
1608
 
}
1609
 
 
1610
 
 
1611
 
/* Override this to say what interfaces we support and where */
1612
 
 
1613
 
STDMETHODIMP
1614
 
CBasePin::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv)
1615
 
{
1616
 
    /* Do we have this interface */
1617
 
 
1618
 
    if (riid == IID_IPin) {
1619
 
        return GetInterface((IPin *) this, ppv);
1620
 
    } else if (riid == IID_IQualityControl) {
1621
 
        return GetInterface((IQualityControl *) this, ppv);
1622
 
    } else {
1623
 
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1624
 
    }
1625
 
}
1626
 
 
1627
 
 
1628
 
/* Override to increment the owning filter's reference count */
1629
 
 
1630
 
STDMETHODIMP_(ULONG)
1631
 
CBasePin::NonDelegatingAddRef()
1632
 
{
1633
 
    ASSERT(InterlockedIncrement(&m_cRef) > 0);
1634
 
    return m_pFilter->AddRef();
1635
 
}
1636
 
 
1637
 
 
1638
 
/* Override to decrement the owning filter's reference count */
1639
 
 
1640
 
STDMETHODIMP_(ULONG)
1641
 
CBasePin::NonDelegatingRelease()
1642
 
{
1643
 
    ASSERT(InterlockedDecrement(&m_cRef) >= 0);
1644
 
    return m_pFilter->Release();
1645
 
}
1646
 
 
1647
 
 
1648
 
/* Displays pin connection information */
1649
 
 
1650
 
#ifdef DEBUG
1651
 
void
1652
 
CBasePin::DisplayPinInfo(IPin *pReceivePin)
1653
 
{
1654
 
 
1655
 
    if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) {
1656
 
        PIN_INFO ConnectPinInfo;
1657
 
        PIN_INFO ReceivePinInfo;
1658
 
 
1659
 
        if (FAILED(QueryPinInfo(&ConnectPinInfo))) {
1660
 
            StringCchCopyW(ConnectPinInfo.achName, sizeof(ConnectPinInfo.achName)/sizeof(WCHAR), L"Bad Pin");
1661
 
        } else {
1662
 
            QueryPinInfoReleaseFilter(ConnectPinInfo);
1663
 
        }
1664
 
 
1665
 
        if (FAILED(pReceivePin->QueryPinInfo(&ReceivePinInfo))) {
1666
 
            StringCchCopyW(ReceivePinInfo.achName, sizeof(ReceivePinInfo.achName)/sizeof(WCHAR), L"Bad Pin");
1667
 
        } else {
1668
 
            QueryPinInfoReleaseFilter(ReceivePinInfo);
1669
 
        }
1670
 
 
1671
 
        DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying to connect Pins :")));
1672
 
        DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("    <%ls>"), ConnectPinInfo.achName));
1673
 
        DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("    <%ls>"), ReceivePinInfo.achName));
1674
 
    }
1675
 
}
1676
 
#endif
1677
 
 
1678
 
 
1679
 
/* Displays general information on the pin media type */
1680
 
 
1681
 
#ifdef DEBUG
1682
 
void CBasePin::DisplayTypeInfo(IPin *pPin, const CMediaType *pmt)
1683
 
{
1684
 
    UNREFERENCED_PARAMETER(pPin);
1685
 
    if (DbgCheckModuleLevel(LOG_TRACE, CONNECT_TRACE_LEVEL)) {
1686
 
        DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Trying media type:")));
1687
 
        DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("    major type:  %hs"),
1688
 
               GuidNames[*pmt->Type()]));
1689
 
        DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("    sub type  :  %hs"),
1690
 
               GuidNames[*pmt->Subtype()]));
1691
 
    }
1692
 
}
1693
 
#endif
1694
 
 
1695
 
/* Asked to connect to a pin. A pin is always attached to an owning filter
1696
 
   object so we always delegate our locking to that object. We first of all
1697
 
   retrieve a media type enumerator for the input pin and see if we accept
1698
 
   any of the formats that it would ideally like, failing that we retrieve
1699
 
   our enumerator and see if it will accept any of our preferred types */
1700
 
 
1701
 
STDMETHODIMP
1702
 
CBasePin::Connect(
1703
 
    IPin * pReceivePin,
1704
 
    __in_opt const AM_MEDIA_TYPE *pmt   // optional media type
1705
 
)
1706
 
{
1707
 
    CheckPointer(pReceivePin,E_POINTER);
1708
 
    ValidateReadPtr(pReceivePin,sizeof(IPin));
1709
 
    CAutoLock cObjectLock(m_pLock);
1710
 
    DisplayPinInfo(pReceivePin);
1711
 
 
1712
 
    /* See if we are already connected */
1713
 
 
1714
 
    if (m_Connected) {
1715
 
        DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Already connected")));
1716
 
        return VFW_E_ALREADY_CONNECTED;
1717
 
    }
1718
 
 
1719
 
    /* See if the filter is active */
1720
 
    if (!IsStopped() && !m_bCanReconnectWhenActive) {
1721
 
        return VFW_E_NOT_STOPPED;
1722
 
    }
1723
 
 
1724
 
 
1725
 
    // Find a mutually agreeable media type -
1726
 
    // Pass in the template media type. If this is partially specified,
1727
 
    // each of the enumerated media types will need to be checked against
1728
 
    // it. If it is non-null and fully specified, we will just try to connect
1729
 
    // with this.
1730
 
 
1731
 
    const CMediaType * ptype = (CMediaType*)pmt;
1732
 
    HRESULT hr = AgreeMediaType(pReceivePin, ptype);
1733
 
    if (FAILED(hr)) {
1734
 
        DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to agree type")));
1735
 
 
1736
 
        // Since the procedure is already returning an error code, there
1737
 
        // is nothing else this function can do to report the error.
1738
 
        EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
1739
 
 
1740
 
#ifdef DXMPERF
1741
 
        PERFLOG_CONNECT( (IPin *) this, pReceivePin, hr, pmt );
1742
 
#endif // DXMPERF
1743
 
 
1744
 
        return hr;
1745
 
    }
1746
 
 
1747
 
    DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Connection succeeded")));
1748
 
 
1749
 
#ifdef DXMPERF
1750
 
    PERFLOG_CONNECT( (IPin *) this, pReceivePin, NOERROR, pmt );
1751
 
#endif // DXMPERF
1752
 
 
1753
 
    return NOERROR;
1754
 
}
1755
 
 
1756
 
// given a specific media type, attempt a connection (includes
1757
 
// checking that the type is acceptable to this pin)
1758
 
HRESULT
1759
 
CBasePin::AttemptConnection(
1760
 
    IPin* pReceivePin,      // connect to this pin
1761
 
    const CMediaType* pmt   // using this type
1762
 
)
1763
 
{
1764
 
    // The caller should hold the filter lock becasue this function
1765
 
    // uses m_Connected.  The caller should also hold the filter lock
1766
 
    // because this function calls SetMediaType(), IsStopped() and
1767
 
    // CompleteConnect().
1768
 
    ASSERT(CritCheckIn(m_pLock));
1769
 
 
1770
 
    // Check that the connection is valid  -- need to do this for every
1771
 
    // connect attempt since BreakConnect will undo it.
1772
 
    HRESULT hr = CheckConnect(pReceivePin);
1773
 
    if (FAILED(hr)) {
1774
 
        DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("CheckConnect failed")));
1775
 
 
1776
 
        // Since the procedure is already returning an error code, there
1777
 
        // is nothing else this function can do to report the error.
1778
 
        EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
1779
 
 
1780
 
        return hr;
1781
 
    }
1782
 
 
1783
 
    DisplayTypeInfo(pReceivePin, pmt);
1784
 
 
1785
 
    /* Check we will accept this media type */
1786
 
 
1787
 
    hr = CheckMediaType(pmt);
1788
 
    if (hr == NOERROR) {
1789
 
 
1790
 
        /*  Make ourselves look connected otherwise ReceiveConnection
1791
 
            may not be able to complete the connection
1792
 
        */
1793
 
        m_Connected = pReceivePin;
1794
 
        m_Connected->AddRef();
1795
 
        hr = SetMediaType(pmt);
1796
 
        if (SUCCEEDED(hr)) {
1797
 
            /* See if the other pin will accept this type */
1798
 
 
1799
 
            hr = pReceivePin->ReceiveConnection((IPin *)this, pmt);
1800
 
            if (SUCCEEDED(hr)) {
1801
 
                /* Complete the connection */
1802
 
 
1803
 
                hr = CompleteConnect(pReceivePin);
1804
 
                if (SUCCEEDED(hr)) {
1805
 
                    return hr;
1806
 
                } else {
1807
 
                    DbgLog((LOG_TRACE,
1808
 
                            CONNECT_TRACE_LEVEL,
1809
 
                            TEXT("Failed to complete connection")));
1810
 
                    pReceivePin->Disconnect();
1811
 
                }
1812
 
            }
1813
 
        }
1814
 
    } else {
1815
 
        // we cannot use this media type
1816
 
 
1817
 
        // return a specific media type error if there is one
1818
 
        // or map a general failure code to something more helpful
1819
 
        // (in particular S_FALSE gets changed to an error code)
1820
 
        if (SUCCEEDED(hr) ||
1821
 
            (hr == E_FAIL) ||
1822
 
            (hr == E_INVALIDARG)) {
1823
 
            hr = VFW_E_TYPE_NOT_ACCEPTED;
1824
 
        }
1825
 
    }
1826
 
 
1827
 
    // BreakConnect and release any connection here in case CheckMediaType
1828
 
    // failed, or if we set anything up during a call back during
1829
 
    // ReceiveConnection.
1830
 
 
1831
 
    // Since the procedure is already returning an error code, there
1832
 
    // is nothing else this function can do to report the error.
1833
 
    EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
1834
 
 
1835
 
    /*  If failed then undo our state */
1836
 
    if (m_Connected) {
1837
 
        m_Connected->Release();
1838
 
        m_Connected = NULL;
1839
 
    }
1840
 
 
1841
 
    return hr;
1842
 
}
1843
 
 
1844
 
/* Given an enumerator we cycle through all the media types it proposes and
1845
 
   firstly suggest them to our derived pin class and if that succeeds try
1846
 
   them with the pin in a ReceiveConnection call. This means that if our pin
1847
 
   proposes a media type we still check in here that we can support it. This
1848
 
   is deliberate so that in simple cases the enumerator can hold all of the
1849
 
   media types even if some of them are not really currently available */
1850
 
 
1851
 
HRESULT CBasePin::TryMediaTypes(
1852
 
    IPin *pReceivePin,
1853
 
    __in_opt const CMediaType *pmt,
1854
 
    IEnumMediaTypes *pEnum)
1855
 
{
1856
 
    /* Reset the current enumerator position */
1857
 
 
1858
 
    HRESULT hr = pEnum->Reset();
1859
 
    if (FAILED(hr)) {
1860
 
        return hr;
1861
 
    }
1862
 
 
1863
 
    CMediaType *pMediaType = NULL;
1864
 
    ULONG ulMediaCount = 0;
1865
 
 
1866
 
    // attempt to remember a specific error code if there is one
1867
 
    HRESULT hrFailure = S_OK;
1868
 
 
1869
 
    for (;;) {
1870
 
 
1871
 
        /* Retrieve the next media type NOTE each time round the loop the
1872
 
           enumerator interface will allocate another AM_MEDIA_TYPE structure
1873
 
           If we are successful then we copy it into our output object, if
1874
 
           not then we must delete the memory allocated before returning */
1875
 
 
1876
 
        hr = pEnum->Next(1, (AM_MEDIA_TYPE**)&pMediaType,&ulMediaCount);
1877
 
        if (hr != S_OK) {
1878
 
            if (S_OK == hrFailure) {
1879
 
                hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
1880
 
            }
1881
 
            return hrFailure;
1882
 
        }
1883
 
 
1884
 
 
1885
 
        ASSERT(ulMediaCount == 1);
1886
 
        ASSERT(pMediaType);
1887
 
 
1888
 
        // check that this matches the partial type (if any)
1889
 
 
1890
 
        if (pMediaType &&
1891
 
            ((pmt == NULL) ||
1892
 
            pMediaType->MatchesPartial(pmt))) {
1893
 
 
1894
 
            hr = AttemptConnection(pReceivePin, pMediaType);
1895
 
 
1896
 
            // attempt to remember a specific error code
1897
 
            if (FAILED(hr) &&
1898
 
            SUCCEEDED(hrFailure) &&
1899
 
            (hr != E_FAIL) &&
1900
 
            (hr != E_INVALIDARG) &&
1901
 
            (hr != VFW_E_TYPE_NOT_ACCEPTED)) {
1902
 
                hrFailure = hr;
1903
 
            }
1904
 
        } else {
1905
 
            hr = VFW_E_NO_ACCEPTABLE_TYPES;
1906
 
        }
1907
 
 
1908
 
        if(pMediaType) {
1909
 
            DeleteMediaType(pMediaType);
1910
 
            pMediaType = NULL;
1911
 
        }
1912
 
 
1913
 
        if (S_OK == hr) {
1914
 
            return hr;
1915
 
        }
1916
 
    }
1917
 
}
1918
 
 
1919
 
 
1920
 
/* This is called to make the connection, including the taask of finding
1921
 
   a media type for the pin connection. pmt is the proposed media type
1922
 
   from the Connect call: if this is fully specified, we will try that.
1923
 
   Otherwise we enumerate and try all the input pin's types first and
1924
 
   if that fails we then enumerate and try all our preferred media types.
1925
 
   For each media type we check it against pmt (if non-null and partially
1926
 
   specified) as well as checking that both pins will accept it.
1927
 
 */
1928
 
 
1929
 
HRESULT CBasePin::AgreeMediaType(
1930
 
    IPin *pReceivePin,
1931
 
    const CMediaType *pmt)
1932
 
{
1933
 
    ASSERT(pReceivePin);
1934
 
    IEnumMediaTypes *pEnumMediaTypes = NULL;
1935
 
 
1936
 
    // if the media type is fully specified then use that
1937
 
    if ( (pmt != NULL) && (!pmt->IsPartiallySpecified())) {
1938
 
 
1939
 
        // if this media type fails, then we must fail the connection
1940
 
        // since if pmt is nonnull we are only allowed to connect
1941
 
        // using a type that matches it.
1942
 
 
1943
 
        return AttemptConnection(pReceivePin, pmt);
1944
 
    }
1945
 
 
1946
 
 
1947
 
    /* Try the other pin's enumerator */
1948
 
 
1949
 
    HRESULT hrFailure = VFW_E_NO_ACCEPTABLE_TYPES;
1950
 
 
1951
 
    for (int i = 0; i < 2; i++) {
1952
 
        HRESULT hr;
1953
 
        if (i == (int)m_bTryMyTypesFirst) {
1954
 
            hr = pReceivePin->EnumMediaTypes(&pEnumMediaTypes);
1955
 
        } else {
1956
 
            hr = EnumMediaTypes(&pEnumMediaTypes);
1957
 
        }
1958
 
        if (SUCCEEDED(hr)) {
1959
 
            ASSERT(pEnumMediaTypes);
1960
 
            hr = TryMediaTypes(pReceivePin,pmt,pEnumMediaTypes);
1961
 
            pEnumMediaTypes->Release();
1962
 
            if (SUCCEEDED(hr)) {
1963
 
                return NOERROR;
1964
 
            } else {
1965
 
                // try to remember specific error codes if there are any
1966
 
                if ((hr != E_FAIL) &&
1967
 
                    (hr != E_INVALIDARG) &&
1968
 
                    (hr != VFW_E_TYPE_NOT_ACCEPTED)) {
1969
 
                    hrFailure = hr;
1970
 
                }
1971
 
            }
1972
 
        }
1973
 
    }
1974
 
 
1975
 
    return hrFailure;
1976
 
}
1977
 
 
1978
 
 
1979
 
/* Called when we want to complete a connection to another filter. Failing
1980
 
   this will also fail the connection and disconnect the other pin as well */
1981
 
 
1982
 
HRESULT
1983
 
CBasePin::CompleteConnect(IPin *pReceivePin)
1984
 
{
1985
 
    UNREFERENCED_PARAMETER(pReceivePin);
1986
 
    return NOERROR;
1987
 
}
1988
 
 
1989
 
 
1990
 
/* This is called to set the format for a pin connection - CheckMediaType
1991
 
   will have been called to check the connection format and if it didn't
1992
 
   return an error code then this (virtual) function will be invoked */
1993
 
 
1994
 
HRESULT
1995
 
CBasePin::SetMediaType(const CMediaType *pmt)
1996
 
{
1997
 
    HRESULT hr = m_mt.Set(*pmt);
1998
 
    if (FAILED(hr)) {
1999
 
        return hr;
2000
 
    }
2001
 
 
2002
 
    return NOERROR;
2003
 
}
2004
 
 
2005
 
 
2006
 
/* This is called during Connect() to provide a virtual method that can do
2007
 
   any specific check needed for connection such as QueryInterface. This
2008
 
   base class method just checks that the pin directions don't match */
2009
 
 
2010
 
HRESULT
2011
 
CBasePin::CheckConnect(IPin * pPin)
2012
 
{
2013
 
    /* Check that pin directions DONT match */
2014
 
 
2015
 
    PIN_DIRECTION pd;
2016
 
    pPin->QueryDirection(&pd);
2017
 
 
2018
 
    ASSERT((pd == PINDIR_OUTPUT) || (pd == PINDIR_INPUT));
2019
 
    ASSERT((m_dir == PINDIR_OUTPUT) || (m_dir == PINDIR_INPUT));
2020
 
 
2021
 
    // we should allow for non-input and non-output connections?
2022
 
    if (pd == m_dir) {
2023
 
        return VFW_E_INVALID_DIRECTION;
2024
 
    }
2025
 
    return NOERROR;
2026
 
}
2027
 
 
2028
 
 
2029
 
/* This is called when we realise we can't make a connection to the pin and
2030
 
   must undo anything we did in CheckConnect - override to release QIs done */
2031
 
 
2032
 
HRESULT
2033
 
CBasePin::BreakConnect()
2034
 
{
2035
 
    return NOERROR;
2036
 
}
2037
 
 
2038
 
 
2039
 
/* Called normally by an output pin on an input pin to try and establish a
2040
 
   connection.
2041
 
*/
2042
 
 
2043
 
STDMETHODIMP
2044
 
CBasePin::ReceiveConnection(
2045
 
    IPin * pConnector,   // this is the pin who we will connect to
2046
 
    const AM_MEDIA_TYPE *pmt  // this is the media type we will exchange
2047
 
)
2048
 
{
2049
 
    CheckPointer(pConnector,E_POINTER);
2050
 
    CheckPointer(pmt,E_POINTER);
2051
 
    ValidateReadPtr(pConnector,sizeof(IPin));
2052
 
    ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE));
2053
 
    CAutoLock cObjectLock(m_pLock);
2054
 
 
2055
 
    /* Are we already connected */
2056
 
    if (m_Connected) {
2057
 
        return VFW_E_ALREADY_CONNECTED;
2058
 
    }
2059
 
 
2060
 
    /* See if the filter is active */
2061
 
    if (!IsStopped() && !m_bCanReconnectWhenActive) {
2062
 
        return VFW_E_NOT_STOPPED;
2063
 
    }
2064
 
 
2065
 
    HRESULT hr = CheckConnect(pConnector);
2066
 
    if (FAILED(hr)) {
2067
 
        // Since the procedure is already returning an error code, there
2068
 
        // is nothing else this function can do to report the error.
2069
 
        EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
2070
 
 
2071
 
#ifdef DXMPERF
2072
 
        PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt );
2073
 
#endif // DXMPERF
2074
 
 
2075
 
        return hr;
2076
 
    }
2077
 
 
2078
 
    /* Ask derived class if this media type is ok */
2079
 
 
2080
 
    CMediaType * pcmt = (CMediaType*) pmt;
2081
 
    hr = CheckMediaType(pcmt);
2082
 
    if (hr != NOERROR) {
2083
 
        // no -we don't support this media type
2084
 
 
2085
 
        // Since the procedure is already returning an error code, there
2086
 
        // is nothing else this function can do to report the error.
2087
 
        EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
2088
 
 
2089
 
        // return a specific media type error if there is one
2090
 
        // or map a general failure code to something more helpful
2091
 
        // (in particular S_FALSE gets changed to an error code)
2092
 
        if (SUCCEEDED(hr) ||
2093
 
            (hr == E_FAIL) ||
2094
 
            (hr == E_INVALIDARG)) {
2095
 
            hr = VFW_E_TYPE_NOT_ACCEPTED;
2096
 
        }
2097
 
 
2098
 
#ifdef DXMPERF
2099
 
        PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt );
2100
 
#endif // DXMPERF
2101
 
 
2102
 
        return hr;
2103
 
    }
2104
 
 
2105
 
    /* Complete the connection */
2106
 
 
2107
 
    m_Connected = pConnector;
2108
 
    m_Connected->AddRef();
2109
 
    hr = SetMediaType(pcmt);
2110
 
    if (SUCCEEDED(hr)) {
2111
 
        hr = CompleteConnect(pConnector);
2112
 
        if (SUCCEEDED(hr)) {
2113
 
 
2114
 
#ifdef DXMPERF
2115
 
            PERFLOG_RXCONNECT( pConnector, (IPin *) this, NOERROR, pmt );
2116
 
#endif // DXMPERF
2117
 
 
2118
 
            return NOERROR;
2119
 
        }
2120
 
    }
2121
 
 
2122
 
    DbgLog((LOG_TRACE, CONNECT_TRACE_LEVEL, TEXT("Failed to set the media type or failed to complete the connection.")));
2123
 
    m_Connected->Release();
2124
 
    m_Connected = NULL;
2125
 
 
2126
 
    // Since the procedure is already returning an error code, there
2127
 
    // is nothing else this function can do to report the error.
2128
 
    EXECUTE_ASSERT( SUCCEEDED( BreakConnect() ) );
2129
 
 
2130
 
#ifdef DXMPERF
2131
 
    PERFLOG_RXCONNECT( pConnector, (IPin *) this, hr, pmt );
2132
 
#endif // DXMPERF
2133
 
 
2134
 
    return hr;
2135
 
}
2136
 
 
2137
 
 
2138
 
/* Called when we want to terminate a pin connection */
2139
 
 
2140
 
STDMETHODIMP
2141
 
CBasePin::Disconnect()
2142
 
{
2143
 
    CAutoLock cObjectLock(m_pLock);
2144
 
 
2145
 
    /* See if the filter is active */
2146
 
    if (!IsStopped()) {
2147
 
        return VFW_E_NOT_STOPPED;
2148
 
    }
2149
 
 
2150
 
    return DisconnectInternal();
2151
 
}
2152
 
 
2153
 
STDMETHODIMP
2154
 
CBasePin::DisconnectInternal()
2155
 
{
2156
 
    ASSERT(CritCheckIn(m_pLock));
2157
 
 
2158
 
    if (m_Connected) {
2159
 
        HRESULT hr = BreakConnect();
2160
 
        if( FAILED( hr ) ) {
2161
 
 
2162
 
#ifdef DXMPERF
2163
 
            PERFLOG_DISCONNECT( (IPin *) this, m_Connected, hr );
2164
 
#endif // DXMPERF
2165
 
 
2166
 
            // There is usually a bug in the program if BreakConnect() fails.
2167
 
            DbgBreak( "WARNING: BreakConnect() failed in CBasePin::Disconnect()." );
2168
 
            return hr;
2169
 
        }
2170
 
 
2171
 
        m_Connected->Release();
2172
 
        m_Connected = NULL;
2173
 
 
2174
 
#ifdef DXMPERF
2175
 
        PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_OK );
2176
 
#endif // DXMPERF
2177
 
 
2178
 
        return S_OK;
2179
 
    } else {
2180
 
        // no connection - not an error
2181
 
 
2182
 
#ifdef DXMPERF
2183
 
        PERFLOG_DISCONNECT( (IPin *) this, m_Connected, S_FALSE );
2184
 
#endif // DXMPERF
2185
 
 
2186
 
        return S_FALSE;
2187
 
    }
2188
 
}
2189
 
 
2190
 
 
2191
 
/* Return an AddRef()'d pointer to the connected pin if there is one */
2192
 
STDMETHODIMP
2193
 
CBasePin::ConnectedTo(
2194
 
    __deref_out IPin **ppPin
2195
 
)
2196
 
{
2197
 
    CheckPointer(ppPin,E_POINTER);
2198
 
    ValidateReadWritePtr(ppPin,sizeof(IPin *));
2199
 
    //
2200
 
    //  It's pointless to lock here.
2201
 
    //  The caller should ensure integrity.
2202
 
    //
2203
 
 
2204
 
    IPin *pPin = m_Connected;
2205
 
    *ppPin = pPin;
2206
 
    if (pPin != NULL) {
2207
 
        pPin->AddRef();
2208
 
        return S_OK;
2209
 
    } else {
2210
 
        ASSERT(*ppPin == NULL);
2211
 
        return VFW_E_NOT_CONNECTED;
2212
 
    }
2213
 
}
2214
 
 
2215
 
/* Return the media type of the connection */
2216
 
STDMETHODIMP
2217
 
CBasePin::ConnectionMediaType(
2218
 
    __out AM_MEDIA_TYPE *pmt
2219
 
)
2220
 
{
2221
 
    CheckPointer(pmt,E_POINTER);
2222
 
    ValidateReadWritePtr(pmt,sizeof(AM_MEDIA_TYPE));
2223
 
    CAutoLock cObjectLock(m_pLock);
2224
 
 
2225
 
    /*  Copy constructor of m_mt allocates the memory */
2226
 
    if (IsConnected()) {
2227
 
        CopyMediaType( pmt, &m_mt );
2228
 
        return S_OK;
2229
 
    } else {
2230
 
        ((CMediaType *)pmt)->InitMediaType();
2231
 
        return VFW_E_NOT_CONNECTED;
2232
 
    }
2233
 
}
2234
 
 
2235
 
/* Return information about the filter we are connect to */
2236
 
 
2237
 
STDMETHODIMP
2238
 
CBasePin::QueryPinInfo(
2239
 
    __out PIN_INFO * pInfo
2240
 
)
2241
 
{
2242
 
    CheckPointer(pInfo,E_POINTER);
2243
 
    ValidateReadWritePtr(pInfo,sizeof(PIN_INFO));
2244
 
 
2245
 
    pInfo->pFilter = m_pFilter;
2246
 
    if (m_pFilter) {
2247
 
        m_pFilter->AddRef();
2248
 
    }
2249
 
 
2250
 
    if (m_pName) {
2251
 
        (void)StringCchCopyW(pInfo->achName, NUMELMS(pInfo->achName), m_pName);
2252
 
    } else {
2253
 
        pInfo->achName[0] = L'\0';
2254
 
    }
2255
 
 
2256
 
    pInfo->dir = m_dir;
2257
 
 
2258
 
    return NOERROR;
2259
 
}
2260
 
 
2261
 
STDMETHODIMP
2262
 
CBasePin::QueryDirection(
2263
 
    __out PIN_DIRECTION * pPinDir
2264
 
)
2265
 
{
2266
 
    CheckPointer(pPinDir,E_POINTER);
2267
 
    ValidateReadWritePtr(pPinDir,sizeof(PIN_DIRECTION));
2268
 
 
2269
 
    *pPinDir = m_dir;
2270
 
    return NOERROR;
2271
 
}
2272
 
 
2273
 
// Default QueryId to return the pin's name
2274
 
STDMETHODIMP
2275
 
CBasePin::QueryId(
2276
 
    __deref_out LPWSTR * Id
2277
 
)
2278
 
{
2279
 
    //  We're not going away because someone's got a pointer to us
2280
 
    //  so there's no need to lock
2281
 
 
2282
 
    return AMGetWideString(Name(), Id);
2283
 
}
2284
 
 
2285
 
/* Does this pin support this media type WARNING this interface function does
2286
 
   not lock the main object as it is meant to be asynchronous by nature - if
2287
 
   the media types you support depend on some internal state that is updated
2288
 
   dynamically then you will need to implement locking in a derived class */
2289
 
 
2290
 
STDMETHODIMP
2291
 
CBasePin::QueryAccept(
2292
 
    const AM_MEDIA_TYPE *pmt
2293
 
)
2294
 
{
2295
 
    CheckPointer(pmt,E_POINTER);
2296
 
    ValidateReadPtr(pmt,sizeof(AM_MEDIA_TYPE));
2297
 
 
2298
 
    /* The CheckMediaType method is valid to return error codes if the media
2299
 
       type is horrible, an example might be E_INVALIDARG. What we do here
2300
 
       is map all the error codes into either S_OK or S_FALSE regardless */
2301
 
 
2302
 
    HRESULT hr = CheckMediaType((CMediaType*)pmt);
2303
 
    if (FAILED(hr)) {
2304
 
        return S_FALSE;
2305
 
    }
2306
 
    // note that the only defined success codes should be S_OK and S_FALSE...
2307
 
    return hr;
2308
 
}
2309
 
 
2310
 
 
2311
 
/* This can be called to return an enumerator for the pin's list of preferred
2312
 
   media types. An input pin is not obliged to have any preferred formats
2313
 
   although it can do. For example, the window renderer has a preferred type
2314
 
   which describes a video image that matches the current window size. All
2315
 
   output pins should expose at least one preferred format otherwise it is
2316
 
   possible that neither pin has any types and so no connection is possible */
2317
 
 
2318
 
STDMETHODIMP
2319
 
CBasePin::EnumMediaTypes(
2320
 
    __deref_out IEnumMediaTypes **ppEnum
2321
 
)
2322
 
{
2323
 
    CheckPointer(ppEnum,E_POINTER);
2324
 
    ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));
2325
 
 
2326
 
    /* Create a new ref counted enumerator */
2327
 
 
2328
 
    *ppEnum = new CEnumMediaTypes(this,
2329
 
                              NULL);
2330
 
 
2331
 
    if (*ppEnum == NULL) {
2332
 
        return E_OUTOFMEMORY;
2333
 
    }
2334
 
 
2335
 
    return NOERROR;
2336
 
}
2337
 
 
2338
 
 
2339
 
 
2340
 
/* This is a virtual function that returns a media type corresponding with
2341
 
   place iPosition in the list. This base class simply returns an error as
2342
 
   we support no media types by default but derived classes should override */
2343
 
 
2344
 
HRESULT CBasePin::GetMediaType(int iPosition, __inout CMediaType *pMediaType)
2345
 
{
2346
 
    UNREFERENCED_PARAMETER(iPosition);
2347
 
    UNREFERENCED_PARAMETER(pMediaType);
2348
 
    return E_UNEXPECTED;
2349
 
}
2350
 
 
2351
 
 
2352
 
/* This is a virtual function that returns the current media type version.
2353
 
   The base class initialises the media type enumerators with the value 1
2354
 
   By default we always returns that same value. A Derived class may change
2355
 
   the list of media types available and after doing so it should increment
2356
 
   the version either in a method derived from this, or more simply by just
2357
 
   incrementing the m_TypeVersion base pin variable. The type enumerators
2358
 
   call this when they want to see if their enumerations are out of date */
2359
 
 
2360
 
LONG CBasePin::GetMediaTypeVersion()
2361
 
{
2362
 
    return m_TypeVersion;
2363
 
}
2364
 
 
2365
 
 
2366
 
/* Increment the cookie representing the current media type version */
2367
 
 
2368
 
void CBasePin::IncrementTypeVersion()
2369
 
{
2370
 
    InterlockedIncrement(&m_TypeVersion);
2371
 
}
2372
 
 
2373
 
 
2374
 
/* Called by IMediaFilter implementation when the state changes from Stopped
2375
 
   to either paused or running and in derived classes could do things like
2376
 
   commit memory and grab hardware resource (the default is to do nothing) */
2377
 
 
2378
 
HRESULT
2379
 
CBasePin::Active(void)
2380
 
{
2381
 
    return NOERROR;
2382
 
}
2383
 
 
2384
 
/* Called by IMediaFilter implementation when the state changes from
2385
 
   to either paused to running and in derived classes could do things like
2386
 
   commit memory and grab hardware resource (the default is to do nothing) */
2387
 
 
2388
 
HRESULT
2389
 
CBasePin::Run(REFERENCE_TIME tStart)
2390
 
{
2391
 
    UNREFERENCED_PARAMETER(tStart);
2392
 
    return NOERROR;
2393
 
}
2394
 
 
2395
 
 
2396
 
/* Also called by the IMediaFilter implementation when the state changes to
2397
 
   Stopped at which point you should decommit allocators and free hardware
2398
 
   resources you grabbed in the Active call (default is also to do nothing) */
2399
 
 
2400
 
HRESULT
2401
 
CBasePin::Inactive(void)
2402
 
{
2403
 
    m_bRunTimeError = FALSE;
2404
 
    return NOERROR;
2405
 
}
2406
 
 
2407
 
 
2408
 
// Called when no more data will arrive
2409
 
STDMETHODIMP
2410
 
CBasePin::EndOfStream(void)
2411
 
{
2412
 
    return S_OK;
2413
 
}
2414
 
 
2415
 
 
2416
 
STDMETHODIMP
2417
 
CBasePin::SetSink(IQualityControl * piqc)
2418
 
{
2419
 
    CAutoLock cObjectLock(m_pLock);
2420
 
    if (piqc) ValidateReadPtr(piqc,sizeof(IQualityControl));
2421
 
    m_pQSink = piqc;
2422
 
    return NOERROR;
2423
 
} // SetSink
2424
 
 
2425
 
 
2426
 
STDMETHODIMP
2427
 
CBasePin::Notify(IBaseFilter * pSender, Quality q)
2428
 
{
2429
 
    UNREFERENCED_PARAMETER(q);
2430
 
    UNREFERENCED_PARAMETER(pSender);
2431
 
    DbgBreak("IQualityControl::Notify not over-ridden from CBasePin.  (IGNORE is OK)");
2432
 
    return E_NOTIMPL;
2433
 
} //Notify
2434
 
 
2435
 
 
2436
 
// NewSegment notifies of the start/stop/rate applying to the data
2437
 
// about to be received. Default implementation records data and
2438
 
// returns S_OK.
2439
 
// Override this to pass downstream.
2440
 
STDMETHODIMP
2441
 
CBasePin::NewSegment(
2442
 
                REFERENCE_TIME tStart,
2443
 
                REFERENCE_TIME tStop,
2444
 
                double dRate)
2445
 
{
2446
 
    m_tStart = tStart;
2447
 
    m_tStop = tStop;
2448
 
    m_dRate = dRate;
2449
 
 
2450
 
    return S_OK;
2451
 
}
2452
 
 
2453
 
 
2454
 
//=====================================================================
2455
 
//=====================================================================
2456
 
// Implements CBaseOutputPin
2457
 
//=====================================================================
2458
 
//=====================================================================
2459
 
 
2460
 
 
2461
 
CBaseOutputPin::CBaseOutputPin(__in_opt LPCTSTR pObjectName,
2462
 
                   __in CBaseFilter *pFilter,
2463
 
                   __in CCritSec *pLock,
2464
 
                   __inout HRESULT *phr,
2465
 
                   __in_opt LPCWSTR pName) :
2466
 
    CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT),
2467
 
    m_pAllocator(NULL),
2468
 
    m_pInputPin(NULL)
2469
 
{
2470
 
    ASSERT(pFilter);
2471
 
}
2472
 
 
2473
 
#ifdef UNICODE
2474
 
CBaseOutputPin::CBaseOutputPin(__in_opt LPCSTR pObjectName,
2475
 
                   __in CBaseFilter *pFilter,
2476
 
                   __in CCritSec *pLock,
2477
 
                   __inout HRESULT *phr,
2478
 
                   __in_opt LPCWSTR pName) :
2479
 
    CBasePin(pObjectName, pFilter, pLock, phr, pName, PINDIR_OUTPUT),
2480
 
    m_pAllocator(NULL),
2481
 
    m_pInputPin(NULL)
2482
 
{
2483
 
    ASSERT(pFilter);
2484
 
}
2485
 
#endif
2486
 
 
2487
 
/*   This is called after a media type has been proposed
2488
 
 
2489
 
     Try to complete the connection by agreeing the allocator
2490
 
*/
2491
 
HRESULT
2492
 
CBaseOutputPin::CompleteConnect(IPin *pReceivePin)
2493
 
{
2494
 
    UNREFERENCED_PARAMETER(pReceivePin);
2495
 
    return DecideAllocator(m_pInputPin, &m_pAllocator);
2496
 
}
2497
 
 
2498
 
 
2499
 
/* This method is called when the output pin is about to try and connect to
2500
 
   an input pin. It is at this point that you should try and grab any extra
2501
 
   interfaces that you need, in this case IMemInputPin. Because this is
2502
 
   only called if we are not currently connected we do NOT need to call
2503
 
   BreakConnect. This also makes it easier to derive classes from us as
2504
 
   BreakConnect is only called when we actually have to break a connection
2505
 
   (or a partly made connection) and not when we are checking a connection */
2506
 
 
2507
 
/* Overriden from CBasePin */
2508
 
 
2509
 
HRESULT
2510
 
CBaseOutputPin::CheckConnect(IPin * pPin)
2511
 
{
2512
 
    HRESULT hr = CBasePin::CheckConnect(pPin);
2513
 
    if (FAILED(hr)) {
2514
 
    return hr;
2515
 
    }
2516
 
 
2517
 
    // get an input pin and an allocator interface
2518
 
    hr = pPin->QueryInterface(IID_IMemInputPin, (void **) &m_pInputPin);
2519
 
    if (FAILED(hr)) {
2520
 
        return hr;
2521
 
    }
2522
 
    return NOERROR;
2523
 
}
2524
 
 
2525
 
 
2526
 
/* Overriden from CBasePin */
2527
 
 
2528
 
HRESULT
2529
 
CBaseOutputPin::BreakConnect()
2530
 
{
2531
 
    /* Release any allocator we hold */
2532
 
 
2533
 
    if (m_pAllocator) {
2534
 
        // Always decommit the allocator because a downstream filter may or
2535
 
        // may not decommit the connection's allocator.  A memory leak could
2536
 
        // occur if the allocator is not decommited when a connection is broken.
2537
 
        HRESULT hr = m_pAllocator->Decommit();
2538
 
        if( FAILED( hr ) ) {
2539
 
            return hr;
2540
 
        }
2541
 
 
2542
 
        m_pAllocator->Release();
2543
 
        m_pAllocator = NULL;
2544
 
    }
2545
 
 
2546
 
    /* Release any input pin interface we hold */
2547
 
 
2548
 
    if (m_pInputPin) {
2549
 
        m_pInputPin->Release();
2550
 
        m_pInputPin = NULL;
2551
 
    }
2552
 
    return NOERROR;
2553
 
}
2554
 
 
2555
 
 
2556
 
/* This is called when the input pin didn't give us a valid allocator */
2557
 
 
2558
 
HRESULT
2559
 
CBaseOutputPin::InitAllocator(__deref_out IMemAllocator **ppAlloc)
2560
 
{
2561
 
    return CreateMemoryAllocator(ppAlloc);
2562
 
}
2563
 
 
2564
 
 
2565
 
/* Decide on an allocator, override this if you want to use your own allocator
2566
 
   Override DecideBufferSize to call SetProperties. If the input pin fails
2567
 
   the GetAllocator call then this will construct a CMemAllocator and call
2568
 
   DecideBufferSize on that, and if that fails then we are completely hosed.
2569
 
   If the you succeed the DecideBufferSize call, we will notify the input
2570
 
   pin of the selected allocator. NOTE this is called during Connect() which
2571
 
   therefore looks after grabbing and locking the object's critical section */
2572
 
 
2573
 
// We query the input pin for its requested properties and pass this to
2574
 
// DecideBufferSize to allow it to fulfill requests that it is happy
2575
 
// with (eg most people don't care about alignment and are thus happy to
2576
 
// use the downstream pin's alignment request).
2577
 
 
2578
 
HRESULT
2579
 
CBaseOutputPin::DecideAllocator(IMemInputPin *pPin, __deref_out IMemAllocator **ppAlloc)
2580
 
{
2581
 
    HRESULT hr = NOERROR;
2582
 
    *ppAlloc = NULL;
2583
 
 
2584
 
    // get downstream prop request
2585
 
    // the derived class may modify this in DecideBufferSize, but
2586
 
    // we assume that he will consistently modify it the same way,
2587
 
    // so we only get it once
2588
 
    ALLOCATOR_PROPERTIES prop;
2589
 
    ZeroMemory(&prop, sizeof(prop));
2590
 
 
2591
 
    // whatever he returns, we assume prop is either all zeros
2592
 
    // or he has filled it out.
2593
 
    pPin->GetAllocatorRequirements(&prop);
2594
 
 
2595
 
    // if he doesn't care about alignment, then set it to 1
2596
 
    if (prop.cbAlign == 0) {
2597
 
        prop.cbAlign = 1;
2598
 
    }
2599
 
 
2600
 
    /* Try the allocator provided by the input pin */
2601
 
 
2602
 
    hr = pPin->GetAllocator(ppAlloc);
2603
 
    if (SUCCEEDED(hr)) {
2604
 
 
2605
 
        hr = DecideBufferSize(*ppAlloc, &prop);
2606
 
        if (SUCCEEDED(hr)) {
2607
 
            hr = pPin->NotifyAllocator(*ppAlloc, FALSE);
2608
 
            if (SUCCEEDED(hr)) {
2609
 
                return NOERROR;
2610
 
            }
2611
 
        }
2612
 
    }
2613
 
 
2614
 
    /* If the GetAllocator failed we may not have an interface */
2615
 
 
2616
 
    if (*ppAlloc) {
2617
 
        (*ppAlloc)->Release();
2618
 
        *ppAlloc = NULL;
2619
 
    }
2620
 
 
2621
 
    /* Try the output pin's allocator by the same method */
2622
 
 
2623
 
    hr = InitAllocator(ppAlloc);
2624
 
    if (SUCCEEDED(hr)) {
2625
 
 
2626
 
        // note - the properties passed here are in the same
2627
 
        // structure as above and may have been modified by
2628
 
        // the previous call to DecideBufferSize
2629
 
        hr = DecideBufferSize(*ppAlloc, &prop);
2630
 
        if (SUCCEEDED(hr)) {
2631
 
            hr = pPin->NotifyAllocator(*ppAlloc, FALSE);
2632
 
            if (SUCCEEDED(hr)) {
2633
 
                return NOERROR;
2634
 
            }
2635
 
        }
2636
 
    }
2637
 
 
2638
 
    /* Likewise we may not have an interface to release */
2639
 
 
2640
 
    if (*ppAlloc) {
2641
 
        (*ppAlloc)->Release();
2642
 
        *ppAlloc = NULL;
2643
 
    }
2644
 
    return hr;
2645
 
}
2646
 
 
2647
 
 
2648
 
/* This returns an empty sample buffer from the allocator WARNING the same
2649
 
   dangers and restrictions apply here as described below for Deliver() */
2650
 
 
2651
 
HRESULT
2652
 
CBaseOutputPin::GetDeliveryBuffer(__deref_out IMediaSample ** ppSample,
2653
 
                                  __in_opt REFERENCE_TIME * pStartTime,
2654
 
                                  __in_opt REFERENCE_TIME * pEndTime,
2655
 
                                  DWORD dwFlags)
2656
 
{
2657
 
    if (m_pAllocator != NULL) {
2658
 
        return m_pAllocator->GetBuffer(ppSample,pStartTime,pEndTime,dwFlags);
2659
 
    } else {
2660
 
        return E_NOINTERFACE;
2661
 
    }
2662
 
}
2663
 
 
2664
 
 
2665
 
/* Deliver a filled-in sample to the connected input pin. NOTE the object must
2666
 
   have locked itself before calling us otherwise we may get halfway through
2667
 
   executing this method only to find the filter graph has got in and
2668
 
   disconnected us from the input pin. If the filter has no worker threads
2669
 
   then the lock is best applied on Receive(), otherwise it should be done
2670
 
   when the worker thread is ready to deliver. There is a wee snag to worker
2671
 
   threads that this shows up. The worker thread must lock the object when
2672
 
   it is ready to deliver a sample, but it may have to wait until a state
2673
 
   change has completed, but that may never complete because the state change
2674
 
   is waiting for the worker thread to complete. The way to handle this is for
2675
 
   the state change code to grab the critical section, then set an abort event
2676
 
   for the worker thread, then release the critical section and wait for the
2677
 
   worker thread to see the event we set and then signal that it has finished
2678
 
   (with another event). At which point the state change code can complete */
2679
 
 
2680
 
// note (if you've still got any breath left after reading that) that you
2681
 
// need to release the sample yourself after this call. if the connected
2682
 
// input pin needs to hold onto the sample beyond the call, it will addref
2683
 
// the sample itself.
2684
 
 
2685
 
// of course you must release this one and call GetDeliveryBuffer for the
2686
 
// next. You cannot reuse it directly.
2687
 
 
2688
 
HRESULT
2689
 
CBaseOutputPin::Deliver(IMediaSample * pSample)
2690
 
{
2691
 
    if (m_pInputPin == NULL) {
2692
 
        return VFW_E_NOT_CONNECTED;
2693
 
    }
2694
 
 
2695
 
#ifdef DXMPERF
2696
 
    PERFLOG_DELIVER( m_pName ? m_pName : L"CBaseOutputPin", (IPin *) this, (IPin  *) m_pInputPin, pSample, &m_mt );
2697
 
#endif // DXMPERF
2698
 
 
2699
 
    return m_pInputPin->Receive(pSample);
2700
 
}
2701
 
 
2702
 
 
2703
 
// called from elsewhere in our filter to pass EOS downstream to
2704
 
// our connected input pin
2705
 
HRESULT
2706
 
CBaseOutputPin::DeliverEndOfStream(void)
2707
 
{
2708
 
    // remember this is on IPin not IMemInputPin
2709
 
    if (m_Connected == NULL) {
2710
 
        return VFW_E_NOT_CONNECTED;
2711
 
    }
2712
 
    return m_Connected->EndOfStream();
2713
 
}
2714
 
 
2715
 
 
2716
 
/* Commit the allocator's memory, this is called through IMediaFilter
2717
 
   which is responsible for locking the object before calling us */
2718
 
 
2719
 
HRESULT
2720
 
CBaseOutputPin::Active(void)
2721
 
{
2722
 
    if (m_pAllocator == NULL) {
2723
 
        return VFW_E_NO_ALLOCATOR;
2724
 
    }
2725
 
    return m_pAllocator->Commit();
2726
 
}
2727
 
 
2728
 
 
2729
 
/* Free up or unprepare allocator's memory, this is called through
2730
 
   IMediaFilter which is responsible for locking the object first */
2731
 
 
2732
 
HRESULT
2733
 
CBaseOutputPin::Inactive(void)
2734
 
{
2735
 
    m_bRunTimeError = FALSE;
2736
 
    if (m_pAllocator == NULL) {
2737
 
        return VFW_E_NO_ALLOCATOR;
2738
 
    }
2739
 
    return m_pAllocator->Decommit();
2740
 
}
2741
 
 
2742
 
// we have a default handling of EndOfStream which is to return
2743
 
// an error, since this should be called on input pins only
2744
 
STDMETHODIMP
2745
 
CBaseOutputPin::EndOfStream(void)
2746
 
{
2747
 
    return E_UNEXPECTED;
2748
 
}
2749
 
 
2750
 
 
2751
 
// BeginFlush should be called on input pins only
2752
 
STDMETHODIMP
2753
 
CBaseOutputPin::BeginFlush(void)
2754
 
{
2755
 
    return E_UNEXPECTED;
2756
 
}
2757
 
 
2758
 
// EndFlush should be called on input pins only
2759
 
STDMETHODIMP
2760
 
CBaseOutputPin::EndFlush(void)
2761
 
{
2762
 
    return E_UNEXPECTED;
2763
 
}
2764
 
 
2765
 
// call BeginFlush on the connected input pin
2766
 
HRESULT
2767
 
CBaseOutputPin::DeliverBeginFlush(void)
2768
 
{
2769
 
    // remember this is on IPin not IMemInputPin
2770
 
    if (m_Connected == NULL) {
2771
 
        return VFW_E_NOT_CONNECTED;
2772
 
    }
2773
 
    return m_Connected->BeginFlush();
2774
 
}
2775
 
 
2776
 
// call EndFlush on the connected input pin
2777
 
HRESULT
2778
 
CBaseOutputPin::DeliverEndFlush(void)
2779
 
{
2780
 
    // remember this is on IPin not IMemInputPin
2781
 
    if (m_Connected == NULL) {
2782
 
        return VFW_E_NOT_CONNECTED;
2783
 
    }
2784
 
    return m_Connected->EndFlush();
2785
 
}
2786
 
// deliver NewSegment to connected pin
2787
 
HRESULT
2788
 
CBaseOutputPin::DeliverNewSegment(
2789
 
    REFERENCE_TIME tStart,
2790
 
    REFERENCE_TIME tStop,
2791
 
    double dRate)
2792
 
{
2793
 
    if (m_Connected == NULL) {
2794
 
        return VFW_E_NOT_CONNECTED;
2795
 
    }
2796
 
    return m_Connected->NewSegment(tStart, tStop, dRate);
2797
 
}
2798
 
 
2799
 
 
2800
 
//=====================================================================
2801
 
//=====================================================================
2802
 
// Implements CBaseInputPin
2803
 
//=====================================================================
2804
 
//=====================================================================
2805
 
 
2806
 
 
2807
 
/* Constructor creates a default allocator object */
2808
 
 
2809
 
CBaseInputPin::CBaseInputPin(__in_opt LPCTSTR pObjectName,
2810
 
                 __in CBaseFilter *pFilter,
2811
 
                 __in CCritSec *pLock,
2812
 
                 __inout HRESULT *phr,
2813
 
                 __in_opt LPCWSTR pPinName) :
2814
 
    CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT),
2815
 
    m_pAllocator(NULL),
2816
 
    m_bReadOnly(FALSE),
2817
 
    m_bFlushing(FALSE)
2818
 
{
2819
 
    ZeroMemory(&m_SampleProps, sizeof(m_SampleProps));
2820
 
}
2821
 
 
2822
 
#ifdef UNICODE
2823
 
CBaseInputPin::CBaseInputPin(__in LPCSTR pObjectName,
2824
 
                 __in CBaseFilter *pFilter,
2825
 
                 __in CCritSec *pLock,
2826
 
                 __inout HRESULT *phr,
2827
 
                 __in_opt LPCWSTR pPinName) :
2828
 
    CBasePin(pObjectName, pFilter, pLock, phr, pPinName, PINDIR_INPUT),
2829
 
    m_pAllocator(NULL),
2830
 
    m_bReadOnly(FALSE),
2831
 
    m_bFlushing(FALSE)
2832
 
{
2833
 
    ZeroMemory(&m_SampleProps, sizeof(m_SampleProps));
2834
 
}
2835
 
#endif
2836
 
 
2837
 
/* Destructor releases it's reference count on the default allocator */
2838
 
 
2839
 
CBaseInputPin::~CBaseInputPin()
2840
 
{
2841
 
    if (m_pAllocator != NULL) {
2842
 
    m_pAllocator->Release();
2843
 
    m_pAllocator = NULL;
2844
 
    }
2845
 
}
2846
 
 
2847
 
 
2848
 
// override this to publicise our interfaces
2849
 
STDMETHODIMP
2850
 
CBaseInputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
2851
 
{
2852
 
    /* Do we know about this interface */
2853
 
 
2854
 
    if (riid == IID_IMemInputPin) {
2855
 
        return GetInterface((IMemInputPin *) this, ppv);
2856
 
    } else {
2857
 
        return CBasePin::NonDelegatingQueryInterface(riid, ppv);
2858
 
    }
2859
 
}
2860
 
 
2861
 
 
2862
 
/* Return the allocator interface that this input pin would like the output
2863
 
   pin to use. NOTE subsequent calls to GetAllocator should all return an
2864
 
   interface onto the SAME object so we create one object at the start
2865
 
 
2866
 
   Note:
2867
 
       The allocator is Release()'d on disconnect and replaced on
2868
 
       NotifyAllocator().
2869
 
 
2870
 
   Override this to provide your own allocator.
2871
 
*/
2872
 
 
2873
 
STDMETHODIMP
2874
 
CBaseInputPin::GetAllocator(
2875
 
    __deref_out IMemAllocator **ppAllocator)
2876
 
{
2877
 
    CheckPointer(ppAllocator,E_POINTER);
2878
 
    ValidateReadWritePtr(ppAllocator,sizeof(IMemAllocator *));
2879
 
    CAutoLock cObjectLock(m_pLock);
2880
 
 
2881
 
    if (m_pAllocator == NULL) {
2882
 
        HRESULT hr = CreateMemoryAllocator(&m_pAllocator);
2883
 
        if (FAILED(hr)) {
2884
 
            return hr;
2885
 
        }
2886
 
    }
2887
 
    ASSERT(m_pAllocator != NULL);
2888
 
    *ppAllocator = m_pAllocator;
2889
 
    m_pAllocator->AddRef();
2890
 
    return NOERROR;
2891
 
}
2892
 
 
2893
 
 
2894
 
/* Tell the input pin which allocator the output pin is actually going to use
2895
 
   Override this if you care - NOTE the locking we do both here and also in
2896
 
   GetAllocator is unnecessary but derived classes that do something useful
2897
 
   will undoubtedly have to lock the object so this might help remind people */
2898
 
 
2899
 
STDMETHODIMP
2900
 
CBaseInputPin::NotifyAllocator(
2901
 
    IMemAllocator * pAllocator,
2902
 
    BOOL bReadOnly)
2903
 
{
2904
 
    CheckPointer(pAllocator,E_POINTER);
2905
 
    ValidateReadPtr(pAllocator,sizeof(IMemAllocator));
2906
 
    CAutoLock cObjectLock(m_pLock);
2907
 
 
2908
 
    IMemAllocator *pOldAllocator = m_pAllocator;
2909
 
    pAllocator->AddRef();
2910
 
    m_pAllocator = pAllocator;
2911
 
 
2912
 
    if (pOldAllocator != NULL) {
2913
 
        pOldAllocator->Release();
2914
 
    }
2915
 
 
2916
 
    // the readonly flag indicates whether samples from this allocator should
2917
 
    // be regarded as readonly - if true, then inplace transforms will not be
2918
 
    // allowed.
2919
 
    m_bReadOnly = (BYTE)bReadOnly;
2920
 
    return NOERROR;
2921
 
}
2922
 
 
2923
 
 
2924
 
HRESULT
2925
 
CBaseInputPin::BreakConnect()
2926
 
{
2927
 
    /* We don't need our allocator any more */
2928
 
    if (m_pAllocator) {
2929
 
        // Always decommit the allocator because a downstream filter may or
2930
 
        // may not decommit the connection's allocator.  A memory leak could
2931
 
        // occur if the allocator is not decommited when a pin is disconnected.
2932
 
        HRESULT hr = m_pAllocator->Decommit();
2933
 
        if( FAILED( hr ) ) {
2934
 
            return hr;
2935
 
        }
2936
 
 
2937
 
        m_pAllocator->Release();
2938
 
        m_pAllocator = NULL;
2939
 
    }
2940
 
 
2941
 
    return S_OK;
2942
 
}
2943
 
 
2944
 
 
2945
 
/* Do something with this media sample - this base class checks to see if the
2946
 
   format has changed with this media sample and if so checks that the filter
2947
 
   will accept it, generating a run time error if not. Once we have raised a
2948
 
   run time error we set a flag so that no more samples will be accepted
2949
 
 
2950
 
   It is important that any filter should override this method and implement
2951
 
   synchronization so that samples are not processed when the pin is
2952
 
   disconnected etc
2953
 
*/
2954
 
 
2955
 
STDMETHODIMP
2956
 
CBaseInputPin::Receive(IMediaSample *pSample)
2957
 
{
2958
 
    CheckPointer(pSample,E_POINTER);
2959
 
    ValidateReadPtr(pSample,sizeof(IMediaSample));
2960
 
    ASSERT(pSample);
2961
 
 
2962
 
    HRESULT hr = CheckStreaming();
2963
 
    if (S_OK != hr) {
2964
 
        return hr;
2965
 
    }
2966
 
 
2967
 
#ifdef DXMPERF
2968
 
    PERFLOG_RECEIVE( m_pName ? m_pName : L"CBaseInputPin", (IPin *) m_Connected, (IPin *) this, pSample, &m_mt );
2969
 
#endif // DXMPERF
2970
 
 
2971
 
 
2972
 
    /* Check for IMediaSample2 */
2973
 
    IMediaSample2 *pSample2;
2974
 
    if (SUCCEEDED(pSample->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) {
2975
 
        hr = pSample2->GetProperties(sizeof(m_SampleProps), (PBYTE)&m_SampleProps);
2976
 
        pSample2->Release();
2977
 
        if (FAILED(hr)) {
2978
 
            return hr;
2979
 
        }
2980
 
    } else {
2981
 
        /*  Get the properties the hard way */
2982
 
        m_SampleProps.cbData = sizeof(m_SampleProps);
2983
 
        m_SampleProps.dwTypeSpecificFlags = 0;
2984
 
        m_SampleProps.dwStreamId = AM_STREAM_MEDIA;
2985
 
        m_SampleProps.dwSampleFlags = 0;
2986
 
        if (S_OK == pSample->IsDiscontinuity()) {
2987
 
            m_SampleProps.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
2988
 
        }
2989
 
        if (S_OK == pSample->IsPreroll()) {
2990
 
            m_SampleProps.dwSampleFlags |= AM_SAMPLE_PREROLL;
2991
 
        }
2992
 
        if (S_OK == pSample->IsSyncPoint()) {
2993
 
            m_SampleProps.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
2994
 
        }
2995
 
        if (SUCCEEDED(pSample->GetTime(&m_SampleProps.tStart,
2996
 
                                       &m_SampleProps.tStop))) {
2997
 
            m_SampleProps.dwSampleFlags |= AM_SAMPLE_TIMEVALID |
2998
 
                                           AM_SAMPLE_STOPVALID;
2999
 
        }
3000
 
        if (S_OK == pSample->GetMediaType(&m_SampleProps.pMediaType)) {
3001
 
            m_SampleProps.dwSampleFlags |= AM_SAMPLE_TYPECHANGED;
3002
 
        }
3003
 
        pSample->GetPointer(&m_SampleProps.pbBuffer);
3004
 
        m_SampleProps.lActual = pSample->GetActualDataLength();
3005
 
        m_SampleProps.cbBuffer = pSample->GetSize();
3006
 
    }
3007
 
 
3008
 
    /* Has the format changed in this sample */
3009
 
 
3010
 
    if (!(m_SampleProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED)) {
3011
 
        return NOERROR;
3012
 
    }
3013
 
 
3014
 
    /* Check the derived class accepts this format */
3015
 
    /* This shouldn't fail as the source must call QueryAccept first */
3016
 
 
3017
 
    hr = CheckMediaType((CMediaType *)m_SampleProps.pMediaType);
3018
 
 
3019
 
    if (hr == NOERROR) {
3020
 
        return NOERROR;
3021
 
    }
3022
 
 
3023
 
    /* Raise a runtime error if we fail the media type */
3024
 
 
3025
 
    m_bRunTimeError = TRUE;
3026
 
    EndOfStream();
3027
 
    m_pFilter->NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0);
3028
 
    return VFW_E_INVALIDMEDIATYPE;
3029
 
}
3030
 
 
3031
 
 
3032
 
/*  Receive multiple samples */
3033
 
STDMETHODIMP
3034
 
CBaseInputPin::ReceiveMultiple (
3035
 
    __in_ecount(nSamples) IMediaSample **pSamples,
3036
 
    long nSamples,
3037
 
    __out long *nSamplesProcessed)
3038
 
{
3039
 
    CheckPointer(pSamples,E_POINTER);
3040
 
    ValidateReadPtr(pSamples,nSamples * sizeof(IMediaSample *));
3041
 
 
3042
 
    HRESULT hr = S_OK;
3043
 
    *nSamplesProcessed = 0;
3044
 
    while (nSamples-- > 0) {
3045
 
         hr = Receive(pSamples[*nSamplesProcessed]);
3046
 
 
3047
 
         /*  S_FALSE means don't send any more */
3048
 
         if (hr != S_OK) {
3049
 
             break;
3050
 
         }
3051
 
         (*nSamplesProcessed)++;
3052
 
    }
3053
 
    return hr;
3054
 
}
3055
 
 
3056
 
/*  See if Receive() might block */
3057
 
STDMETHODIMP
3058
 
CBaseInputPin::ReceiveCanBlock()
3059
 
{
3060
 
    /*  Ask all the output pins if they block
3061
 
        If there are no output pin assume we do block
3062
 
    */
3063
 
    int cPins = m_pFilter->GetPinCount();
3064
 
    int cOutputPins = 0;
3065
 
    for (int c = 0; c < cPins; c++) {
3066
 
        CBasePin *pPin = m_pFilter->GetPin(c);
3067
 
        if (NULL == pPin) {
3068
 
            break;
3069
 
        }
3070
 
        PIN_DIRECTION pd;
3071
 
        HRESULT hr = pPin->QueryDirection(&pd);
3072
 
        if (FAILED(hr)) {
3073
 
            return hr;
3074
 
        }
3075
 
 
3076
 
        if (pd == PINDIR_OUTPUT) {
3077
 
 
3078
 
            IPin *pConnected;
3079
 
            hr = pPin->ConnectedTo(&pConnected);
3080
 
            if (SUCCEEDED(hr)) {
3081
 
                ASSERT(pConnected != NULL);
3082
 
                cOutputPins++;
3083
 
                IMemInputPin *pInputPin;
3084
 
                hr = pConnected->QueryInterface(
3085
 
                                              IID_IMemInputPin,
3086
 
                                              (void **)&pInputPin);
3087
 
                pConnected->Release();
3088
 
                if (SUCCEEDED(hr)) {
3089
 
                    hr = pInputPin->ReceiveCanBlock();
3090
 
                    pInputPin->Release();
3091
 
                    if (hr != S_FALSE) {
3092
 
                        return S_OK;
3093
 
                    }
3094
 
                } else {
3095
 
                    /*  There's a transport we don't understand here */
3096
 
                    return S_OK;
3097
 
                }
3098
 
            }
3099
 
        }
3100
 
    }
3101
 
    return cOutputPins == 0 ? S_OK : S_FALSE;
3102
 
}
3103
 
 
3104
 
// Default handling for BeginFlush - call at the beginning
3105
 
// of your implementation (makes sure that all Receive calls
3106
 
// fail). After calling this, you need to free any queued data
3107
 
// and then call downstream.
3108
 
STDMETHODIMP
3109
 
CBaseInputPin::BeginFlush(void)
3110
 
{
3111
 
    //  BeginFlush is NOT synchronized with streaming but is part of
3112
 
    //  a control action - hence we synchronize with the filter
3113
 
    CAutoLock lck(m_pLock);
3114
 
 
3115
 
    // if we are already in mid-flush, this is probably a mistake
3116
 
    // though not harmful - try to pick it up for now so I can think about it
3117
 
    ASSERT(!m_bFlushing);
3118
 
 
3119
 
    // first thing to do is ensure that no further Receive calls succeed
3120
 
    m_bFlushing = TRUE;
3121
 
 
3122
 
    // now discard any data and call downstream - must do that
3123
 
    // in derived classes
3124
 
    return S_OK;
3125
 
}
3126
 
 
3127
 
// default handling for EndFlush - call at end of your implementation
3128
 
// - before calling this, ensure that there is no queued data and no thread
3129
 
// pushing any more without a further receive, then call downstream,
3130
 
// then call this method to clear the m_bFlushing flag and re-enable
3131
 
// receives
3132
 
STDMETHODIMP
3133
 
CBaseInputPin::EndFlush(void)
3134
 
{
3135
 
    //  Endlush is NOT synchronized with streaming but is part of
3136
 
    //  a control action - hence we synchronize with the filter
3137
 
    CAutoLock lck(m_pLock);
3138
 
 
3139
 
    // almost certainly a mistake if we are not in mid-flush
3140
 
    ASSERT(m_bFlushing);
3141
 
 
3142
 
    // before calling, sync with pushing thread and ensure
3143
 
    // no more data is going downstream, then call EndFlush on
3144
 
    // downstream pins.
3145
 
 
3146
 
    // now re-enable Receives
3147
 
    m_bFlushing = FALSE;
3148
 
 
3149
 
    // No more errors
3150
 
    m_bRunTimeError = FALSE;
3151
 
 
3152
 
    return S_OK;
3153
 
}
3154
 
 
3155
 
 
3156
 
STDMETHODIMP
3157
 
CBaseInputPin::Notify(IBaseFilter * pSender, Quality q)
3158
 
{
3159
 
    UNREFERENCED_PARAMETER(q);
3160
 
    CheckPointer(pSender,E_POINTER);
3161
 
    ValidateReadPtr(pSender,sizeof(IBaseFilter));
3162
 
    DbgBreak("IQuality::Notify called on an input pin");
3163
 
    return NOERROR;
3164
 
} // Notify
3165
 
 
3166
 
/* Free up or unprepare allocator's memory, this is called through
3167
 
   IMediaFilter which is responsible for locking the object first */
3168
 
 
3169
 
HRESULT
3170
 
CBaseInputPin::Inactive(void)
3171
 
{
3172
 
    m_bRunTimeError = FALSE;
3173
 
    if (m_pAllocator == NULL) {
3174
 
        return VFW_E_NO_ALLOCATOR;
3175
 
    }
3176
 
 
3177
 
    m_bFlushing = FALSE;
3178
 
 
3179
 
    return m_pAllocator->Decommit();
3180
 
}
3181
 
 
3182
 
// what requirements do we have of the allocator - override if you want
3183
 
// to support other people's allocators but need a specific alignment
3184
 
// or prefix.
3185
 
STDMETHODIMP
3186
 
CBaseInputPin::GetAllocatorRequirements(__out ALLOCATOR_PROPERTIES*pProps)
3187
 
{
3188
 
    UNREFERENCED_PARAMETER(pProps);
3189
 
    return E_NOTIMPL;
3190
 
}
3191
 
 
3192
 
//  Check if it's OK to process data
3193
 
//
3194
 
HRESULT
3195
 
CBaseInputPin::CheckStreaming()
3196
 
{
3197
 
    //  Shouldn't be able to get any data if we're not connected!
3198
 
    ASSERT(IsConnected());
3199
 
 
3200
 
    //  Don't process stuff in Stopped state
3201
 
    if (IsStopped()) {
3202
 
        return VFW_E_WRONG_STATE;
3203
 
    }
3204
 
    if (m_bFlushing) {
3205
 
        return S_FALSE;
3206
 
    }
3207
 
    if (m_bRunTimeError) {
3208
 
        return VFW_E_RUNTIME_ERROR;
3209
 
    }
3210
 
    return S_OK;
3211
 
}
3212
 
 
3213
 
// Pass on the Quality notification q to
3214
 
// a. Our QualityControl sink (if we have one) or else
3215
 
// b. to our upstream filter
3216
 
// and if that doesn't work, throw it away with a bad return code
3217
 
HRESULT
3218
 
CBaseInputPin::PassNotify(Quality& q)
3219
 
{
3220
 
    // We pass the message on, which means that we find the quality sink
3221
 
    // for our input pin and send it there
3222
 
 
3223
 
    DbgLog((LOG_TRACE,3,TEXT("Passing Quality notification through transform")));
3224
 
    if (m_pQSink!=NULL) {
3225
 
        return m_pQSink->Notify(m_pFilter, q);
3226
 
    } else {
3227
 
        // no sink set, so pass it upstream
3228
 
        HRESULT hr;
3229
 
        IQualityControl * pIQC;
3230
 
 
3231
 
        hr = VFW_E_NOT_FOUND;                   // default
3232
 
        if (m_Connected) {
3233
 
            m_Connected->QueryInterface(IID_IQualityControl, (void**)&pIQC);
3234
 
 
3235
 
            if (pIQC!=NULL) {
3236
 
                hr = pIQC->Notify(m_pFilter, q);
3237
 
                pIQC->Release();
3238
 
            }
3239
 
        }
3240
 
        return hr;
3241
 
    }
3242
 
 
3243
 
} // PassNotify
3244
 
 
3245
 
//=====================================================================
3246
 
//=====================================================================
3247
 
// Memory allocation class, implements CMediaSample
3248
 
//=====================================================================
3249
 
//=====================================================================
3250
 
 
3251
 
 
3252
 
/* NOTE The implementation of this class calls the CUnknown constructor with
3253
 
   a NULL outer unknown pointer. This has the effect of making us a self
3254
 
   contained class, ie any QueryInterface, AddRef or Release calls will be
3255
 
   routed to the class's NonDelegatingUnknown methods. You will typically
3256
 
   find that the classes that do this then override one or more of these
3257
 
   virtual functions to provide more specialised behaviour. A good example
3258
 
   of this is where a class wants to keep the QueryInterface internal but
3259
 
   still wants it's lifetime controlled by the external object */
3260
 
 
3261
 
/* The last two parameters have default values of NULL and zero */
3262
 
 
3263
 
CMediaSample::CMediaSample(__in_opt LPCTSTR pName,
3264
 
               __in_opt CBaseAllocator *pAllocator,
3265
 
               __inout_opt HRESULT *phr,
3266
 
               __in_bcount_opt(length) LPBYTE pBuffer,
3267
 
               LONG length) :
3268
 
    m_pBuffer(pBuffer),             // Initialise the buffer
3269
 
    m_cbBuffer(length),             // And it's length
3270
 
    m_lActual(length),              // By default, actual = length
3271
 
    m_pMediaType(NULL),             // No media type change
3272
 
    m_dwFlags(0),                   // Nothing set
3273
 
    m_cRef(0),                      // 0 ref count
3274
 
    m_dwTypeSpecificFlags(0),       // Type specific flags
3275
 
    m_dwStreamId(AM_STREAM_MEDIA),  // Stream id
3276
 
    m_pAllocator(pAllocator)        // Allocator
3277
 
{
3278
 
#ifdef DXMPERF
3279
 
    PERFLOG_CTOR( pName ? pName : L"CMediaSample", (IMediaSample *) this );
3280
 
#endif // DXMPERF
3281
 
 
3282
 
    /* We must have an owner and it must also be derived from class
3283
 
       CBaseAllocator BUT we do not hold a reference count on it */
3284
 
 
3285
 
    ASSERT(pAllocator);
3286
 
 
3287
 
    if (length < 0) {
3288
 
        *phr = VFW_E_BUFFER_OVERFLOW;
3289
 
        m_cbBuffer = 0;
3290
 
    }
3291
 
}
3292
 
 
3293
 
#ifdef UNICODE
3294
 
CMediaSample::CMediaSample(__in_opt LPCSTR pName,
3295
 
               __in_opt CBaseAllocator *pAllocator,
3296
 
               __inout_opt HRESULT *phr,
3297
 
               __in_bcount_opt(length) LPBYTE pBuffer,
3298
 
               LONG length) :
3299
 
    m_pBuffer(pBuffer),             // Initialise the buffer
3300
 
    m_cbBuffer(length),             // And it's length
3301
 
    m_lActual(length),              // By default, actual = length
3302
 
    m_pMediaType(NULL),             // No media type change
3303
 
    m_dwFlags(0),                   // Nothing set
3304
 
    m_cRef(0),                      // 0 ref count
3305
 
    m_dwTypeSpecificFlags(0),       // Type specific flags
3306
 
    m_dwStreamId(AM_STREAM_MEDIA),  // Stream id
3307
 
    m_pAllocator(pAllocator)        // Allocator
3308
 
{
3309
 
#ifdef DXMPERF
3310
 
    PERFLOG_CTOR( L"CMediaSample", (IMediaSample *) this );
3311
 
#endif // DXMPERF
3312
 
 
3313
 
    /* We must have an owner and it must also be derived from class
3314
 
       CBaseAllocator BUT we do not hold a reference count on it */
3315
 
 
3316
 
    ASSERT(pAllocator);
3317
 
}
3318
 
#endif
3319
 
 
3320
 
/* Destructor deletes the media type memory */
3321
 
 
3322
 
CMediaSample::~CMediaSample()
3323
 
{
3324
 
#ifdef DXMPERF
3325
 
    PERFLOG_DTOR( L"CMediaSample", (IMediaSample *) this );
3326
 
#endif // DXMPERF
3327
 
 
3328
 
    if (m_pMediaType) {
3329
 
    DeleteMediaType(m_pMediaType);
3330
 
    }
3331
 
}
3332
 
 
3333
 
/* Override this to publicise our interfaces */
3334
 
 
3335
 
STDMETHODIMP
3336
 
CMediaSample::QueryInterface(REFIID riid, __deref_out void **ppv)
3337
 
{
3338
 
    if (riid == IID_IMediaSample ||
3339
 
        riid == IID_IMediaSample2 ||
3340
 
        riid == IID_IUnknown) {
3341
 
        return GetInterface((IMediaSample *) this, ppv);
3342
 
    } else {
3343
 
        *ppv = NULL;
3344
 
        return E_NOINTERFACE;
3345
 
    }
3346
 
}
3347
 
 
3348
 
STDMETHODIMP_(ULONG)
3349
 
CMediaSample::AddRef()
3350
 
{
3351
 
    return InterlockedIncrement(&m_cRef);
3352
 
}
3353
 
 
3354
 
 
3355
 
// --  CMediaSample lifetimes --
3356
 
//
3357
 
// On final release of this sample buffer it is not deleted but
3358
 
// returned to the freelist of the owning memory allocator
3359
 
//
3360
 
// The allocator may be waiting for the last buffer to be placed on the free
3361
 
// list in order to decommit all the memory, so the ReleaseBuffer() call may
3362
 
// result in this sample being deleted. We also need to hold a refcount on
3363
 
// the allocator to stop that going away until we have finished with this.
3364
 
// However, we cannot release the allocator before the ReleaseBuffer, as the
3365
 
// release may cause us to be deleted. Similarly we can't do it afterwards.
3366
 
//
3367
 
// Thus we must leave it to the allocator to hold an addref on our behalf.
3368
 
// When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer
3369
 
// is called, he releases himself, possibly causing us and him to be deleted.
3370
 
 
3371
 
 
3372
 
STDMETHODIMP_(ULONG)
3373
 
CMediaSample::Release()
3374
 
{
3375
 
    /* Decrement our own private reference count */
3376
 
    LONG lRef;
3377
 
    if (m_cRef == 1) {
3378
 
        lRef = 0;
3379
 
        m_cRef = 0;
3380
 
    } else {
3381
 
        lRef = InterlockedDecrement(&m_cRef);
3382
 
    }
3383
 
    ASSERT(lRef >= 0);
3384
 
 
3385
 
    DbgLog((LOG_MEMORY,3,TEXT("    Unknown %X ref-- = %d"),
3386
 
        this, m_cRef));
3387
 
 
3388
 
    /* Did we release our final reference count */
3389
 
    if (lRef == 0) {
3390
 
        /* Free all resources */
3391
 
        if (m_dwFlags & Sample_TypeChanged) {
3392
 
            SetMediaType(NULL);
3393
 
        }
3394
 
        ASSERT(m_pMediaType == NULL);
3395
 
        m_dwFlags = 0;
3396
 
        m_dwTypeSpecificFlags = 0;
3397
 
        m_dwStreamId = AM_STREAM_MEDIA;
3398
 
 
3399
 
        /* This may cause us to be deleted */
3400
 
        // Our refcount is reliably 0 thus no-one will mess with us
3401
 
        m_pAllocator->ReleaseBuffer(this);
3402
 
    }
3403
 
    return (ULONG)lRef;
3404
 
}
3405
 
 
3406
 
 
3407
 
// set the buffer pointer and length. Used by allocators that
3408
 
// want variable sized pointers or pointers into already-read data.
3409
 
// This is only available through a CMediaSample* not an IMediaSample*
3410
 
// and so cannot be changed by clients.
3411
 
HRESULT
3412
 
CMediaSample::SetPointer(__in_bcount(cBytes) BYTE * ptr, LONG cBytes)
3413
 
{
3414
 
    if (cBytes < 0) {
3415
 
        return VFW_E_BUFFER_OVERFLOW;
3416
 
    }
3417
 
    m_pBuffer = ptr;            // new buffer area (could be null)
3418
 
    m_cbBuffer = cBytes;        // length of buffer
3419
 
    m_lActual = cBytes;         // length of data in buffer (assume full)
3420
 
 
3421
 
    return S_OK;
3422
 
}
3423
 
 
3424
 
 
3425
 
// get me a read/write pointer to this buffer's memory. I will actually
3426
 
// want to use sizeUsed bytes.
3427
 
STDMETHODIMP
3428
 
CMediaSample::GetPointer(__deref_out BYTE ** ppBuffer)
3429
 
{
3430
 
    ValidateReadWritePtr(ppBuffer,sizeof(BYTE *));
3431
 
 
3432
 
    // creator must have set pointer either during
3433
 
    // constructor or by SetPointer
3434
 
    ASSERT(m_pBuffer);
3435
 
 
3436
 
    *ppBuffer = m_pBuffer;
3437
 
    return NOERROR;
3438
 
}
3439
 
 
3440
 
 
3441
 
// return the size in bytes of this buffer
3442
 
STDMETHODIMP_(LONG)
3443
 
CMediaSample::GetSize(void)
3444
 
{
3445
 
    return m_cbBuffer;
3446
 
}
3447
 
 
3448
 
 
3449
 
// get the stream time at which this sample should start and finish.
3450
 
STDMETHODIMP
3451
 
CMediaSample::GetTime(
3452
 
    __out REFERENCE_TIME * pTimeStart,     // put time here
3453
 
    __out REFERENCE_TIME * pTimeEnd
3454
 
)
3455
 
{
3456
 
    ValidateReadWritePtr(pTimeStart,sizeof(REFERENCE_TIME));
3457
 
    ValidateReadWritePtr(pTimeEnd,sizeof(REFERENCE_TIME));
3458
 
 
3459
 
    if (!(m_dwFlags & Sample_StopValid)) {
3460
 
        if (!(m_dwFlags & Sample_TimeValid)) {
3461
 
            return VFW_E_SAMPLE_TIME_NOT_SET;
3462
 
        } else {
3463
 
            *pTimeStart = m_Start;
3464
 
 
3465
 
            //  Make sure old stuff works
3466
 
            *pTimeEnd = m_Start + 1;
3467
 
            return VFW_S_NO_STOP_TIME;
3468
 
        }
3469
 
    }
3470
 
 
3471
 
    *pTimeStart = m_Start;
3472
 
    *pTimeEnd = m_End;
3473
 
    return NOERROR;
3474
 
}
3475
 
 
3476
 
 
3477
 
// Set the stream time at which this sample should start and finish.
3478
 
// NULL pointers means the time is reset
3479
 
STDMETHODIMP
3480
 
CMediaSample::SetTime(
3481
 
    __in_opt REFERENCE_TIME * pTimeStart,
3482
 
    __in_opt REFERENCE_TIME * pTimeEnd
3483
 
)
3484
 
{
3485
 
    if (pTimeStart == NULL) {
3486
 
        ASSERT(pTimeEnd == NULL);
3487
 
        m_dwFlags &= ~(Sample_TimeValid | Sample_StopValid);
3488
 
    } else {
3489
 
        if (pTimeEnd == NULL) {
3490
 
            m_Start = *pTimeStart;
3491
 
            m_dwFlags |= Sample_TimeValid;
3492
 
            m_dwFlags &= ~Sample_StopValid;
3493
 
        } else {
3494
 
            ValidateReadPtr(pTimeStart,sizeof(REFERENCE_TIME));
3495
 
            ValidateReadPtr(pTimeEnd,sizeof(REFERENCE_TIME));
3496
 
            ASSERT(*pTimeEnd >= *pTimeStart);
3497
 
 
3498
 
            m_Start = *pTimeStart;
3499
 
            m_End = *pTimeEnd;
3500
 
            m_dwFlags |= Sample_TimeValid | Sample_StopValid;
3501
 
        }
3502
 
    }
3503
 
    return NOERROR;
3504
 
}
3505
 
 
3506
 
 
3507
 
// get the media times (eg bytes) for this sample
3508
 
STDMETHODIMP
3509
 
CMediaSample::GetMediaTime(
3510
 
    __out LONGLONG * pTimeStart,
3511
 
    __out LONGLONG * pTimeEnd
3512
 
)
3513
 
{
3514
 
    ValidateReadWritePtr(pTimeStart,sizeof(LONGLONG));
3515
 
    ValidateReadWritePtr(pTimeEnd,sizeof(LONGLONG));
3516
 
 
3517
 
    if (!(m_dwFlags & Sample_MediaTimeValid)) {
3518
 
        return VFW_E_MEDIA_TIME_NOT_SET;
3519
 
    }
3520
 
 
3521
 
    *pTimeStart = m_MediaStart;
3522
 
    *pTimeEnd = (m_MediaStart + m_MediaEnd);
3523
 
    return NOERROR;
3524
 
}
3525
 
 
3526
 
 
3527
 
// Set the media times for this sample
3528
 
STDMETHODIMP
3529
 
CMediaSample::SetMediaTime(
3530
 
    __in_opt LONGLONG * pTimeStart,
3531
 
    __in_opt LONGLONG * pTimeEnd
3532
 
)
3533
 
{
3534
 
    if (pTimeStart == NULL) {
3535
 
        ASSERT(pTimeEnd == NULL);
3536
 
        m_dwFlags &= ~Sample_MediaTimeValid;
3537
 
    } else {
3538
 
        if (NULL == pTimeEnd) {
3539
 
            return E_POINTER;
3540
 
        }
3541
 
        ValidateReadPtr(pTimeStart,sizeof(LONGLONG));
3542
 
        ValidateReadPtr(pTimeEnd,sizeof(LONGLONG));
3543
 
        ASSERT(*pTimeEnd >= *pTimeStart);
3544
 
 
3545
 
        m_MediaStart = *pTimeStart;
3546
 
        m_MediaEnd = (LONG)(*pTimeEnd - *pTimeStart);
3547
 
        m_dwFlags |= Sample_MediaTimeValid;
3548
 
    }
3549
 
    return NOERROR;
3550
 
}
3551
 
 
3552
 
 
3553
 
STDMETHODIMP
3554
 
CMediaSample::IsSyncPoint(void)
3555
 
{
3556
 
    if (m_dwFlags & Sample_SyncPoint) {
3557
 
        return S_OK;
3558
 
    } else {
3559
 
        return S_FALSE;
3560
 
    }
3561
 
}
3562
 
 
3563
 
 
3564
 
STDMETHODIMP
3565
 
CMediaSample::SetSyncPoint(BOOL bIsSyncPoint)
3566
 
{
3567
 
    if (bIsSyncPoint) {
3568
 
        m_dwFlags |= Sample_SyncPoint;
3569
 
    } else {
3570
 
        m_dwFlags &= ~Sample_SyncPoint;
3571
 
    }
3572
 
    return NOERROR;
3573
 
}
3574
 
 
3575
 
// returns S_OK if there is a discontinuity in the data (this same is
3576
 
// not a continuation of the previous stream of data
3577
 
// - there has been a seek).
3578
 
STDMETHODIMP
3579
 
CMediaSample::IsDiscontinuity(void)
3580
 
{
3581
 
    if (m_dwFlags & Sample_Discontinuity) {
3582
 
        return S_OK;
3583
 
    } else {
3584
 
        return S_FALSE;
3585
 
    }
3586
 
}
3587
 
 
3588
 
// set the discontinuity property - TRUE if this sample is not a
3589
 
// continuation, but a new sample after a seek.
3590
 
STDMETHODIMP
3591
 
CMediaSample::SetDiscontinuity(BOOL bDiscont)
3592
 
{
3593
 
    // should be TRUE or FALSE
3594
 
    if (bDiscont) {
3595
 
        m_dwFlags |= Sample_Discontinuity;
3596
 
    } else {
3597
 
        m_dwFlags &= ~Sample_Discontinuity;
3598
 
    }
3599
 
    return S_OK;
3600
 
}
3601
 
 
3602
 
STDMETHODIMP
3603
 
CMediaSample::IsPreroll(void)
3604
 
{
3605
 
    if (m_dwFlags & Sample_Preroll) {
3606
 
        return S_OK;
3607
 
    } else {
3608
 
        return S_FALSE;
3609
 
    }
3610
 
}
3611
 
 
3612
 
 
3613
 
STDMETHODIMP
3614
 
CMediaSample::SetPreroll(BOOL bIsPreroll)
3615
 
{
3616
 
    if (bIsPreroll) {
3617
 
        m_dwFlags |= Sample_Preroll;
3618
 
    } else {
3619
 
        m_dwFlags &= ~Sample_Preroll;
3620
 
    }
3621
 
    return NOERROR;
3622
 
}
3623
 
 
3624
 
STDMETHODIMP_(LONG)
3625
 
CMediaSample::GetActualDataLength(void)
3626
 
{
3627
 
    return m_lActual;
3628
 
}
3629
 
 
3630
 
 
3631
 
STDMETHODIMP
3632
 
CMediaSample::SetActualDataLength(LONG lActual)
3633
 
{
3634
 
    if (lActual > m_cbBuffer || lActual < 0) {
3635
 
        ASSERT(lActual <= GetSize());
3636
 
        return VFW_E_BUFFER_OVERFLOW;
3637
 
    }
3638
 
    m_lActual = lActual;
3639
 
    return NOERROR;
3640
 
}
3641
 
 
3642
 
 
3643
 
/* These allow for limited format changes in band */
3644
 
 
3645
 
STDMETHODIMP
3646
 
CMediaSample::GetMediaType(__deref_out AM_MEDIA_TYPE **ppMediaType)
3647
 
{
3648
 
    ValidateReadWritePtr(ppMediaType,sizeof(AM_MEDIA_TYPE *));
3649
 
    ASSERT(ppMediaType);
3650
 
 
3651
 
    /* Do we have a new media type for them */
3652
 
 
3653
 
    if (!(m_dwFlags & Sample_TypeChanged)) {
3654
 
        ASSERT(m_pMediaType == NULL);
3655
 
        *ppMediaType = NULL;
3656
 
        return S_FALSE;
3657
 
    }
3658
 
 
3659
 
    ASSERT(m_pMediaType);
3660
 
 
3661
 
    /* Create a copy of our media type */
3662
 
 
3663
 
    *ppMediaType = CreateMediaType(m_pMediaType);
3664
 
    if (*ppMediaType == NULL) {
3665
 
        return E_OUTOFMEMORY;
3666
 
    }
3667
 
    return NOERROR;
3668
 
}
3669
 
 
3670
 
 
3671
 
/* Mark this sample as having a different format type */
3672
 
 
3673
 
STDMETHODIMP
3674
 
CMediaSample::SetMediaType(__in_opt AM_MEDIA_TYPE *pMediaType)
3675
 
{
3676
 
    /* Delete the current media type */
3677
 
 
3678
 
    if (m_pMediaType) {
3679
 
        DeleteMediaType(m_pMediaType);
3680
 
        m_pMediaType = NULL;
3681
 
    }
3682
 
 
3683
 
    /* Mechanism for resetting the format type */
3684
 
 
3685
 
    if (pMediaType == NULL) {
3686
 
        m_dwFlags &= ~Sample_TypeChanged;
3687
 
        return NOERROR;
3688
 
    }
3689
 
 
3690
 
    ASSERT(pMediaType);
3691
 
    ValidateReadPtr(pMediaType,sizeof(AM_MEDIA_TYPE));
3692
 
 
3693
 
    /* Take a copy of the media type */
3694
 
 
3695
 
    m_pMediaType = CreateMediaType(pMediaType);
3696
 
    if (m_pMediaType == NULL) {
3697
 
        m_dwFlags &= ~Sample_TypeChanged;
3698
 
        return E_OUTOFMEMORY;
3699
 
    }
3700
 
 
3701
 
    m_dwFlags |= Sample_TypeChanged;
3702
 
    return NOERROR;
3703
 
}
3704
 
 
3705
 
// Set and get properties (IMediaSample2)
3706
 
STDMETHODIMP CMediaSample::GetProperties(
3707
 
    DWORD cbProperties,
3708
 
    __out_bcount(cbProperties) BYTE * pbProperties
3709
 
)
3710
 
{
3711
 
    if (0 != cbProperties) {
3712
 
        CheckPointer(pbProperties, E_POINTER);
3713
 
        //  Return generic stuff up to the length
3714
 
        AM_SAMPLE2_PROPERTIES Props;
3715
 
        Props.cbData     = min(cbProperties, sizeof(Props));
3716
 
        Props.dwSampleFlags = m_dwFlags & ~Sample_MediaTimeValid;
3717
 
        Props.dwTypeSpecificFlags = m_dwTypeSpecificFlags;
3718
 
        Props.pbBuffer   = m_pBuffer;
3719
 
        Props.cbBuffer   = m_cbBuffer;
3720
 
        Props.lActual    = m_lActual;
3721
 
        Props.tStart     = m_Start;
3722
 
        Props.tStop      = m_End;
3723
 
        Props.dwStreamId = m_dwStreamId;
3724
 
        if (m_dwFlags & AM_SAMPLE_TYPECHANGED) {
3725
 
            Props.pMediaType = m_pMediaType;
3726
 
        } else {
3727
 
            Props.pMediaType = NULL;
3728
 
        }
3729
 
        CopyMemory(pbProperties, &Props, Props.cbData);
3730
 
    }
3731
 
    return S_OK;
3732
 
}
3733
 
 
3734
 
#define CONTAINS_FIELD(type, field, offset) \
3735
 
    ((FIELD_OFFSET(type, field) + sizeof(((type *)0)->field)) <= offset)
3736
 
 
3737
 
HRESULT CMediaSample::SetProperties(
3738
 
    DWORD cbProperties,
3739
 
    __in_bcount(cbProperties) const BYTE * pbProperties
3740
 
)
3741
 
{
3742
 
 
3743
 
    /*  Generic properties */
3744
 
    AM_MEDIA_TYPE *pMediaType = NULL;
3745
 
 
3746
 
    if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbData, cbProperties)) {
3747
 
        CheckPointer(pbProperties, E_POINTER);
3748
 
        AM_SAMPLE2_PROPERTIES *pProps =
3749
 
            (AM_SAMPLE2_PROPERTIES *)pbProperties;
3750
 
 
3751
 
        /*  Don't use more data than is actually there */
3752
 
        if (pProps->cbData < cbProperties) {
3753
 
            cbProperties = pProps->cbData;
3754
 
        }
3755
 
        /*  We only handle IMediaSample2 */
3756
 
        if (cbProperties > sizeof(*pProps) ||
3757
 
            pProps->cbData > sizeof(*pProps)) {
3758
 
            return E_INVALIDARG;
3759
 
        }
3760
 
        /*  Do checks first, the assignments (for backout) */
3761
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) {
3762
 
            /*  Check the flags */
3763
 
            if (pProps->dwSampleFlags &
3764
 
                    (~Sample_ValidFlags | Sample_MediaTimeValid)) {
3765
 
                return E_INVALIDARG;
3766
 
            }
3767
 
            /*  Check a flag isn't being set for a property
3768
 
                not being provided
3769
 
            */
3770
 
            if ((pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) &&
3771
 
                 !(m_dwFlags & AM_SAMPLE_TIMEVALID) &&
3772
 
                 !CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) {
3773
 
                 return E_INVALIDARG;
3774
 
            }
3775
 
        }
3776
 
        /*  NB - can't SET the pointer or size */
3777
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pbBuffer, cbProperties)) {
3778
 
 
3779
 
            /*  Check pbBuffer */
3780
 
            if (pProps->pbBuffer != 0 && pProps->pbBuffer != m_pBuffer) {
3781
 
                return E_INVALIDARG;
3782
 
            }
3783
 
        }
3784
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties)) {
3785
 
 
3786
 
            /*  Check cbBuffer */
3787
 
            if (pProps->cbBuffer != 0 && pProps->cbBuffer != m_cbBuffer) {
3788
 
                return E_INVALIDARG;
3789
 
            }
3790
 
        }
3791
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, cbBuffer, cbProperties) &&
3792
 
            CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) {
3793
 
 
3794
 
            /*  Check lActual */
3795
 
            if (pProps->cbBuffer < pProps->lActual) {
3796
 
                return E_INVALIDARG;
3797
 
            }
3798
 
        }
3799
 
 
3800
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) {
3801
 
 
3802
 
            /*  Check pMediaType */
3803
 
            if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
3804
 
                CheckPointer(pProps->pMediaType, E_POINTER);
3805
 
                pMediaType = CreateMediaType(pProps->pMediaType);
3806
 
                if (pMediaType == NULL) {
3807
 
                    return E_OUTOFMEMORY;
3808
 
                }
3809
 
            }
3810
 
        }
3811
 
 
3812
 
        /*  Now do the assignments */
3813
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwStreamId, cbProperties)) {
3814
 
            m_dwStreamId = pProps->dwStreamId;
3815
 
        }
3816
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwSampleFlags, cbProperties)) {
3817
 
            /*  Set the flags */
3818
 
            m_dwFlags = pProps->dwSampleFlags |
3819
 
                                (m_dwFlags & Sample_MediaTimeValid);
3820
 
            m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
3821
 
        } else {
3822
 
            if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, dwTypeSpecificFlags, cbProperties)) {
3823
 
                m_dwTypeSpecificFlags = pProps->dwTypeSpecificFlags;
3824
 
            }
3825
 
        }
3826
 
 
3827
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, lActual, cbProperties)) {
3828
 
            /*  Set lActual */
3829
 
            m_lActual = pProps->lActual;
3830
 
        }
3831
 
 
3832
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStop, cbProperties)) {
3833
 
 
3834
 
            /*  Set the times */
3835
 
            m_End   = pProps->tStop;
3836
 
        }
3837
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, tStart, cbProperties)) {
3838
 
 
3839
 
            /*  Set the times */
3840
 
            m_Start = pProps->tStart;
3841
 
        }
3842
 
 
3843
 
        if (CONTAINS_FIELD(AM_SAMPLE2_PROPERTIES, pMediaType, cbProperties)) {
3844
 
            /*  Set pMediaType */
3845
 
            if (pProps->dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
3846
 
                if (m_pMediaType != NULL) {
3847
 
                    DeleteMediaType(m_pMediaType);
3848
 
                }
3849
 
                m_pMediaType = pMediaType;
3850
 
            }
3851
 
        }
3852
 
 
3853
 
        /*  Fix up the type changed flag to correctly reflect the current state
3854
 
            If, for instance the input contained no type change but the
3855
 
            output does then if we don't do this we'd lose the
3856
 
            output media type.
3857
 
        */
3858
 
        if (m_pMediaType) {
3859
 
            m_dwFlags |= Sample_TypeChanged;
3860
 
        } else {
3861
 
            m_dwFlags &= ~Sample_TypeChanged;
3862
 
        }
3863
 
    }
3864
 
 
3865
 
    return S_OK;
3866
 
}
3867
 
 
3868
 
 
3869
 
//
3870
 
// The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(),
3871
 
// IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the
3872
 
// connected input pin.  The application thread calls Block().  The
3873
 
// following class members can only be called by the streaming thread.
3874
 
//
3875
 
//    Deliver()
3876
 
//    DeliverNewSegment()
3877
 
//    StartUsingOutputPin()
3878
 
//    StopUsingOutputPin()
3879
 
//    ChangeOutputFormat()
3880
 
//    ChangeMediaType()
3881
 
//    DynamicReconnect()
3882
 
//
3883
 
// The following class members can only be called by the application thread.
3884
 
//
3885
 
//    Block()
3886
 
//    SynchronousBlockOutputPin()
3887
 
//    AsynchronousBlockOutputPin()
3888
 
//
3889
 
 
3890
 
CDynamicOutputPin::CDynamicOutputPin(
3891
 
    __in_opt LPCTSTR pObjectName,
3892
 
    __in CBaseFilter *pFilter,
3893
 
    __in CCritSec *pLock,
3894
 
    __inout HRESULT *phr,
3895
 
    __in_opt LPCWSTR pName) :
3896
 
        CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName),
3897
 
        m_hStopEvent(NULL),
3898
 
        m_pGraphConfig(NULL),
3899
 
        m_bPinUsesReadOnlyAllocator(FALSE),
3900
 
        m_BlockState(NOT_BLOCKED),
3901
 
        m_hUnblockOutputPinEvent(NULL),
3902
 
        m_hNotifyCallerPinBlockedEvent(NULL),
3903
 
        m_dwBlockCallerThreadID(0),
3904
 
        m_dwNumOutstandingOutputPinUsers(0)
3905
 
{
3906
 
    HRESULT hr = Initialize();
3907
 
    if( FAILED( hr ) ) {
3908
 
        *phr = hr;
3909
 
        return;
3910
 
    }
3911
 
}
3912
 
 
3913
 
#ifdef UNICODE
3914
 
CDynamicOutputPin::CDynamicOutputPin(
3915
 
    __in_opt LPCSTR pObjectName,
3916
 
    __in CBaseFilter *pFilter,
3917
 
    __in CCritSec *pLock,
3918
 
    __inout HRESULT *phr,
3919
 
    __in_opt LPCWSTR pName) :
3920
 
        CBaseOutputPin(pObjectName, pFilter, pLock, phr, pName),
3921
 
        m_hStopEvent(NULL),
3922
 
        m_pGraphConfig(NULL),
3923
 
        m_bPinUsesReadOnlyAllocator(FALSE),
3924
 
        m_BlockState(NOT_BLOCKED),
3925
 
        m_hUnblockOutputPinEvent(NULL),
3926
 
        m_hNotifyCallerPinBlockedEvent(NULL),
3927
 
        m_dwBlockCallerThreadID(0),
3928
 
        m_dwNumOutstandingOutputPinUsers(0)
3929
 
{
3930
 
    HRESULT hr = Initialize();
3931
 
    if( FAILED( hr ) ) {
3932
 
        *phr = hr;
3933
 
        return;
3934
 
    }
3935
 
}
3936
 
#endif
3937
 
 
3938
 
CDynamicOutputPin::~CDynamicOutputPin()
3939
 
{
3940
 
    if(NULL != m_hUnblockOutputPinEvent) {
3941
 
        // This call should not fail because we have access to m_hUnblockOutputPinEvent
3942
 
        // and m_hUnblockOutputPinEvent is a valid event.
3943
 
        EXECUTE_ASSERT(::CloseHandle(m_hUnblockOutputPinEvent));
3944
 
    }
3945
 
 
3946
 
    if(NULL != m_hNotifyCallerPinBlockedEvent) {
3947
 
        // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent
3948
 
        // and m_hNotifyCallerPinBlockedEvent is a valid event.
3949
 
        EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent));
3950
 
    }
3951
 
}
3952
 
 
3953
 
HRESULT CDynamicOutputPin::Initialize(void)
3954
 
{
3955
 
    m_hUnblockOutputPinEvent = ::CreateEvent( NULL,   // The event will have the default security descriptor.
3956
 
                                              TRUE,   // This is a manual reset event.
3957
 
                                              TRUE,   // The event is initially signaled.
3958
 
                                              NULL ); // The event is not named.
3959
 
 
3960
 
    // CreateEvent() returns NULL if an error occurs.
3961
 
    if(NULL == m_hUnblockOutputPinEvent) {
3962
 
        return AmGetLastErrorToHResult();
3963
 
    }
3964
 
 
3965
 
    //  Set flag to say we can reconnect while streaming.
3966
 
    SetReconnectWhenActive(true);
3967
 
 
3968
 
    return S_OK;
3969
 
}
3970
 
 
3971
 
STDMETHODIMP CDynamicOutputPin::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
3972
 
{
3973
 
    if(riid == IID_IPinFlowControl) {
3974
 
        return GetInterface(static_cast<IPinFlowControl*>(this), ppv);
3975
 
    } else {
3976
 
        return CBaseOutputPin::NonDelegatingQueryInterface(riid, ppv);
3977
 
    }
3978
 
}
3979
 
 
3980
 
STDMETHODIMP CDynamicOutputPin::Disconnect(void)
3981
 
{
3982
 
    CAutoLock cObjectLock(m_pLock);
3983
 
    return DisconnectInternal();
3984
 
}
3985
 
 
3986
 
STDMETHODIMP CDynamicOutputPin::Block(DWORD dwBlockFlags, HANDLE hEvent)
3987
 
{
3988
 
    const DWORD VALID_FLAGS = AM_PIN_FLOW_CONTROL_BLOCK;
3989
 
 
3990
 
    // Check for illegal flags.
3991
 
    if(dwBlockFlags & ~VALID_FLAGS) {
3992
 
        return E_INVALIDARG;
3993
 
    }
3994
 
 
3995
 
    // Make sure the event is unsignaled.
3996
 
    if((dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) && (NULL != hEvent)) {
3997
 
        if( !::ResetEvent( hEvent ) ) {
3998
 
            return AmGetLastErrorToHResult();
3999
 
        }
4000
 
    }
4001
 
 
4002
 
    // No flags are set if we are unblocking the output pin.
4003
 
    if(0 == dwBlockFlags) {
4004
 
 
4005
 
        // This parameter should be NULL because unblock operations are always synchronous.
4006
 
        // There is no need to notify the caller when the event is done.
4007
 
        if(NULL != hEvent) {
4008
 
            return E_INVALIDARG;
4009
 
        }
4010
 
    }
4011
 
 
4012
 
    #ifdef DEBUG
4013
 
    AssertValid();
4014
 
    #endif // DEBUG
4015
 
 
4016
 
    HRESULT hr;
4017
 
 
4018
 
    if(dwBlockFlags & AM_PIN_FLOW_CONTROL_BLOCK) {
4019
 
        // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous.
4020
 
        // If hEvent is not NULL, the block is asynchronous.
4021
 
        if(NULL == hEvent) {
4022
 
            hr = SynchronousBlockOutputPin();
4023
 
        } else {
4024
 
            hr = AsynchronousBlockOutputPin(hEvent);
4025
 
        }
4026
 
    } else {
4027
 
        hr = UnblockOutputPin();
4028
 
    }
4029
 
 
4030
 
    #ifdef DEBUG
4031
 
    AssertValid();
4032
 
    #endif // DEBUG
4033
 
 
4034
 
    if(FAILED(hr)) {
4035
 
        return hr;
4036
 
    }
4037
 
 
4038
 
    return S_OK;
4039
 
}
4040
 
 
4041
 
HRESULT CDynamicOutputPin::SynchronousBlockOutputPin(void)
4042
 
{
4043
 
    HANDLE hNotifyCallerPinBlockedEvent = :: CreateEvent( NULL,   // The event will have the default security attributes.
4044
 
                                                          FALSE,  // This is an automatic reset event.
4045
 
                                                          FALSE,  // The event is initially unsignaled.
4046
 
                                                          NULL ); // The event is not named.
4047
 
 
4048
 
    // CreateEvent() returns NULL if an error occurs.
4049
 
    if(NULL == hNotifyCallerPinBlockedEvent) {
4050
 
        return AmGetLastErrorToHResult();
4051
 
    }
4052
 
 
4053
 
    HRESULT hr = AsynchronousBlockOutputPin(hNotifyCallerPinBlockedEvent);
4054
 
    if(FAILED(hr)) {
4055
 
        // This call should not fail because we have access to hNotifyCallerPinBlockedEvent
4056
 
        // and hNotifyCallerPinBlockedEvent is a valid event.
4057
 
        EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent));
4058
 
 
4059
 
        return hr;
4060
 
    }
4061
 
 
4062
 
    hr = WaitEvent(hNotifyCallerPinBlockedEvent);
4063
 
 
4064
 
    // This call should not fail because we have access to hNotifyCallerPinBlockedEvent
4065
 
    // and hNotifyCallerPinBlockedEvent is a valid event.
4066
 
    EXECUTE_ASSERT(::CloseHandle(hNotifyCallerPinBlockedEvent));
4067
 
 
4068
 
    if(FAILED(hr)) {
4069
 
        return hr;
4070
 
    }
4071
 
 
4072
 
    return S_OK;
4073
 
}
4074
 
 
4075
 
HRESULT CDynamicOutputPin::AsynchronousBlockOutputPin(HANDLE hNotifyCallerPinBlockedEvent)
4076
 
{
4077
 
    // This function holds the m_BlockStateLock because it uses
4078
 
    // m_dwBlockCallerThreadID, m_BlockState and
4079
 
    // m_hNotifyCallerPinBlockedEvent.
4080
 
    CAutoLock alBlockStateLock(&m_BlockStateLock);
4081
 
 
4082
 
    if(NOT_BLOCKED != m_BlockState) {
4083
 
        if(m_dwBlockCallerThreadID == ::GetCurrentThreadId()) {
4084
 
            return VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD;
4085
 
        } else {
4086
 
            return VFW_E_PIN_ALREADY_BLOCKED;
4087
 
        }
4088
 
    }
4089
 
 
4090
 
    BOOL fSuccess = ::DuplicateHandle( ::GetCurrentProcess(),
4091
 
                                       hNotifyCallerPinBlockedEvent,
4092
 
                                       ::GetCurrentProcess(),
4093
 
                                       &m_hNotifyCallerPinBlockedEvent,
4094
 
                                       EVENT_MODIFY_STATE,
4095
 
                                       FALSE,
4096
 
                                       0 );
4097
 
    if( !fSuccess ) {
4098
 
        return AmGetLastErrorToHResult();
4099
 
    }
4100
 
 
4101
 
    m_BlockState = PENDING;
4102
 
    m_dwBlockCallerThreadID = ::GetCurrentThreadId();
4103
 
 
4104
 
    // The output pin cannot be blocked if the streaming thread is
4105
 
    // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive()
4106
 
    // or IMemInputPin::ReceiveMultiple() on the connected input pin.  Also, it
4107
 
    // cannot be blocked if the streaming thread is calling DynamicReconnect(),
4108
 
    // ChangeMediaType() or ChangeOutputFormat().
4109
 
    if(!StreamingThreadUsingOutputPin()) {
4110
 
 
4111
 
        // The output pin can be immediately blocked.
4112
 
        BlockOutputPin();
4113
 
    }
4114
 
 
4115
 
    return S_OK;
4116
 
}
4117
 
 
4118
 
void CDynamicOutputPin::BlockOutputPin(void)
4119
 
{
4120
 
    // The caller should always hold the m_BlockStateLock because this function
4121
 
    // uses m_BlockState and m_hNotifyCallerPinBlockedEvent.
4122
 
    ASSERT(CritCheckIn(&m_BlockStateLock));
4123
 
 
4124
 
    // This function should not be called if the streaming thread is modifying
4125
 
    // the connection state or it's passing data downstream.
4126
 
    ASSERT(!StreamingThreadUsingOutputPin());
4127
 
 
4128
 
    // This should not fail because we successfully created the event
4129
 
    // and we have the security permissions to change it's state.
4130
 
    EXECUTE_ASSERT(::ResetEvent(m_hUnblockOutputPinEvent));
4131
 
 
4132
 
    // This event should not fail because AsynchronousBlockOutputPin() successfully
4133
 
    // duplicated this handle and we have the appropriate security permissions.
4134
 
    EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent));
4135
 
    EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent));
4136
 
 
4137
 
    m_BlockState = BLOCKED;
4138
 
    m_hNotifyCallerPinBlockedEvent = NULL;
4139
 
}
4140
 
 
4141
 
HRESULT CDynamicOutputPin::UnblockOutputPin(void)
4142
 
{
4143
 
    // UnblockOutputPin() holds the m_BlockStateLock because it
4144
 
    // uses m_BlockState, m_dwBlockCallerThreadID and
4145
 
    // m_hNotifyCallerPinBlockedEvent.
4146
 
    CAutoLock alBlockStateLock(&m_BlockStateLock);
4147
 
 
4148
 
    if(NOT_BLOCKED == m_BlockState) {
4149
 
        return S_FALSE;
4150
 
    }
4151
 
 
4152
 
    // This should not fail because we successfully created the event
4153
 
    // and we have the security permissions to change it's state.
4154
 
    EXECUTE_ASSERT(::SetEvent(m_hUnblockOutputPinEvent));
4155
 
 
4156
 
    // Cancel the block operation if it's still pending.
4157
 
    if(NULL != m_hNotifyCallerPinBlockedEvent) {
4158
 
        // This event should not fail because AsynchronousBlockOutputPin() successfully
4159
 
        // duplicated this handle and we have the appropriate security permissions.
4160
 
        EXECUTE_ASSERT(::SetEvent(m_hNotifyCallerPinBlockedEvent));
4161
 
        EXECUTE_ASSERT(::CloseHandle(m_hNotifyCallerPinBlockedEvent));
4162
 
    }
4163
 
 
4164
 
    m_BlockState = NOT_BLOCKED;
4165
 
    m_dwBlockCallerThreadID = 0;
4166
 
    m_hNotifyCallerPinBlockedEvent = NULL;
4167
 
 
4168
 
    return S_OK;
4169
 
}
4170
 
 
4171
 
HRESULT CDynamicOutputPin::StartUsingOutputPin(void)
4172
 
{
4173
 
    // The caller should not hold m_BlockStateLock.  If the caller does,
4174
 
    // a deadlock could occur.
4175
 
    ASSERT(CritCheckOut(&m_BlockStateLock));
4176
 
 
4177
 
    CAutoLock alBlockStateLock(&m_BlockStateLock);
4178
 
 
4179
 
    #ifdef DEBUG
4180
 
    AssertValid();
4181
 
    #endif // DEBUG
4182
 
 
4183
 
    // Are we in the middle of a block operation?
4184
 
    while(BLOCKED == m_BlockState) {
4185
 
        m_BlockStateLock.Unlock();
4186
 
 
4187
 
        // If this ASSERT fires, a deadlock could occur.  The caller should make sure
4188
 
        // that this thread never acquires the Block State lock more than once.
4189
 
        ASSERT(CritCheckOut( &m_BlockStateLock ));
4190
 
 
4191
 
        // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event
4192
 
        // is fired.  It returns WAIT_OBJECT_0 + 1 if the stop event if fired.
4193
 
        // See the Windows SDK documentation for more information on
4194
 
        // WaitForMultipleObjects().
4195
 
        const DWORD UNBLOCK = WAIT_OBJECT_0;
4196
 
        const DWORD STOP = WAIT_OBJECT_0 + 1;
4197
 
 
4198
 
        HANDLE ahWaitEvents[] = { m_hUnblockOutputPinEvent, m_hStopEvent };
4199
 
        DWORD dwNumWaitEvents = sizeof(ahWaitEvents)/sizeof(HANDLE);
4200
 
 
4201
 
        DWORD dwReturnValue = ::WaitForMultipleObjects( dwNumWaitEvents, ahWaitEvents, FALSE, INFINITE );
4202
 
 
4203
 
        m_BlockStateLock.Lock();
4204
 
 
4205
 
        #ifdef DEBUG
4206
 
        AssertValid();
4207
 
        #endif // DEBUG
4208
 
 
4209
 
        switch( dwReturnValue ) {
4210
 
        case UNBLOCK:
4211
 
            break;
4212
 
 
4213
 
        case STOP:
4214
 
            return VFW_E_STATE_CHANGED;
4215
 
 
4216
 
        case WAIT_FAILED:
4217
 
            return AmGetLastErrorToHResult();
4218
 
 
4219
 
        default:
4220
 
            DbgBreak( "An Unexpected case occured in CDynamicOutputPin::StartUsingOutputPin()." );
4221
 
            return E_UNEXPECTED;
4222
 
        }
4223
 
    }
4224
 
 
4225
 
    m_dwNumOutstandingOutputPinUsers++;
4226
 
 
4227
 
    #ifdef DEBUG
4228
 
    AssertValid();
4229
 
    #endif // DEBUG
4230
 
 
4231
 
    return S_OK;
4232
 
}
4233
 
 
4234
 
void CDynamicOutputPin::StopUsingOutputPin(void)
4235
 
{
4236
 
    CAutoLock alBlockStateLock(&m_BlockStateLock);
4237
 
 
4238
 
    #ifdef DEBUG
4239
 
    AssertValid();
4240
 
    #endif // DEBUG
4241
 
 
4242
 
    m_dwNumOutstandingOutputPinUsers--;
4243
 
 
4244
 
    if((m_dwNumOutstandingOutputPinUsers == 0) && (NOT_BLOCKED != m_BlockState)) {
4245
 
        BlockOutputPin();
4246
 
    }
4247
 
 
4248
 
    #ifdef DEBUG
4249
 
    AssertValid();
4250
 
    #endif // DEBUG
4251
 
}
4252
 
 
4253
 
bool CDynamicOutputPin::StreamingThreadUsingOutputPin(void)
4254
 
{
4255
 
    CAutoLock alBlockStateLock(&m_BlockStateLock);
4256
 
 
4257
 
    return (m_dwNumOutstandingOutputPinUsers > 0);
4258
 
}
4259
 
 
4260
 
void CDynamicOutputPin::SetConfigInfo(IGraphConfig *pGraphConfig, HANDLE hStopEvent)
4261
 
{
4262
 
    // This pointer is not addrefed because filters are not allowed to
4263
 
    // hold references to the filter graph manager.  See the documentation for
4264
 
    // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information.
4265
 
    m_pGraphConfig = pGraphConfig;
4266
 
 
4267
 
    m_hStopEvent = hStopEvent;
4268
 
}
4269
 
 
4270
 
HRESULT CDynamicOutputPin::Active(void)
4271
 
{
4272
 
    // Make sure the user initialized the object by calling SetConfigInfo().
4273
 
    if((NULL == m_hStopEvent) || (NULL == m_pGraphConfig)) {
4274
 
        DbgBreak( ERROR: CDynamicOutputPin::Active() failed because m_pGraphConfig and m_hStopEvent were not initialized.  Call SetConfigInfo() to initialize them. );
4275
 
        return E_FAIL;
4276
 
    }
4277
 
 
4278
 
    // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
4279
 
    // The ASSERT can also fire if the event if destroyed and then Active() is called.  An event
4280
 
    // handle is invalid if 1) the event does not exist or the user does not have the security
4281
 
    // permissions to use the event.
4282
 
    EXECUTE_ASSERT(ResetEvent(m_hStopEvent));
4283
 
 
4284
 
    return CBaseOutputPin::Active();
4285
 
}
4286
 
 
4287
 
HRESULT CDynamicOutputPin::Inactive(void)
4288
 
{
4289
 
    // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
4290
 
    // The ASSERT can also fire if the event if destroyed and then Active() is called.  An event
4291
 
    // handle is invalid if 1) the event does not exist or the user does not have the security
4292
 
    // permissions to use the event.
4293
 
    EXECUTE_ASSERT(SetEvent(m_hStopEvent));
4294
 
 
4295
 
    return CBaseOutputPin::Inactive();
4296
 
}
4297
 
 
4298
 
HRESULT CDynamicOutputPin::DeliverBeginFlush(void)
4299
 
{
4300
 
    // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
4301
 
    // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called.
4302
 
    // An event handle is invalid if 1) the event does not exist or the user does not have the security
4303
 
    // permissions to use the event.
4304
 
    EXECUTE_ASSERT(SetEvent(m_hStopEvent));
4305
 
 
4306
 
    return CBaseOutputPin::DeliverBeginFlush();
4307
 
}
4308
 
 
4309
 
HRESULT CDynamicOutputPin::DeliverEndFlush(void)
4310
 
{
4311
 
    // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
4312
 
    // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called.
4313
 
    // An event handle is invalid if 1) the event does not exist or the user does not have the security
4314
 
    // permissions to use the event.
4315
 
    EXECUTE_ASSERT(ResetEvent(m_hStopEvent));
4316
 
 
4317
 
    return CBaseOutputPin::DeliverEndFlush();
4318
 
}
4319
 
 
4320
 
 
4321
 
// ChangeOutputFormat() either dynamicly changes the connection's format type or it dynamicly
4322
 
// reconnects the output pin.
4323
 
HRESULT CDynamicOutputPin::ChangeOutputFormat
4324
 
    (
4325
 
    const AM_MEDIA_TYPE *pmt,
4326
 
    REFERENCE_TIME tSegmentStart,
4327
 
    REFERENCE_TIME tSegmentStop,
4328
 
    double dSegmentRate
4329
 
    )
4330
 
{
4331
 
    // The caller should call StartUsingOutputPin() before calling this
4332
 
    // method.
4333
 
    ASSERT(StreamingThreadUsingOutputPin());
4334
 
 
4335
 
    // Callers should always pass a valid media type to ChangeOutputFormat() .
4336
 
    ASSERT(NULL != pmt);
4337
 
 
4338
 
    CMediaType cmt(*pmt);
4339
 
    HRESULT hr = ChangeMediaType(&cmt);
4340
 
    if (FAILED(hr)) {
4341
 
        return hr;
4342
 
    }
4343
 
 
4344
 
    hr = DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate);
4345
 
    if( FAILED( hr ) ) {
4346
 
        return hr;
4347
 
    }
4348
 
 
4349
 
    return S_OK;
4350
 
}
4351
 
 
4352
 
HRESULT CDynamicOutputPin::ChangeMediaType(const CMediaType *pmt)
4353
 
{
4354
 
    // The caller should call StartUsingOutputPin() before calling this
4355
 
    // method.
4356
 
    ASSERT(StreamingThreadUsingOutputPin());
4357
 
 
4358
 
    // This function assumes the filter graph is running.
4359
 
    ASSERT(!IsStopped());
4360
 
 
4361
 
    if(!IsConnected()) {
4362
 
        return VFW_E_NOT_CONNECTED;
4363
 
    }
4364
 
 
4365
 
    /*  First check if the downstream pin will accept a dynamic
4366
 
        format change
4367
 
    */
4368
 
    QzCComPtr<IPinConnection> pConnection;
4369
 
 
4370
 
    m_Connected->QueryInterface(IID_IPinConnection, (void **)&pConnection);
4371
 
    if(pConnection != NULL) {
4372
 
 
4373
 
        if(S_OK == pConnection->DynamicQueryAccept(pmt)) {
4374
 
 
4375
 
            HRESULT hr = ChangeMediaTypeHelper(pmt);
4376
 
            if(FAILED(hr)) {
4377
 
                return hr;
4378
 
            }
4379
 
 
4380
 
            return S_OK;
4381
 
        }
4382
 
    }
4383
 
 
4384
 
    /*  Can't do the dynamic connection */
4385
 
    return DynamicReconnect(pmt);
4386
 
}
4387
 
 
4388
 
HRESULT CDynamicOutputPin::ChangeMediaTypeHelper(const CMediaType *pmt)
4389
 
{
4390
 
    // The caller should call StartUsingOutputPin() before calling this
4391
 
    // method.
4392
 
    ASSERT(StreamingThreadUsingOutputPin());
4393
 
 
4394
 
    HRESULT hr = m_Connected->ReceiveConnection(this, pmt);
4395
 
    if(FAILED(hr)) {
4396
 
        return hr;
4397
 
    }
4398
 
 
4399
 
    hr = SetMediaType(pmt);
4400
 
    if(FAILED(hr)) {
4401
 
        return hr;
4402
 
    }
4403
 
 
4404
 
    // Does this pin use the local memory transport?
4405
 
    if(NULL != m_pInputPin) {
4406
 
        // This function assumes that m_pInputPin and m_Connected are
4407
 
        // two different interfaces to the same object.
4408
 
        ASSERT(::IsEqualObject(m_Connected, m_pInputPin));
4409
 
 
4410
 
        ALLOCATOR_PROPERTIES apInputPinRequirements;
4411
 
        apInputPinRequirements.cbAlign = 0;
4412
 
        apInputPinRequirements.cbBuffer = 0;
4413
 
        apInputPinRequirements.cbPrefix = 0;
4414
 
        apInputPinRequirements.cBuffers = 0;
4415
 
 
4416
 
        m_pInputPin->GetAllocatorRequirements(&apInputPinRequirements);
4417
 
 
4418
 
        // A zero allignment does not make any sense.
4419
 
        if(0 == apInputPinRequirements.cbAlign) {
4420
 
            apInputPinRequirements.cbAlign = 1;
4421
 
        }
4422
 
 
4423
 
        hr = m_pAllocator->Decommit();
4424
 
        if(FAILED(hr)) {
4425
 
            return hr;
4426
 
        }
4427
 
 
4428
 
        hr = DecideBufferSize(m_pAllocator,  &apInputPinRequirements);
4429
 
        if(FAILED(hr)) {
4430
 
            return hr;
4431
 
        }
4432
 
 
4433
 
        hr = m_pAllocator->Commit();
4434
 
        if(FAILED(hr)) {
4435
 
            return hr;
4436
 
        }
4437
 
 
4438
 
        hr = m_pInputPin->NotifyAllocator(m_pAllocator, m_bPinUsesReadOnlyAllocator);
4439
 
        if(FAILED(hr)) {
4440
 
            return hr;
4441
 
        }
4442
 
    }
4443
 
 
4444
 
    return S_OK;
4445
 
}
4446
 
 
4447
 
// this method has to be called from the thread that is pushing data,
4448
 
// and it's the caller's responsibility to make sure that the thread
4449
 
// has no outstand samples because they cannot be delivered after a
4450
 
// reconnect
4451
 
//
4452
 
HRESULT CDynamicOutputPin::DynamicReconnect( const CMediaType* pmt )
4453
 
{
4454
 
    // The caller should call StartUsingOutputPin() before calling this
4455
 
    // method.
4456
 
    ASSERT(StreamingThreadUsingOutputPin());
4457
 
 
4458
 
    if((m_pGraphConfig == NULL) || (NULL == m_hStopEvent)) {
4459
 
        return E_FAIL;
4460
 
    }
4461
 
 
4462
 
    HRESULT hr = m_pGraphConfig->Reconnect(
4463
 
        this,
4464
 
        NULL,
4465
 
        pmt,
4466
 
        NULL,
4467
 
        m_hStopEvent,
4468
 
        AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS );
4469
 
 
4470
 
    return hr;
4471
 
}
4472
 
 
4473
 
HRESULT CDynamicOutputPin::CompleteConnect(IPin *pReceivePin)
4474
 
{
4475
 
    HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin);
4476
 
    if(SUCCEEDED(hr)) {
4477
 
        if(!IsStopped() && m_pAllocator) {
4478
 
            hr = m_pAllocator->Commit();
4479
 
            ASSERT(hr != VFW_E_ALREADY_COMMITTED);
4480
 
        }
4481
 
    }
4482
 
 
4483
 
    return hr;
4484
 
}
4485
 
 
4486
 
#ifdef DEBUG
4487
 
void CDynamicOutputPin::AssertValid(void)
4488
 
{
4489
 
    // Make sure the object was correctly initialized.
4490
 
 
4491
 
    // This ASSERT only fires if the object failed to initialize
4492
 
    // and the user ignored the constructor's return code (phr).
4493
 
    ASSERT(NULL != m_hUnblockOutputPinEvent);
4494
 
 
4495
 
    // If either of these ASSERTs fire, the user did not correctly call
4496
 
    // SetConfigInfo().
4497
 
    ASSERT(NULL != m_hStopEvent);
4498
 
    ASSERT(NULL != m_pGraphConfig);
4499
 
 
4500
 
    // Make sure the block state is consistent.
4501
 
 
4502
 
    CAutoLock alBlockStateLock(&m_BlockStateLock);
4503
 
 
4504
 
    // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED.
4505
 
    ASSERT((NOT_BLOCKED == m_BlockState) || (PENDING == m_BlockState) || (BLOCKED == m_BlockState));
4506
 
 
4507
 
    // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete
4508
 
    // immediately.
4509
 
    ASSERT(((NULL == m_hNotifyCallerPinBlockedEvent) && (PENDING != m_BlockState)) ||
4510
 
           ((NULL != m_hNotifyCallerPinBlockedEvent) && (PENDING == m_BlockState)) );
4511
 
 
4512
 
    // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and
4513
 
    // the user is not trying to block the pin.
4514
 
    ASSERT((0 == m_dwBlockCallerThreadID) || (NOT_BLOCKED != m_BlockState));
4515
 
 
4516
 
    // If this ASSERT fires, the streaming thread is using the output pin and the
4517
 
    // output pin is blocked.
4518
 
    ASSERT(((0 != m_dwNumOutstandingOutputPinUsers) && (BLOCKED != m_BlockState)) ||
4519
 
           ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED != m_BlockState)) ||
4520
 
           ((0 == m_dwNumOutstandingOutputPinUsers) && (NOT_BLOCKED == m_BlockState)) );
4521
 
}
4522
 
#endif // DEBUG
4523
 
 
4524
 
HRESULT CDynamicOutputPin::WaitEvent(HANDLE hEvent)
4525
 
{
4526
 
    const DWORD EVENT_SIGNALED = WAIT_OBJECT_0;
4527
 
 
4528
 
    DWORD dwReturnValue = ::WaitForSingleObject(hEvent, INFINITE);
4529
 
 
4530
 
    switch( dwReturnValue ) {
4531
 
    case EVENT_SIGNALED:
4532
 
        return S_OK;
4533
 
 
4534
 
    case WAIT_FAILED:
4535
 
        return AmGetLastErrorToHResult();
4536
 
 
4537
 
    default:
4538
 
        DbgBreak( "An Unexpected case occured in CDynamicOutputPin::WaitEvent()." );
4539
 
        return E_UNEXPECTED;
4540
 
    }
4541
 
}
4542
 
 
4543
 
//=====================================================================
4544
 
//=====================================================================
4545
 
// Implements CBaseAllocator
4546
 
//=====================================================================
4547
 
//=====================================================================
4548
 
 
4549
 
 
4550
 
/* Constructor overrides the default settings for the free list to request
4551
 
   that it be alertable (ie the list can be cast to a handle which can be
4552
 
   passed to WaitForSingleObject). Both of the allocator lists also ask for
4553
 
   object locking, the all list matches the object default settings but I
4554
 
   have included them here just so it is obvious what kind of list it is */
4555
 
 
4556
 
CBaseAllocator::CBaseAllocator(__in_opt LPCTSTR pName,
4557
 
                               __inout_opt LPUNKNOWN pUnk,
4558
 
                               __inout HRESULT *phr,
4559
 
                               BOOL bEvent,
4560
 
                               BOOL fEnableReleaseCallback
4561
 
                               ) :
4562
 
    CUnknown(pName, pUnk),
4563
 
    m_lAllocated(0),
4564
 
    m_bChanged(FALSE),
4565
 
    m_bCommitted(FALSE),
4566
 
    m_bDecommitInProgress(FALSE),
4567
 
    m_lSize(0),
4568
 
    m_lCount(0),
4569
 
    m_lAlignment(0),
4570
 
    m_lPrefix(0),
4571
 
    m_hSem(NULL),
4572
 
    m_lWaiting(0),
4573
 
    m_fEnableReleaseCallback(fEnableReleaseCallback),
4574
 
    m_pNotify(NULL)
4575
 
{
4576
 
#ifdef DXMPERF
4577
 
    PERFLOG_CTOR( pName ? pName : L"CBaseAllocator", (IMemAllocator *) this );
4578
 
#endif // DXMPERF
4579
 
 
4580
 
    if (bEvent) {
4581
 
        m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
4582
 
        if (m_hSem == NULL) {
4583
 
            *phr = E_OUTOFMEMORY;
4584
 
            return;
4585
 
        }
4586
 
    }
4587
 
}
4588
 
 
4589
 
#ifdef UNICODE
4590
 
CBaseAllocator::CBaseAllocator(__in_opt LPCSTR pName,
4591
 
                               __inout_opt LPUNKNOWN pUnk,
4592
 
                               __inout HRESULT *phr,
4593
 
                               BOOL bEvent,
4594
 
                               BOOL fEnableReleaseCallback) :
4595
 
    CUnknown(pName, pUnk),
4596
 
    m_lAllocated(0),
4597
 
    m_bChanged(FALSE),
4598
 
    m_bCommitted(FALSE),
4599
 
    m_bDecommitInProgress(FALSE),
4600
 
    m_lSize(0),
4601
 
    m_lCount(0),
4602
 
    m_lAlignment(0),
4603
 
    m_lPrefix(0),
4604
 
    m_hSem(NULL),
4605
 
    m_lWaiting(0),
4606
 
    m_fEnableReleaseCallback(fEnableReleaseCallback),
4607
 
    m_pNotify(NULL)
4608
 
{
4609
 
#ifdef DXMPERF
4610
 
    PERFLOG_CTOR( L"CBaseAllocator", (IMemAllocator *) this );
4611
 
#endif // DXMPERF
4612
 
 
4613
 
    if (bEvent) {
4614
 
        m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
4615
 
        if (m_hSem == NULL) {
4616
 
            *phr = E_OUTOFMEMORY;
4617
 
            return;
4618
 
        }
4619
 
    }
4620
 
}
4621
 
#endif
4622
 
 
4623
 
/* Destructor */
4624
 
 
4625
 
CBaseAllocator::~CBaseAllocator()
4626
 
{
4627
 
    // we can't call Decommit here since that would mean a call to a
4628
 
    // pure virtual in destructor.
4629
 
    // We must assume that the derived class has gone into decommit state in
4630
 
    // its destructor.
4631
 
#ifdef DXMPERF
4632
 
    PERFLOG_DTOR( L"CBaseAllocator", (IMemAllocator *) this );
4633
 
#endif // DXMPERF
4634
 
 
4635
 
    ASSERT(!m_bCommitted);
4636
 
    if (m_hSem != NULL) {
4637
 
        EXECUTE_ASSERT(CloseHandle(m_hSem));
4638
 
    }
4639
 
    if (m_pNotify) {
4640
 
        m_pNotify->Release();
4641
 
    }
4642
 
}
4643
 
 
4644
 
 
4645
 
/* Override this to publicise our interfaces */
4646
 
 
4647
 
STDMETHODIMP
4648
 
CBaseAllocator::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
4649
 
{
4650
 
    /* Do we know about this interface */
4651
 
 
4652
 
    if (riid == IID_IMemAllocator ||
4653
 
        riid == IID_IMemAllocatorCallbackTemp && m_fEnableReleaseCallback) {
4654
 
        return GetInterface((IMemAllocatorCallbackTemp *) this, ppv);
4655
 
    } else {
4656
 
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
4657
 
    }
4658
 
}
4659
 
 
4660
 
 
4661
 
/* This sets the size and count of the required samples. The memory isn't
4662
 
   actually allocated until Commit() is called, if memory has already been
4663
 
   allocated then assuming no samples are outstanding the user may call us
4664
 
   to change the buffering, the memory will be released in Commit() */
4665
 
 
4666
 
STDMETHODIMP
4667
 
CBaseAllocator::SetProperties(
4668
 
                __in ALLOCATOR_PROPERTIES* pRequest,
4669
 
                __out ALLOCATOR_PROPERTIES* pActual)
4670
 
{
4671
 
    CheckPointer(pRequest, E_POINTER);
4672
 
    CheckPointer(pActual, E_POINTER);
4673
 
    ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES));
4674
 
    CAutoLock cObjectLock(this);
4675
 
 
4676
 
    ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
4677
 
 
4678
 
    ASSERT(pRequest->cbBuffer > 0);
4679
 
 
4680
 
    /*  Check the alignment requested */
4681
 
    if (pRequest->cbAlign != 1) {
4682
 
        DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"),
4683
 
               pRequest->cbAlign));
4684
 
        return VFW_E_BADALIGN;
4685
 
    }
4686
 
 
4687
 
    /* Can't do this if already committed, there is an argument that says we
4688
 
       should not reject the SetProperties call if there are buffers still
4689
 
       active. However this is called by the source filter, which is the same
4690
 
       person who is holding the samples. Therefore it is not unreasonable
4691
 
       for them to free all their samples before changing the requirements */
4692
 
 
4693
 
    if (m_bCommitted) {
4694
 
        return VFW_E_ALREADY_COMMITTED;
4695
 
    }
4696
 
 
4697
 
    /* Must be no outstanding buffers */
4698
 
 
4699
 
    if (m_lAllocated != m_lFree.GetCount()) {
4700
 
        return VFW_E_BUFFERS_OUTSTANDING;
4701
 
    }
4702
 
 
4703
 
    /* There isn't any real need to check the parameters as they
4704
 
       will just be rejected when the user finally calls Commit */
4705
 
 
4706
 
    pActual->cbBuffer = m_lSize = pRequest->cbBuffer;
4707
 
    pActual->cBuffers = m_lCount = pRequest->cBuffers;
4708
 
    pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
4709
 
    pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
4710
 
 
4711
 
    m_bChanged = TRUE;
4712
 
    return NOERROR;
4713
 
}
4714
 
 
4715
 
STDMETHODIMP
4716
 
CBaseAllocator::GetProperties(
4717
 
    __out ALLOCATOR_PROPERTIES * pActual)
4718
 
{
4719
 
    CheckPointer(pActual,E_POINTER);
4720
 
    ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES));
4721
 
 
4722
 
    CAutoLock cObjectLock(this);
4723
 
    pActual->cbBuffer = m_lSize;
4724
 
    pActual->cBuffers = m_lCount;
4725
 
    pActual->cbAlign = m_lAlignment;
4726
 
    pActual->cbPrefix = m_lPrefix;
4727
 
    return NOERROR;
4728
 
}
4729
 
 
4730
 
// get container for a sample. Blocking, synchronous call to get the
4731
 
// next free buffer (as represented by an IMediaSample interface).
4732
 
// on return, the time etc properties will be invalid, but the buffer
4733
 
// pointer and size will be correct.
4734
 
 
4735
 
HRESULT CBaseAllocator::GetBuffer(__deref_out IMediaSample **ppBuffer,
4736
 
                                  __in_opt REFERENCE_TIME *pStartTime,
4737
 
                                  __in_opt REFERENCE_TIME *pEndTime,
4738
 
                                  DWORD dwFlags
4739
 
                                  )
4740
 
{
4741
 
    UNREFERENCED_PARAMETER(pStartTime);
4742
 
    UNREFERENCED_PARAMETER(pEndTime);
4743
 
    UNREFERENCED_PARAMETER(dwFlags);
4744
 
    CMediaSample *pSample;
4745
 
 
4746
 
    *ppBuffer = NULL;
4747
 
    for (;;)
4748
 
    {
4749
 
        {  // scope for lock
4750
 
            CAutoLock cObjectLock(this);
4751
 
 
4752
 
            /* Check we are committed */
4753
 
            if (!m_bCommitted) {
4754
 
                return VFW_E_NOT_COMMITTED;
4755
 
            }
4756
 
            pSample = (CMediaSample *) m_lFree.RemoveHead();
4757
 
            if (pSample == NULL) {
4758
 
                SetWaiting();
4759
 
            }
4760
 
        }
4761
 
 
4762
 
        /* If we didn't get a sample then wait for the list to signal */
4763
 
 
4764
 
        if (pSample) {
4765
 
            break;
4766
 
        }
4767
 
        if (dwFlags & AM_GBF_NOWAIT) {
4768
 
            return VFW_E_TIMEOUT;
4769
 
        }
4770
 
        ASSERT(m_hSem != NULL);
4771
 
        WaitForSingleObject(m_hSem, INFINITE);
4772
 
    }
4773
 
 
4774
 
    /* Addref the buffer up to one. On release
4775
 
       back to zero instead of being deleted, it will requeue itself by
4776
 
       calling the ReleaseBuffer member function. NOTE the owner of a
4777
 
       media sample must always be derived from CBaseAllocator */
4778
 
 
4779
 
 
4780
 
    ASSERT(pSample->m_cRef == 0);
4781
 
    pSample->m_cRef = 1;
4782
 
    *ppBuffer = pSample;
4783
 
 
4784
 
#ifdef DXMPERF
4785
 
    PERFLOG_GETBUFFER( (IMemAllocator *) this, pSample );
4786
 
#endif // DXMPERF
4787
 
 
4788
 
    return NOERROR;
4789
 
}
4790
 
 
4791
 
 
4792
 
/* Final release of a CMediaSample will call this */
4793
 
 
4794
 
STDMETHODIMP
4795
 
CBaseAllocator::ReleaseBuffer(IMediaSample * pSample)
4796
 
{
4797
 
    CheckPointer(pSample,E_POINTER);
4798
 
    ValidateReadPtr(pSample,sizeof(IMediaSample));
4799
 
 
4800
 
#ifdef DXMPERF
4801
 
    PERFLOG_RELBUFFER( (IMemAllocator *) this, pSample );
4802
 
#endif // DXMPERF
4803
 
 
4804
 
 
4805
 
    BOOL bRelease = FALSE;
4806
 
    {
4807
 
        CAutoLock cal(this);
4808
 
 
4809
 
        /* Put back on the free list */
4810
 
 
4811
 
        m_lFree.Add((CMediaSample *)pSample);
4812
 
        if (m_lWaiting != 0) {
4813
 
            NotifySample();
4814
 
        }
4815
 
 
4816
 
        // if there is a pending Decommit, then we need to complete it by
4817
 
        // calling Free() when the last buffer is placed on the free list
4818
 
 
4819
 
        LONG l1 = m_lFree.GetCount();
4820
 
        if (m_bDecommitInProgress && (l1 == m_lAllocated)) {
4821
 
            Free();
4822
 
            m_bDecommitInProgress = FALSE;
4823
 
            bRelease = TRUE;
4824
 
        }
4825
 
    }
4826
 
 
4827
 
    if (m_pNotify) {
4828
 
 
4829
 
        ASSERT(m_fEnableReleaseCallback);
4830
 
 
4831
 
        //
4832
 
        // Note that this is not synchronized with setting up a notification
4833
 
        // method.
4834
 
        //
4835
 
        m_pNotify->NotifyRelease();
4836
 
    }
4837
 
 
4838
 
    /* For each buffer there is one AddRef, made in GetBuffer and released
4839
 
       here. This may cause the allocator and all samples to be deleted */
4840
 
 
4841
 
    if (bRelease) {
4842
 
        Release();
4843
 
    }
4844
 
    return NOERROR;
4845
 
}
4846
 
 
4847
 
STDMETHODIMP
4848
 
CBaseAllocator::SetNotify(
4849
 
    IMemAllocatorNotifyCallbackTemp* pNotify
4850
 
    )
4851
 
{
4852
 
    ASSERT(m_fEnableReleaseCallback);
4853
 
    CAutoLock lck(this);
4854
 
    if (pNotify) {
4855
 
        pNotify->AddRef();
4856
 
    }
4857
 
    if (m_pNotify) {
4858
 
        m_pNotify->Release();
4859
 
    }
4860
 
    m_pNotify = pNotify;
4861
 
    return S_OK;
4862
 
}
4863
 
 
4864
 
STDMETHODIMP
4865
 
CBaseAllocator::GetFreeCount(
4866
 
    __out LONG* plBuffersFree
4867
 
    )
4868
 
{
4869
 
    ASSERT(m_fEnableReleaseCallback);
4870
 
    CAutoLock cObjectLock(this);
4871
 
    *plBuffersFree = m_lCount - m_lAllocated + m_lFree.GetCount();
4872
 
    return NOERROR;
4873
 
}
4874
 
 
4875
 
void
4876
 
CBaseAllocator::NotifySample()
4877
 
{
4878
 
    if (m_lWaiting != 0) {
4879
 
        ASSERT(m_hSem != NULL);
4880
 
        ReleaseSemaphore(m_hSem, m_lWaiting, 0);
4881
 
        m_lWaiting = 0;
4882
 
    }
4883
 
}
4884
 
 
4885
 
STDMETHODIMP
4886
 
CBaseAllocator::Commit()
4887
 
{
4888
 
    /* Check we are not decommitted */
4889
 
    CAutoLock cObjectLock(this);
4890
 
 
4891
 
    // cannot need to alloc or re-alloc if we are committed
4892
 
    if (m_bCommitted) {
4893
 
        return NOERROR;
4894
 
    }
4895
 
 
4896
 
    /* Allow GetBuffer calls */
4897
 
 
4898
 
    m_bCommitted = TRUE;
4899
 
 
4900
 
    // is there a pending decommit ? if so, just cancel it
4901
 
    if (m_bDecommitInProgress) {
4902
 
        m_bDecommitInProgress = FALSE;
4903
 
 
4904
 
        // don't call Alloc at this point. He cannot allow SetProperties
4905
 
        // between Decommit and the last free, so the buffer size cannot have
4906
 
        // changed. And because some of the buffers are not free yet, he
4907
 
        // cannot re-alloc anyway.
4908
 
        return NOERROR;
4909
 
    }
4910
 
 
4911
 
    DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize));
4912
 
 
4913
 
    // actually need to allocate the samples
4914
 
    HRESULT hr = Alloc();
4915
 
    if (FAILED(hr)) {
4916
 
        m_bCommitted = FALSE;
4917
 
        return hr;
4918
 
    }
4919
 
    AddRef();
4920
 
    return NOERROR;
4921
 
}
4922
 
 
4923
 
 
4924
 
STDMETHODIMP
4925
 
CBaseAllocator::Decommit()
4926
 
{
4927
 
    BOOL bRelease = FALSE;
4928
 
    {
4929
 
        /* Check we are not already decommitted */
4930
 
        CAutoLock cObjectLock(this);
4931
 
        if (m_bCommitted == FALSE) {
4932
 
            if (m_bDecommitInProgress == FALSE) {
4933
 
                return NOERROR;
4934
 
            }
4935
 
        }
4936
 
 
4937
 
        /* No more GetBuffer calls will succeed */
4938
 
        m_bCommitted = FALSE;
4939
 
 
4940
 
        // are any buffers outstanding?
4941
 
        if (m_lFree.GetCount() < m_lAllocated) {
4942
 
            // please complete the decommit when last buffer is freed
4943
 
            m_bDecommitInProgress = TRUE;
4944
 
        } else {
4945
 
            m_bDecommitInProgress = FALSE;
4946
 
 
4947
 
            // need to complete the decommit here as there are no
4948
 
            // outstanding buffers
4949
 
 
4950
 
            Free();
4951
 
            bRelease = TRUE;
4952
 
        }
4953
 
 
4954
 
        // Tell anyone waiting that they can go now so we can
4955
 
        // reject their call
4956
 
#pragma warning(push)
4957
 
#ifndef _PREFAST_
4958
 
#pragma warning(disable:4068)
4959
 
#endif
4960
 
#pragma prefast(suppress:__WARNING_DEREF_NULL_PTR, "Suppress warning related to Free() invalidating 'this' which is no applicable to CBaseAllocator::Free()")
4961
 
        NotifySample();
4962
 
 
4963
 
#pragma warning(pop)
4964
 
    }
4965
 
 
4966
 
    if (bRelease) {
4967
 
        Release();
4968
 
    }
4969
 
    return NOERROR;
4970
 
}
4971
 
 
4972
 
 
4973
 
/* Base definition of allocation which checks we are ok to go ahead and do
4974
 
   the full allocation. We return S_FALSE if the requirements are the same */
4975
 
 
4976
 
HRESULT
4977
 
CBaseAllocator::Alloc(void)
4978
 
{
4979
 
    /* Error if he hasn't set the size yet */
4980
 
    if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0) {
4981
 
        return VFW_E_SIZENOTSET;
4982
 
    }
4983
 
 
4984
 
    /* should never get here while buffers outstanding */
4985
 
    ASSERT(m_lFree.GetCount() == m_lAllocated);
4986
 
 
4987
 
    /* If the requirements haven't changed then don't reallocate */
4988
 
    if (m_bChanged == FALSE) {
4989
 
        return S_FALSE;
4990
 
    }
4991
 
 
4992
 
    return NOERROR;
4993
 
}
4994
 
 
4995
 
/*  Implement CBaseAllocator::CSampleList::Remove(pSample)
4996
 
    Removes pSample from the list
4997
 
*/
4998
 
void
4999
 
CBaseAllocator::CSampleList::Remove(__inout CMediaSample * pSample)
5000
 
{
5001
 
    CMediaSample **pSearch;
5002
 
    for (pSearch = &m_List;
5003
 
         *pSearch != NULL;
5004
 
         pSearch = &(CBaseAllocator::NextSample(*pSearch))) {
5005
 
       if (*pSearch == pSample) {
5006
 
           *pSearch = CBaseAllocator::NextSample(pSample);
5007
 
           CBaseAllocator::NextSample(pSample) = NULL;
5008
 
           m_nOnList--;
5009
 
           return;
5010
 
       }
5011
 
    }
5012
 
    DbgBreak("Couldn't find sample in list");
5013
 
}
5014
 
 
5015
 
//=====================================================================
5016
 
//=====================================================================
5017
 
// Implements CMemAllocator
5018
 
//=====================================================================
5019
 
//=====================================================================
5020
 
 
5021
 
 
5022
 
/* This goes in the factory template table to create new instances */
5023
 
CUnknown *CMemAllocator::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr)
5024
 
{
5025
 
    CUnknown *pUnkRet = new CMemAllocator(NAME("CMemAllocator"), pUnk, phr);
5026
 
    return pUnkRet;
5027
 
}
5028
 
 
5029
 
CMemAllocator::CMemAllocator(
5030
 
    __in_opt LPCTSTR pName,
5031
 
    __inout_opt LPUNKNOWN pUnk,
5032
 
    __inout HRESULT *phr)
5033
 
    : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE),
5034
 
    m_pBuffer(NULL)
5035
 
{
5036
 
}
5037
 
 
5038
 
#ifdef UNICODE
5039
 
CMemAllocator::CMemAllocator(
5040
 
    __in_opt LPCSTR pName,
5041
 
    __inout_opt LPUNKNOWN pUnk,
5042
 
    __inout HRESULT *phr)
5043
 
    : CBaseAllocator(pName, pUnk, phr, TRUE, TRUE),
5044
 
    m_pBuffer(NULL)
5045
 
{
5046
 
}
5047
 
#endif
5048
 
 
5049
 
/* This sets the size and count of the required samples. The memory isn't
5050
 
   actually allocated until Commit() is called, if memory has already been
5051
 
   allocated then assuming no samples are outstanding the user may call us
5052
 
   to change the buffering, the memory will be released in Commit() */
5053
 
STDMETHODIMP
5054
 
CMemAllocator::SetProperties(
5055
 
                __in ALLOCATOR_PROPERTIES* pRequest,
5056
 
                __out ALLOCATOR_PROPERTIES* pActual)
5057
 
{
5058
 
    CheckPointer(pActual,E_POINTER);
5059
 
    ValidateReadWritePtr(pActual,sizeof(ALLOCATOR_PROPERTIES));
5060
 
    CAutoLock cObjectLock(this);
5061
 
 
5062
 
    ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
5063
 
 
5064
 
    ASSERT(pRequest->cbBuffer > 0);
5065
 
 
5066
 
    SYSTEM_INFO SysInfo;
5067
 
    GetSystemInfo(&SysInfo);
5068
 
 
5069
 
    /*  Check the alignment request is a power of 2 */
5070
 
    if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign) {
5071
 
        DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"),
5072
 
               pRequest->cbAlign));
5073
 
    }
5074
 
    /*  Check the alignment requested */
5075
 
    if (pRequest->cbAlign == 0 ||
5076
 
    (SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1)) != 0) {
5077
 
        DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"),
5078
 
               pRequest->cbAlign, SysInfo.dwAllocationGranularity));
5079
 
        return VFW_E_BADALIGN;
5080
 
    }
5081
 
 
5082
 
    /* Can't do this if already committed, there is an argument that says we
5083
 
       should not reject the SetProperties call if there are buffers still
5084
 
       active. However this is called by the source filter, which is the same
5085
 
       person who is holding the samples. Therefore it is not unreasonable
5086
 
       for them to free all their samples before changing the requirements */
5087
 
 
5088
 
    if (m_bCommitted == TRUE) {
5089
 
        return VFW_E_ALREADY_COMMITTED;
5090
 
    }
5091
 
 
5092
 
    /* Must be no outstanding buffers */
5093
 
 
5094
 
    if (m_lFree.GetCount() < m_lAllocated) {
5095
 
        return VFW_E_BUFFERS_OUTSTANDING;
5096
 
    }
5097
 
 
5098
 
    /* There isn't any real need to check the parameters as they
5099
 
       will just be rejected when the user finally calls Commit */
5100
 
 
5101
 
    // round length up to alignment - remember that prefix is included in
5102
 
    // the alignment
5103
 
    LONG lSize = pRequest->cbBuffer + pRequest->cbPrefix;
5104
 
    LONG lRemainder = lSize % pRequest->cbAlign;
5105
 
    if (lRemainder != 0) {
5106
 
        lSize = lSize - lRemainder + pRequest->cbAlign;
5107
 
    }
5108
 
    pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix);
5109
 
 
5110
 
    pActual->cBuffers = m_lCount = pRequest->cBuffers;
5111
 
    pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
5112
 
    pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
5113
 
 
5114
 
    m_bChanged = TRUE;
5115
 
    return NOERROR;
5116
 
}
5117
 
 
5118
 
// override this to allocate our resources when Commit is called.
5119
 
//
5120
 
// note that our resources may be already allocated when this is called,
5121
 
// since we don't free them on Decommit. We will only be called when in
5122
 
// decommit state with all buffers free.
5123
 
//
5124
 
// object locked by caller
5125
 
HRESULT
5126
 
CMemAllocator::Alloc(void)
5127
 
{
5128
 
    CAutoLock lck(this);
5129
 
 
5130
 
    /* Check he has called SetProperties */
5131
 
    HRESULT hr = CBaseAllocator::Alloc();
5132
 
    if (FAILED(hr)) {
5133
 
        return hr;
5134
 
    }
5135
 
 
5136
 
    /* If the requirements haven't changed then don't reallocate */
5137
 
    if (hr == S_FALSE) {
5138
 
        ASSERT(m_pBuffer);
5139
 
        return NOERROR;
5140
 
    }
5141
 
    ASSERT(hr == S_OK); // we use this fact in the loop below
5142
 
 
5143
 
    /* Free the old resources */
5144
 
    if (m_pBuffer) {
5145
 
        ReallyFree();
5146
 
    }
5147
 
 
5148
 
    /* Make sure we've got reasonable values */
5149
 
    if ( m_lSize < 0 || m_lPrefix < 0 || m_lCount < 0 ) {
5150
 
        return E_OUTOFMEMORY;
5151
 
    }
5152
 
 
5153
 
    /* Compute the aligned size */
5154
 
    LONG lAlignedSize = m_lSize + m_lPrefix;
5155
 
 
5156
 
    /*  Check overflow */
5157
 
    if (lAlignedSize < m_lSize) {
5158
 
        return E_OUTOFMEMORY;
5159
 
    }
5160
 
 
5161
 
    if (m_lAlignment > 1) {
5162
 
        LONG lRemainder = lAlignedSize % m_lAlignment;
5163
 
        if (lRemainder != 0) {
5164
 
            LONG lNewSize = lAlignedSize + m_lAlignment - lRemainder;
5165
 
            if (lNewSize < lAlignedSize) {
5166
 
                return E_OUTOFMEMORY;
5167
 
            }
5168
 
            lAlignedSize = lNewSize;
5169
 
        }
5170
 
    }
5171
 
 
5172
 
    /* Create the contiguous memory block for the samples
5173
 
       making sure it's properly aligned (64K should be enough!)
5174
 
    */
5175
 
    ASSERT(lAlignedSize % m_lAlignment == 0);
5176
 
 
5177
 
    LONGLONG lToAllocate = m_lCount * (LONGLONG)lAlignedSize;
5178
 
 
5179
 
    /*  Check overflow */
5180
 
    if (lToAllocate > MAXLONG) {
5181
 
        return E_OUTOFMEMORY;
5182
 
    }
5183
 
 
5184
 
    m_pBuffer = (PBYTE)VirtualAlloc(NULL,
5185
 
                    (LONG)lToAllocate,
5186
 
                    MEM_COMMIT,
5187
 
                    PAGE_READWRITE);
5188
 
 
5189
 
    if (m_pBuffer == NULL) {
5190
 
        return E_OUTOFMEMORY;
5191
 
    }
5192
 
 
5193
 
    LPBYTE pNext = m_pBuffer;
5194
 
    CMediaSample *pSample;
5195
 
 
5196
 
    ASSERT(m_lAllocated == 0);
5197
 
 
5198
 
    // Create the new samples - we have allocated m_lSize bytes for each sample
5199
 
    // plus m_lPrefix bytes per sample as a prefix. We set the pointer to
5200
 
    // the memory after the prefix - so that GetPointer() will return a pointer
5201
 
    // to m_lSize bytes.
5202
 
    for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) {
5203
 
 
5204
 
 
5205
 
        pSample = new CMediaSample(
5206
 
                            NAME("Default memory media sample"),
5207
 
                this,
5208
 
                            &hr,
5209
 
                            pNext + m_lPrefix,      // GetPointer() value
5210
 
                            m_lSize);               // not including prefix
5211
 
 
5212
 
            ASSERT(SUCCEEDED(hr));
5213
 
        if (pSample == NULL) {
5214
 
            return E_OUTOFMEMORY;
5215
 
        }
5216
 
 
5217
 
        // This CANNOT fail
5218
 
        m_lFree.Add(pSample);
5219
 
    }
5220
 
 
5221
 
    m_bChanged = FALSE;
5222
 
    return NOERROR;
5223
 
}
5224
 
 
5225
 
 
5226
 
// override this to free up any resources we have allocated.
5227
 
// called from the base class on Decommit when all buffers have been
5228
 
// returned to the free list.
5229
 
//
5230
 
// caller has already locked the object.
5231
 
 
5232
 
// in our case, we keep the memory until we are deleted, so
5233
 
// we do nothing here. The memory is deleted in the destructor by
5234
 
// calling ReallyFree()
5235
 
void
5236
 
CMemAllocator::Free(void)
5237
 
{
5238
 
    return;
5239
 
}
5240
 
 
5241
 
 
5242
 
// called from the destructor (and from Alloc if changing size/count) to
5243
 
// actually free up the memory
5244
 
void
5245
 
CMemAllocator::ReallyFree(void)
5246
 
{
5247
 
    /* Should never be deleting this unless all buffers are freed */
5248
 
 
5249
 
    ASSERT(m_lAllocated == m_lFree.GetCount());
5250
 
 
5251
 
    /* Free up all the CMediaSamples */
5252
 
 
5253
 
    CMediaSample *pSample;
5254
 
    for (;;) {
5255
 
        pSample = m_lFree.RemoveHead();
5256
 
        if (pSample != NULL) {
5257
 
            delete pSample;
5258
 
        } else {
5259
 
            break;
5260
 
        }
5261
 
    }
5262
 
 
5263
 
    m_lAllocated = 0;
5264
 
 
5265
 
    // free the block of buffer memory
5266
 
    if (m_pBuffer) {
5267
 
        EXECUTE_ASSERT(VirtualFree(m_pBuffer, 0, MEM_RELEASE));
5268
 
        m_pBuffer = NULL;
5269
 
    }
5270
 
}
5271
 
 
5272
 
 
5273
 
/* Destructor frees our memory resources */
5274
 
 
5275
 
CMemAllocator::~CMemAllocator()
5276
 
{
5277
 
    Decommit();
5278
 
    ReallyFree();
5279
 
}
5280
 
 
5281
 
// ------------------------------------------------------------------------
5282
 
// filter registration through IFilterMapper. used if IFilterMapper is
5283
 
// not found (Quartz 1.0 install)
5284
 
 
5285
 
STDAPI
5286
 
AMovieSetupRegisterFilter( const AMOVIESETUP_FILTER * const psetupdata
5287
 
                         , IFilterMapper *                  pIFM
5288
 
                         , BOOL                             bRegister  )
5289
 
{
5290
 
  DbgLog((LOG_TRACE, 3, TEXT("= AMovieSetupRegisterFilter")));
5291
 
 
5292
 
  // check we've got data
5293
 
  //
5294
 
  if( NULL == psetupdata ) return S_FALSE;
5295
 
 
5296
 
 
5297
 
  // unregister filter
5298
 
  // (as pins are subkeys of filter's CLSID key
5299
 
  // they do not need to be removed separately).
5300
 
  //
5301
 
  DbgLog((LOG_TRACE, 3, TEXT("= = unregister filter")));
5302
 
  HRESULT hr = pIFM->UnregisterFilter( *(psetupdata->clsID) );
5303
 
 
5304
 
 
5305
 
  if( bRegister )
5306
 
  {
5307
 
    // register filter
5308
 
    //
5309
 
    DbgLog((LOG_TRACE, 3, TEXT("= = register filter")));
5310
 
    hr = pIFM->RegisterFilter( *(psetupdata->clsID)
5311
 
                             , psetupdata->strName
5312
 
                             , psetupdata->dwMerit    );
5313
 
    if( SUCCEEDED(hr) )
5314
 
    {
5315
 
      // all its pins
5316
 
      //
5317
 
      DbgLog((LOG_TRACE, 3, TEXT("= = register filter pins")));
5318
 
      for( UINT m1=0; m1 < psetupdata->nPins; m1++ )
5319
 
      {
5320
 
        hr = pIFM->RegisterPin( *(psetupdata->clsID)
5321
 
                              , psetupdata->lpPin[m1].strName
5322
 
                              , psetupdata->lpPin[m1].bRendered
5323
 
                              , psetupdata->lpPin[m1].bOutput
5324
 
                              , psetupdata->lpPin[m1].bZero
5325
 
                              , psetupdata->lpPin[m1].bMany
5326
 
                              , *(psetupdata->lpPin[m1].clsConnectsToFilter)
5327
 
                              , psetupdata->lpPin[m1].strConnectsToPin );
5328
 
 
5329
 
        if( SUCCEEDED(hr) )
5330
 
        {
5331
 
          // and each pin's media types
5332
 
          //
5333
 
          DbgLog((LOG_TRACE, 3, TEXT("= = register filter pin types")));
5334
 
          for( UINT m2=0; m2 < psetupdata->lpPin[m1].nMediaTypes; m2++ )
5335
 
          {
5336
 
            hr = pIFM->RegisterPinType( *(psetupdata->clsID)
5337
 
                                      , psetupdata->lpPin[m1].strName
5338
 
                                      , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMajorType)
5339
 
                                      , *(psetupdata->lpPin[m1].lpMediaType[m2].clsMinorType) );
5340
 
            if( FAILED(hr) ) break;
5341
 
          }
5342
 
          if( FAILED(hr) ) break;
5343
 
        }
5344
 
        if( FAILED(hr) ) break;
5345
 
      }
5346
 
    }
5347
 
  }
5348
 
 
5349
 
  // handle one acceptable "error" - that
5350
 
  // of filter not being registered!
5351
 
  // (couldn't find a suitable #define'd
5352
 
  // name for the error!)
5353
 
  //
5354
 
  if( 0x80070002 == hr)
5355
 
    return NOERROR;
5356
 
  else
5357
 
    return hr;
5358
 
}
5359
 
 
5360
 
//  Remove warnings about unreferenced inline functions
5361
 
#pragma warning(disable:4514)
5362
 
 
5363
 
#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */