2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy
4 * FILE: dll/directx/ksproxy/proxy.cpp
5 * PURPOSE: IKsProxy interface
7 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
11 const GUID IID_IPersistPropertyBag
= {0x37D84F60, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
12 const GUID GUID_NULL
= {0x00000000L
, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
13 const GUID IID_IBDA_DeviceControl
= {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}};
15 Needs IKsClock, IKsNotifyEvent
18 class CKsProxy
: public IBaseFilter
,
20 public IPersistPropertyBag
,
23 public IPersistStream,
24 public ISpecifyPropertyPages,
25 public IReferenceClock,
28 public IKsPropertySet,
29 public IKsClockPropertySet,
30 public IAMFilterMiscFlags,
33 public IKsAggregateControl,
34 public IAMDeviceRemoval
38 typedef std::vector
<IUnknown
*>ProxyPluginVector
;
39 typedef std::vector
<IPin
*> PinVector
;
41 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
43 STDMETHODIMP_(ULONG
) AddRef()
45 InterlockedIncrement(&m_Ref
);
48 STDMETHODIMP_(ULONG
) Release()
50 InterlockedDecrement(&m_Ref
);
59 // IBaseFilter methods
60 HRESULT STDMETHODCALLTYPE
GetClassID(CLSID
*pClassID
);
61 HRESULT STDMETHODCALLTYPE
Stop( void);
62 HRESULT STDMETHODCALLTYPE
Pause( void);
63 HRESULT STDMETHODCALLTYPE
Run(REFERENCE_TIME tStart
);
64 HRESULT STDMETHODCALLTYPE
GetState(DWORD dwMilliSecsTimeout
, FILTER_STATE
*State
);
65 HRESULT STDMETHODCALLTYPE
SetSyncSource(IReferenceClock
*pClock
);
66 HRESULT STDMETHODCALLTYPE
GetSyncSource(IReferenceClock
**pClock
);
67 HRESULT STDMETHODCALLTYPE
EnumPins(IEnumPins
**ppEnum
);
68 HRESULT STDMETHODCALLTYPE
FindPin(LPCWSTR Id
, IPin
**ppPin
);
69 HRESULT STDMETHODCALLTYPE
QueryFilterInfo(FILTER_INFO
*pInfo
);
70 HRESULT STDMETHODCALLTYPE
JoinFilterGraph(IFilterGraph
*pGraph
, LPCWSTR pName
);
71 HRESULT STDMETHODCALLTYPE
QueryVendorInfo(LPWSTR
*pVendorInfo
);
73 //IAMovieSetup methods
74 HRESULT STDMETHODCALLTYPE
Register( void);
75 HRESULT STDMETHODCALLTYPE
Unregister( void);
77 // IPersistPropertyBag methods
78 HRESULT STDMETHODCALLTYPE
InitNew( void);
79 HRESULT STDMETHODCALLTYPE
Load(IPropertyBag
*pPropBag
, IErrorLog
*pErrorLog
);
80 HRESULT STDMETHODCALLTYPE
Save(IPropertyBag
*pPropBag
, BOOL fClearDirty
, BOOL fSaveAllProperties
);
83 HANDLE STDMETHODCALLTYPE
KsGetObjectHandle();
85 CKsProxy() : m_Ref(0), m_pGraph(0), m_ReferenceClock(0), m_FilterState(State_Stopped
), m_hDevice(0), m_Plugins(), m_Pins() {};
89 CloseHandle(m_hDevice
);
92 HRESULT STDMETHODCALLTYPE
GetSupportedSets(LPGUID
* pOutGuid
, PULONG NumGuids
);
93 HRESULT STDMETHODCALLTYPE
LoadProxyPlugins(LPGUID pGuids
, ULONG NumGuids
);
94 HRESULT STDMETHODCALLTYPE
GetNumberOfPins(PULONG NumPins
);
95 HRESULT STDMETHODCALLTYPE
GetPinInstanceCount(ULONG PinId
, PKSPIN_CINSTANCES Instances
);
96 HRESULT STDMETHODCALLTYPE
GetPinDataflow(ULONG PinId
, KSPIN_DATAFLOW
* DataFlow
);
97 HRESULT STDMETHODCALLTYPE
GetPinName(ULONG PinId
, KSPIN_DATAFLOW DataFlow
, ULONG PinCount
, LPWSTR
* OutPinName
);
98 HRESULT STDMETHODCALLTYPE
GetPinCommunication(ULONG PinId
, KSPIN_COMMUNICATION
* Communication
);
99 HRESULT STDMETHODCALLTYPE
CreatePins();
102 IFilterGraph
*m_pGraph
;
103 IReferenceClock
* m_ReferenceClock
;
104 FILTER_STATE m_FilterState
;
106 ProxyPluginVector m_Plugins
;
112 CKsProxy::QueryInterface(
118 if (IsEqualGUID(refiid
, IID_IUnknown
) ||
119 IsEqualGUID(refiid
, IID_IBaseFilter
))
121 *Output
= PVOID(this);
122 reinterpret_cast<IUnknown
*>(*Output
)->AddRef();
125 else if (IsEqualGUID(refiid
, IID_IPersistPropertyBag
))
127 *Output
= (IPersistPropertyBag
*)(this);
128 reinterpret_cast<IPersistPropertyBag
*>(*Output
)->AddRef();
131 if (IsEqualGUID(refiid
, IID_IKsObject
))
133 *Output
= (IKsObject
*)(this);
134 reinterpret_cast<IKsObject
*>(*Output
)->AddRef();
138 for(ULONG Index
= 0; Index
< m_Plugins
.size(); Index
++)
142 HRESULT hr
= m_Plugins
[Index
]->QueryInterface(refiid
, Output
);
147 StringFromCLSID(refiid
, &lpstr
);
148 swprintf(Buffer
, L
"CKsProxy::QueryInterface plugin %lu supports interface %s\n", Index
, lpstr
);
149 OutputDebugStringW(Buffer
);
150 CoTaskMemFree(lpstr
);
156 WCHAR Buffer
[MAX_PATH
];
158 StringFromCLSID(refiid
, &lpstr
);
159 swprintf(Buffer
, L
"CKsProxy::QueryInterface: NoInterface for %s !!!\n", lpstr
);
160 OutputDebugStringW(Buffer
);
161 CoTaskMemFree(lpstr
);
164 return E_NOINTERFACE
;
167 //-------------------------------------------------------------------
168 // IKsObject interface
173 CKsProxy::KsGetObjectHandle()
178 //-------------------------------------------------------------------
179 // IPersistPropertyBag interface
183 CKsProxy::InitNew( void)
190 CKsProxy::GetSupportedSets(
196 ULONG NumProperty
= 0;
197 ULONG NumMethods
= 0;
203 Property
.Set
= GUID_NULL
;
205 Property
.Flags
= KSPROPERTY_TYPE_SETSUPPORT
;
207 KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), NULL
, 0, &NumProperty
);
208 KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_METHOD
, (PVOID
)&Property
, sizeof(KSPROPERTY
), NULL
, 0, &NumMethods
);
209 KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSPROPERTY
), NULL
, 0, &NumEvents
);
211 Length
= NumProperty
+ NumMethods
+ NumEvents
;
213 // allocate guid buffer
214 pGuid
= (LPGUID
)CoTaskMemAlloc(Length
);
218 return E_OUTOFMEMORY
;
221 NumProperty
/= sizeof(GUID
);
222 NumMethods
/= sizeof(GUID
);
223 NumEvents
/= sizeof(GUID
);
225 // get all properties
226 hr
= KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)pGuid
, Length
, &BytesReturned
);
229 CoTaskMemFree(pGuid
);
232 Length
-= BytesReturned
;
237 hr
= KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_METHOD
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)&pGuid
[NumProperty
], Length
, &BytesReturned
);
240 CoTaskMemFree(pGuid
);
243 Length
-= BytesReturned
;
249 hr
= KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_ENABLE_EVENT
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)&pGuid
[NumProperty
+NumMethods
], Length
, &BytesReturned
);
252 CoTaskMemFree(pGuid
);
255 Length
-= BytesReturned
;
260 swprintf(Buffer
, L
"NumProperty %lu NumMethods %lu NumEvents %lu\n", NumProperty
, NumMethods
, NumEvents
);
261 OutputDebugStringW(Buffer
);
265 *NumGuids
= NumProperty
+NumEvents
+NumMethods
;
271 CKsProxy::LoadProxyPlugins(
281 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, L
"SYSTEM\\CurrentControlSet\\Control\\MediaInterfaces", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
283 OutputDebugStringW(L
"CKsProxy::LoadProxyPlugins failed to open MediaInterfaces key\n");
287 // enumerate all sets
288 for(Index
= 0; Index
< NumGuids
; Index
++)
291 hr
= StringFromCLSID(pGuids
[Index
], &pStr
);
295 // now try open class key
296 if (RegOpenKeyExW(hKey
, pStr
, 0, KEY_READ
, &hSubKey
) != ERROR_SUCCESS
)
298 // no plugin for that set exists
304 hr
= CoCreateInstance(pGuids
[Index
], (IBaseFilter
*)this, CLSCTX_INPROC_SERVER
, IID_IUnknown
, (void**)&pUnknown
);
308 m_Plugins
.push_back(pUnknown
);
311 RegCloseKey(hSubKey
);
314 // close media interfaces key
321 CKsProxy::GetNumberOfPins(
328 Property
.Set
= KSPROPSETID_Pin
;
329 Property
.Id
= KSPROPERTY_PIN_CTYPES
;
330 Property
.Flags
= KSPROPERTY_TYPE_GET
;
332 return KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSPROPERTY
), (PVOID
)NumPins
, sizeof(ULONG
), &BytesReturned
);
337 CKsProxy::GetPinInstanceCount(
339 PKSPIN_CINSTANCES Instances
)
345 Property
.Property
.Set
= KSPROPSETID_Pin
;
346 Property
.Property
.Id
= KSPROPERTY_PIN_CINSTANCES
;
347 Property
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
348 Property
.PinId
= PinId
;
349 Property
.Reserved
= 0;
351 return KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSP_PIN
), (PVOID
)Instances
, sizeof(KSPIN_CINSTANCES
), &BytesReturned
);
356 CKsProxy::GetPinCommunication(
358 KSPIN_COMMUNICATION
* Communication
)
364 Property
.Property
.Set
= KSPROPSETID_Pin
;
365 Property
.Property
.Id
= KSPROPERTY_PIN_COMMUNICATION
;
366 Property
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
367 Property
.PinId
= PinId
;
368 Property
.Reserved
= 0;
370 return KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSP_PIN
), (PVOID
)Communication
, sizeof(KSPIN_COMMUNICATION
), &BytesReturned
);
375 CKsProxy::GetPinDataflow(
377 KSPIN_DATAFLOW
* DataFlow
)
383 Property
.Property
.Set
= KSPROPSETID_Pin
;
384 Property
.Property
.Id
= KSPROPERTY_PIN_DATAFLOW
;
385 Property
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
386 Property
.PinId
= PinId
;
387 Property
.Reserved
= 0;
389 return KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSP_PIN
), (PVOID
)DataFlow
, sizeof(KSPIN_DATAFLOW
), &BytesReturned
);
394 CKsProxy::GetPinName(
396 KSPIN_DATAFLOW DataFlow
,
407 Property
.Property
.Set
= KSPROPSETID_Pin
;
408 Property
.Property
.Id
= KSPROPERTY_PIN_NAME
;
409 Property
.Property
.Flags
= KSPROPERTY_TYPE_GET
;
410 Property
.PinId
= PinId
;
411 Property
.Reserved
= 0;
413 // #1 try get it from pin directly
414 hr
= KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSP_PIN
), NULL
, 0, &BytesReturned
);
416 if (hr
== MAKE_HRESULT(SEVERITY_ERROR
, FACILITY_WIN32
, ERROR_MORE_DATA
))
419 PinName
= (LPWSTR
)CoTaskMemAlloc(BytesReturned
);
421 return E_OUTOFMEMORY
;
423 // retry with allocated buffer
424 hr
= KsSynchronousDeviceControl(m_hDevice
, IOCTL_KS_PROPERTY
, (PVOID
)&Property
, sizeof(KSP_PIN
), PinName
, BytesReturned
, &BytesReturned
);
427 *OutPinName
= PinName
;
432 CoTaskMemFree(PinName
);
436 // TODO: retrieve pin name from topology node
439 if (DataFlow
== KSPIN_DATAFLOW_IN
)
441 swprintf(Buffer
, L
"Input%lu", PinCount
);
445 swprintf(Buffer
, L
"Output%lu", PinCount
);
449 PinName
= (LPWSTR
)CoTaskMemAlloc((wcslen(Buffer
)+1) * sizeof(WCHAR
));
451 return E_OUTOFMEMORY
;
454 wcscpy(PinName
, Buffer
);
457 *OutPinName
= PinName
;
464 CKsProxy::CreatePins()
466 ULONG NumPins
, Index
;
467 KSPIN_CINSTANCES Instances
;
468 KSPIN_DATAFLOW DataFlow
;
469 KSPIN_COMMUNICATION Communication
;
477 // get number of pins
478 hr
= GetNumberOfPins(&NumPins
);
482 for(Index
= 0; Index
< NumPins
; Index
++)
484 // query current instance count
485 hr
= GetPinInstanceCount(Index
, &Instances
);
489 // query pin communication;
490 hr
= GetPinCommunication(Index
, &Communication
);
494 if (Instances
.CurrentCount
== Instances
.PossibleCount
)
496 // already maximum reached for this pin
500 // get direction of pin
501 hr
= GetPinDataflow(Index
, &DataFlow
);
505 if (DataFlow
== KSPIN_DATAFLOW_IN
)
506 hr
= GetPinName(Index
, DataFlow
, InputPin
, &PinName
);
508 hr
= GetPinName(Index
, DataFlow
, OutputPin
, &PinName
);
513 // construct the pins
514 if (DataFlow
== KSPIN_DATAFLOW_IN
)
516 hr
= CInputPin_Constructor((IBaseFilter
*)this, PinName
, m_hDevice
, Index
, Communication
, IID_IPin
, (void**)&pPin
);
519 CoTaskMemFree(PinName
);
526 hr
= COutputPin_Constructor((IBaseFilter
*)this, PinName
, IID_IPin
, (void**)&pPin
);
529 CoTaskMemFree(PinName
);
536 m_Pins
.push_back(pPin
);
538 swprintf(Buffer
, L
"Index %lu DataFlow %lu Name %s\n", Index
, DataFlow
, PinName
);
539 OutputDebugStringW(Buffer
);
547 CKsProxy::Load(IPropertyBag
*pPropBag
, IErrorLog
*pErrorLog
)
556 varName
.vt
= VT_BSTR
;
557 hr
= pPropBag
->Read(L
"DevicePath", &varName
, pErrorLog
);
561 swprintf(Buffer
, L
"CKsProxy::Load Read %lx\n", hr
);
562 OutputDebugStringW(Buffer
);
563 return MAKE_HRESULT(SEVERITY_ERROR
, FACILITY_WIN32
, GetLastError());
567 m_hDevice
= CreateFileW(varName
.bstrVal
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_OVERLAPPED
, NULL
);
569 if (m_hDevice
== INVALID_HANDLE_VALUE
)
571 // failed to open device
572 swprintf(Buffer
, L
"CKsProxy:: failed to open device with %lx\n", GetLastError());
573 OutputDebugStringW(Buffer
);
575 return MAKE_HRESULT(SEVERITY_ERROR
, FACILITY_WIN32
, GetLastError());
578 // get all supported sets
579 hr
= GetSupportedSets(&pGuid
, &NumGuids
);
582 CloseHandle(m_hDevice
);
587 // load all proxy plugins
588 hr
= LoadProxyPlugins(pGuid
, NumGuids
);
591 CloseHandle(m_hDevice
);
597 CoTaskMemFree(pGuid
);
599 // now create the input / output pins
607 CKsProxy::Save(IPropertyBag
*pPropBag
, BOOL fClearDirty
, BOOL fSaveAllProperties
)
612 //-------------------------------------------------------------------
613 // IBaseFilter interface
618 CKsProxy::GetClassID(
621 OutputDebugStringW(L
"CKsProxy::GetClassID : NotImplemented\n");
629 OutputDebugStringW(L
"CKsProxy::Stop : NotImplemented\n");
637 OutputDebugStringW(L
"CKsProxy::Pause : NotImplemented\n");
644 REFERENCE_TIME tStart
)
646 OutputDebugStringW(L
"CKsProxy::Run : NotImplemented\n");
653 DWORD dwMilliSecsTimeout
,
656 *State
= m_FilterState
;
662 CKsProxy::SetSyncSource(
663 IReferenceClock
*pClock
)
670 if (m_ReferenceClock
)
672 m_ReferenceClock
->Release();
675 m_ReferenceClock
= pClock
;
681 CKsProxy::GetSyncSource(
682 IReferenceClock
**pClock
)
687 if (m_ReferenceClock
)
688 m_ReferenceClock
->AddRef();
690 *pClock
= m_ReferenceClock
;
699 return CEnumPins_fnConstructor(m_Pins
, IID_IEnumPins
, (void**)ppEnum
);
705 LPCWSTR Id
, IPin
**ppPin
)
713 int ret
= swscanf(Id
, L
"%u", &PinId
);
715 if (!ret
|| ret
== EOF
)
718 return VFW_E_NOT_FOUND
;
721 if (PinId
>= m_Pins
.size() || m_Pins
[PinId
] == NULL
)
724 return VFW_E_NOT_FOUND
;
728 *ppPin
= m_Pins
[PinId
];
729 m_Pins
[PinId
]->AddRef();
737 CKsProxy::QueryFilterInfo(
743 pInfo
->achName
[0] = L
'\0';
744 pInfo
->pGraph
= m_pGraph
;
751 CKsProxy::JoinFilterGraph(
752 IFilterGraph
*pGraph
,
757 // joining filter graph
772 CKsProxy::QueryVendorInfo(
775 OutputDebugStringW(L
"CKsProxy::QueryVendorInfo : NotImplemented\n");
779 //-------------------------------------------------------------------
780 // IAMovieSetup interface
787 OutputDebugStringW(L
"CKsProxy::Register : NotImplemented\n");
793 CKsProxy::Unregister()
795 OutputDebugStringW(L
"CKsProxy::Unregister : NotImplemented\n");
801 CKsProxy_Constructor(
802 IUnknown
* pUnkOuter
,
808 StringFromCLSID(riid
, &pstr
);
809 swprintf(Buffer
, L
"CKsProxy_Constructor pUnkOuter %p riid %s\n", pUnkOuter
, pstr
);
810 OutputDebugStringW(Buffer
);
812 CKsProxy
* handler
= new CKsProxy();
815 return E_OUTOFMEMORY
;
817 if (FAILED(handler
->QueryInterface(riid
, ppv
)))
821 return E_NOINTERFACE
;