~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* 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 */