1
//------------------------------------------------------------------------------
4
// Desc: DirectShow base classes.
6
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7
//------------------------------------------------------------------------------
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
15
#include <pjmedia-videodev/config.h>
17
#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
23
// 'bool' non standard reserved word
24
#pragma warning(disable:4237)
27
// --- CBaseDispatch implementation ----------
28
CBaseDispatch::~CBaseDispatch()
36
// return 1 if we support GetTypeInfo
39
CBaseDispatch::GetTypeInfoCount(__out UINT * pctinfo)
41
CheckPointer(pctinfo,E_POINTER);
42
ValidateReadWritePtr(pctinfo,sizeof(UINT *));
48
typedef HRESULT (STDAPICALLTYPE *LPLOADTYPELIB)(
49
const OLECHAR FAR *szFile,
50
__deref_out ITypeLib FAR* FAR* pptlib);
52
typedef HRESULT (STDAPICALLTYPE *LPLOADREGTYPELIB)(REFGUID rguid,
56
__deref_out ITypeLib FAR* FAR* pptlib);
58
// attempt to find our type library
61
CBaseDispatch::GetTypeInfo(
65
__deref_out ITypeInfo ** pptinfo)
67
CheckPointer(pptinfo,E_POINTER);
68
ValidateReadWritePtr(pptinfo,sizeof(ITypeInfo *));
73
// we only support one type element
75
return TYPE_E_ELEMENTNOTFOUND;
78
if (NULL == pptinfo) {
82
// always look for neutral
85
LPLOADTYPELIB lpfnLoadTypeLib;
86
LPLOADREGTYPELIB lpfnLoadRegTypeLib;
90
static const char szTypeLib[] = "LoadTypeLib";
91
static const char szRegTypeLib[] = "LoadRegTypeLib";
92
static const WCHAR szControl[] = L"control.tlb";
95
// Try to get the Ole32Aut.dll module handle.
98
hInst = LoadOLEAut32();
100
DWORD dwError = GetLastError();
101
return AmHresultFromWin32(dwError);
103
lpfnLoadRegTypeLib = (LPLOADREGTYPELIB)GetProcAddress(hInst,
105
if (lpfnLoadRegTypeLib == NULL) {
106
DWORD dwError = GetLastError();
107
return AmHresultFromWin32(dwError);
110
hr = (*lpfnLoadRegTypeLib)(LIBID_QuartzTypeLib, 1, 0, // version 1.0
115
// attempt to load directly - this will fill the
116
// registry in if it finds it
118
lpfnLoadTypeLib = (LPLOADTYPELIB)GetProcAddress(hInst, szTypeLib);
119
if (lpfnLoadTypeLib == NULL) {
120
DWORD dwError = GetLastError();
121
return AmHresultFromWin32(dwError);
124
hr = (*lpfnLoadTypeLib)(szControl, &ptlib);
130
hr = ptlib->GetTypeInfoOfGuid(
148
CBaseDispatch::GetIDsOfNames(
150
__in_ecount(cNames) LPOLESTR * rgszNames,
153
__out_ecount(cNames) DISPID * rgdispid)
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.
159
HRESULT hr = GetTypeInfo(riid, 0, lcid, &pti);
162
hr = pti->GetIDsOfNames(rgszNames, cNames, rgdispid);
170
// --- CMediaControl implementation ---------
172
CMediaControl::CMediaControl(const TCHAR * name,LPUNKNOWN pUnk) :
177
// expose our interfaces IMediaControl and IUnknown
180
CMediaControl::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
182
ValidateReadWritePtr(ppv,sizeof(PVOID));
183
if (riid == IID_IMediaControl) {
184
return GetInterface( (IMediaControl *) this, ppv);
186
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
191
// return 1 if we support GetTypeInfo
194
CMediaControl::GetTypeInfoCount(__out UINT * pctinfo)
196
return m_basedisp.GetTypeInfoCount(pctinfo);
200
// attempt to find our type library
203
CMediaControl::GetTypeInfo(
206
__deref_out ITypeInfo ** pptinfo)
208
return m_basedisp.GetTypeInfo(
217
CMediaControl::GetIDsOfNames(
219
__in_ecount(cNames) LPOLESTR * rgszNames,
222
__out_ecount(cNames) DISPID * rgdispid)
224
return m_basedisp.GetIDsOfNames(
234
CMediaControl::Invoke(
239
__in DISPPARAMS * pdispparams,
240
__out_opt VARIANT * pvarResult,
241
__out_opt EXCEPINFO * pexcepinfo,
242
__out_opt UINT * puArgErr)
244
// this parameter is a dead leftover from an earlier interface
245
if (IID_NULL != riid) {
246
return DISP_E_UNKNOWNINTERFACE;
250
HRESULT hr = GetTypeInfo(0, lcid, &pti);
257
(IMediaControl *)this,
270
// --- CMediaEvent implementation ----------
273
CMediaEvent::CMediaEvent(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) :
279
// expose our interfaces IMediaEvent and IUnknown
282
CMediaEvent::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
284
ValidateReadWritePtr(ppv,sizeof(PVOID));
285
if (riid == IID_IMediaEvent || riid == IID_IMediaEventEx) {
286
return GetInterface( (IMediaEventEx *) this, ppv);
288
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
293
// return 1 if we support GetTypeInfo
296
CMediaEvent::GetTypeInfoCount(__out UINT * pctinfo)
298
return m_basedisp.GetTypeInfoCount(pctinfo);
302
// attempt to find our type library
305
CMediaEvent::GetTypeInfo(
308
__deref_out ITypeInfo ** pptinfo)
310
return m_basedisp.GetTypeInfo(
319
CMediaEvent::GetIDsOfNames(
321
__in_ecount(cNames) LPOLESTR * rgszNames,
324
__out_ecount(cNames) DISPID * rgdispid)
326
return m_basedisp.GetIDsOfNames(
341
__in DISPPARAMS * pdispparams,
342
__out_opt VARIANT * pvarResult,
343
__out_opt EXCEPINFO * pexcepinfo,
344
__out_opt UINT * puArgErr)
346
// this parameter is a dead leftover from an earlier interface
347
if (IID_NULL != riid) {
348
return DISP_E_UNKNOWNINTERFACE;
352
HRESULT hr = GetTypeInfo(0, lcid, &pti);
372
// --- CMediaPosition implementation ----------
375
CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,__in_opt LPUNKNOWN pUnk) :
380
CMediaPosition::CMediaPosition(__in_opt LPCTSTR name,
381
__in_opt LPUNKNOWN pUnk,
382
__inout HRESULT * phr) :
385
UNREFERENCED_PARAMETER(phr);
389
// expose our interfaces IMediaPosition and IUnknown
392
CMediaPosition::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
394
ValidateReadWritePtr(ppv,sizeof(PVOID));
395
if (riid == IID_IMediaPosition) {
396
return GetInterface( (IMediaPosition *) this, ppv);
398
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
403
// return 1 if we support GetTypeInfo
406
CMediaPosition::GetTypeInfoCount(__out UINT * pctinfo)
408
return m_basedisp.GetTypeInfoCount(pctinfo);
412
// attempt to find our type library
415
CMediaPosition::GetTypeInfo(
418
__deref_out ITypeInfo ** pptinfo)
420
return m_basedisp.GetTypeInfo(
429
CMediaPosition::GetIDsOfNames(
431
__in_ecount(cNames) LPOLESTR * rgszNames,
434
__out_ecount(cNames) DISPID * rgdispid)
436
return m_basedisp.GetIDsOfNames(
446
CMediaPosition::Invoke(
451
__in DISPPARAMS * pdispparams,
452
__out_opt VARIANT * pvarResult,
453
__out_opt EXCEPINFO * pexcepinfo,
454
__out_opt UINT * puArgErr)
456
// this parameter is a dead leftover from an earlier interface
457
if (IID_NULL != riid) {
458
return DISP_E_UNKNOWNINTERFACE;
462
HRESULT hr = GetTypeInfo(0, lcid, &pti);
469
(IMediaPosition *)this,
482
// --- IMediaPosition and IMediaSeeking pass through class ----------
485
CPosPassThru::CPosPassThru(__in_opt LPCTSTR pName,
486
__in_opt LPUNKNOWN pUnk,
487
__inout HRESULT *phr,
489
CMediaPosition(pName,pUnk),
499
// Expose our IMediaSeeking and IMediaPosition interfaces
502
CPosPassThru::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv)
504
CheckPointer(ppv,E_POINTER);
507
if (riid == IID_IMediaSeeking) {
508
return GetInterface( static_cast<IMediaSeeking *>(this), ppv);
510
return CMediaPosition::NonDelegatingQueryInterface(riid,ppv);
514
// Return the IMediaPosition interface from our peer
517
CPosPassThru::GetPeer(IMediaPosition ** ppMP)
522
HRESULT hr = m_pPin->ConnectedTo(&pConnected);
526
IMediaPosition * pMP;
527
hr = pConnected->QueryInterface(IID_IMediaPosition, (void **) &pMP);
528
pConnected->Release();
538
// Return the IMediaSeeking interface from our peer
541
CPosPassThru::GetPeerSeeking(__deref_out IMediaSeeking ** ppMS)
546
HRESULT hr = m_pPin->ConnectedTo(&pConnected);
551
hr = pConnected->QueryInterface(IID_IMediaSeeking, (void **) &pMS);
552
pConnected->Release();
562
// --- IMediaSeeking methods ----------
566
CPosPassThru::GetCapabilities(__out DWORD * pCaps)
569
HRESULT hr = GetPeerSeeking(&pMS);
574
hr = pMS->GetCapabilities(pCaps);
580
CPosPassThru::CheckCapabilities(__inout DWORD * pCaps)
583
HRESULT hr = GetPeerSeeking(&pMS);
588
hr = pMS->CheckCapabilities(pCaps);
594
CPosPassThru::IsFormatSupported(const GUID * pFormat)
597
HRESULT hr = GetPeerSeeking(&pMS);
602
hr = pMS->IsFormatSupported(pFormat);
609
CPosPassThru::QueryPreferredFormat(__out GUID *pFormat)
612
HRESULT hr = GetPeerSeeking(&pMS);
617
hr = pMS->QueryPreferredFormat(pFormat);
624
CPosPassThru::SetTimeFormat(const GUID * pFormat)
627
HRESULT hr = GetPeerSeeking(&pMS);
632
hr = pMS->SetTimeFormat(pFormat);
639
CPosPassThru::GetTimeFormat(__out GUID *pFormat)
642
HRESULT hr = GetPeerSeeking(&pMS);
647
hr = pMS->GetTimeFormat(pFormat);
654
CPosPassThru::IsUsingTimeFormat(const GUID * pFormat)
657
HRESULT hr = GetPeerSeeking(&pMS);
662
hr = pMS->IsUsingTimeFormat(pFormat);
669
CPosPassThru::ConvertTimeFormat(__out LONGLONG * pTarget,
670
__in_opt const GUID * pTargetFormat,
672
__in_opt const GUID * pSourceFormat )
675
HRESULT hr = GetPeerSeeking(&pMS);
680
hr = pMS->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat );
687
CPosPassThru::SetPositions( __inout_opt LONGLONG * pCurrent,
689
__inout_opt LONGLONG * pStop,
693
HRESULT hr = GetPeerSeeking(&pMS);
698
hr = pMS->SetPositions(pCurrent, CurrentFlags, pStop, StopFlags );
704
CPosPassThru::GetPositions(__out_opt LONGLONG *pCurrent, __out_opt LONGLONG * pStop)
707
HRESULT hr = GetPeerSeeking(&pMS);
712
hr = pMS->GetPositions(pCurrent,pStop);
718
CPosPassThru::GetSeekingLongLong
719
( HRESULT (__stdcall IMediaSeeking::*pMethod)( __out LONGLONG * )
724
HRESULT hr = GetPeerSeeking(&pMS);
727
hr = (pMS->*pMethod)(pll);
733
// If we don't have a current position then ask upstream
736
CPosPassThru::GetCurrentPosition(__out LONGLONG *pCurrent)
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 );
747
CPosPassThru::GetStopPosition(__out LONGLONG *pStop)
749
return GetSeekingLongLong( &IMediaSeeking::GetStopPosition, pStop );;
753
CPosPassThru::GetDuration(__out LONGLONG *pDuration)
755
return GetSeekingLongLong( &IMediaSeeking::GetDuration, pDuration );;
760
CPosPassThru::GetPreroll(__out LONGLONG *pllPreroll)
762
return GetSeekingLongLong( &IMediaSeeking::GetPreroll, pllPreroll );;
767
CPosPassThru::GetAvailable( __out_opt LONGLONG *pEarliest, __out_opt LONGLONG *pLatest )
770
HRESULT hr = GetPeerSeeking(&pMS);
775
hr = pMS->GetAvailable( pEarliest, pLatest );
782
CPosPassThru::GetRate(__out double * pdRate)
785
HRESULT hr = GetPeerSeeking(&pMS);
789
hr = pMS->GetRate(pdRate);
796
CPosPassThru::SetRate(double dRate)
803
HRESULT hr = GetPeerSeeking(&pMS);
807
hr = pMS->SetRate(dRate);
815
// --- IMediaPosition methods ----------
819
CPosPassThru::get_Duration(__out REFTIME * plength)
822
HRESULT hr = GetPeer(&pMP);
827
hr = pMP->get_Duration(plength);
834
CPosPassThru::get_CurrentPosition(__out REFTIME * pllTime)
837
HRESULT hr = GetPeer(&pMP);
841
hr = pMP->get_CurrentPosition(pllTime);
848
CPosPassThru::put_CurrentPosition(REFTIME llTime)
851
HRESULT hr = GetPeer(&pMP);
855
hr = pMP->put_CurrentPosition(llTime);
862
CPosPassThru::get_StopTime(__out REFTIME * pllTime)
865
HRESULT hr = GetPeer(&pMP);
869
hr = pMP->get_StopTime(pllTime);
876
CPosPassThru::put_StopTime(REFTIME llTime)
879
HRESULT hr = GetPeer(&pMP);
883
hr = pMP->put_StopTime(llTime);
890
CPosPassThru::get_PrerollTime(__out REFTIME * pllTime)
893
HRESULT hr = GetPeer(&pMP);
897
hr = pMP->get_PrerollTime(pllTime);
904
CPosPassThru::put_PrerollTime(REFTIME llTime)
907
HRESULT hr = GetPeer(&pMP);
911
hr = pMP->put_PrerollTime(llTime);
918
CPosPassThru::get_Rate(__out double * pdRate)
921
HRESULT hr = GetPeer(&pMP);
925
hr = pMP->get_Rate(pdRate);
932
CPosPassThru::put_Rate(double dRate)
939
HRESULT hr = GetPeer(&pMP);
943
hr = pMP->put_Rate(dRate);
950
CPosPassThru::CanSeekForward(__out LONG *pCanSeekForward)
953
HRESULT hr = GetPeer(&pMP);
957
hr = pMP->CanSeekForward(pCanSeekForward);
964
CPosPassThru::CanSeekBackward(__out LONG *pCanSeekBackward)
967
HRESULT hr = GetPeer(&pMP);
971
hr = pMP->CanSeekBackward(pCanSeekBackward);
977
// --- Implements the CRendererPosPassThru class ----------
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.
986
CRendererPosPassThru::CRendererPosPassThru(__in_opt LPCTSTR pName,
987
__in_opt LPUNKNOWN pUnk,
988
__inout HRESULT *phr,
990
CPosPassThru(pName,pUnk,phr,pPin),
998
// Sets the media times the object should report
1001
CRendererPosPassThru::RegisterMediaTime(IMediaSample *pMediaSample)
1003
ASSERT(pMediaSample);
1004
LONGLONG StartMedia;
1007
CAutoLock cAutoLock(&m_PositionLock);
1009
// Get the media times from the sample
1011
HRESULT hr = pMediaSample->GetTime(&StartMedia,&EndMedia);
1014
ASSERT(hr == VFW_E_SAMPLE_TIME_NOT_SET);
1018
m_StartMedia = StartMedia;
1019
m_EndMedia = EndMedia;
1025
// Sets the media times the object should report
1028
CRendererPosPassThru::RegisterMediaTime(LONGLONG StartTime,LONGLONG EndTime)
1030
CAutoLock cAutoLock(&m_PositionLock);
1031
m_StartMedia = StartTime;
1032
m_EndMedia = EndTime;
1038
// Return the current media times registered in the object
1041
CRendererPosPassThru::GetMediaTime(__out LONGLONG *pStartTime, __out_opt LONGLONG *pEndTime)
1045
CAutoLock cAutoLock(&m_PositionLock);
1046
if (m_bReset == TRUE) {
1050
// We don't have to return the end time
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 );
1060
// Resets the media times we hold
1063
CRendererPosPassThru::ResetMediaTime()
1065
CAutoLock cAutoLock(&m_PositionLock);
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.
1076
CRendererPosPassThru::EOS()
1080
if ( m_bReset == TRUE ) hr = E_FAIL;
1084
if SUCCEEDED(hr=GetStopPosition(&llStop))
1086
CAutoLock cAutoLock(&m_PositionLock);
1088
m_EndMedia = llStop;
1094
// -- CSourceSeeking implementation ------------
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),
1105
m_rtStop = _I64_MAX / 2;
1106
m_rtDuration = m_rtStop;
1107
m_dRateSeeking = 1.0;
1109
m_dwSeekingCaps = AM_SEEKING_CanSeekForwards
1110
| AM_SEEKING_CanSeekBackwards
1111
| AM_SEEKING_CanSeekAbsolute
1112
| AM_SEEKING_CanGetStopPos
1113
| AM_SEEKING_CanGetDuration;
1116
HRESULT CSourceSeeking::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
1118
if(riid == IID_IMediaSeeking) {
1119
CheckPointer(ppv, E_POINTER);
1120
return GetInterface(static_cast<IMediaSeeking *>(this), ppv);
1123
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1128
HRESULT CSourceSeeking::IsFormatSupported(const GUID * pFormat)
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;
1135
HRESULT CSourceSeeking::QueryPreferredFormat(__out GUID *pFormat)
1137
CheckPointer(pFormat, E_POINTER);
1138
*pFormat = TIME_FORMAT_MEDIA_TIME;
1142
HRESULT CSourceSeeking::SetTimeFormat(const GUID * pFormat)
1144
CheckPointer(pFormat, E_POINTER);
1146
// nothing to set; just check that it's TIME_FORMAT_TIME
1147
return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG;
1150
HRESULT CSourceSeeking::IsUsingTimeFormat(const GUID * pFormat)
1152
CheckPointer(pFormat, E_POINTER);
1153
return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
1156
HRESULT CSourceSeeking::GetTimeFormat(__out GUID *pFormat)
1158
CheckPointer(pFormat, E_POINTER);
1159
*pFormat = TIME_FORMAT_MEDIA_TIME;
1163
HRESULT CSourceSeeking::GetDuration(__out LONGLONG *pDuration)
1165
CheckPointer(pDuration, E_POINTER);
1166
CAutoLock lock(m_pLock);
1167
*pDuration = m_rtDuration;
1171
HRESULT CSourceSeeking::GetStopPosition(__out LONGLONG *pStop)
1173
CheckPointer(pStop, E_POINTER);
1174
CAutoLock lock(m_pLock);
1179
HRESULT CSourceSeeking::GetCurrentPosition(__out LONGLONG *pCurrent)
1181
// GetCurrentPosition is typically supported only in renderers and
1182
// not in source filters.
1186
HRESULT CSourceSeeking::GetCapabilities( __out DWORD * pCapabilities )
1188
CheckPointer(pCapabilities, E_POINTER);
1189
*pCapabilities = m_dwSeekingCaps;
1193
HRESULT CSourceSeeking::CheckCapabilities( __inout DWORD * pCapabilities )
1195
CheckPointer(pCapabilities, E_POINTER);
1197
// make sure all requested capabilities are in our mask
1198
return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK;
1201
HRESULT CSourceSeeking::ConvertTimeFormat( __out LONGLONG * pTarget,
1202
__in_opt const GUID * pTargetFormat,
1204
__in_opt const GUID * pSourceFormat )
1206
CheckPointer(pTarget, E_POINTER);
1207
// format guids can be null to indicate current format
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)
1213
if(pSourceFormat == 0 || *pSourceFormat == TIME_FORMAT_MEDIA_TIME)
1220
return E_INVALIDARG;
1224
HRESULT CSourceSeeking::SetPositions( __inout_opt LONGLONG * pCurrent,
1226
__inout_opt LONGLONG * pStop,
1229
DWORD StopPosBits = StopFlags & AM_SEEKING_PositioningBitsMask;
1230
DWORD StartPosBits = CurrentFlags & AM_SEEKING_PositioningBitsMask;
1233
CheckPointer(pStop, E_POINTER);
1235
// accept only relative, incremental, or absolute positioning
1236
if(StopPosBits != StopFlags) {
1237
return E_INVALIDARG;
1242
CheckPointer(pCurrent, E_POINTER);
1243
if(StartPosBits != AM_SEEKING_AbsolutePositioning &&
1244
StartPosBits != AM_SEEKING_RelativePositioning) {
1245
return E_INVALIDARG;
1250
// scope for autolock
1252
CAutoLock lock(m_pLock);
1254
// set start position
1255
if(StartPosBits == AM_SEEKING_AbsolutePositioning)
1257
m_rtStart = *pCurrent;
1259
else if(StartPosBits == AM_SEEKING_RelativePositioning)
1261
m_rtStart += *pCurrent;
1264
// set stop position
1265
if(StopPosBits == AM_SEEKING_AbsolutePositioning)
1269
else if(StopPosBits == AM_SEEKING_IncrementalPositioning)
1271
m_rtStop = m_rtStart + *pStop;
1273
else if(StopPosBits == AM_SEEKING_RelativePositioning)
1275
m_rtStop = m_rtStop + *pStop;
1281
if(SUCCEEDED(hr) && StopPosBits) {
1292
HRESULT CSourceSeeking::GetPositions( __out_opt LONGLONG * pCurrent, __out_opt LONGLONG * pStop )
1295
*pCurrent = m_rtStart;
1305
HRESULT CSourceSeeking::GetAvailable( __out_opt LONGLONG * pEarliest, __out_opt LONGLONG * pLatest )
1311
CAutoLock lock(m_pLock);
1312
*pLatest = m_rtDuration;
1317
HRESULT CSourceSeeking::SetRate( double dRate)
1320
CAutoLock lock(m_pLock);
1321
m_dRateSeeking = dRate;
1323
return ChangeRate();
1326
HRESULT CSourceSeeking::GetRate( __out double * pdRate)
1328
CheckPointer(pdRate, E_POINTER);
1329
CAutoLock lock(m_pLock);
1330
*pdRate = m_dRateSeeking;
1334
HRESULT CSourceSeeking::GetPreroll(__out LONGLONG *pPreroll)
1336
CheckPointer(pPreroll, E_POINTER);
1345
// --- CSourcePosition implementation ----------
1348
CSourcePosition::CSourcePosition(__in_opt LPCTSTR pName,
1349
__in_opt LPUNKNOWN pUnk,
1350
__inout HRESULT* phr,
1351
__in CCritSec * pLock) :
1352
CMediaPosition(pName, pUnk),
1354
m_Start(CRefTime((LONGLONG)0))
1362
CSourcePosition::get_Duration(__out REFTIME * plength)
1364
CheckPointer(plength,E_POINTER);
1365
ValidateReadWritePtr(plength,sizeof(REFTIME));
1366
CAutoLock lock(m_pLock);
1368
*plength = m_Duration;
1374
CSourcePosition::put_CurrentPosition(REFTIME llTime)
1380
return ChangeStart();
1385
CSourcePosition::get_StopTime(__out REFTIME * pllTime)
1387
CheckPointer(pllTime,E_POINTER);
1388
ValidateReadWritePtr(pllTime,sizeof(REFTIME));
1389
CAutoLock lock(m_pLock);
1397
CSourcePosition::put_StopTime(REFTIME llTime)
1403
return ChangeStop();
1408
CSourcePosition::get_PrerollTime(__out REFTIME * pllTime)
1410
CheckPointer(pllTime,E_POINTER);
1411
ValidateReadWritePtr(pllTime,sizeof(REFTIME));
1417
CSourcePosition::put_PrerollTime(REFTIME llTime)
1424
CSourcePosition::get_Rate(__out double * pdRate)
1426
CheckPointer(pdRate,E_POINTER);
1427
ValidateReadWritePtr(pdRate,sizeof(double));
1428
CAutoLock lock(m_pLock);
1436
CSourcePosition::put_Rate(double dRate)
1442
return ChangeRate();
1446
// By default we can seek forwards
1449
CSourcePosition::CanSeekForward(__out LONG *pCanSeekForward)
1451
CheckPointer(pCanSeekForward,E_POINTER);
1452
*pCanSeekForward = OATRUE;
1457
// By default we can seek backwards
1460
CSourcePosition::CanSeekBackward(__out LONG *pCanSeekBackward)
1462
CheckPointer(pCanSeekBackward,E_POINTER);
1463
*pCanSeekBackward = OATRUE;
1468
// --- Implementation of CBasicAudio class ----------
1471
CBasicAudio::CBasicAudio(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) :
1472
CUnknown(pName, punk)
1476
// overriden to publicise our interfaces
1479
CBasicAudio::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
1481
ValidateReadWritePtr(ppv,sizeof(PVOID));
1482
if (riid == IID_IBasicAudio) {
1483
return GetInterface( (IBasicAudio *) this, ppv);
1485
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1491
CBasicAudio::GetTypeInfoCount(__out UINT * pctinfo)
1493
return m_basedisp.GetTypeInfoCount(pctinfo);
1498
CBasicAudio::GetTypeInfo(
1501
__deref_out ITypeInfo ** pptinfo)
1503
return m_basedisp.GetTypeInfo(
1512
CBasicAudio::GetIDsOfNames(
1514
__in_ecount(cNames) LPOLESTR * rgszNames,
1517
__out_ecount(cNames) DISPID * rgdispid)
1519
return m_basedisp.GetIDsOfNames(
1529
CBasicAudio::Invoke(
1530
DISPID dispidMember,
1534
__in DISPPARAMS * pdispparams,
1535
__out_opt VARIANT * pvarResult,
1536
__out_opt EXCEPINFO * pexcepinfo,
1537
__out_opt UINT * puArgErr)
1539
// this parameter is a dead leftover from an earlier interface
1540
if (IID_NULL != riid) {
1541
return DISP_E_UNKNOWNINTERFACE;
1545
HRESULT hr = GetTypeInfo(0, lcid, &pti);
1552
(IBasicAudio *)this,
1565
// --- IVideoWindow implementation ----------
1567
CBaseVideoWindow::CBaseVideoWindow(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) :
1568
CUnknown(pName, punk)
1573
// overriden to publicise our interfaces
1576
CBaseVideoWindow::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
1578
ValidateReadWritePtr(ppv,sizeof(PVOID));
1579
if (riid == IID_IVideoWindow) {
1580
return GetInterface( (IVideoWindow *) this, ppv);
1582
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1588
CBaseVideoWindow::GetTypeInfoCount(__out UINT * pctinfo)
1590
return m_basedisp.GetTypeInfoCount(pctinfo);
1595
CBaseVideoWindow::GetTypeInfo(
1598
__deref_out ITypeInfo ** pptinfo)
1600
return m_basedisp.GetTypeInfo(
1609
CBaseVideoWindow::GetIDsOfNames(
1611
__in_ecount(cNames) LPOLESTR * rgszNames,
1614
__out_ecount(cNames) DISPID * rgdispid)
1616
return m_basedisp.GetIDsOfNames(
1626
CBaseVideoWindow::Invoke(
1627
DISPID dispidMember,
1631
__in DISPPARAMS * pdispparams,
1632
__out_opt VARIANT * pvarResult,
1633
__out_opt EXCEPINFO * pexcepinfo,
1634
__out_opt UINT * puArgErr)
1636
// this parameter is a dead leftover from an earlier interface
1637
if (IID_NULL != riid) {
1638
return DISP_E_UNKNOWNINTERFACE;
1642
HRESULT hr = GetTypeInfo(0, lcid, &pti);
1649
(IVideoWindow *)this,
1662
// --- IBasicVideo implementation ----------
1665
CBaseBasicVideo::CBaseBasicVideo(__in_opt LPCTSTR pName,__in_opt LPUNKNOWN punk) :
1666
CUnknown(pName, punk)
1671
// overriden to publicise our interfaces
1674
CBaseBasicVideo::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
1676
ValidateReadWritePtr(ppv,sizeof(PVOID));
1677
if (riid == IID_IBasicVideo || riid == IID_IBasicVideo2) {
1678
return GetInterface( static_cast<IBasicVideo2 *>(this), ppv);
1680
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
1686
CBaseBasicVideo::GetTypeInfoCount(__out UINT * pctinfo)
1688
return m_basedisp.GetTypeInfoCount(pctinfo);
1693
CBaseBasicVideo::GetTypeInfo(
1696
__deref_out ITypeInfo ** pptinfo)
1698
return m_basedisp.GetTypeInfo(
1707
CBaseBasicVideo::GetIDsOfNames(
1709
__in_ecount(cNames) LPOLESTR * rgszNames,
1712
__out_ecount(cNames) DISPID * rgdispid)
1714
return m_basedisp.GetIDsOfNames(
1724
CBaseBasicVideo::Invoke(
1725
DISPID dispidMember,
1729
__in DISPPARAMS * pdispparams,
1730
__out_opt VARIANT * pvarResult,
1731
__out_opt EXCEPINFO * pexcepinfo,
1732
__out_opt UINT * puArgErr)
1734
// this parameter is a dead leftover from an earlier interface
1735
if (IID_NULL != riid) {
1736
return DISP_E_UNKNOWNINTERFACE;
1740
HRESULT hr = GetTypeInfo(0, lcid, &pti);
1747
(IBasicVideo *)this,
1760
// --- Implementation of Deferred Commands ----------
1763
CDispParams::CDispParams(UINT nArgs, __in_ecount(nArgs) VARIANT* pArgs, __inout_opt HRESULT *phr)
1766
rgdispidNamedArgs = NULL;
1770
rgvarg = new VARIANT[cArgs];
1771
if (NULL == rgvarg) {
1774
*phr = E_OUTOFMEMORY;
1779
for (UINT i = 0; i < cArgs; i++) {
1781
// Why aren't we using VariantCopy?
1783
VARIANT * pDest = &rgvarg[i];
1784
VARIANT * pSrc = &pArgs[i];
1786
pDest->vt = pSrc->vt;
1790
pDest->lVal = pSrc->lVal;
1794
pDest->bVal = pSrc->bVal;
1798
pDest->iVal = pSrc->iVal;
1802
pDest->fltVal = pSrc->fltVal;
1806
pDest->dblVal = pSrc->dblVal;
1810
pDest->boolVal = pSrc->boolVal;
1814
pDest->scode = pSrc->scode;
1818
pDest->cyVal = pSrc->cyVal;
1822
pDest->date = pSrc->date;
1826
if ((PVOID)pSrc->bstrVal == NULL) {
1827
pDest->bstrVal = NULL;
1830
// a BSTR is a WORD followed by a UNICODE string.
1831
// the pointer points just after the WORD
1833
WORD len = * (WORD*) (pSrc->bstrVal - (sizeof(WORD) / sizeof(OLECHAR)));
1834
OLECHAR* pch = new OLECHAR[len + (sizeof(WORD)/sizeof(OLECHAR))];
1836
WORD *pui = (WORD*)pch;
1838
pDest->bstrVal = pch + (sizeof(WORD)/sizeof(OLECHAR));
1839
CopyMemory(pDest->bstrVal, pSrc->bstrVal, len*sizeof(OLECHAR));
1843
*phr = E_OUTOFMEMORY;
1850
pDest->punkVal = pSrc->punkVal;
1851
pDest->punkVal->AddRef();
1855
pDest->pdispVal = pSrc->pdispVal;
1856
pDest->pdispVal->AddRef();
1860
// a type we haven't got round to adding yet!
1873
CDispParams::~CDispParams()
1875
for (UINT i = 0; i < cArgs; i++) {
1876
switch(rgvarg[i].vt) {
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));
1886
rgvarg[i].punkVal->Release();
1890
rgvarg[i].pdispVal->Release();
1898
// lifetime is controlled by refcounts (see defer.h)
1900
CDeferredCommand::CDeferredCommand(
1901
__inout CCmdQueue * pQ,
1902
__in_opt LPUNKNOWN pUnk,
1903
__inout HRESULT * phr,
1904
__in LPUNKNOWN pUnkExecutor,
1910
__in_ecount(nArgs) VARIANT* pDispParams,
1911
__out VARIANT* pvarResult,
1912
__out short* puArgErr,
1915
CUnknown(NAME("DeferredCommand"), pUnk),
1917
m_pUnk(pUnkExecutor),
1919
m_dispidMethod(dispidMethod),
1921
m_DispParams(nArgs, pDispParams, phr),
1922
m_pvarResult(pvarResult),
1927
// convert REFTIME to REFERENCE_TIME
1928
COARefTime convertor(time);
1931
// no check of time validity - it's ok to queue a command that's
1934
// check iid is supportable on pUnk by QueryInterface for it
1935
IUnknown * pInterface;
1936
HRESULT hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface);
1941
pInterface->Release();
1944
// !!! check dispidMethod and param/return types using typelib
1946
hr = m_Dispatch.GetTypeInfo(*iid, 0, 0, &pti);
1951
// !!! some sort of ITypeInfo validity check here
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;
1962
// all checks ok - add to queue
1963
hr = pQ->Insert(this);
1970
// refcounts are held by caller of InvokeAt... and by list. So if
1971
// we get here, we can't be on the list
1974
CDeferredCommand::~CDeferredCommand()
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);
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
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.
1994
// overriden to publicise our interfaces
1997
CDeferredCommand::NonDelegatingQueryInterface(REFIID riid, __out void **ppv)
1999
ValidateReadWritePtr(ppv,sizeof(PVOID));
2000
if (riid == IID_IDeferredCommand) {
2001
return GetInterface( (IDeferredCommand *) this, ppv);
2003
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
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.
2013
CDeferredCommand::Cancel()
2015
if (m_pQueue == NULL) {
2016
return VFW_E_ALREADY_CANCELLED;
2019
HRESULT hr = m_pQueue->Remove(this);
2030
CDeferredCommand::Confidence(__out LONG* pConfidence)
2037
CDeferredCommand::GetHResult(__out HRESULT * phrResult)
2039
CheckPointer(phrResult,E_POINTER);
2040
ValidateReadWritePtr(phrResult,sizeof(HRESULT));
2042
if (m_pQueue != NULL) {
2045
*phrResult = m_hrResult;
2050
// set the time to be a new time (checking that it is valid) and
2054
CDeferredCommand::Postpone(REFTIME newtime)
2057
// check that this time is not past
2058
// convert REFTIME to REFERENCE_TIME
2059
COARefTime convertor(newtime);
2061
// check that the time has not passed
2062
if (m_pQueue->CheckTime(convertor, IsStreamTime())) {
2063
return VFW_E_TIME_ALREADY_PASSED;
2066
// extract from list
2067
HRESULT hr = m_pQueue->Remove(this);
2076
hr = m_pQueue->Insert(this);
2083
CDeferredCommand::Invoke()
2085
// check that we are still outstanding
2086
if (m_pQueue == NULL) {
2087
return VFW_E_ALREADY_CANCELLED;
2090
// get the type info
2092
HRESULT hr = m_Dispatch.GetTypeInfo(GetIID(), 0, 0, &pti);
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;
2101
hr = m_pUnk->QueryInterface(GetIID(), (void**) &pInterface);
2109
m_hrResult = pti->Invoke(
2118
// release the interface we QI'd for
2119
pInterface->Release();
2123
// remove from list whether or not successful
2124
// or we loop indefinitely
2125
hr = m_pQueue->Remove(this);
2132
// --- CCmdQueue methods ----------
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
2146
CCmdQueue::~CCmdQueue()
2148
// empty all our lists
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();
2155
CDeferredCommand* pCmd = m_listPresentation.GetNext(pos);
2158
m_listPresentation.RemoveAll();
2160
pos = m_listStream.GetHeadPosition();
2163
CDeferredCommand* pCmd = m_listStream.GetNext(pos);
2166
m_listStream.RemoveAll();
2170
m_pClock->Unadvise(m_dwAdvise);
2173
m_pClock->Release();
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.
2185
__out CDeferredCommand **ppCmd,
2186
__in LPUNKNOWN pUnk, // this object will execute command
2192
__in_ecount(cArgs) VARIANT* pDispParams,
2193
__out VARIANT* pvarResult,
2194
__out short* puArgErr,
2198
CAutoLock lock(&m_Lock);
2203
CDeferredCommand* pCmd;
2204
pCmd = new CDeferredCommand(
2206
NULL, // not aggregated
2208
pUnk, // this guy will execute
2229
CCmdQueue::Insert(__in CDeferredCommand* pCmd)
2231
CAutoLock lock(&m_Lock);
2236
CGenericList<CDeferredCommand> * pList;
2237
if (pCmd->IsStreamTime()) {
2238
pList = &m_listStream;
2240
pList = &m_listPresentation;
2242
POSITION pos = pList->GetHeadPosition();
2244
// seek past all items that are before us
2246
(pList->GetValid(pos)->GetTime() <= pCmd->GetTime())) {
2248
pList->GetNext(pos);
2251
// now at end of list or in front of items that come later
2253
pList->AddTail(pCmd);
2255
pList->AddBefore(pos, pCmd);
2264
CCmdQueue::Remove(__in CDeferredCommand* pCmd)
2266
CAutoLock lock(&m_Lock);
2269
CGenericList<CDeferredCommand> * pList;
2270
if (pCmd->IsStreamTime()) {
2271
pList = &m_listStream;
2273
pList = &m_listPresentation;
2275
POSITION pos = pList->GetHeadPosition();
2277
// traverse the list
2278
while (pos && (pList->GetValid(pos) != pCmd)) {
2279
pList->GetNext(pos);
2282
// did we drop off the end?
2284
hr = VFW_E_NOT_FOUND;
2287
// found it - now take off list
2290
// Insert did an AddRef, so release it
2293
// check that timer request is still for earliest time
2300
// set the clock used for timing
2303
CCmdQueue::SetSyncSource(__in_opt IReferenceClock* pClock)
2305
CAutoLock lock(&m_Lock);
2307
// addref the new clock first in case they are the same
2312
// kill any advise on the old clock
2315
m_pClock->Unadvise(m_dwAdvise);
2318
m_pClock->Release();
2322
// set up a new advise
2328
// set up a timer event with the reference clock
2331
CCmdQueue::SetTimeAdvise(void)
2333
// make sure we have a clock to use
2338
// reset the event whenever we are requesting a new signal
2341
// time 0 is earliest
2344
// find the earliest presentation time
2345
POSITION pos = m_listPresentation.GetHeadPosition();
2347
current = m_listPresentation.GetValid(pos)->GetTime();
2350
// if we're running, check the stream times too
2354
pos = m_listStream.GetHeadPosition();
2356
t = m_listStream.GetValid(pos)->GetTime();
2358
// add on stream time offset to get presentation time
2359
t += m_StreamTimeOffset;
2362
if ((current == TimeZero) || (t < current)) {
2369
if ((current > TimeZero) && (current != m_tCurrentAdvise)) {
2371
m_pClock->Unadvise(m_dwAdvise);
2372
// reset the event whenever we are requesting a new signal
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,
2382
(HEVENT) HANDLE(m_evDue),
2385
ASSERT(SUCCEEDED(hr));
2386
m_tCurrentAdvise = current;
2391
// switch to run mode. Streamtime to Presentation time mapping known.
2394
CCmdQueue::Run(REFERENCE_TIME tStreamTimeOffset)
2396
CAutoLock lock(&m_Lock);
2398
m_StreamTimeOffset = tStreamTimeOffset;
2401
// ensure advise is accurate
2407
// switch to Stopped or Paused mode. Time mapping not known.
2412
CAutoLock lock(&m_Lock);
2416
// check timer setting - stream times
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).
2428
// returns an AddRef'd object
2431
CCmdQueue::GetDueCommand(__out CDeferredCommand ** ppCmd, long msTimeout)
2433
// loop until we timeout or find a due command
2437
CAutoLock lock(&m_Lock);
2440
// find the earliest command
2441
CDeferredCommand * pCmd = NULL;
2443
// check the presentation time and the
2444
// stream time list to find the earliest
2446
POSITION pos = m_listPresentation.GetHeadPosition();
2449
pCmd = m_listPresentation.GetValid(pos);
2453
pos = m_listStream.GetHeadPosition();
2455
CDeferredCommand* pStrm = m_listStream.GetValid(pos);
2457
CRefTime t = pStrm->GetTime() + m_StreamTimeOffset;
2458
if (!pCmd || (t < pCmd->GetTime())) {
2464
// if we have found one, is it due?
2466
if (CheckTime(pCmd->GetTime(), pCmd->IsStreamTime())) {
2468
// yes it's due - addref it
2476
// block until the advise is signalled
2477
if (WaitForSingleObject(m_evDue, msTimeout) != WAIT_OBJECT_0) {
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.
2491
// returns an AddRef'd object
2494
CCmdQueue::GetCommandDueFor(REFERENCE_TIME rtStream, __out CDeferredCommand**ppCmd)
2496
CAutoLock lock(&m_Lock);
2498
CRefTime tStream(rtStream);
2500
// find the earliest stream and presentation time commands
2501
CDeferredCommand* pStream = NULL;
2502
POSITION pos = m_listStream.GetHeadPosition();
2504
pStream = m_listStream.GetValid(pos);
2506
CDeferredCommand* pPresent = NULL;
2507
pos = m_listPresentation.GetHeadPosition();
2509
pPresent = m_listPresentation.GetValid(pos);
2512
// is there a presentation time that has passed already
2513
if (pPresent && CheckTime(pPresent->GetTime(), FALSE)) {
2519
// is there a stream time command due before this stream time
2520
if (pStream && (pStream->GetTime() <= tStream)) {
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) {
2531
// this stream time will appear at...
2532
tStream += m_StreamTimeOffset;
2535
if (pPresent->GetTime() <= tStream) {
2541
// no commands due yet
2542
return VFW_E_NOT_FOUND;
2545
#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */