~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/ctlutil.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: CtlUtil.cpp
 
3
//
 
4
// Desc: DirectShow base classes.
 
5
//
 
6
// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
 
7
//------------------------------------------------------------------------------
 
8
 
 
9
 
 
10
// Base classes implementing IDispatch parsing for the basic control dual
 
11
// interfaces. Derive from these and implement just the custom method and
 
12
// property methods. We also implement CPosPassThru that can be used by
 
13
// renderers and transforms to pass by IMediaPosition and IMediaSeeking
 
14
 
 
15
#include <pjmedia-videodev/config.h>
 
16
 
 
17
#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
 
18
 
 
19
#include <streams.h>
 
20
#include <limits.h>
 
21
#include "seekpt.h"
 
22
 
 
23
// 'bool' non standard reserved word
 
24
#pragma warning(disable:4237)
 
25
 
 
26
 
 
27
// --- CBaseDispatch implementation ----------
 
28
CBaseDispatch::~CBaseDispatch()
 
29
{
 
30
    if (m_pti) {
 
31
        m_pti->Release();
 
32
    }
 
33
}
 
34
 
 
35
 
 
36
// return 1 if we support GetTypeInfo
 
37
 
 
38
STDMETHODIMP
 
39
CBaseDispatch::GetTypeInfoCount(__out UINT * pctinfo)
 
40
{
 
41
    CheckPointer(pctinfo,E_POINTER);
 
42
    ValidateReadWritePtr(pctinfo,sizeof(UINT *));
 
43
    *pctinfo = 1;
 
44
    return S_OK;
 
45
}
 
46
 
 
47
 
 
48
typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)(
 
49
                            const OLECHAR FAR *szFile,
 
50
                            __deref_out ITypeLib FAR* FAR* pptlib);
 
51
 
 
52
typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid,
 
53
                            WORD wVerMajor,
 
54
                            WORD wVerMinor,
 
55
                            LCID lcid,
 
56
                            __deref_out ITypeLib FAR* FAR* pptlib);
 
57
 
 
58
// attempt to find our type library
 
59
 
 
60
STDMETHODIMP
 
61
CBaseDispatch::GetTypeInfo(
 
62
  REFIID riid,
 
63
  UINT itinfo,
 
64
  LCID lcid,
 
65
  __deref_out ITypeInfo ** pptinfo)
 
66
{
 
67
    CheckPointer(pptinfo,E_POINTER);
 
68
    ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *));
 
69
    HRESULT hr;
 
70
 
 
71
    *pptinfo = NULL;
 
72
 
 
73
    // we only support one type element
 
74
    if (0 != itinfo) {
 
75
        return TYPE_E_ELEMENTNOTFOUND;
 
76
    }
 
77
 
 
78
    if (NULL == pptinfo) {
 
79
        return E_POINTER;
 
80
    }
 
81
 
 
82
    // always look for neutral
 
83
    if (NULL == m_pti) {
 
84
 
 
85
        LPLOADTYPELIB       lpfnLoadTypeLib;
 
86
        LPLOADREGTYPELIB    lpfnLoadRegTypeLib;
 
87
        ITypeLib            *ptlib;
 
88
        HINSTANCE           hInst;
 
89
 
 
90
        static const char  szTypeLib[]    = "LoadTypeLib";
 
91
        static const char  szRegTypeLib[] = "LoadRegTypeLib";
 
92
        static const WCHAR szControl[]    = L"control.tlb";
 
93
 
 
94
        //
 
95
        // Try to get the Ole32Aut.dll module handle.
 
96
        //
 
97
 
 
98
        hInst = LoadOLEAut32();
 
99
        if (hInst == NULL) {
 
100
            DWORD dwError = GetLastError();
 
101
            return AmHresultFromWin32(dwError);
 
102
        }
 
103
        lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst,
 
104
                                                              szRegTypeLib);
 
105
        if (lpfnLoadRegTypeLib == NULL) {
 
106
            DWORD dwError = GetLastError();
 
107
            return AmHresultFromWin32(dwError);
 
108
        }
 
109
 
 
110
        hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0
 
111
                                   lcid, &ptlib);
 
112
 
 
113
        if (FAILED(hr)) {
 
114
 
 
115
            // attempt to load directly - this will fill the
 
116
            // registry in if it finds it
 
117
 
 
118
            lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib);
 
119
            if (lpfnLoadTypeLib == NULL) {
 
120
                DWORD dwError = GetLastError();
 
121
                return AmHresultFromWin32(dwError);
 
122
            }
 
123
 
 
124
            hr = (*lpfnLoadTypeLib)(szControl, &ptlib);
 
125
            if (FAILED(hr)) {
 
126
                return hr;
 
127
            }
 
128
        }
 
129
 
 
130
        hr = ptlib->GetTypeInfoOfGuid(
 
131
                    riid,
 
132
                    &m_pti);
 
133
 
 
134
        ptlib->Release();
 
135
 
 
136
        if (FAILED(hr)) {
 
137
            return hr;
 
138
        }
 
139
    }
 
140
 
 
141
    *pptinfo = m_pti;
 
142
    m_pti->AddRef();
 
143
    return S_OK;
 
144
}
 
145
 
 
146
 
 
147
STDMETHODIMP
 
148
CBaseDispatch::GetIDsOfNames(
 
149
  REFIID riid,
 
150
  __in_ecount(cNames) LPOLESTR * rgszNames,
 
151
  UINT cNames,
 
152
  LCID lcid,
 
153
  __out_ecount(cNames) DISPID * rgdispid)
 
154
{
 
155
    // although the IDispatch riid is dead, we use this to pass from
 
156
    // the interface implementation class to us the iid we are talking about.
 
157
 
 
158
    ITypeInfo * pti;
 
159
    HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti);
 
160
 
 
161
    if (SUCCEEDED(hr)) {
 
162
        hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid);
 
163
 
 
164
        pti->Release();
 
165
    }
 
166
    return hr;
 
167
}
 
168
 
 
169
 
 
170
// --- CMediaControl implementation ---------
 
171
 
 
172
CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) :
 
173
    CUnknown(name, pUnk)
 
174
{
 
175
}
 
176
 
 
177
// expose our interfaces IMediaControl and IUnknown
 
178
 
 
179
STDMETHODIMP
 
180
CMediaControl::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
 
181
{
 
182
    ValidateReadWritePtr(ppv,sizeof(PVOID));
 
183
    if (riid == IID_IMediaControl) {
 
184
        return GetInterface( (IMediaControl *) this, ppv);
 
185
    } else {
 
186
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
 
187
    }
 
188
}
 
189
 
 
190
 
 
191
// return 1 if we support GetTypeInfo
 
192
 
 
193
STDMETHODIMP
 
194
CMediaControl::GetTypeInfoCount(__out UINT * pctinfo)
 
195
{
 
196
    return m_basedisp.GetTypeInfoCount(pctinfo);
 
197
}
 
198
 
 
199
 
 
200
// attempt to find our type library
 
201
 
 
202
STDMETHODIMP
 
203
CMediaControl::GetTypeInfo(
 
204
  UINT itinfo,
 
205
  LCID lcid,
 
206
  __deref_out ITypeInfo ** pptinfo)
 
207
{
 
208
    return m_basedisp.GetTypeInfo(
 
209
                IID_IMediaControl,
 
210
                itinfo,
 
211
                lcid,
 
212
                pptinfo);
 
213
}
 
214
 
 
215
 
 
216
STDMETHODIMP
 
217
CMediaControl::GetIDsOfNames(
 
218
  REFIID riid,
 
219
  __in_ecount(cNames) LPOLESTR * rgszNames,
 
220
  UINT cNames,
 
221
  LCID lcid,
 
222
  __out_ecount(cNames) DISPID * rgdispid)
 
223
{
 
224
    return m_basedisp.GetIDsOfNames(
 
225
                        IID_IMediaControl,
 
226
                        rgszNames,
 
227
                        cNames,
 
228
                        lcid,
 
229
                        rgdispid);
 
230
}
 
231
 
 
232
 
 
233
STDMETHODIMP
 
234
CMediaControl::Invoke(
 
235
  DISPID dispidMember,
 
236
  REFIID riid,
 
237
  LCID lcid,
 
238
  WORD wFlags,
 
239
  __in DISPPARAMS * pdispparams,
 
240
  __out_opt VARIANT * pvarResult,
 
241
  __out_opt EXCEPINFO * pexcepinfo,
 
242
  __out_opt UINT * puArgErr)
 
243
{
 
244
    // this parameter is a dead leftover from an earlier interface
 
245
    if (IID_NULL != riid) {
 
246
        return DISP_E_UNKNOWNINTERFACE;
 
247
    }
 
248
 
 
249
    ITypeInfo * pti;
 
250
    HRESULT hr = GetTypeInfo(0, lcid, &pti);
 
251
 
 
252
    if (FAILED(hr)) {
 
253
        return hr;
 
254
    }
 
255
 
 
256
    hr = pti->Invoke(
 
257
            (IMediaControl *)this,
 
258
            dispidMember,
 
259
            wFlags,
 
260
            pdispparams,
 
261
            pvarResult,
 
262
            pexcepinfo,
 
263
            puArgErr);
 
264
 
 
265
    pti->Release();
 
266
    return hr;
 
267
}
 
268
 
 
269
 
 
270
// --- CMediaEvent implementation ----------
 
271
 
 
272
 
 
273
CMediaEvent::CMediaEvent(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) :
 
274
    CUnknown(name, pUnk)
 
275
{
 
276
}
 
277
 
 
278
 
 
279
// expose our interfaces IMediaEvent and IUnknown
 
280
 
 
281
STDMETHODIMP
 
282
CMediaEvent::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
 
283
{
 
284
    ValidateReadWritePtr(ppv,sizeof(PVOID));
 
285
    if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) {
 
286
        return GetInterface( (IMediaEventEx *) this, ppv);
 
287
    } else {
 
288
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
 
289
    }
 
290
}
 
291
 
 
292
 
 
293
// return 1 if we support GetTypeInfo
 
294
 
 
295
STDMETHODIMP
 
296
CMediaEvent::GetTypeInfoCount(__out UINT * pctinfo)
 
297
{
 
298
    return m_basedisp.GetTypeInfoCount(pctinfo);
 
299
}
 
300
 
 
301
 
 
302
// attempt to find our type library
 
303
 
 
304
STDMETHODIMP
 
305
CMediaEvent::GetTypeInfo(
 
306
  UINT itinfo,
 
307
  LCID lcid,
 
308
  __deref_out ITypeInfo ** pptinfo)
 
309
{
 
310
    return m_basedisp.GetTypeInfo(
 
311
                IID_IMediaEvent,
 
312
                itinfo,
 
313
                lcid,
 
314
                pptinfo);
 
315
}
 
316
 
 
317
 
 
318
STDMETHODIMP
 
319
CMediaEvent::GetIDsOfNames(
 
320
  REFIID riid,
 
321
  __in_ecount(cNames) LPOLESTR * rgszNames,
 
322
  UINT cNames,
 
323
  LCID lcid,
 
324
  __out_ecount(cNames) DISPID * rgdispid)
 
325
{
 
326
    return m_basedisp.GetIDsOfNames(
 
327
                        IID_IMediaEvent,
 
328
                        rgszNames,
 
329
                        cNames,
 
330
                        lcid,
 
331
                        rgdispid);
 
332
}
 
333
 
 
334
 
 
335
STDMETHODIMP
 
336
CMediaEvent::Invoke(
 
337
  DISPID dispidMember,
 
338
  REFIID riid,
 
339
  LCID lcid,
 
340
  WORD wFlags,
 
341
  __in DISPPARAMS * pdispparams,
 
342
  __out_opt VARIANT * pvarResult,
 
343
  __out_opt EXCEPINFO * pexcepinfo,
 
344
  __out_opt UINT * puArgErr)
 
345
{
 
346
    // this parameter is a dead leftover from an earlier interface
 
347
    if (IID_NULL != riid) {
 
348
        return DISP_E_UNKNOWNINTERFACE;
 
349
    }
 
350
 
 
351
    ITypeInfo * pti;
 
352
    HRESULT hr = GetTypeInfo(0, lcid, &pti);
 
353
 
 
354
    if (FAILED(hr)) {
 
355
        return hr;
 
356
    }
 
357
 
 
358
    hr = pti->Invoke(
 
359
            (IMediaEvent *)this,
 
360
            dispidMember,
 
361
            wFlags,
 
362
            pdispparams,
 
363
            pvarResult,
 
364
            pexcepinfo,
 
365
            puArgErr);
 
366
 
 
367
    pti->Release();
 
368
    return hr;
 
369
}
 
370
 
 
371
 
 
372
// --- CMediaPosition implementation ----------
 
373
 
 
374
 
 
375
CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) :
 
376
    CUnknown(name, pUnk)
 
377
{
 
378
}
 
379
 
 
380
CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,
 
381
                               __in_opt LPUNKNOWN pUnk,
 
382
                               __inout HRESULT * phr) :
 
383
    CUnknown(name, pUnk)
 
384
{
 
385
    UNREFERENCED_PARAMETER(phr);
 
386
}
 
387
 
 
388
 
 
389
// expose our interfaces IMediaPosition and IUnknown
 
390
 
 
391
STDMETHODIMP
 
392
CMediaPosition::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
 
393
{
 
394
    ValidateReadWritePtr(ppv,sizeof(PVOID));
 
395
    if (riid == IID_IMediaPosition) {
 
396
        return GetInterface( (IMediaPosition *) this, ppv);
 
397
    } else {
 
398
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
 
399
    }
 
400
}
 
401
 
 
402
 
 
403
// return 1 if we support GetTypeInfo
 
404
 
 
405
STDMETHODIMP
 
406
CMediaPosition::GetTypeInfoCount(__out UINT * pctinfo)
 
407
{
 
408
    return m_basedisp.GetTypeInfoCount(pctinfo);
 
409
}
 
410
 
 
411
 
 
412
// attempt to find our type library
 
413
 
 
414
STDMETHODIMP
 
415
CMediaPosition::GetTypeInfo(
 
416
  UINT itinfo,
 
417
  LCID lcid,
 
418
  __deref_out ITypeInfo ** pptinfo)
 
419
{
 
420
    return m_basedisp.GetTypeInfo(
 
421
                IID_IMediaPosition,
 
422
                itinfo,
 
423
                lcid,
 
424
                pptinfo);
 
425
}
 
426
 
 
427
 
 
428
STDMETHODIMP
 
429
CMediaPosition::GetIDsOfNames(
 
430
  REFIID riid,
 
431
  __in_ecount(cNames) LPOLESTR * rgszNames,
 
432
  UINT cNames,
 
433
  LCID lcid,
 
434
  __out_ecount(cNames) DISPID * rgdispid)
 
435
{
 
436
    return m_basedisp.GetIDsOfNames(
 
437
                        IID_IMediaPosition,
 
438
                        rgszNames,
 
439
                        cNames,
 
440
                        lcid,
 
441
                        rgdispid);
 
442
}
 
443
 
 
444
 
 
445
STDMETHODIMP
 
446
CMediaPosition::Invoke(
 
447
  DISPID dispidMember,
 
448
  REFIID riid,
 
449
  LCID lcid,
 
450
  WORD wFlags,
 
451
  __in DISPPARAMS * pdispparams,
 
452
  __out_opt VARIANT * pvarResult,
 
453
  __out_opt EXCEPINFO * pexcepinfo,
 
454
  __out_opt UINT * puArgErr)
 
455
{
 
456
    // this parameter is a dead leftover from an earlier interface
 
457
    if (IID_NULL != riid) {
 
458
        return DISP_E_UNKNOWNINTERFACE;
 
459
    }
 
460
 
 
461
    ITypeInfo * pti;
 
462
    HRESULT hr = GetTypeInfo(0, lcid, &pti);
 
463
 
 
464
    if (FAILED(hr)) {
 
465
        return hr;
 
466
    }
 
467
 
 
468
    hr = pti->Invoke(
 
469
            (IMediaPosition *)this,
 
470
            dispidMember,
 
471
            wFlags,
 
472
            pdispparams,
 
473
            pvarResult,
 
474
            pexcepinfo,
 
475
            puArgErr);
 
476
 
 
477
    pti->Release();
 
478
    return hr;
 
479
}
 
480
 
 
481
 
 
482
// --- IMediaPosition and IMediaSeeking pass through class ----------
 
483
 
 
484
 
 
485
CPosPassThru::CPosPassThru(__in_opt LPCTSTR pName,
 
486
                           __in_opt LPUNKNOWN pUnk,
 
487
                           __inout HRESULT *phr,
 
488
                           IPin *pPin) :
 
489
    CMediaPosition(pName,pUnk),
 
490
    m_pPin(pPin)
 
491
{
 
492
    if (pPin == NULL) {
 
493
        *phr = E_POINTER;
 
494
        return;
 
495
    }
 
496
}
 
497
 
 
498
 
 
499
// Expose our IMediaSeeking and IMediaPosition interfaces
 
500
 
 
501
STDMETHODIMP
 
502
CPosPassThru::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv)
 
503
{
 
504
    CheckPointer(ppv,E_POINTER);
 
505
    *ppv = NULL;
 
506
 
 
507
    if (riid == IID_IMediaSeeking) {
 
508
        return GetInterface( static_cast<IMediaSeeking *>(this), ppv);
 
509
    }
 
510
    return CMediaPosition::NonDelegatingQueryInterface(riid,ppv);
 
511
}
 
512
 
 
513
 
 
514
// Return the IMediaPosition interface from our peer
 
515
 
 
516
HRESULT
 
517
CPosPassThru::GetPeer(IMediaPosition ** ppMP)
 
518
{
 
519
    *ppMP = NULL;
 
520
 
 
521
    IPin *pConnected;
 
522
    HRESULT hr = m_pPin->ConnectedTo(&pConnected);
 
523
    if (FAILED(hr)) {
 
524
        return E_NOTIMPL;
 
525
    }
 
526
    IMediaPosition * pMP;
 
527
    hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP);
 
528
    pConnected->Release();
 
529
    if (FAILED(hr)) {
 
530
        return E_NOTIMPL;
 
531
    }
 
532
 
 
533
    *ppMP = pMP;
 
534
    return S_OK;
 
535
}
 
536
 
 
537
 
 
538
// Return the IMediaSeeking interface from our peer
 
539
 
 
540
HRESULT
 
541
CPosPassThru::GetPeerSeeking(__deref_out IMediaSeeking ** ppMS)
 
542
{
 
543
    *ppMS = NULL;
 
544
 
 
545
    IPin *pConnected;
 
546
    HRESULT hr = m_pPin->ConnectedTo(&pConnected);
 
547
    if (FAILED(hr)) {
 
548
        return E_NOTIMPL;
 
549
    }
 
550
    IMediaSeeking * pMS;
 
551
    hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS);
 
552
    pConnected->Release();
 
553
    if (FAILED(hr)) {
 
554
        return E_NOTIMPL;
 
555
    }
 
556
 
 
557
    *ppMS = pMS;
 
558
    return S_OK;
 
559
}
 
560
 
 
561
 
 
562
// --- IMediaSeeking methods ----------
 
563
 
 
564
 
 
565
STDMETHODIMP
 
566
CPosPassThru::GetCapabilities(__out DWORD * pCaps)
 
567
{
 
568
    IMediaSeeking* pMS;
 
569
    HRESULT hr = GetPeerSeeking(&pMS);
 
570
    if (FAILED(hr)) {
 
571
        return hr;
 
572
    }
 
573
 
 
574
    hr = pMS->GetCapabilities(pCaps);
 
575
    pMS->Release();
 
576
    return hr;
 
577
}
 
578
 
 
579
STDMETHODIMP
 
580
CPosPassThru::CheckCapabilities(__inout DWORD * pCaps)
 
581
{
 
582
    IMediaSeeking* pMS;
 
583
    HRESULT hr = GetPeerSeeking(&pMS);
 
584
    if (FAILED(hr)) {
 
585
        return hr;
 
586
    }
 
587
 
 
588
    hr = pMS->CheckCapabilities(pCaps);
 
589
    pMS->Release();
 
590
    return hr;
 
591
}
 
592
 
 
593
STDMETHODIMP
 
594
CPosPassThru::IsFormatSupported(const GUID * pFormat)
 
595
{
 
596
    IMediaSeeking* pMS;
 
597
    HRESULT hr = GetPeerSeeking(&pMS);
 
598
    if (FAILED(hr)) {
 
599
        return hr;
 
600
    }
 
601
 
 
602
    hr = pMS->IsFormatSupported(pFormat);
 
603
    pMS->Release();
 
604
    return hr;
 
605
}
 
606
 
 
607
 
 
608
STDMETHODIMP
 
609
CPosPassThru::QueryPreferredFormat(__out GUID *pFormat)
 
610
{
 
611
    IMediaSeeking* pMS;
 
612
    HRESULT hr = GetPeerSeeking(&pMS);
 
613
    if (FAILED(hr)) {
 
614
        return hr;
 
615
    }
 
616
 
 
617
    hr = pMS->QueryPreferredFormat(pFormat);
 
618
    pMS->Release();
 
619
    return hr;
 
620
}
 
621
 
 
622
 
 
623
STDMETHODIMP
 
624
CPosPassThru::SetTimeFormat(const GUID * pFormat)
 
625
{
 
626
    IMediaSeeking* pMS;
 
627
    HRESULT hr = GetPeerSeeking(&pMS);
 
628
    if (FAILED(hr)) {
 
629
        return hr;
 
630
    }
 
631
 
 
632
    hr = pMS->SetTimeFormat(pFormat);
 
633
    pMS->Release();
 
634
    return hr;
 
635
}
 
636
 
 
637
 
 
638
STDMETHODIMP
 
639
CPosPassThru::GetTimeFormat(__out GUID *pFormat)
 
640
{
 
641
    IMediaSeeking* pMS;
 
642
    HRESULT hr = GetPeerSeeking(&pMS);
 
643
    if (FAILED(hr)) {
 
644
        return hr;
 
645
    }
 
646
 
 
647
    hr = pMS->GetTimeFormat(pFormat);
 
648
    pMS->Release();
 
649
    return hr;
 
650
}
 
651
 
 
652
 
 
653
STDMETHODIMP
 
654
CPosPassThru::IsUsingTimeFormat(const GUID * pFormat)
 
655
{
 
656
    IMediaSeeking* pMS;
 
657
    HRESULT hr = GetPeerSeeking(&pMS);
 
658
    if (FAILED(hr)) {
 
659
        return hr;
 
660
    }
 
661
 
 
662
    hr = pMS->IsUsingTimeFormat(pFormat);
 
663
    pMS->Release();
 
664
    return hr;
 
665
}
 
666
 
 
667
 
 
668
STDMETHODIMP
 
669
CPosPassThru::ConvertTimeFormat(__out LONGLONG * pTarget, 
 
670
                                __in_opt const GUID * pTargetFormat,
 
671
                                LONGLONG Source, 
 
672
                                __in_opt const GUID * pSourceFormat )
 
673
{
 
674
    IMediaSeeking* pMS;
 
675
    HRESULT hr = GetPeerSeeking(&pMS);
 
676
    if (FAILED(hr)) {
 
677
        return hr;
 
678
    }
 
679
 
 
680
    hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat );
 
681
    pMS->Release();
 
682
    return hr;
 
683
}
 
684
 
 
685
 
 
686
STDMETHODIMP
 
687
CPosPassThru::SetPositions( __inout_opt LONGLONG * pCurrent, 
 
688
                            DWORD CurrentFlags, 
 
689
                            __inout_opt LONGLONG * pStop, 
 
690
                            DWORD StopFlags )
 
691
{
 
692
    IMediaSeeking* pMS;
 
693
    HRESULT hr = GetPeerSeeking(&pMS);
 
694
    if (FAILED(hr)) {
 
695
        return hr;
 
696
    }
 
697
 
 
698
    hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags );
 
699
    pMS->Release();
 
700
    return hr;
 
701
}
 
702
 
 
703
STDMETHODIMP
 
704
CPosPassThru::GetPositions(__out_opt LONGLONG *pCurrent, __out_opt LONGLONG * pStop)
 
705
{
 
706
    IMediaSeeking* pMS;
 
707
    HRESULT hr = GetPeerSeeking(&pMS);
 
708
    if (FAILED(hr)) {
 
709
        return hr;
 
710
    }
 
711
 
 
712
    hr = pMS->GetPositions(pCurrent,pStop);
 
713
    pMS->Release();
 
714
    return hr;
 
715
}
 
716
 
 
717
HRESULT
 
718
CPosPassThru::GetSeekingLongLong
 
719
( HRESULT (__stdcall IMediaSeeking::*pMethod)( __out LONGLONG * )
 
720
, LONGLONG * pll
 
721
)
 
722
{
 
723
    IMediaSeeking* pMS;
 
724
    HRESULT hr = GetPeerSeeking(&pMS);
 
725
    if (SUCCEEDED(hr))
 
726
    {
 
727
        hr = (pMS->*pMethod)(pll);
 
728
        pMS->Release();
 
729
    }
 
730
    return hr;
 
731
}
 
732
 
 
733
// If we don't have a current position then ask upstream
 
734
 
 
735
STDMETHODIMP
 
736
CPosPassThru::GetCurrentPosition(__out LONGLONG *pCurrent)
 
737
{
 
738
    // Can we report the current position
 
739
    HRESULT hr = GetMediaTime(pCurrent,NULL);
 
740
    if (SUCCEEDED(hr)) hr = NOERROR;
 
741
    else hr = GetSeekingLongLong( &IMediaSeeking::GetCurrentPosition, pCurrent );
 
742
    return hr;
 
743
}
 
744
 
 
745
 
 
746
STDMETHODIMP
 
747
CPosPassThru::GetStopPosition(__out LONGLONG *pStop)
 
748
{
 
749
    return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );;
 
750
}
 
751
 
 
752
STDMETHODIMP
 
753
CPosPassThru::GetDuration(__out LONGLONG *pDuration)
 
754
{
 
755
    return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );;
 
756
}
 
757
 
 
758
 
 
759
STDMETHODIMP
 
760
CPosPassThru::GetPreroll(__out LONGLONG *pllPreroll)
 
761
{
 
762
    return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );;
 
763
}
 
764
 
 
765
 
 
766
STDMETHODIMP
 
767
CPosPassThru::GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest )
 
768
{
 
769
    IMediaSeeking* pMS;
 
770
    HRESULT hr = GetPeerSeeking(&pMS);
 
771
    if (FAILED(hr)) {
 
772
        return hr;
 
773
    }
 
774
 
 
775
    hr = pMS->GetAvailable( pEarliest, pLatest );
 
776
    pMS->Release();
 
777
    return hr;
 
778
}
 
779
 
 
780
 
 
781
STDMETHODIMP
 
782
CPosPassThru::GetRate(__out double * pdRate)
 
783
{
 
784
    IMediaSeeking* pMS;
 
785
    HRESULT hr = GetPeerSeeking(&pMS);
 
786
    if (FAILED(hr)) {
 
787
        return hr;
 
788
    }
 
789
    hr = pMS->GetRate(pdRate);
 
790
    pMS->Release();
 
791
    return hr;
 
792
}
 
793
 
 
794
 
 
795
STDMETHODIMP
 
796
CPosPassThru::SetRate(double dRate)
 
797
{
 
798
    if (0.0 == dRate) {
 
799
                return E_INVALIDARG;
 
800
    }
 
801
 
 
802
    IMediaSeeking* pMS;
 
803
    HRESULT hr = GetPeerSeeking(&pMS);
 
804
    if (FAILED(hr)) {
 
805
        return hr;
 
806
    }
 
807
    hr = pMS->SetRate(dRate);
 
808
    pMS->Release();
 
809
    return hr;
 
810
}
 
811
 
 
812
 
 
813
 
 
814
 
 
815
// --- IMediaPosition methods ----------
 
816
 
 
817
 
 
818
STDMETHODIMP
 
819
CPosPassThru::get_Duration(__out REFTIME * plength)
 
820
{
 
821
    IMediaPosition* pMP;
 
822
    HRESULT hr = GetPeer(&pMP);
 
823
    if (FAILED(hr)) {
 
824
        return hr;
 
825
    }
 
826
 
 
827
    hr = pMP->get_Duration(plength);
 
828
    pMP->Release();
 
829
    return hr;
 
830
}
 
831
 
 
832
 
 
833
STDMETHODIMP
 
834
CPosPassThru::get_CurrentPosition(__out REFTIME * pllTime)
 
835
{
 
836
    IMediaPosition* pMP;
 
837
    HRESULT hr = GetPeer(&pMP);
 
838
    if (FAILED(hr)) {
 
839
        return hr;
 
840
    }
 
841
    hr = pMP->get_CurrentPosition(pllTime);
 
842
    pMP->Release();
 
843
    return hr;
 
844
}
 
845
 
 
846
 
 
847
STDMETHODIMP
 
848
CPosPassThru::put_CurrentPosition(REFTIME llTime)
 
849
{
 
850
    IMediaPosition* pMP;
 
851
    HRESULT hr = GetPeer(&pMP);
 
852
    if (FAILED(hr)) {
 
853
        return hr;
 
854
    }
 
855
    hr = pMP->put_CurrentPosition(llTime);
 
856
    pMP->Release();
 
857
    return hr;
 
858
}
 
859
 
 
860
 
 
861
STDMETHODIMP
 
862
CPosPassThru::get_StopTime(__out REFTIME * pllTime)
 
863
{
 
864
    IMediaPosition* pMP;
 
865
    HRESULT hr = GetPeer(&pMP);
 
866
    if (FAILED(hr)) {
 
867
        return hr;
 
868
    }
 
869
    hr = pMP->get_StopTime(pllTime);
 
870
    pMP->Release();
 
871
    return hr;
 
872
}
 
873
 
 
874
 
 
875
STDMETHODIMP
 
876
CPosPassThru::put_StopTime(REFTIME llTime)
 
877
{
 
878
    IMediaPosition* pMP;
 
879
    HRESULT hr = GetPeer(&pMP);
 
880
    if (FAILED(hr)) {
 
881
        return hr;
 
882
    }
 
883
    hr = pMP->put_StopTime(llTime);
 
884
    pMP->Release();
 
885
    return hr;
 
886
}
 
887
 
 
888
 
 
889
STDMETHODIMP
 
890
CPosPassThru::get_PrerollTime(__out REFTIME * pllTime)
 
891
{
 
892
    IMediaPosition* pMP;
 
893
    HRESULT hr = GetPeer(&pMP);
 
894
    if (FAILED(hr)) {
 
895
        return hr;
 
896
    }
 
897
    hr = pMP->get_PrerollTime(pllTime);
 
898
    pMP->Release();
 
899
    return hr;
 
900
}
 
901
 
 
902
 
 
903
STDMETHODIMP
 
904
CPosPassThru::put_PrerollTime(REFTIME llTime)
 
905
{
 
906
    IMediaPosition* pMP;
 
907
    HRESULT hr = GetPeer(&pMP);
 
908
    if (FAILED(hr)) {
 
909
        return hr;
 
910
    }
 
911
    hr = pMP->put_PrerollTime(llTime);
 
912
    pMP->Release();
 
913
    return hr;
 
914
}
 
915
 
 
916
 
 
917
STDMETHODIMP
 
918
CPosPassThru::get_Rate(__out double * pdRate)
 
919
{
 
920
    IMediaPosition* pMP;
 
921
    HRESULT hr = GetPeer(&pMP);
 
922
    if (FAILED(hr)) {
 
923
        return hr;
 
924
    }
 
925
    hr = pMP->get_Rate(pdRate);
 
926
    pMP->Release();
 
927
    return hr;
 
928
}
 
929
 
 
930
 
 
931
STDMETHODIMP
 
932
CPosPassThru::put_Rate(double dRate)
 
933
{
 
934
    if (0.0 == dRate) {
 
935
                return E_INVALIDARG;
 
936
    }
 
937
 
 
938
    IMediaPosition* pMP;
 
939
    HRESULT hr = GetPeer(&pMP);
 
940
    if (FAILED(hr)) {
 
941
        return hr;
 
942
    }
 
943
    hr = pMP->put_Rate(dRate);
 
944
    pMP->Release();
 
945
    return hr;
 
946
}
 
947
 
 
948
 
 
949
STDMETHODIMP
 
950
CPosPassThru::CanSeekForward(__out LONG *pCanSeekForward)
 
951
{
 
952
    IMediaPosition* pMP;
 
953
    HRESULT hr = GetPeer(&pMP);
 
954
    if (FAILED(hr)) {
 
955
        return hr;
 
956
    }
 
957
    hr = pMP->CanSeekForward(pCanSeekForward);
 
958
    pMP->Release();
 
959
    return hr;
 
960
}
 
961
 
 
962
 
 
963
STDMETHODIMP
 
964
CPosPassThru::CanSeekBackward(__out LONG *pCanSeekBackward)
 
965
{
 
966
    IMediaPosition* pMP;
 
967
    HRESULT hr = GetPeer(&pMP);
 
968
    if (FAILED(hr)) {
 
969
        return hr;
 
970
    }
 
971
    hr = pMP->CanSeekBackward(pCanSeekBackward);
 
972
    pMP->Release();
 
973
    return hr;
 
974
}
 
975
 
 
976
 
 
977
// --- Implements the CRendererPosPassThru class ----------
 
978
 
 
979
 
 
980
// Media times (eg current frame, field, sample etc) are passed through the
 
981
// filtergraph in media samples. When a renderer gets a sample with media
 
982
// times in it, it will call one of the RegisterMediaTime methods we expose
 
983
// (one takes an IMediaSample, the other takes the media times direct). We
 
984
// store the media times internally and return them in GetCurrentPosition.
 
985
 
 
986
CRendererPosPassThru::CRendererPosPassThru(__in_opt LPCTSTR pName,
 
987
                                           __in_opt LPUNKNOWN pUnk,
 
988
                                           __inout HRESULT *phr,
 
989
                                           IPin *pPin) :
 
990
    CPosPassThru(pName,pUnk,phr,pPin),
 
991
    m_StartMedia(0),
 
992
    m_EndMedia(0),
 
993
    m_bReset(TRUE)
 
994
{
 
995
}
 
996
 
 
997
 
 
998
// Sets the media times the object should report
 
999
 
 
1000
HRESULT
 
1001
CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample)
 
1002
{
 
1003
    ASSERT(pMediaSample);
 
1004
    LONGLONG StartMedia;
 
1005
    LONGLONG EndMedia;
 
1006
 
 
1007
    CAutoLock cAutoLock(&m_PositionLock);
 
1008
 
 
1009
    // Get the media times from the sample
 
1010
 
 
1011
    HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia);
 
1012
    if (FAILED(hr))
 
1013
    {
 
1014
        ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET);
 
1015
        return hr;
 
1016
    }
 
1017
 
 
1018
    m_StartMedia = StartMedia;
 
1019
    m_EndMedia = EndMedia;
 
1020
    m_bReset = FALSE;
 
1021
    return NOERROR;
 
1022
}
 
1023
 
 
1024
 
 
1025
// Sets the media times the object should report
 
1026
 
 
1027
HRESULT
 
1028
CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime)
 
1029
{
 
1030
    CAutoLock cAutoLock(&m_PositionLock);
 
1031
    m_StartMedia = StartTime;
 
1032
    m_EndMedia = EndTime;
 
1033
    m_bReset = FALSE;
 
1034
    return NOERROR;
 
1035
}
 
1036
 
 
1037
 
 
1038
// Return the current media times registered in the object
 
1039
 
 
1040
HRESULT
 
1041
CRendererPosPassThru::GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime)
 
1042
{
 
1043
    ASSERT(pStartTime);
 
1044
 
 
1045
    CAutoLock cAutoLock(&m_PositionLock);
 
1046
    if (m_bReset == TRUE) {
 
1047
        return E_FAIL;
 
1048
    }
 
1049
 
 
1050
    // We don't have to return the end time
 
1051
 
 
1052
    HRESULT hr = ConvertTimeFormat( pStartTime, 0, m_StartMedia, &TIME_FORMAT_MEDIA_TIME );
 
1053
    if (pEndTime && SUCCEEDED(hr)) {
 
1054
        hr = ConvertTimeFormat( pEndTime, 0, m_EndMedia, &TIME_FORMAT_MEDIA_TIME );
 
1055
    }
 
1056
    return hr;
 
1057
}
 
1058
 
 
1059
 
 
1060
// Resets the media times we hold
 
1061
 
 
1062
HRESULT
 
1063
CRendererPosPassThru::ResetMediaTime()
 
1064
{
 
1065
    CAutoLock cAutoLock(&m_PositionLock);
 
1066
    m_StartMedia = 0;
 
1067
    m_EndMedia = 0;
 
1068
    m_bReset = TRUE;
 
1069
    return NOERROR;
 
1070
}
 
1071
 
 
1072
// Intended to be called by the owing filter during EOS processing so
 
1073
// that the media times can be adjusted to the stop time.  This ensures
 
1074
// that the GetCurrentPosition will actully get to the stop position.
 
1075
HRESULT
 
1076
CRendererPosPassThru::EOS()
 
1077
{
 
1078
    HRESULT hr;
 
1079
 
 
1080
    if ( m_bReset == TRUE ) hr = E_FAIL;
 
1081
    else
 
1082
    {
 
1083
        LONGLONG llStop;
 
1084
        if SUCCEEDED(hr=GetStopPosition(&llStop))
 
1085
        {
 
1086
            CAutoLock cAutoLock(&m_PositionLock);
 
1087
            m_StartMedia =
 
1088
            m_EndMedia   = llStop;
 
1089
        }
 
1090
    }
 
1091
    return hr;
 
1092
}
 
1093
 
 
1094
// -- CSourceSeeking implementation ------------
 
1095
 
 
1096
CSourceSeeking::CSourceSeeking(
 
1097
    __in_opt LPCTSTR pName,
 
1098
    __in_opt LPUNKNOWN pUnk,
 
1099
    __inout HRESULT* phr,
 
1100
    __in CCritSec * pLock) :
 
1101
        CUnknown(pName, pUnk),
 
1102
        m_pLock(pLock),
 
1103
        m_rtStart((long)0)
 
1104
{
 
1105
    m_rtStop = _I64_MAX / 2;
 
1106
    m_rtDuration = m_rtStop;
 
1107
    m_dRateSeeking = 1.0;
 
1108
 
 
1109
    m_dwSeekingCaps = AM_SEEKING_CanSeekForwards
 
1110
        | AM_SEEKING_CanSeekBackwards
 
1111
        | AM_SEEKING_CanSeekAbsolute
 
1112
        | AM_SEEKING_CanGetStopPos
 
1113
        | AM_SEEKING_CanGetDuration;
 
1114
}
 
1115
 
 
1116
HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
 
1117
{
 
1118
    if(riid == IID_IMediaSeeking) {
 
1119
        CheckPointer(ppv, E_POINTER);
 
1120
        return GetInterface(static_cast<IMediaSeeking *>(this), ppv);
 
1121
    }
 
1122
    else {
 
1123
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
 
1124
    }
 
1125
}
 
1126
 
 
1127
 
 
1128
HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat)
 
1129
{
 
1130
    CheckPointer(pFormat, E_POINTER);
 
1131
    // only seeking in time (REFERENCE_TIME units) is supported
 
1132
    return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
 
1133
}
 
1134
 
 
1135
HRESULT CSourceSeeking::QueryPreferredFormat(__out GUID *pFormat)
 
1136
{
 
1137
    CheckPointer(pFormat, E_POINTER);
 
1138
    *pFormat = TIME_FORMAT_MEDIA_TIME;
 
1139
    return S_OK;
 
1140
}
 
1141
 
 
1142
HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat)
 
1143
{
 
1144
    CheckPointer(pFormat, E_POINTER);
 
1145
 
 
1146
    // nothing to set; just check that it's TIME_FORMAT_TIME
 
1147
    return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG;
 
1148
}
 
1149
 
 
1150
HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat)
 
1151
{
 
1152
    CheckPointer(pFormat, E_POINTER);
 
1153
    return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
 
1154
}
 
1155
 
 
1156
HRESULT CSourceSeeking::GetTimeFormat(__out GUID *pFormat)
 
1157
{
 
1158
    CheckPointer(pFormat, E_POINTER);
 
1159
    *pFormat = TIME_FORMAT_MEDIA_TIME;
 
1160
    return S_OK;
 
1161
}
 
1162
 
 
1163
HRESULT CSourceSeeking::GetDuration(__out LONGLONG *pDuration)
 
1164
{
 
1165
    CheckPointer(pDuration, E_POINTER);
 
1166
    CAutoLock lock(m_pLock);
 
1167
    *pDuration = m_rtDuration;
 
1168
    return S_OK;
 
1169
}
 
1170
 
 
1171
HRESULT CSourceSeeking::GetStopPosition(__out LONGLONG *pStop)
 
1172
{
 
1173
    CheckPointer(pStop, E_POINTER);
 
1174
    CAutoLock lock(m_pLock);
 
1175
    *pStop = m_rtStop;
 
1176
    return S_OK;
 
1177
}
 
1178
 
 
1179
HRESULT CSourceSeeking::GetCurrentPosition(__out LONGLONG *pCurrent)
 
1180
{
 
1181
    // GetCurrentPosition is typically supported only in renderers and
 
1182
    // not in source filters.
 
1183
    return E_NOTIMPL;
 
1184
}
 
1185
 
 
1186
HRESULT CSourceSeeking::GetCapabilities( __out DWORD * pCapabilities )
 
1187
{
 
1188
    CheckPointer(pCapabilities, E_POINTER);
 
1189
    *pCapabilities = m_dwSeekingCaps;
 
1190
    return S_OK;
 
1191
}
 
1192
 
 
1193
HRESULT CSourceSeeking::CheckCapabilities( __inout DWORD * pCapabilities )
 
1194
{
 
1195
    CheckPointer(pCapabilities, E_POINTER);
 
1196
 
 
1197
    // make sure all requested capabilities are in our mask
 
1198
    return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK;
 
1199
}
 
1200
 
 
1201
HRESULT CSourceSeeking::ConvertTimeFormat( __out LONGLONG * pTarget, 
 
1202
                                           __in_opt const GUID * pTargetFormat,
 
1203
                                           LONGLONG Source, 
 
1204
                                           __in_opt const GUID * pSourceFormat )
 
1205
{
 
1206
    CheckPointer(pTarget, E_POINTER);
 
1207
    // format guids can be null to indicate current format
 
1208
 
 
1209
    // since we only support TIME_FORMAT_MEDIA_TIME, we don't really
 
1210
    // offer any conversions.
 
1211
    if(pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME)
 
1212
    {
 
1213
        if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME)
 
1214
        {
 
1215
            *pTarget = Source;
 
1216
            return S_OK;
 
1217
        }
 
1218
    }
 
1219
 
 
1220
    return E_INVALIDARG;
 
1221
}
 
1222
 
 
1223
 
 
1224
HRESULT CSourceSeeking::SetPositions( __inout_opt LONGLONG * pCurrent,  
 
1225
                                      DWORD CurrentFlags, 
 
1226
                                      __inout_opt LONGLONG * pStop,  
 
1227
                                      DWORD StopFlags )
 
1228
{
 
1229
    DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask;
 
1230
    DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask;
 
1231
 
 
1232
    if(StopFlags) {
 
1233
        CheckPointer(pStop, E_POINTER);
 
1234
 
 
1235
        // accept only relative, incremental, or absolute positioning
 
1236
        if(StopPosBits != StopFlags) {
 
1237
            return E_INVALIDARG;
 
1238
        }
 
1239
    }
 
1240
 
 
1241
    if(CurrentFlags) {
 
1242
        CheckPointer(pCurrent, E_POINTER);
 
1243
        if(StartPosBits != AM_SEEKING_AbsolutePositioning &&
 
1244
           StartPosBits != AM_SEEKING_RelativePositioning) {
 
1245
            return E_INVALIDARG;
 
1246
        }
 
1247
    }
 
1248
 
 
1249
 
 
1250
    // scope for autolock
 
1251
    {
 
1252
        CAutoLock lock(m_pLock);
 
1253
 
 
1254
        // set start position
 
1255
        if(StartPosBits == AM_SEEKING_AbsolutePositioning)
 
1256
        {
 
1257
            m_rtStart = *pCurrent;
 
1258
        }
 
1259
        else if(StartPosBits == AM_SEEKING_RelativePositioning)
 
1260
        {
 
1261
            m_rtStart += *pCurrent;
 
1262
        }
 
1263
 
 
1264
        // set stop position
 
1265
        if(StopPosBits == AM_SEEKING_AbsolutePositioning)
 
1266
        {
 
1267
            m_rtStop = *pStop;
 
1268
        }
 
1269
        else if(StopPosBits == AM_SEEKING_IncrementalPositioning)
 
1270
        {
 
1271
            m_rtStop = m_rtStart + *pStop;
 
1272
        }
 
1273
        else if(StopPosBits == AM_SEEKING_RelativePositioning)
 
1274
        {
 
1275
            m_rtStop = m_rtStop + *pStop;
 
1276
        }
 
1277
    }
 
1278
 
 
1279
 
 
1280
    HRESULT hr = S_OK;
 
1281
    if(SUCCEEDED(hr) && StopPosBits) {
 
1282
        hr = ChangeStop();
 
1283
    }
 
1284
    if(StartPosBits) {
 
1285
        hr = ChangeStart();
 
1286
    }
 
1287
 
 
1288
    return hr;
 
1289
}
 
1290
 
 
1291
 
 
1292
HRESULT CSourceSeeking::GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop )
 
1293
{
 
1294
    if(pCurrent) {
 
1295
        *pCurrent = m_rtStart;
 
1296
    }
 
1297
    if(pStop) {
 
1298
        *pStop = m_rtStop;
 
1299
    }
 
1300
 
 
1301
    return S_OK;;
 
1302
}
 
1303
 
 
1304
 
 
1305
HRESULT CSourceSeeking::GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest )
 
1306
{
 
1307
    if(pEarliest) {
 
1308
        *pEarliest = 0;
 
1309
    }
 
1310
    if(pLatest) {
 
1311
        CAutoLock lock(m_pLock);
 
1312
        *pLatest = m_rtDuration;
 
1313
    }
 
1314
    return S_OK;
 
1315
}
 
1316
 
 
1317
HRESULT CSourceSeeking::SetRate( double dRate)
 
1318
{
 
1319
    {
 
1320
        CAutoLock lock(m_pLock);
 
1321
        m_dRateSeeking = dRate;
 
1322
    }
 
1323
    return ChangeRate();
 
1324
}
 
1325
 
 
1326
HRESULT CSourceSeeking::GetRate( __out double * pdRate)
 
1327
{
 
1328
    CheckPointer(pdRate, E_POINTER);
 
1329
    CAutoLock lock(m_pLock);
 
1330
    *pdRate = m_dRateSeeking;
 
1331
    return S_OK;
 
1332
}
 
1333
 
 
1334
HRESULT CSourceSeeking::GetPreroll(__out LONGLONG *pPreroll)
 
1335
{
 
1336
    CheckPointer(pPreroll, E_POINTER);
 
1337
    *pPreroll = 0;
 
1338
    return S_OK;
 
1339
}
 
1340
 
 
1341
 
 
1342
 
 
1343
 
 
1344
 
 
1345
// --- CSourcePosition implementation ----------
 
1346
 
 
1347
 
 
1348
CSourcePosition::CSourcePosition(__in_opt LPCTSTR pName,
 
1349
                                 __in_opt LPUNKNOWN pUnk,
 
1350
                                 __inout HRESULT* phr,
 
1351
                                 __in CCritSec * pLock) :
 
1352
    CMediaPosition(pName, pUnk),
 
1353
    m_pLock(pLock),
 
1354
    m_Start(CRefTime((LONGLONG)0))
 
1355
{
 
1356
    m_Stop = _I64_MAX;
 
1357
    m_Rate = 1.0;
 
1358
}
 
1359
 
 
1360
 
 
1361
STDMETHODIMP
 
1362
CSourcePosition::get_Duration(__out REFTIME * plength)
 
1363
{
 
1364
    CheckPointer(plength,E_POINTER);
 
1365
    ValidateReadWritePtr(plength,sizeof(REFTIME));
 
1366
    CAutoLock lock(m_pLock);
 
1367
 
 
1368
    *plength = m_Duration;
 
1369
    return S_OK;
 
1370
}
 
1371
 
 
1372
 
 
1373
STDMETHODIMP
 
1374
CSourcePosition::put_CurrentPosition(REFTIME llTime)
 
1375
{
 
1376
    m_pLock->Lock();
 
1377
    m_Start = llTime;
 
1378
    m_pLock->Unlock();
 
1379
 
 
1380
    return ChangeStart();
 
1381
}
 
1382
 
 
1383
 
 
1384
STDMETHODIMP
 
1385
CSourcePosition::get_StopTime(__out REFTIME * pllTime)
 
1386
{
 
1387
    CheckPointer(pllTime,E_POINTER);
 
1388
    ValidateReadWritePtr(pllTime,sizeof(REFTIME));
 
1389
    CAutoLock lock(m_pLock);
 
1390
 
 
1391
    *pllTime = m_Stop;
 
1392
    return S_OK;
 
1393
}
 
1394
 
 
1395
 
 
1396
STDMETHODIMP
 
1397
CSourcePosition::put_StopTime(REFTIME llTime)
 
1398
{
 
1399
    m_pLock->Lock();
 
1400
    m_Stop = llTime;
 
1401
    m_pLock->Unlock();
 
1402
 
 
1403
    return ChangeStop();
 
1404
}
 
1405
 
 
1406
 
 
1407
STDMETHODIMP
 
1408
CSourcePosition::get_PrerollTime(__out REFTIME * pllTime)
 
1409
{
 
1410
    CheckPointer(pllTime,E_POINTER);
 
1411
    ValidateReadWritePtr(pllTime,sizeof(REFTIME));
 
1412
    return E_NOTIMPL;
 
1413
}
 
1414
 
 
1415
 
 
1416
STDMETHODIMP
 
1417
CSourcePosition::put_PrerollTime(REFTIME llTime)
 
1418
{
 
1419
    return E_NOTIMPL;
 
1420
}
 
1421
 
 
1422
 
 
1423
STDMETHODIMP
 
1424
CSourcePosition::get_Rate(__out double * pdRate)
 
1425
{
 
1426
    CheckPointer(pdRate,E_POINTER);
 
1427
    ValidateReadWritePtr(pdRate,sizeof(double));
 
1428
    CAutoLock lock(m_pLock);
 
1429
 
 
1430
    *pdRate = m_Rate;
 
1431
    return S_OK;
 
1432
}
 
1433
 
 
1434
 
 
1435
STDMETHODIMP
 
1436
CSourcePosition::put_Rate(double dRate)
 
1437
{
 
1438
    m_pLock->Lock();
 
1439
    m_Rate = dRate;
 
1440
    m_pLock->Unlock();
 
1441
 
 
1442
    return ChangeRate();
 
1443
}
 
1444
 
 
1445
 
 
1446
// By default we can seek forwards
 
1447
 
 
1448
STDMETHODIMP
 
1449
CSourcePosition::CanSeekForward(__out LONG *pCanSeekForward)
 
1450
{
 
1451
    CheckPointer(pCanSeekForward,E_POINTER);
 
1452
    *pCanSeekForward = OATRUE;
 
1453
    return S_OK;
 
1454
}
 
1455
 
 
1456
 
 
1457
// By default we can seek backwards
 
1458
 
 
1459
STDMETHODIMP
 
1460
CSourcePosition::CanSeekBackward(__out LONG *pCanSeekBackward)
 
1461
{
 
1462
    CheckPointer(pCanSeekBackward,E_POINTER);
 
1463
    *pCanSeekBackward = OATRUE;
 
1464
    return S_OK;
 
1465
}
 
1466
 
 
1467
 
 
1468
// --- Implementation of CBasicAudio class ----------
 
1469
 
 
1470
 
 
1471
CBasicAudio::CBasicAudio(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) :
 
1472
    CUnknown(pName, punk)
 
1473
{
 
1474
}
 
1475
 
 
1476
// overriden to publicise our interfaces
 
1477
 
 
1478
STDMETHODIMP
 
1479
CBasicAudio::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
 
1480
{
 
1481
    ValidateReadWritePtr(ppv,sizeof(PVOID));
 
1482
    if (riid == IID_IBasicAudio) {
 
1483
        return GetInterface( (IBasicAudio *) this, ppv);
 
1484
    } else {
 
1485
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
 
1486
    }
 
1487
}
 
1488
 
 
1489
 
 
1490
STDMETHODIMP
 
1491
CBasicAudio::GetTypeInfoCount(__out UINT * pctinfo)
 
1492
{
 
1493
    return m_basedisp.GetTypeInfoCount(pctinfo);
 
1494
}
 
1495
 
 
1496
 
 
1497
STDMETHODIMP
 
1498
CBasicAudio::GetTypeInfo(
 
1499
  UINT itinfo,
 
1500
  LCID lcid,
 
1501
  __deref_out ITypeInfo ** pptinfo)
 
1502
{
 
1503
    return m_basedisp.GetTypeInfo(
 
1504
                IID_IBasicAudio,
 
1505
                itinfo,
 
1506
                lcid,
 
1507
                pptinfo);
 
1508
}
 
1509
 
 
1510
 
 
1511
STDMETHODIMP
 
1512
CBasicAudio::GetIDsOfNames(
 
1513
  REFIID riid,
 
1514
  __in_ecount(cNames) LPOLESTR * rgszNames,
 
1515
  UINT cNames,
 
1516
  LCID lcid,
 
1517
  __out_ecount(cNames) DISPID * rgdispid)
 
1518
{
 
1519
    return m_basedisp.GetIDsOfNames(
 
1520
                        IID_IBasicAudio,
 
1521
                        rgszNames,
 
1522
                        cNames,
 
1523
                        lcid,
 
1524
                        rgdispid);
 
1525
}
 
1526
 
 
1527
 
 
1528
STDMETHODIMP
 
1529
CBasicAudio::Invoke(
 
1530
  DISPID dispidMember,
 
1531
  REFIID riid,
 
1532
  LCID lcid,
 
1533
  WORD wFlags,
 
1534
  __in DISPPARAMS * pdispparams,
 
1535
  __out_opt VARIANT * pvarResult,
 
1536
  __out_opt EXCEPINFO * pexcepinfo,
 
1537
  __out_opt UINT * puArgErr)
 
1538
{
 
1539
    // this parameter is a dead leftover from an earlier interface
 
1540
    if (IID_NULL != riid) {
 
1541
        return DISP_E_UNKNOWNINTERFACE;
 
1542
    }
 
1543
 
 
1544
    ITypeInfo * pti;
 
1545
    HRESULT hr = GetTypeInfo(0, lcid, &pti);
 
1546
 
 
1547
    if (FAILED(hr)) {
 
1548
        return hr;
 
1549
    }
 
1550
 
 
1551
    hr = pti->Invoke(
 
1552
            (IBasicAudio *)this,
 
1553
            dispidMember,
 
1554
            wFlags,
 
1555
            pdispparams,
 
1556
            pvarResult,
 
1557
            pexcepinfo,
 
1558
            puArgErr);
 
1559
 
 
1560
    pti->Release();
 
1561
    return hr;
 
1562
}
 
1563
 
 
1564
 
 
1565
// --- IVideoWindow implementation ----------
 
1566
 
 
1567
CBaseVideoWindow::CBaseVideoWindow(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) :
 
1568
    CUnknown(pName, punk)
 
1569
{
 
1570
}
 
1571
 
 
1572
 
 
1573
// overriden to publicise our interfaces
 
1574
 
 
1575
STDMETHODIMP
 
1576
CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
 
1577
{
 
1578
    ValidateReadWritePtr(ppv,sizeof(PVOID));
 
1579
    if (riid == IID_IVideoWindow) {
 
1580
        return GetInterface( (IVideoWindow *) this, ppv);
 
1581
    } else {
 
1582
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
 
1583
    }
 
1584
}
 
1585
 
 
1586
 
 
1587
STDMETHODIMP
 
1588
CBaseVideoWindow::GetTypeInfoCount(__out UINT * pctinfo)
 
1589
{
 
1590
    return m_basedisp.GetTypeInfoCount(pctinfo);
 
1591
}
 
1592
 
 
1593
 
 
1594
STDMETHODIMP
 
1595
CBaseVideoWindow::GetTypeInfo(
 
1596
  UINT itinfo,
 
1597
  LCID lcid,
 
1598
  __deref_out ITypeInfo ** pptinfo)
 
1599
{
 
1600
    return m_basedisp.GetTypeInfo(
 
1601
                IID_IVideoWindow,
 
1602
                itinfo,
 
1603
                lcid,
 
1604
                pptinfo);
 
1605
}
 
1606
 
 
1607
 
 
1608
STDMETHODIMP
 
1609
CBaseVideoWindow::GetIDsOfNames(
 
1610
  REFIID riid,
 
1611
  __in_ecount(cNames) LPOLESTR * rgszNames,
 
1612
  UINT cNames,
 
1613
  LCID lcid,
 
1614
  __out_ecount(cNames) DISPID * rgdispid)
 
