blob: 2902df26406098e0d454db166429e7380c6519b0 [file] [log] [blame]
Sauw Ming93ba7fe2012-04-18 02:38:42 +00001//------------------------------------------------------------------------------
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
Nanang Izzuddinc46d1152012-04-24 07:07:39 +000015#include <pjmedia-videodev/config.h>
16
17#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
Sauw Ming93ba7fe2012-04-18 02:38:42 +000018
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 ----------
28CBaseDispatch::~CBaseDispatch()
29{
30 if (m_pti) {
31 m_pti->Release();
32 }
33}
34
35
36// return 1 if we support GetTypeInfo
37
38STDMETHODIMP
39CBaseDispatch::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
48typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)(
49 const OLECHAR FAR *szFile,
50 __deref_out ITypeLib FAR* FAR* pptlib);
51
52typedef 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
60STDMETHODIMP
61CBaseDispatch::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
147STDMETHODIMP
148CBaseDispatch::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
172CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) :
173 CUnknown(name, pUnk)
174{
175}
176
177// expose our interfaces IMediaControl and IUnknown
178
179STDMETHODIMP
180CMediaControl::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
193STDMETHODIMP
194CMediaControl::GetTypeInfoCount(__out UINT * pctinfo)
195{
196 return m_basedisp.GetTypeInfoCount(pctinfo);
197}
198
199
200// attempt to find our type library
201
202STDMETHODIMP
203CMediaControl::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
216STDMETHODIMP
217CMediaControl::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
233STDMETHODIMP
234CMediaControl::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
273CMediaEvent::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
281STDMETHODIMP
282CMediaEvent::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
295STDMETHODIMP
296CMediaEvent::GetTypeInfoCount(__out UINT * pctinfo)
297{
298 return m_basedisp.GetTypeInfoCount(pctinfo);
299}
300
301
302// attempt to find our type library
303
304STDMETHODIMP
305CMediaEvent::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
318STDMETHODIMP
319CMediaEvent::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
335STDMETHODIMP
336CMediaEvent::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
375CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) :
376 CUnknown(name, pUnk)
377{
378}
379
380CMediaPosition::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
391STDMETHODIMP
392CMediaPosition::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
405STDMETHODIMP
406CMediaPosition::GetTypeInfoCount(__out UINT * pctinfo)
407{
408 return m_basedisp.GetTypeInfoCount(pctinfo);
409}
410
411
412// attempt to find our type library
413
414STDMETHODIMP
415CMediaPosition::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
428STDMETHODIMP
429CMediaPosition::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
445STDMETHODIMP
446CMediaPosition::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
485CPosPassThru::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
501STDMETHODIMP
502CPosPassThru::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
516HRESULT
517CPosPassThru::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
540HRESULT
541CPosPassThru::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
565STDMETHODIMP
566CPosPassThru::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
579STDMETHODIMP
580CPosPassThru::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
593STDMETHODIMP
594CPosPassThru::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
608STDMETHODIMP
609CPosPassThru::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
623STDMETHODIMP
624CPosPassThru::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
638STDMETHODIMP
639CPosPassThru::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
653STDMETHODIMP
654CPosPassThru::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
668STDMETHODIMP
669CPosPassThru::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
686STDMETHODIMP
687CPosPassThru::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
703STDMETHODIMP
704CPosPassThru::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
717HRESULT
718CPosPassThru::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
735STDMETHODIMP
736CPosPassThru::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
746STDMETHODIMP
747CPosPassThru::GetStopPosition(__out LONGLONG *pStop)
748{
749 return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );;
750}
751
752STDMETHODIMP
753CPosPassThru::GetDuration(__out LONGLONG *pDuration)
754{
755 return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );;
756}
757
758
759STDMETHODIMP
760CPosPassThru::GetPreroll(__out LONGLONG *pllPreroll)
761{
762 return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );;
763}
764
765
766STDMETHODIMP
767CPosPassThru::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
781STDMETHODIMP
782CPosPassThru::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
795STDMETHODIMP
796CPosPassThru::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
818STDMETHODIMP
819CPosPassThru::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
833STDMETHODIMP
834CPosPassThru::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
847STDMETHODIMP
848CPosPassThru::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
861STDMETHODIMP
862CPosPassThru::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
875STDMETHODIMP
876CPosPassThru::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
889STDMETHODIMP
890CPosPassThru::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
903STDMETHODIMP
904CPosPassThru::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
917STDMETHODIMP
918CPosPassThru::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
931STDMETHODIMP
932CPosPassThru::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
949STDMETHODIMP
950CPosPassThru::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
963STDMETHODIMP
964CPosPassThru::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
986CRendererPosPassThru::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
1000HRESULT
1001CRendererPosPassThru::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
1027HRESULT
1028CRendererPosPassThru::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
1040HRESULT
1041CRendererPosPassThru::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
1062HRESULT
1063CRendererPosPassThru::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.
1075HRESULT
1076CRendererPosPassThru::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
1096CSourceSeeking::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
1116HRESULT 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
1128HRESULT 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
1135HRESULT CSourceSeeking::QueryPreferredFormat(__out GUID *pFormat)
1136{
1137 CheckPointer(pFormat, E_POINTER);
1138 *pFormat = TIME_FORMAT_MEDIA_TIME;
1139 return S_OK;
1140}
1141
1142HRESULT 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
1150HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat)
1151{
1152 CheckPointer(pFormat, E_POINTER);
1153 return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
1154}
1155
1156HRESULT CSourceSeeking::GetTimeFormat(__out GUID *pFormat)
1157{
1158 CheckPointer(pFormat, E_POINTER);
1159 *pFormat = TIME_FORMAT_MEDIA_TIME;
1160 return S_OK;
1161}
1162
1163HRESULT 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
1171HRESULT 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
1179HRESULT 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
1186HRESULT CSourceSeeking::GetCapabilities( __out DWORD * pCapabilities )
1187{
1188 CheckPointer(pCapabilities, E_POINTER);
1189 *pCapabilities = m_dwSeekingCaps;
1190 return S_OK;
1191}
1192
1193HRESULT 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
1201HRESULT 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
1224HRESULT 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
1292HRESULT 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
1305HRESULT 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
1317HRESULT CSourceSeeking::SetRate( double dRate)
1318{
1319 {
1320 CAutoLock lock(m_pLock);
1321 m_dRateSeeking = dRate;
1322 }
1323 return ChangeRate();
1324}
1325
1326HRESULT 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
1334HRESULT 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
1348CSourcePosition::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
1361STDMETHODIMP
1362CSourcePosition::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
1373STDMETHODIMP
1374CSourcePosition::put_CurrentPosition(REFTIME llTime)
1375{
1376 m_pLock->Lock();
1377 m_Start = llTime;
1378 m_pLock->Unlock();
1379
1380 return ChangeStart();
1381}
1382
1383
1384STDMETHODIMP
1385CSourcePosition::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
1396STDMETHODIMP
1397CSourcePosition::put_StopTime(REFTIME llTime)
1398{
1399 m_pLock->Lock();
1400 m_Stop = llTime;
1401 m_pLock->Unlock();
1402
1403 return ChangeStop();
1404}
1405
1406
1407STDMETHODIMP
1408CSourcePosition::get_PrerollTime(__out REFTIME * pllTime)
1409{
1410 CheckPointer(pllTime,E_POINTER);
1411 ValidateReadWritePtr(pllTime,sizeof(REFTIME));
1412 return E_NOTIMPL;
1413}
1414
1415
1416STDMETHODIMP
1417CSourcePosition::put_PrerollTime(REFTIME llTime)
1418{
1419 return E_NOTIMPL;
1420}
1421
1422
1423STDMETHODIMP
1424CSourcePosition::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
1435STDMETHODIMP
1436CSourcePosition::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
1448STDMETHODIMP
1449CSourcePosition::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
1459STDMETHODIMP
1460CSourcePosition::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
1471CBasicAudio::CBasicAudio(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) :
1472 CUnknown(pName, punk)
1473{
1474}
1475
1476// overriden to publicise our interfaces
1477
1478STDMETHODIMP
1479CBasicAudio::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
1490STDMETHODIMP
1491CBasicAudio::GetTypeInfoCount(__out UINT * pctinfo)
1492{
1493 return m_basedisp.GetTypeInfoCount(pctinfo);
1494}
1495
1496
1497STDMETHODIMP
1498CBasicAudio::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
1511STDMETHODIMP
1512CBasicAudio::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
1528STDMETHODIMP
1529CBasicAudio::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
1567CBaseVideoWindow::CBaseVideoWindow(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) :
1568 CUnknown(pName, punk)
1569{
1570}
1571
1572
1573// overriden to publicise our interfaces
1574
1575STDMETHODIMP
1576CBaseVideoWindow::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
1587STDMETHODIMP
1588CBaseVideoWindow::GetTypeInfoCount(__out UINT * pctinfo)
1589{
1590 return m_basedisp.GetTypeInfoCount(pctinfo);
1591}
1592
1593
1594STDMETHODIMP
1595CBaseVideoWindow::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
1608STDMETHODIMP
1609CBaseVideoWindow::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
1625STDMETHODIMP
1626CBaseVideoWindow::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
1665CBaseBasicVideo::CBaseBasicVideo(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) :
1666 CUnknown(pName, punk)
1667{
1668}
1669
1670
1671// overriden to publicise our interfaces
1672
1673STDMETHODIMP
1674CBaseBasicVideo::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
1685STDMETHODIMP
1686CBaseBasicVideo::GetTypeInfoCount(__out UINT * pctinfo)
1687{
1688 return m_basedisp.GetTypeInfoCount(pctinfo);
1689}
1690
1691
1692STDMETHODIMP
1693CBaseBasicVideo::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
1706STDMETHODIMP
1707CBaseBasicVideo::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
1723STDMETHODIMP
1724CBaseBasicVideo::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
1763CDispParams::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
1873CDispParams::~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
1900CDeferredCommand::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
1974CDeferredCommand::~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
1996STDMETHODIMP
1997CDeferredCommand::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
2012STDMETHODIMP
2013CDeferredCommand::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
2029STDMETHODIMP
2030CDeferredCommand::Confidence(__out LONG* pConfidence)
2031{
2032 return E_NOTIMPL;
2033}
2034
2035
2036STDMETHODIMP
2037CDeferredCommand::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
2053STDMETHODIMP
2054CDeferredCommand::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
2082HRESULT
2083CDeferredCommand::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
2135CCmdQueue::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
2146CCmdQueue::~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
2183HRESULT
2184CCmdQueue::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
2228HRESULT
2229CCmdQueue::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
2263HRESULT
2264CCmdQueue::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
2302HRESULT
2303CCmdQueue::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
2330void
2331CCmdQueue::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
2393HRESULT
2394CCmdQueue::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
2409HRESULT
2410CCmdQueue::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
2430HRESULT
2431CCmdQueue::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
2493HRESULT
2494CCmdQueue::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
Nanang Izzuddinc46d1152012-04-24 07:07:39 +00002545#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */