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 ----------
~CBaseDispatch()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
GetTypeInfoCount(__out UINT * pctinfo)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
GetTypeInfo(REFIID riid,UINT itinfo,LCID lcid,__deref_out ITypeInfo ** pptinfo)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
GetIDsOfNames(REFIID riid,__in_ecount (cNames)LPOLESTR * rgszNames,UINT cNames,LCID lcid,__out_ecount (cNames)DISPID * rgdispid)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
CMediaControl(const TCHAR * name,LPUNKNOWN pUnk)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
NonDelegatingQueryInterface(REFIID riid,__deref_out void ** ppv)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
GetTypeInfoCount(__out UINT * pctinfo)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
GetTypeInfo(UINT itinfo,LCID lcid,__deref_out ITypeInfo ** pptinfo)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
GetIDsOfNames(REFIID riid,__in_ecount (cNames)LPOLESTR * rgszNames,UINT cNames,LCID lcid,__out_ecount (cNames)DISPID * rgdispid)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
Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags,__in DISPPARAMS * pdispparams,__out_opt VARIANT * pvarResult,__out_opt EXCEPINFO * pexcepinfo,__out_opt UINT * puArgErr)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
CMediaEvent(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk)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
NonDelegatingQueryInterface(REFIID riid,__deref_out void ** ppv)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
GetTypeInfoCount(__out UINT * pctinfo)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
GetTypeInfo(UINT itinfo,LCID lcid,__deref_out ITypeInfo ** pptinfo)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
GetIDsOfNames(REFIID riid,__in_ecount (cNames)LPOLESTR * rgszNames,UINT cNames,LCID lcid,__out_ecount (cNames)DISPID * rgdispid)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
Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags,__in DISPPARAMS * pdispparams,__out_opt VARIANT * pvarResult,__out_opt EXCEPINFO * pexcepinfo,__out_opt UINT * puArgErr)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
CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk)375 CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) :
376 CUnknown(name, pUnk)
377 {
378 }
379
CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk,__inout HRESULT * phr)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
NonDelegatingQueryInterface(REFIID riid,__deref_out void ** ppv)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
GetTypeInfoCount(__out UINT * pctinfo)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
GetTypeInfo(UINT itinfo,LCID lcid,__deref_out ITypeInfo ** pptinfo)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
GetIDsOfNames(REFIID riid,__in_ecount (cNames)LPOLESTR * rgszNames,UINT cNames,LCID lcid,__out_ecount (cNames)DISPID * rgdispid)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
Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags,__in DISPPARAMS * pdispparams,__out_opt VARIANT * pvarResult,__out_opt EXCEPINFO * pexcepinfo,__out_opt UINT * puArgErr)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
CPosPassThru(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN pUnk,__inout HRESULT * phr,IPin * pPin)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
NonDelegatingQueryInterface(REFIID riid,__deref_out void ** ppv)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
GetPeer(IMediaPosition ** ppMP)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
GetPeerSeeking(__deref_out IMediaSeeking ** ppMS)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
GetCapabilities(__out DWORD * pCaps)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
CheckCapabilities(__inout DWORD * pCaps)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
IsFormatSupported(const GUID * pFormat)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
QueryPreferredFormat(__out GUID * pFormat)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
SetTimeFormat(const GUID * pFormat)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
GetTimeFormat(__out GUID * pFormat)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
IsUsingTimeFormat(const GUID * pFormat)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
ConvertTimeFormat(__out LONGLONG * pTarget,__in_opt const GUID * pTargetFormat,LONGLONG Source,__in_opt const GUID * pSourceFormat)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
SetPositions(__inout_opt LONGLONG * pCurrent,DWORD CurrentFlags,__inout_opt LONGLONG * pStop,DWORD StopFlags)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
GetPositions(__out_opt LONGLONG * pCurrent,__out_opt LONGLONG * pStop)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
GetSeekingLongLong(HRESULT (__stdcall IMediaSeeking::* pMethod)(__out LONGLONG *),LONGLONG * pll)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
GetCurrentPosition(__out LONGLONG * pCurrent)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
GetStopPosition(__out LONGLONG * pStop)747 CPosPassThru::GetStopPosition(__out LONGLONG *pStop)
748 {
749 return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );;
750 }
751
752 STDMETHODIMP
GetDuration(__out LONGLONG * pDuration)753 CPosPassThru::GetDuration(__out LONGLONG *pDuration)
754 {
755 return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );;
756 }
757
758
759 STDMETHODIMP
GetPreroll(__out LONGLONG * pllPreroll)760 CPosPassThru::GetPreroll(__out LONGLONG *pllPreroll)
761 {
762 return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );;
763 }
764
765
766 STDMETHODIMP
GetAvailable(__out_opt LONGLONG * pEarliest,__out_opt LONGLONG * pLatest)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
GetRate(__out double * pdRate)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
SetRate(double dRate)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
get_Duration(__out REFTIME * plength)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
get_CurrentPosition(__out REFTIME * pllTime)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
put_CurrentPosition(REFTIME llTime)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
get_StopTime(__out REFTIME * pllTime)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
put_StopTime(REFTIME llTime)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
get_PrerollTime(__out REFTIME * pllTime)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
put_PrerollTime(REFTIME llTime)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
get_Rate(__out double * pdRate)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
put_Rate(double dRate)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
CanSeekForward(__out LONG * pCanSeekForward)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
CanSeekBackward(__out LONG * pCanSeekBackward)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
CRendererPosPassThru(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN pUnk,__inout HRESULT * phr,IPin * pPin)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
RegisterMediaTime(IMediaSample * pMediaSample)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
RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime)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
GetMediaTime(__out LONGLONG * pStartTime,__out_opt LONGLONG * pEndTime)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
ResetMediaTime()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
EOS()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
CSourceSeeking(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN pUnk,__inout HRESULT * phr,__in CCritSec * pLock)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
NonDelegatingQueryInterface(REFIID riid,__deref_out void ** ppv)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
IsFormatSupported(const GUID * pFormat)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
QueryPreferredFormat(__out GUID * pFormat)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
SetTimeFormat(const GUID * pFormat)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
IsUsingTimeFormat(const GUID * pFormat)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
GetTimeFormat(__out GUID * pFormat)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
GetDuration(__out LONGLONG * pDuration)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
GetStopPosition(__out LONGLONG * pStop)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
GetCurrentPosition(__out LONGLONG * pCurrent)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
GetCapabilities(__out DWORD * pCapabilities)1186 HRESULT CSourceSeeking::GetCapabilities( __out DWORD * pCapabilities )
1187 {
1188 CheckPointer(pCapabilities, E_POINTER);
1189 *pCapabilities = m_dwSeekingCaps;
1190 return S_OK;
1191 }
1192
CheckCapabilities(__inout DWORD * pCapabilities)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
ConvertTimeFormat(__out LONGLONG * pTarget,__in_opt const GUID * pTargetFormat,LONGLONG Source,__in_opt const GUID * pSourceFormat)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
SetPositions(__inout_opt LONGLONG * pCurrent,DWORD CurrentFlags,__inout_opt LONGLONG * pStop,DWORD StopFlags)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
GetPositions(__out_opt LONGLONG * pCurrent,__out_opt LONGLONG * pStop)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
GetAvailable(__out_opt LONGLONG * pEarliest,__out_opt LONGLONG * pLatest)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
SetRate(double dRate)1317 HRESULT CSourceSeeking::SetRate( double dRate)
1318 {
1319 {
1320 CAutoLock lock(m_pLock);
1321 m_dRateSeeking = dRate;
1322 }
1323 return ChangeRate();
1324 }
1325
GetRate(__out double * pdRate)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
GetPreroll(__out LONGLONG * pPreroll)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
CSourcePosition(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN pUnk,__inout HRESULT * phr,__in CCritSec * pLock)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
get_Duration(__out REFTIME * plength)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
put_CurrentPosition(REFTIME llTime)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
get_StopTime(__out REFTIME * pllTime)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
put_StopTime(REFTIME llTime)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
get_PrerollTime(__out REFTIME * pllTime)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
put_PrerollTime(REFTIME llTime)1417 CSourcePosition::put_PrerollTime(REFTIME llTime)
1418 {
1419 return E_NOTIMPL;
1420 }
1421
1422
1423 STDMETHODIMP
get_Rate(__out double * pdRate)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
put_Rate(double dRate)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
CanSeekForward(__out LONG * pCanSeekForward)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
CanSeekBackward(__out LONG * pCanSeekBackward)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
CBasicAudio(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk)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
NonDelegatingQueryInterface(REFIID riid,__deref_out void ** ppv)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
GetTypeInfoCount(__out UINT * pctinfo)1491 CBasicAudio::GetTypeInfoCount(__out UINT * pctinfo)
1492 {
1493 return m_basedisp.GetTypeInfoCount(pctinfo);
1494 }
1495
1496
1497 STDMETHODIMP
GetTypeInfo(UINT itinfo,LCID lcid,__deref_out ITypeInfo ** pptinfo)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
GetIDsOfNames(REFIID riid,__in_ecount (cNames)LPOLESTR * rgszNames,UINT cNames,LCID lcid,__out_ecount (cNames)DISPID * rgdispid)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
Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags,__in DISPPARAMS * pdispparams,__out_opt VARIANT * pvarResult,__out_opt EXCEPINFO * pexcepinfo,__out_opt UINT * puArgErr)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
CBaseVideoWindow(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk)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
NonDelegatingQueryInterface(REFIID riid,__deref_out void ** ppv)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
GetTypeInfoCount(__out UINT * pctinfo)1588 CBaseVideoWindow::GetTypeInfoCount(__out UINT * pctinfo)
1589 {
1590 return m_basedisp.GetTypeInfoCount(pctinfo);
1591 }
1592
1593
1594 STDMETHODIMP
GetTypeInfo(UINT itinfo,LCID lcid,__deref_out ITypeInfo ** pptinfo)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
GetIDsOfNames(REFIID riid,__in_ecount (cNames)LPOLESTR * rgszNames,UINT cNames,LCID lcid,__out_ecount (cNames)DISPID * rgdispid)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
Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags,__in DISPPARAMS * pdispparams,__out_opt VARIANT * pvarResult,__out_opt EXCEPINFO * pexcepinfo,__out_opt UINT * puArgErr)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
CBaseBasicVideo(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk)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
NonDelegatingQueryInterface(REFIID riid,__deref_out void ** ppv)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
GetTypeInfoCount(__out UINT * pctinfo)1686 CBaseBasicVideo::GetTypeInfoCount(__out UINT * pctinfo)
1687 {
1688 return m_basedisp.GetTypeInfoCount(pctinfo);
1689 }
1690
1691
1692 STDMETHODIMP
GetTypeInfo(UINT itinfo,LCID lcid,__deref_out ITypeInfo ** pptinfo)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
GetIDsOfNames(REFIID riid,__in_ecount (cNames)LPOLESTR * rgszNames,UINT cNames,LCID lcid,__out_ecount (cNames)DISPID * rgdispid)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
Invoke(DISPID dispidMember,REFIID riid,LCID lcid,WORD wFlags,__in DISPPARAMS * pdispparams,__out_opt VARIANT * pvarResult,__out_opt EXCEPINFO * pexcepinfo,__out_opt UINT * puArgErr)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
CDispParams(UINT nArgs,__in_ecount (nArgs)VARIANT * pArgs,__inout_opt HRESULT * phr)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
~CDispParams()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
CDeferredCommand(__inout CCmdQueue * pQ,__in_opt LPUNKNOWN pUnk,__inout HRESULT * phr,__in LPUNKNOWN pUnkExecutor,REFTIME time,__in GUID * iid,long dispidMethod,short wFlags,long nArgs,__in_ecount (nArgs)VARIANT * pDispParams,__out VARIANT * pvarResult,__out short * puArgErr,BOOL bStream)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
NonDelegatingQueryInterface(REFIID riid,__out void ** ppv)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
Cancel()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
Confidence(__out LONG * pConfidence)2030 CDeferredCommand::Confidence(__out LONG* pConfidence)
2031 {
2032 return E_NOTIMPL;
2033 }
2034
2035
2036 STDMETHODIMP
GetHResult(__out HRESULT * phrResult)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
Postpone(REFTIME newtime)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
Invoke()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
CCmdQueue(__inout_opt HRESULT * phr)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
~CCmdQueue()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
New(__out CDeferredCommand ** ppCmd,__in LPUNKNOWN pUnk,REFTIME time,__in GUID * iid,long dispidMethod,short wFlags,long cArgs,__in_ecount (cArgs)VARIANT * pDispParams,__out VARIANT * pvarResult,__out short * puArgErr,BOOL bStream)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
Insert(__in CDeferredCommand * pCmd)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
Remove(__in CDeferredCommand * pCmd)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
SetSyncSource(__in_opt IReferenceClock * pClock)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
SetTimeAdvise(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
Run(REFERENCE_TIME tStreamTimeOffset)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
EndRun()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
GetDueCommand(__out CDeferredCommand ** ppCmd,long msTimeout)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
GetCommandDueFor(REFERENCE_TIME rtStream,__out CDeferredCommand ** ppCmd)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 */
2546