1615
{
 
1616
    return m_basedisp.GetIDsOfNames(
 
1617
                        IID_IVideoWindow,
 
1618
                        rgszNames,
 
1619
                        cNames,
 
1620
                        lcid,
 
1621
                        rgdispid);
 
1622
}
 
1623
 
 
1624
 
 
1625
STDMETHODIMP
 
1626
CBaseVideoWindow::Invoke(
 
1627
  DISPID dispidMember,
 
1628
  REFIID riid,
 
1629
  LCID lcid,
 
1630
  WORD wFlags,
 
1631
  __in DISPPARAMS * pdispparams,
 
1632
  __out_opt VARIANT * pvarResult,
 
1633
  __out_opt EXCEPINFO * pexcepinfo,
 
1634
  __out_opt UINT * puArgErr)
 
1635
{
 
1636
    // this parameter is a dead leftover from an earlier interface
 
1637
    if (IID_NULL != riid) {
 
1638
        return DISP_E_UNKNOWNINTERFACE;
 
1639
    }
 
1640
 
 
1641
    ITypeInfo * pti;
 
1642
    HRESULT hr = GetTypeInfo(0, lcid, &pti);
 
1643
 
 
1644
    if (FAILED(hr)) {
 
1645
        return hr;
 
1646
    }
 
1647
 
 
1648
    hr = pti->Invoke(
 
1649
            (IVideoWindow *)this,
 
1650
            dispidMember,
 
1651
            wFlags,
 
1652
            pdispparams,
 
1653
            pvarResult,
 
1654
            pexcepinfo,
 
1655
            puArgErr);
 
1656
 
 
1657
    pti->Release();
 
1658
    return hr;
 
1659
}
 
1660
 
 
1661
 
 
1662
// --- IBasicVideo implementation ----------
 
1663
 
 
1664
 
 
1665
CBaseBasicVideo::CBaseBasicVideo(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) :
 
1666
    CUnknown(pName, punk)
 
1667
{
 
1668
}
 
1669
 
 
1670
 
 
1671
// overriden to publicise our interfaces
 
1672
 
 
1673
STDMETHODIMP
 
1674
CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
 
1675
{
 
1676
    ValidateReadWritePtr(ppv,sizeof(PVOID));
 
1677
    if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) {
 
1678
        return GetInterface( static_cast<IBasicVideo2 *>(this), ppv);
 
1679
    } else {
 
1680
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
 
1681
    }
 
1682
}
 
1683
 
 
1684
 
 
1685
STDMETHODIMP
 
1686
CBaseBasicVideo::GetTypeInfoCount(__out UINT * pctinfo)
 
1687
{
 
1688
    return m_basedisp.GetTypeInfoCount(pctinfo);
 
1689
}
 
1690
 
 
1691
 
 
1692
STDMETHODIMP
 
1693
CBaseBasicVideo::GetTypeInfo(
 
1694
  UINT itinfo,
 
1695
  LCID lcid,
 
1696
  __deref_out ITypeInfo ** pptinfo)
 
1697
{
 
1698
    return m_basedisp.GetTypeInfo(
 
1699
                IID_IBasicVideo,
 
1700
                itinfo,
 
1701
                lcid,
 
1702
                pptinfo);
 
1703
}
 
1704
 
 
1705
 
 
1706
STDMETHODIMP
 
1707
CBaseBasicVideo::GetIDsOfNames(
 
1708
  REFIID riid,
 
1709
  __in_ecount(cNames) LPOLESTR * rgszNames,
 
1710
  UINT cNames,
 
1711
  LCID lcid,
 
1712
  __out_ecount(cNames) DISPID * rgdispid)
 
1713
{
 
1714
    return m_basedisp.GetIDsOfNames(
 
1715
                        IID_IBasicVideo,
 
1716
                        rgszNames,
 
1717
                        cNames,
 
1718
                        lcid,
 
1719
                        rgdispid);
 
1720
}
 
1721
 
 
1722
 
 
1723
STDMETHODIMP
 
1724
CBaseBasicVideo::Invoke(
 
1725
  DISPID dispidMember,
 
1726
  REFIID riid,
 
1727
  LCID lcid,
 
1728
  WORD wFlags,
 
1729
  __in DISPPARAMS * pdispparams,
 
1730
  __out_opt VARIANT * pvarResult,
 
1731
  __out_opt EXCEPINFO * pexcepinfo,
 
1732
  __out_opt UINT * puArgErr)
 
1733
{
 
1734
    // this parameter is a dead leftover from an earlier interface
 
1735
    if (IID_NULL != riid) {
 
1736
        return DISP_E_UNKNOWNINTERFACE;
 
1737
    }
 
1738
 
 
1739
    ITypeInfo * pti;
 
1740
    HRESULT hr = GetTypeInfo(0, lcid, &pti);
 
1741
 
 
1742
    if (FAILED(hr)) {
 
1743
        return hr;
 
1744
    }
 
1745
 
 
1746
    hr = pti->Invoke(
 
1747
            (IBasicVideo *)this,
 
1748
            dispidMember,
 
1749
            wFlags,
 
1750
            pdispparams,
 
1751
            pvarResult,
 
1752
            pexcepinfo,
 
1753
            puArgErr);
 
1754
 
 
1755
    pti->Release();
 
1756
    return hr;
 
1757
}
 
1758
 
 
1759
 
 
1760
// --- Implementation of Deferred Commands ----------
 
1761
 
 
1762
 
 
1763
CDispParams::CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr)
 
1764
{
 
1765
   cNamedArgs = 0;
 
1766
   rgdispidNamedArgs = NULL;
 
1767
   cArgs = nArgs;
 
1768
 
 
1769
    if (cArgs) {
 
1770
        rgvarg = new VARIANT[cArgs];
 
1771
        if (NULL == rgvarg) {
 
1772
            cArgs = 0;
 
1773
            if (phr) {
 
1774
                *phr = E_OUTOFMEMORY;
 
1775
            }
 
1776
            return;
 
1777
        }
 
1778
 
 
1779
        for (UINT i = 0; i < cArgs; i++) {
 
1780
 
 
1781
            //  Why aren't we using VariantCopy?
 
1782
 
 
1783
            VARIANT * pDest = &rgvarg[i];
 
1784
            VARIANT * pSrc = &pArgs[i];
 
1785
 
 
1786
            pDest->vt = pSrc->vt;
 
1787
            switch(pDest->vt) {
 
1788
 
 
1789
            case VT_I4:
 
1790
                pDest->lVal = pSrc->lVal;
 
1791
                break;
 
1792
 
 
1793
            case VT_UI1:
 
1794
                pDest->bVal = pSrc->bVal;
 
1795
                break;
 
1796
 
 
1797
            case VT_I2:
 
1798
                pDest->iVal = pSrc->iVal;
 
1799
                break;
 
1800
 
 
1801
            case VT_R4:
 
1802
                pDest->fltVal = pSrc->fltVal;
 
1803
                break;
 
1804
 
 
1805
            case VT_R8:
 
1806
                pDest->dblVal = pSrc->dblVal;
 
1807
                break;
 
1808
 
 
1809
            case VT_BOOL:
 
1810
                pDest->boolVal = pSrc->boolVal;
 
1811
                break;
 
1812
 
 
1813
            case VT_ERROR:
 
1814
                pDest->scode = pSrc->scode;
 
1815
                break;
 
1816
 
 
1817
            case VT_CY:
 
1818
                pDest->cyVal = pSrc->cyVal;
 
1819
                break;
 
1820
 
 
1821
            case VT_DATE:
 
1822
                pDest->date = pSrc->date;
 
1823
                break;
 
1824
 
 
1825
            case VT_BSTR:
 
1826
                if ((PVOID)pSrc->bstrVal == NULL) {
 
1827
                    pDest->bstrVal = NULL;
 
1828
                } else {
 
1829
 
 
1830
                    // a BSTR is a WORD followed by a UNICODE string.
 
1831
                    // the pointer points just after the WORD
 
1832
 
 
1833
                    WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR)));
 
1834
                    OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))];
 
1835
                    if (pch) {
 
1836
                        WORD *pui = (WORD*)pch;
 
1837
                        *pui = len;
 
1838
                        pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR));
 
1839
                        CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR));
 
1840
                    } else {
 
1841
                        cArgs = i;
 
1842
                        if (phr) {
 
1843
                            *phr = E_OUTOFMEMORY;
 
1844
                        }
 
1845
                    }
 
1846
                }
 
1847
                break;
 
1848
 
 
1849
            case VT_UNKNOWN:
 
1850
                pDest->punkVal = pSrc->punkVal;
 
1851
                pDest->punkVal->AddRef();
 
1852
                break;
 
1853
 
 
1854
            case VT_DISPATCH:
 
1855
                pDest->pdispVal = pSrc->pdispVal;
 
1856
                pDest->pdispVal->AddRef();
 
1857
                break;
 
1858
 
 
1859
            default:
 
1860
                // a type we haven't got round to adding yet!
 
1861
                ASSERT(0);
 
1862
                break;
 
1863
            }
 
1864
        }
 
1865
 
 
1866
    } else {
 
1867
        rgvarg = NULL;
 
1868
    }
 
1869
 
 
1870
}
 
1871
 
 
1872
 
 
1873
CDispParams::~CDispParams()
 
1874
{
 
1875
    for (UINT i = 0; i < cArgs; i++) {
 
1876
        switch(rgvarg[i].vt) {
 
1877
        case VT_BSTR:
 
1878
            //  Explicitly cast BSTR to PVOID to tell code scanning tools we really mean to test the pointer
 
1879
            if ((PVOID)rgvarg[i].bstrVal != NULL) {
 
1880
                OLECHAR * pch = rgvarg[i].bstrVal - (sizeof(WORD)/sizeof(OLECHAR));
 
1881
                delete pch;
 
1882
            }
 
1883
            break;
 
1884
 
 
1885
        case VT_UNKNOWN:
 
1886
            rgvarg[i].punkVal->Release();
 
1887
            break;
 
1888
 
 
1889
        case VT_DISPATCH:
 
1890
            rgvarg[i].pdispVal->Release();
 
1891
            break;
 
1892
        }
 
1893
    }
 
1894
    delete[] rgvarg;
 
1895
}
 
1896
 
 
1897
 
 
1898
// lifetime is controlled by refcounts (see defer.h)
 
1899
 
 
1900
CDeferredCommand::CDeferredCommand(
 
1901
    __inout CCmdQueue * pQ,
 
1902
    __in_opt LPUNKNOWN  pUnk,
 
1903
    __inout HRESULT *   phr,
 
1904
    __in LPUNKNOWN      pUnkExecutor,
 
1905
    REFTIME     time,
 
1906
    __in GUID*  iid,
 
1907
    long        dispidMethod,
 
1908
    short       wFlags,
 
1909
    long        nArgs,
 
1910
    __in_ecount(nArgs) VARIANT* pDispParams,
 
1911
    __out VARIANT*      pvarResult,
 
1912
    __out short*        puArgErr,
 
1913
    BOOL        bStream
 
1914
    ) :
 
1915
        CUnknown(NAME("DeferredCommand"), pUnk),
 
1916
        m_pQueue(pQ),
 
1917
        m_pUnk(pUnkExecutor),
 
1918
        m_iid(iid),
 
1919
        m_dispidMethod(dispidMethod),
 
1920
        m_wFlags(wFlags),
 
1921
        m_DispParams(nArgs, pDispParams, phr),
 
1922
        m_pvarResult(pvarResult),
 
1923
        m_bStream(bStream),
 
1924
        m_hrResult(E_ABORT)
 
1925
 
 
1926
{
 
1927
    // convert REFTIME to REFERENCE_TIME
 
1928
    COARefTime convertor(time);
 
1929
    m_time = convertor;
 
1930
 
 
1931
    // no check of time validity - it's ok to queue a command that's
 
1932
    // already late
 
1933
 
 
1934
    // check iid is supportable on pUnk by QueryInterface for it
 
1935
    IUnknown * pInterface;
 
1936
    HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface);
 
1937
    if (FAILED(hr)) {
 
1938
        *phr = hr;
 
1939
        return;
 
1940
    }
 
1941
    pInterface->Release();
 
1942
 
 
1943
 
 
1944
    // !!! check dispidMethod and param/return types using typelib
 
1945
    ITypeInfo *pti;
 
1946
    hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti);
 
1947
    if (FAILED(hr)) {
 
1948
        *phr = hr;
 
1949
        return;
 
1950
    }
 
1951
    // !!! some sort of ITypeInfo validity check here
 
1952
    pti->Release();
 
1953
 
 
1954
 
 
1955
    // Fix up the dispid for put and get
 
1956
    if (wFlags == DISPATCH_PROPERTYPUT) {
 
1957
        m_DispParams.cNamedArgs = 1;
 
1958
        m_DispId = DISPID_PROPERTYPUT;
 
1959
        m_DispParams.rgdispidNamedArgs = &m_DispId;
 
1960
    }
 
1961
 
 
1962
    // all checks ok - add to queue
 
1963
    hr = pQ->Insert(this);
 
1964
    if (FAILED(hr)) {
 
1965
        *phr = hr;
 
1966
    }
 
1967
}
 
1968
 
 
1969
 
 
1970
// refcounts are held by caller of InvokeAt... and by list. So if
 
1971
// we get here, we can't be on the list
 
1972
 
 
1973
#if 0
 
1974
CDeferredCommand::~CDeferredCommand()
 
1975
{
 
1976
    // this assert is invalid since if the queue is deleted while we are
 
1977
    // still on the queue, we will have been removed by the queue and this
 
1978
    // m_pQueue will not have been modified.
 
1979
    // ASSERT(m_pQueue == NULL);
 
1980
 
 
1981
    // we don't hold a ref count on pUnk, which is the object that should
 
1982
    // execute the command.
 
1983
    // This is because there would otherwise be a circular refcount problem
 
1984
    // since pUnk probably owns the CmdQueue object that has a refcount
 
1985
    // on us.
 
1986
    // The lifetime of pUnk is guaranteed by it being part of, or lifetime
 
1987
    // controlled by, our parent object. As long as we are on the list, pUnk
 
1988
    // must be valid. Once we are off the list, we do not use pUnk.
 
1989
 
 
1990
}
 
1991
#endif
 
1992
 
 
1993
 
 
1994
// overriden to publicise our interfaces
 
1995
 
 
1996
STDMETHODIMP
 
1997
CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, __out void **ppv)
 
1998
{
 
1999
    ValidateReadWritePtr(ppv,sizeof(PVOID));
 
2000
    if (riid == IID_IDeferredCommand) {
 
2001
        return GetInterface( (IDeferredCommand *) this, ppv);
 
2002
    } else {
 
2003
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
 
2004
    }
 
2005
}
 
2006
 
 
2007
 
 
2008
// remove from q. this will reduce the refcount by one (since the q
 
2009
// holds a count) but can't make us go away since he must have a
 
2010
// refcount in order to call this method.
 
2011
 
 
2012
STDMETHODIMP
 
2013
CDeferredCommand::Cancel()
 
2014
{
 
2015
    if (m_pQueue == NULL) {
 
2016
        return VFW_E_ALREADY_CANCELLED;
 
2017
    }
 
2018
 
 
2019
    HRESULT hr = m_pQueue->Remove(this);
 
2020
    if (FAILED(hr)) {
 
2021
        return hr;
 
2022
    }
 
2023
 
 
2024
    m_pQueue = NULL;
 
2025
    return S_OK;
 
2026
}
 
2027
 
 
2028
 
 
2029
STDMETHODIMP
 
2030
CDeferredCommand::Confidence(__out LONG* pConfidence)
 
2031
{
 
2032
    return E_NOTIMPL;
 
2033
}
 
2034
 
 
2035
 
 
2036
STDMETHODIMP
 
2037
CDeferredCommand::GetHResult(__out HRESULT * phrResult)
 
2038
{
 
2039
    CheckPointer(phrResult,E_POINTER);
 
2040
    ValidateReadWritePtr(phrResult,sizeof(HRESULT));
 
2041
 
 
2042
    if (m_pQueue != NULL) {
 
2043
        return E_ABORT;
 
2044
    }
 
2045
    *phrResult = m_hrResult;
 
2046
    return S_OK;
 
2047
}
 
2048
 
 
2049
 
 
2050
// set the time to be a new time (checking that it is valid) and
 
2051
// then requeue
 
2052
 
 
2053
STDMETHODIMP
 
2054
CDeferredCommand::Postpone(REFTIME newtime)
 
2055
{
 
2056
 
 
2057
    // check that this time is not past
 
2058
    // convert REFTIME to REFERENCE_TIME
 
2059
    COARefTime convertor(newtime);
 
2060
 
 
2061
    // check that the time has not passed
 
2062
    if (m_pQueue->CheckTime(convertor, IsStreamTime())) {
 
2063
        return VFW_E_TIME_ALREADY_PASSED;
 
2064
    }
 
2065
 
 
2066
    // extract from list
 
2067
    HRESULT hr = m_pQueue->Remove(this);
 
2068
    if (FAILED(hr)) {
 
2069
        return hr;
 
2070
    }
 
2071
 
 
2072
    // change time
 
2073
    m_time = convertor;
 
2074
 
 
2075
    // requeue
 
2076
    hr = m_pQueue->Insert(this);
 
2077
 
 
2078
    return hr;
 
2079
}
 
2080
 
 
2081
 
 
2082
HRESULT
 
2083
CDeferredCommand::Invoke()
 
2084
{
 
2085
    // check that we are still outstanding
 
2086
    if (m_pQueue == NULL) {
 
2087
        return VFW_E_ALREADY_CANCELLED;
 
2088
    }
 
2089
 
 
2090
    // get the type info
 
2091
    ITypeInfo* pti;
 
2092
    HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti);
 
2093
    if (FAILED(hr)) {
 
2094
        return hr;
 
2095
    }
 
2096
 
 
2097
    // qi for the expected interface and then invoke it. Note that we have to
 
2098
    // treat the returned interface as IUnknown since we don't know its type.
 
2099
    IUnknown* pInterface;
 
2100
 
 
2101
    hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface);
 
2102
    if (FAILED(hr)) {
 
2103
        pti->Release();
 
2104
        return hr;
 
2105
    }
 
2106
 
 
2107
    EXCEPINFO expinfo;
 
2108
    UINT uArgErr;
 
2109
    m_hrResult = pti->Invoke(
 
2110
        pInterface,
 
2111
        GetMethod(),
 
2112
        GetFlags(),
 
2113
        GetParams(),
 
2114
        GetResult(),
 
2115
        &expinfo,
 
2116
        &uArgErr);
 
2117
 
 
2118
    // release the interface we QI'd for
 
2119
    pInterface->Release();
 
2120
    pti->Release();
 
2121
 
 
2122
 
 
2123
    // remove from list whether or not successful
 
2124
    // or we loop indefinitely
 
2125
    hr = m_pQueue->Remove(this);
 
2126
    m_pQueue = NULL;
 
2127
    return hr;
 
2128
}
 
2129
 
 
2130
 
 
2131
 
 
2132
// --- CCmdQueue methods ----------
 
2133
 
 
2134
 
 
2135
CCmdQueue::CCmdQueue(__inout_opt HRESULT *phr) :
 
2136
    m_listPresentation(NAME("Presentation time command list")),
 
2137
    m_listStream(NAME("Stream time command list")),
 
2138
    m_evDue(TRUE, phr),    // manual reset
 
2139
    m_dwAdvise(0),
 
2140
    m_pClock(NULL),
 
2141
    m_bRunning(FALSE)
 
2142
{
 
2143
}
 
2144
 
 
2145
 
 
2146
CCmdQueue::~CCmdQueue()
 
2147
{
 
2148
    // empty all our lists
 
2149
 
 
2150
    // we hold a refcount on each, so traverse and Release each
 
2151
    // entry then RemoveAll to empty the list
 
2152
    POSITION pos = m_listPresentation.GetHeadPosition();
 
2153
 
 
2154
    while(pos) {
 
2155
        CDeferredCommand* pCmd = m_listPresentation.GetNext(pos);
 
2156
        pCmd->Release();
 
2157
    }
 
2158
    m_listPresentation.RemoveAll();
 
2159
 
 
2160
    pos = m_listStream.GetHeadPosition();
 
2161
 
 
2162
    while(pos) {
 
2163
        CDeferredCommand* pCmd = m_listStream.GetNext(pos);
 
2164
        pCmd->Release();
 
2165
    }
 
2166
    m_listStream.RemoveAll();
 
2167
 
 
2168
    if (m_pClock) {
 
2169
        if (m_dwAdvise) {
 
2170
            m_pClock->Unadvise(m_dwAdvise);
 
2171
            m_dwAdvise = 0;
 
2172
        }
 
2173
        m_pClock->Release();
 
2174
    }
 
2175
}
 
2176
 
 
2177
 
 
2178
// returns a new CDeferredCommand object that will be initialised with
 
2179
// the parameters and will be added to the queue during construction.
 
2180
// returns S_OK if successfully created otherwise an error and
 
2181
// no object has been queued.
 
2182
 
 
2183
HRESULT
 
2184
CCmdQueue::New(
 
2185
    __out CDeferredCommand **ppCmd,
 
2186
    __in     LPUNKNOWN  pUnk,           // this object will execute command
 
2187
    REFTIME     time,
 
2188
    __in GUID*  iid,
 
2189
    long        dispidMethod,
 
2190
    short       wFlags,
 
2191
    long        cArgs,
 
2192
    __in_ecount(cArgs) VARIANT* pDispParams,
 
2193
    __out VARIANT*      pvarResult,
 
2194
    __out short*        puArgErr,
 
2195
    BOOL        bStream
 
2196
)
 
2197
{
 
2198
    CAutoLock lock(&m_Lock);
 
2199
 
 
2200
    HRESULT hr = S_OK;
 
2201
    *ppCmd = NULL;
 
2202
 
 
2203
    CDeferredCommand* pCmd;
 
2204
    pCmd = new CDeferredCommand(
 
2205
                    this,
 
2206
                    NULL,           // not aggregated
 
2207
                    &hr,
 
2208
                    pUnk,           // this guy will execute
 
2209
                    time,
 
2210
                    iid,
 
2211
                    dispidMethod,
 
2212
                    wFlags,
 
2213
                    cArgs,
 
2214
                    pDispParams,
 
2215
                    pvarResult,
 
2216
                    puArgErr,
 
2217
                    bStream);
 
2218
 
 
2219
    if (pCmd == NULL) {
 
2220
        hr = E_OUTOFMEMORY;
 
2221
    } else {
 
2222
        *ppCmd = pCmd;
 
2223
    }
 
2224
    return hr;
 
2225
}
 
2226
 
 
2227
 
 
2228
HRESULT
 
2229
CCmdQueue::Insert(__in CDeferredCommand* pCmd)
 
2230
{
 
2231
    CAutoLock lock(&m_Lock);
 
2232
 
 
2233
    // addref the item
 
2234
    pCmd->AddRef();
 
2235
 
 
2236
    CGenericList<CDeferredCommand> * pList;
 
2237
    if (pCmd->IsStreamTime()) {
 
2238
        pList = &m_listStream;
 
2239
    } else {
 
2240
        pList = &m_listPresentation;
 
2241
    }
 
2242
    POSITION pos = pList->GetHeadPosition();
 
2243
 
 
2244
    // seek past all items that are before us
 
2245
    while (pos &&
 
2246
        (pList->GetValid(pos)->GetTime() <= pCmd->GetTime())) {
 
2247
 
 
2248
        pList->GetNext(pos);
 
2249
    }
 
2250
 
 
2251
    // now at end of list or in front of items that come later
 
2252
    if (!pos) {
 
2253
        pList->AddTail(pCmd);
 
2254
    } else {
 
2255
        pList->AddBefore(pos, pCmd);
 
2256
    }
 
2257
 
 
2258
    SetTimeAdvise();
 
2259
    return S_OK;
 
2260
}
 
2261
 
 
2262
 
 
2263
HRESULT
 
2264
CCmdQueue::Remove(__in CDeferredCommand* pCmd)
 
2265
{
 
2266
    CAutoLock lock(&m_Lock);
 
2267
    HRESULT hr = S_OK;
 
2268
 
 
2269
    CGenericList<CDeferredCommand> * pList;
 
2270
    if (pCmd->IsStreamTime()) {
 
2271
        pList = &m_listStream;
 
2272
    } else {
 
2273
        pList = &m_listPresentation;
 
2274
    }
 
2275
    POSITION pos = pList->GetHeadPosition();
 
2276
 
 
2277
    // traverse the list
 
2278
    while (pos && (pList->GetValid(pos) != pCmd)) {
 
2279
        pList->GetNext(pos);
 
2280
    }
 
2281
 
 
2282
    // did we drop off the end?
 
2283
    if (!pos) {
 
2284
        hr = VFW_E_NOT_FOUND;
 
2285
    } else {
 
2286
 
 
2287
        // found it - now take off list
 
2288
        pList->Remove(pos);
 
2289
 
 
2290
        // Insert did an AddRef, so release it
 
2291
        pCmd->Release();
 
2292
 
 
2293
        // check that timer request is still for earliest time
 
2294
        SetTimeAdvise();
 
2295
    }
 
2296
    return hr;
 
2297
}
 
2298
 
 
2299
 
 
2300
// set the clock used for timing
 
2301
 
 
2302
HRESULT
 
2303
CCmdQueue::SetSyncSource(__in_opt IReferenceClock* pClock)
 
2304
{
 
2305
    CAutoLock lock(&m_Lock);
 
2306
 
 
2307
    // addref the new clock first in case they are the same
 
2308
    if (pClock) {
 
2309
        pClock->AddRef();
 
2310
    }
 
2311
 
 
2312
    // kill any advise on the old clock
 
2313
    if (m_pClock) {
 
2314
        if (m_dwAdvise) {
 
2315
            m_pClock->Unadvise(m_dwAdvise);
 
2316
            m_dwAdvise = 0;
 
2317
        }
 
2318
        m_pClock->Release();
 
2319
    }
 
2320
    m_pClock = pClock;
 
2321
 
 
2322
    // set up a new advise
 
2323
    SetTimeAdvise();
 
2324
    return S_OK;
 
2325
}
 
2326
 
 
2327
 
 
2328
// set up a timer event with the reference clock
 
2329
 
 
2330
void
 
2331
CCmdQueue::SetTimeAdvise(void)
 
2332
{
 
2333
    // make sure we have a clock to use
 
2334
    if (!m_pClock) {
 
2335
        return;
 
2336
    }
 
2337
 
 
2338
    // reset the event whenever we are requesting a new signal
 
2339
    m_evDue.Reset();
 
2340
 
 
2341
    // time 0 is earliest
 
2342
    CRefTime current;
 
2343
 
 
2344
    // find the earliest presentation time
 
2345
    POSITION pos = m_listPresentation.GetHeadPosition();
 
2346
    if (pos != NULL) {
 
2347
        current = m_listPresentation.GetValid(pos)->GetTime();
 
2348
    }
 
2349
 
 
2350
    // if we're running, check the stream times too
 
2351
    if (m_bRunning) {
 
2352
 
 
2353
        CRefTime t;
 
2354
        pos = m_listStream.GetHeadPosition();
 
2355
        if (NULL != pos) {
 
2356
            t = m_listStream.GetValid(pos)->GetTime();
 
2357
 
 
2358
            // add on stream time offset to get presentation time
 
2359
            t += m_StreamTimeOffset;
 
2360
 
 
2361
            // is this earlier?
 
2362
            if ((current == TimeZero) || (t < current)) {
 
2363
                current = t;
 
2364
            }
 
2365
        }
 
2366
    }
 
2367
 
 
2368
    // need to change?
 
2369
    if ((current > TimeZero) && (current != m_tCurrentAdvise)) {
 
2370
        if (m_dwAdvise) {
 
2371
            m_pClock->Unadvise(m_dwAdvise);
 
2372
            // reset the event whenever we are requesting a new signal
 
2373
            m_evDue.Reset();
 
2374
        }
 
2375
 
 
2376
        // ask for time advice - the first two params are either
 
2377
        // stream time offset and stream time or
 
2378
        // presentation time and 0. we always use the latter
 
2379
        HRESULT hr = m_pClock->AdviseTime(
 
2380
                    (REFERENCE_TIME)current,
 
2381
                    TimeZero,
 
2382
                    (HEVENT) HANDLE(m_evDue),
 
2383
                    &m_dwAdvise);
 
2384
 
 
2385
        ASSERT(SUCCEEDED(hr));
 
2386
        m_tCurrentAdvise = current;
 
2387
    }
 
2388
}
 
2389
 
 
2390
 
 
2391
// switch to run mode. Streamtime to Presentation time mapping known.
 
2392
 
 
2393
HRESULT
 
2394
CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset)
 
2395
{
 
2396
    CAutoLock lock(&m_Lock);
 
2397
 
 
2398
    m_StreamTimeOffset = tStreamTimeOffset;
 
2399
    m_bRunning = TRUE;
 
2400
 
 
2401
    // ensure advise is accurate
 
2402
    SetTimeAdvise();
 
2403
    return S_OK;
 
2404
}
 
2405
 
 
2406
 
 
2407
// switch to Stopped or Paused mode. Time mapping not known.
 
2408
 
 
2409
HRESULT
 
2410
CCmdQueue::EndRun()
 
2411
{
 
2412
    CAutoLock lock(&m_Lock);
 
2413
 
 
2414
    m_bRunning = FALSE;
 
2415
 
 
2416
    // check timer setting - stream times
 
2417
    SetTimeAdvise();
 
2418
    return S_OK;
 
2419
}
 
2420
 
 
2421
 
 
2422
// return a pointer to the next due command. Blocks for msTimeout
 
2423
// milliseconds until there is a due command.
 
2424
// Stream-time commands will only become due between Run and Endrun calls.
 
2425
// The command remains queued until invoked or cancelled.
 
2426
// Returns E_ABORT if timeout occurs, otherwise S_OK (or other error).
 
2427
//
 
2428
// returns an AddRef'd object
 
2429
 
 
2430
HRESULT
 
2431
CCmdQueue::GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout)
 
2432
{
 
2433
    // loop until we timeout or find a due command
 
2434
    for (;;) {
 
2435
 
 
2436
        {
 
2437
            CAutoLock lock(&m_Lock);
 
2438
 
 
2439
 
 
2440
            // find the earliest command
 
2441
            CDeferredCommand * pCmd = NULL;
 
2442
 
 
2443
            // check the presentation time and the
 
2444
            // stream time list to find the earliest
 
2445
 
 
2446
            POSITION pos = m_listPresentation.GetHeadPosition();
 
2447
 
 
2448
            if (NULL != pos) {
 
2449
                pCmd = m_listPresentation.GetValid(pos);
 
2450
            }
 
2451
 
 
2452
            if (m_bRunning) {
 
2453
                pos = m_listStream.GetHeadPosition();
 
2454
                if (NULL != pos) {
 
2455
                    CDeferredCommand* pStrm = m_listStream.GetValid(pos);
 
2456
 
 
2457
                    CRefTime t = pStrm->GetTime() + m_StreamTimeOffset;
 
2458
                    if (!pCmd || (t < pCmd->GetTime())) {
 
2459
                        pCmd = pStrm;
 
2460
                    }
 
2461
                }
 
2462
            }
 
2463
 
 
2464
            //  if we have found one, is it due?
 
2465
            if (pCmd) {
 
2466
                if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) {
 
2467
 
 
2468
                    // yes it's due - addref it
 
2469
                    pCmd->AddRef();
 
2470
                    *ppCmd = pCmd;
 
2471
                    return S_OK;
 
2472
                }
 
2473
            }
 
2474
        }
 
2475
 
 
2476
        // block until the advise is signalled
 
2477
        if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) {
 
2478
            return E_ABORT;
 
2479
        }
 
2480
    }
 
2481
}
 
2482
 
 
2483
 
 
2484
// return a pointer to a command that will be due for a given time.
 
2485
// Pass in a stream time here. The stream time offset will be passed
 
2486
// in via the Run method.
 
2487
// Commands remain queued until invoked or cancelled.
 
2488
// This method will not block. It will report E_ABORT if there are no
 
2489
// commands due yet.
 
2490
//
 
2491
// returns an AddRef'd object
 
2492
 
 
2493
HRESULT
 
2494
CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, __out CDeferredCommand**ppCmd)
 
2495
{
 
2496
    CAutoLock lock(&m_Lock);
 
2497
 
 
2498
    CRefTime tStream(rtStream);
 
2499
 
 
2500
    // find the earliest stream and presentation time commands
 
2501
    CDeferredCommand* pStream = NULL;
 
2502
    POSITION pos = m_listStream.GetHeadPosition();
 
2503
    if (NULL != pos) {
 
2504
        pStream = m_listStream.GetValid(pos);
 
2505
    }
 
2506
    CDeferredCommand* pPresent = NULL;
 
2507
    pos = m_listPresentation.GetHeadPosition();
 
2508
    if (NULL != pos) {
 
2509
        pPresent = m_listPresentation.GetValid(pos);
 
2510
    }
 
2511
 
 
2512
    // is there a presentation time that has passed already
 
2513
    if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) {
 
2514
        pPresent->AddRef();
 
2515
        *ppCmd = pPresent;
 
2516
        return S_OK;
 
2517
    }
 
2518
 
 
2519
    // is there a stream time command due before this stream time
 
2520
    if (pStream && (pStream->GetTime() <= tStream)) {
 
2521
        pStream->AddRef();
 
2522
        *ppCmd = pStream;
 
2523
        return S_OK;
 
2524
    }
 
2525
 
 
2526
    // if we are running, we can map presentation times to
 
2527
    // stream time. In this case, is there a presentation time command
 
2528
    // that will be due before this stream time is presented?
 
2529
    if (m_bRunning && pPresent) {
 
2530
 
 
2531
        // this stream time will appear at...
 
2532
        tStream += m_StreamTimeOffset;
 
2533
 
 
2534
        // due before that?
 
2535
        if (pPresent->GetTime() <= tStream) {
 
2536
            *ppCmd = pPresent;
 
2537
            return S_OK;
 
2538
        }
 
2539
    }
 
2540
 
 
2541
    // no commands due yet
 
2542
    return VFW_E_NOT_FOUND;
 
2543
}
 
2544
 
 
2545
#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */