3ff6f1f4d91563be817f96da96cdc2fd31c6bdb6
[reactos.git] / reactos / dll / directx / ksproxy / proxy.cpp
1 /*
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
6 *
7 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
8 */
9 #include "precomp.h"
10
11 #ifndef _MSC_VER
12 const GUID IID_IPersistPropertyBag = {0x37D84F60, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
13 const GUID IID_ISpecifyPropertyPages = {0xB196B28B, 0xBAB4, 0x101A, {0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}};
14 const GUID IID_IPersistStream = {0x00000109, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
15 const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
16 #endif
17 const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}};
18 const GUID IID_IKsAggregateControl = {0x7F40EAC0, 0x3947, 0x11D2, {0x87, 0x4E, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
19 const GUID IID_IKsClockPropertySet = {0x5C5CBD84, 0xE755, 0x11D0, {0xAC, 0x18, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
20 const GUID IID_IKsTopology = {0x28F54683, 0x06FD, 0x11D2, {0xB2, 0x7A, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
21 const GUID IID_IKsClock = {0x877E4351, 0x6FEA, 0x11D0, {0xB8, 0x63, 0x00, 0xAA, 0x00, 0xA2, 0x16, 0xA1}};
22 /*
23 Needs IKsClock, IKsNotifyEvent
24 */
25
26 class CKsProxy : public IBaseFilter,
27 public IAMovieSetup,
28 public IPersistPropertyBag,
29 public IKsObject,
30 public IPersistStream,
31 public IAMDeviceRemoval,
32 public ISpecifyPropertyPages,
33 public IReferenceClock,
34 public IMediaSeeking,
35 public IKsPropertySet,
36 public IKsClock,
37 public IKsClockPropertySet,
38 public IAMFilterMiscFlags,
39 public IKsControl,
40 public IKsTopology,
41 public IKsAggregateControl
42
43 {
44 public:
45 typedef std::vector<IUnknown *>ProxyPluginVector;
46 typedef std::vector<IPin *> PinVector;
47
48 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
49
50 STDMETHODIMP_(ULONG) AddRef()
51 {
52 InterlockedIncrement(&m_Ref);
53 return m_Ref;
54 }
55 STDMETHODIMP_(ULONG) Release()
56 {
57 InterlockedDecrement(&m_Ref);
58 if (!m_Ref)
59 {
60 //delete this;
61 return 0;
62 }
63 return m_Ref;
64 }
65
66 // IBaseFilter methods
67 HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
68 HRESULT STDMETHODCALLTYPE Stop( void);
69 HRESULT STDMETHODCALLTYPE Pause( void);
70 HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
71 HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *State);
72 HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
73 HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **pClock);
74 HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
75 HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
76 HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
77 HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
78 HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
79
80 //IReferenceClock
81 HRESULT STDMETHODCALLTYPE GetTime(REFERENCE_TIME *pTime);
82 HRESULT STDMETHODCALLTYPE AdviseTime(REFERENCE_TIME baseTime, REFERENCE_TIME streamTime, HEVENT hEvent, DWORD_PTR *pdwAdviseCookie);
83 HRESULT STDMETHODCALLTYPE AdvisePeriodic(REFERENCE_TIME startTime, REFERENCE_TIME periodTime, HSEMAPHORE hSemaphore, DWORD_PTR *pdwAdviseCookie);
84 HRESULT STDMETHODCALLTYPE Unadvise(DWORD_PTR dwAdviseCookie);
85
86 //IMediaSeeking
87 HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities);
88 HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities);
89 HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat);
90 HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat);
91 HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat);
92 HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat);
93 HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat);
94 HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration);
95 HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop);
96 HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent);
97 HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat);
98 HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags);
99 HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop);
100 HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest);
101 HRESULT STDMETHODCALLTYPE SetRate(double dRate);
102 HRESULT STDMETHODCALLTYPE GetRate(double *pdRate);
103 HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll);
104
105 //IKsPropertySet
106 HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData);
107 HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD *pcbReturned);
108 HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport);
109
110 //IAMFilterMiscFlags
111 ULONG STDMETHODCALLTYPE GetMiscFlags( void);
112
113 //IKsControl
114 HRESULT STDMETHODCALLTYPE KsProperty(PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData, ULONG DataLength, ULONG* BytesReturned);
115 HRESULT STDMETHODCALLTYPE KsMethod(PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData, ULONG DataLength, ULONG* BytesReturned);
116 HRESULT STDMETHODCALLTYPE KsEvent(PKSEVENT Event, ULONG EventLength, LPVOID EventData, ULONG DataLength, ULONG* BytesReturned);
117
118 //IKsTopolology
119 HRESULT STDMETHODCALLTYPE CreateNodeInstance(ULONG NodeId, ULONG Flags, ACCESS_MASK DesiredAccess, IUnknown* UnkOuter, REFGUID InterfaceId, LPVOID* Interface);
120
121 //IKsAggregateControl
122 HRESULT STDMETHODCALLTYPE KsAddAggregate(IN REFGUID AggregateClass);
123 HRESULT STDMETHODCALLTYPE KsRemoveAggregate(REFGUID AggregateClass);
124
125 //IKsClockPropertySet
126 HRESULT STDMETHODCALLTYPE KsGetTime(LONGLONG* Time);
127 HRESULT STDMETHODCALLTYPE KsSetTime(LONGLONG Time);
128 HRESULT STDMETHODCALLTYPE KsGetPhysicalTime(LONGLONG* Time);
129 HRESULT STDMETHODCALLTYPE KsSetPhysicalTime(LONGLONG Time);
130 HRESULT STDMETHODCALLTYPE KsGetCorrelatedTime(KSCORRELATED_TIME* CorrelatedTime);
131 HRESULT STDMETHODCALLTYPE KsSetCorrelatedTime(KSCORRELATED_TIME* CorrelatedTime);
132 HRESULT STDMETHODCALLTYPE KsGetCorrelatedPhysicalTime(KSCORRELATED_TIME* CorrelatedTime);
133 HRESULT STDMETHODCALLTYPE KsSetCorrelatedPhysicalTime(KSCORRELATED_TIME* CorrelatedTime);
134 HRESULT STDMETHODCALLTYPE KsGetResolution(KSRESOLUTION* Resolution);
135 HRESULT STDMETHODCALLTYPE KsGetState(KSSTATE* State);
136
137
138 //IAMovieSetup methods
139 HRESULT STDMETHODCALLTYPE Register( void);
140 HRESULT STDMETHODCALLTYPE Unregister( void);
141
142 // IPersistPropertyBag methods
143 HRESULT STDMETHODCALLTYPE InitNew( void);
144 HRESULT STDMETHODCALLTYPE Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog);
145 HRESULT STDMETHODCALLTYPE Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties);
146
147 // IKsObject
148 HANDLE STDMETHODCALLTYPE KsGetObjectHandle();
149
150 // IKsClock
151 HANDLE STDMETHODCALLTYPE KsGetClockHandle();
152
153 //IAMDeviceRemoval
154 HRESULT STDMETHODCALLTYPE DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink);
155 HRESULT STDMETHODCALLTYPE Reassociate(void);
156 HRESULT STDMETHODCALLTYPE Disassociate( void);
157
158 //IPersistStream
159 HRESULT STDMETHODCALLTYPE IsDirty( void);
160 HRESULT STDMETHODCALLTYPE Load(IStream *pStm);
161 HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty);
162 HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize);
163
164 // ISpecifyPropertyPages
165 HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages);
166
167
168 CKsProxy();
169 ~CKsProxy()
170 {
171 if (m_hDevice)
172 CloseHandle(m_hDevice);
173 };
174
175 HRESULT STDMETHODCALLTYPE GetSupportedSets(LPGUID * pOutGuid, PULONG NumGuids);
176 HRESULT STDMETHODCALLTYPE LoadProxyPlugins(LPGUID pGuids, ULONG NumGuids);
177 HRESULT STDMETHODCALLTYPE GetNumberOfPins(PULONG NumPins);
178 HRESULT STDMETHODCALLTYPE GetPinInstanceCount(ULONG PinId, PKSPIN_CINSTANCES Instances);
179 HRESULT STDMETHODCALLTYPE GetPinDataflow(ULONG PinId, KSPIN_DATAFLOW * DataFlow);
180 HRESULT STDMETHODCALLTYPE GetPinName(ULONG PinId, KSPIN_DATAFLOW DataFlow, ULONG PinCount, LPWSTR * OutPinName);
181 HRESULT STDMETHODCALLTYPE GetPinCommunication(ULONG PinId, KSPIN_COMMUNICATION * Communication);
182 HRESULT STDMETHODCALLTYPE CreatePins();
183 HRESULT STDMETHODCALLTYPE GetMediaSeekingFormats(PKSMULTIPLE_ITEM *FormatList);
184 HRESULT STDMETHODCALLTYPE CreateClockInstance();
185 HRESULT STDMETHODCALLTYPE PerformClockProperty(ULONG PropertyId, ULONG PropertyFlags, PVOID OutputBuffer, ULONG OutputBufferSize);
186 HRESULT STDMETHODCALLTYPE SetPinState(KSSTATE State);
187
188
189 protected:
190 LONG m_Ref;
191 IFilterGraph *m_pGraph;
192 IReferenceClock * m_ReferenceClock;
193 FILTER_STATE m_FilterState;
194 HANDLE m_hDevice;
195 ProxyPluginVector m_Plugins;
196 PinVector m_Pins;
197 LPWSTR m_DevicePath;
198 CLSID m_DeviceInterfaceGUID;
199 HANDLE m_hClock;
200 CRITICAL_SECTION m_Lock;
201 };
202
203 CKsProxy::CKsProxy() : m_Ref(0),
204 m_pGraph(0),
205 m_FilterState(State_Stopped),
206 m_hDevice(0),
207 m_Plugins(),
208 m_Pins(),
209 m_DevicePath(0),
210 m_hClock(0)
211 {
212 m_ReferenceClock = this;
213 InitializeCriticalSection(&m_Lock);
214 }
215
216
217 HRESULT
218 STDMETHODCALLTYPE
219 CKsProxy::QueryInterface(
220 IN REFIID refiid,
221 OUT PVOID* Output)
222 {
223 *Output = NULL;
224
225 if (IsEqualGUID(refiid, IID_IUnknown) ||
226 IsEqualGUID(refiid, IID_IBaseFilter))
227 {
228 *Output = PVOID(this);
229 reinterpret_cast<IUnknown*>(*Output)->AddRef();
230 return NOERROR;
231 }
232 else if (IsEqualGUID(refiid, IID_IPersistPropertyBag))
233 {
234 *Output = (IPersistPropertyBag*)(this);
235 reinterpret_cast<IPersistPropertyBag*>(*Output)->AddRef();
236 return NOERROR;
237 }
238 else if (IsEqualGUID(refiid, IID_IAMDeviceRemoval))
239 {
240 *Output = (IAMDeviceRemoval*)(this);
241 reinterpret_cast<IAMDeviceRemoval*>(*Output)->AddRef();
242 return NOERROR;
243 }
244 else if (IsEqualGUID(refiid, IID_IPersistStream))
245 {
246 *Output = (IPersistStream*)(this);
247 reinterpret_cast<IPersistStream*>(*Output)->AddRef();
248 return NOERROR;
249 }
250 else if (IsEqualGUID(refiid, IID_IPersist))
251 {
252 *Output = (IPersistStream*)(this);
253 reinterpret_cast<IPersist*>(*Output)->AddRef();
254 return NOERROR;
255 }
256 else if (IsEqualGUID(refiid, IID_IKsObject))
257 {
258 *Output = (IKsObject*)(this);
259 reinterpret_cast<IKsObject*>(*Output)->AddRef();
260 return NOERROR;
261 }
262 else if (IsEqualGUID(refiid, IID_IKsClock))
263 {
264 *Output = (IKsClock*)(this);
265 reinterpret_cast<IKsClock*>(*Output)->AddRef();
266 return NOERROR;
267 }
268 else if (IsEqualGUID(refiid, IID_IReferenceClock))
269 {
270 if (!m_hClock)
271 {
272 HRESULT hr = CreateClockInstance();
273 if (FAILED(hr))
274 return hr;
275 }
276
277 *Output = (IReferenceClock*)(this);
278 reinterpret_cast<IReferenceClock*>(*Output)->AddRef();
279 return NOERROR;
280 }
281 else if (IsEqualGUID(refiid, IID_IMediaSeeking))
282 {
283 *Output = (IMediaSeeking*)(this);
284 reinterpret_cast<IMediaSeeking*>(*Output)->AddRef();
285 return NOERROR;
286 }
287 else if (IsEqualGUID(refiid, IID_IAMFilterMiscFlags))
288 {
289 *Output = (IAMFilterMiscFlags*)(this);
290 reinterpret_cast<IAMFilterMiscFlags*>(*Output)->AddRef();
291 return NOERROR;
292 }
293 else if (IsEqualGUID(refiid, IID_IKsControl))
294 {
295 *Output = (IKsControl*)(this);
296 reinterpret_cast<IKsControl*>(*Output)->AddRef();
297 return NOERROR;
298 }
299 else if (IsEqualGUID(refiid, IID_IKsPropertySet))
300 {
301 *Output = (IKsPropertySet*)(this);
302 reinterpret_cast<IKsPropertySet*>(*Output)->AddRef();
303 return NOERROR;
304 }
305 else if (IsEqualGUID(refiid, IID_IKsTopology))
306 {
307 *Output = (IKsTopology*)(this);
308 reinterpret_cast<IKsTopology*>(*Output)->AddRef();
309 return NOERROR;
310 }
311 else if (IsEqualGUID(refiid, IID_IKsAggregateControl))
312 {
313 *Output = (IKsAggregateControl*)(this);
314 reinterpret_cast<IKsAggregateControl*>(*Output)->AddRef();
315 return NOERROR;
316 }
317 else if (IsEqualGUID(refiid, IID_IKsClockPropertySet))
318 {
319 if (!m_hClock)
320 {
321 HRESULT hr = CreateClockInstance();
322 if (FAILED(hr))
323 return hr;
324 }
325
326 *Output = (IKsClockPropertySet*)(this);
327 reinterpret_cast<IKsClockPropertySet*>(*Output)->AddRef();
328 return NOERROR;
329 }
330 else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages))
331 {
332 *Output = (ISpecifyPropertyPages*)(this);
333 reinterpret_cast<ISpecifyPropertyPages*>(*Output)->AddRef();
334 return NOERROR;
335 }
336
337 for(ULONG Index = 0; Index < m_Plugins.size(); Index++)
338 {
339 if (m_Pins[Index])
340 {
341 HRESULT hr = m_Plugins[Index]->QueryInterface(refiid, Output);
342 if (SUCCEEDED(hr))
343 {
344 #ifdef KSPROXY_TRACE
345 WCHAR Buffer[100];
346 LPOLESTR lpstr;
347 StringFromCLSID(refiid, &lpstr);
348 swprintf(Buffer, L"CKsProxy::QueryInterface plugin %lu supports interface %s\n", Index, lpstr);
349 OutputDebugStringW(Buffer);
350 CoTaskMemFree(lpstr);
351 #endif
352 return hr;
353 }
354 }
355 }
356 #ifdef KSPROXY_TRACE
357 WCHAR Buffer[MAX_PATH];
358 LPOLESTR lpstr;
359 StringFromCLSID(refiid, &lpstr);
360 swprintf(Buffer, L"CKsProxy::QueryInterface: NoInterface for %s !!!\n", lpstr);
361 OutputDebugStringW(Buffer);
362 CoTaskMemFree(lpstr);
363 #endif
364
365 return E_NOINTERFACE;
366 }
367
368 //-------------------------------------------------------------------
369 // ISpecifyPropertyPages
370 //
371
372 HRESULT
373 STDMETHODCALLTYPE
374 CKsProxy::GetPages(CAUUID *pPages)
375 {
376 #ifdef KSPROXY_TRACE
377 OutputDebugStringW(L"CKsProxy::GetPages NotImplemented\n");
378 #endif
379
380 if (!pPages)
381 return E_POINTER;
382
383 pPages->cElems = 0;
384 pPages->pElems = NULL;
385
386 return S_OK;
387 }
388
389 //-------------------------------------------------------------------
390 // IKsClockPropertySet interface
391 //
392
393 HRESULT
394 STDMETHODCALLTYPE
395 CKsProxy::CreateClockInstance()
396 {
397 HRESULT hr;
398 HANDLE hPin = INVALID_HANDLE_VALUE;
399 ULONG Index;
400 PIN_DIRECTION PinDir;
401 IKsObject *pObject;
402 KSCLOCK_CREATE ClockCreate;
403
404 // find output pin and handle
405 for(Index = 0; Index < m_Pins.size(); Index++)
406 {
407 //get pin
408 IPin * pin = m_Pins[Index];
409 if (!pin)
410 continue;
411
412 // get direction
413 hr = pin->QueryDirection(&PinDir);
414 if (FAILED(hr))
415 continue;
416
417 // query IKsObject interface
418 hr = pin->QueryInterface(IID_IKsObject, (void**)&pObject);
419 if (FAILED(hr))
420 continue;
421
422
423 // get pin handle
424 hPin = pObject->KsGetObjectHandle();
425
426 //release IKsObject
427 pObject->Release();
428
429 if (hPin != INVALID_HANDLE_VALUE)
430 break;
431 }
432
433 if (hPin == INVALID_HANDLE_VALUE)
434 {
435 // clock can only be instantiated on a pin handle
436 return E_NOTIMPL;
437 }
438
439 if (m_hClock)
440 {
441 // release clock handle
442 CloseHandle(m_hClock);
443 }
444
445 //setup clock create request
446 ClockCreate.CreateFlags = 0;
447
448 // setup clock create request
449 hr = KsCreateClock(hPin, &ClockCreate, &m_hClock); // FIXME KsCreateClock returns NTSTATUS
450 if (SUCCEEDED(hr))
451 {
452 // failed to create clock
453 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
454 }
455
456 return S_OK;
457 }
458
459 HRESULT
460 STDMETHODCALLTYPE
461 CKsProxy::PerformClockProperty(
462 ULONG PropertyId,
463 ULONG PropertyFlags,
464 PVOID OutputBuffer,
465 ULONG OutputBufferSize)
466 {
467 KSPROPERTY Property;
468 HRESULT hr;
469 ULONG BytesReturned;
470
471 if (!m_hClock)
472 {
473 // create clock
474 hr = CreateClockInstance();
475 if (FAILED(hr))
476 return hr;
477 }
478
479 // setup request
480 Property.Set = KSPROPSETID_Clock;
481 Property.Id = PropertyId;
482 Property.Flags = PropertyFlags;
483
484 hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)OutputBuffer, OutputBufferSize, &BytesReturned);
485
486 return hr;
487 }
488
489 HRESULT
490 STDMETHODCALLTYPE
491 CKsProxy::KsGetTime(
492 LONGLONG* Time)
493 {
494 #ifdef KSPROXY_TRACE
495 OutputDebugStringW(L"CKsProxy::KsGetTime\n");
496 #endif
497
498 return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG));
499 }
500
501 HRESULT
502 STDMETHODCALLTYPE
503 CKsProxy::KsSetTime(
504 LONGLONG Time)
505 {
506 #ifdef KSPROXY_TRACE
507 OutputDebugStringW(L"CKsProxy::KsSetTime\n");
508 #endif
509
510 return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG));
511 }
512
513 HRESULT
514 STDMETHODCALLTYPE
515 CKsProxy::KsGetPhysicalTime(
516 LONGLONG* Time)
517 {
518 #ifdef KSPROXY_TRACE
519 OutputDebugStringW(L"CKsProxy::KsGetPhysicalTime\n");
520 #endif
521
522 return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG));
523 }
524
525 HRESULT
526 STDMETHODCALLTYPE
527 CKsProxy::KsSetPhysicalTime(
528 LONGLONG Time)
529 {
530 #ifdef KSPROXY_TRACE
531 OutputDebugStringW(L"CKsProxy::KsSetPhysicalTime\n");
532 #endif
533
534 return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG));
535 }
536
537 HRESULT
538 STDMETHODCALLTYPE
539 CKsProxy::KsGetCorrelatedTime(
540 KSCORRELATED_TIME* CorrelatedTime)
541 {
542 #ifdef KSPROXY_TRACE
543 OutputDebugStringW(L"CKsProxy::KsGetCorrelatedTime\n");
544 #endif
545
546 return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
547 }
548
549 HRESULT
550 STDMETHODCALLTYPE
551 CKsProxy::KsSetCorrelatedTime(
552 KSCORRELATED_TIME* CorrelatedTime)
553 {
554 #ifdef KSPROXY_TRACE
555 OutputDebugStringW(L"CKsProxy::KsSetCorrelatedTime\n");
556 #endif
557 return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
558 }
559
560 HRESULT
561 STDMETHODCALLTYPE
562 CKsProxy::KsGetCorrelatedPhysicalTime(
563 KSCORRELATED_TIME* CorrelatedTime)
564 {
565 #ifdef KSPROXY_TRACE
566 OutputDebugStringW(L"CKsProxy::KsGetCorrelatedPhysicalTime\n");
567 #endif
568 return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
569 }
570
571 HRESULT
572 STDMETHODCALLTYPE
573 CKsProxy::KsSetCorrelatedPhysicalTime(
574 KSCORRELATED_TIME* CorrelatedTime)
575 {
576 #ifdef KSPROXY_TRACE
577 OutputDebugStringW(L"CKsProxy::KsSetCorrelatedPhysicalTime\n");
578 #endif
579
580 return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
581 }
582
583 HRESULT
584 STDMETHODCALLTYPE
585 CKsProxy::KsGetResolution(
586 KSRESOLUTION* Resolution)
587 {
588 #ifdef KSPROXY_TRACE
589 OutputDebugStringW(L"CKsProxy::KsGetResolution\n");
590 #endif
591 return PerformClockProperty(KSPROPERTY_CLOCK_RESOLUTION, KSPROPERTY_TYPE_GET, (PVOID)Resolution, sizeof(KSRESOLUTION));
592 }
593
594 HRESULT
595 STDMETHODCALLTYPE
596 CKsProxy::KsGetState(
597 KSSTATE* State)
598 {
599 #ifdef KSPROXY_TRACE
600 OutputDebugStringW(L"CKsProxy::KsGetState\n");
601 #endif
602 return PerformClockProperty(KSPROPERTY_CLOCK_STATE, KSPROPERTY_TYPE_GET, (PVOID)State, sizeof(KSSTATE));
603 }
604
605 //-------------------------------------------------------------------
606 // IReferenceClock interface
607 //
608 HRESULT
609 STDMETHODCALLTYPE
610 CKsProxy::GetTime(
611 REFERENCE_TIME *pTime)
612 {
613 HRESULT hr;
614 KSPROPERTY Property;
615 ULONG BytesReturned;
616
617 #ifdef KSPROXY_TRACE
618 OutputDebugStringW(L"CKsProxy::GetTime\n");
619 #endif
620
621 if (!pTime)
622 return E_POINTER;
623
624 //
625 //FIXME locks
626 //
627
628 if (!m_hClock)
629 {
630 // create clock
631 hr = CreateClockInstance();
632 if (FAILED(hr))
633 return hr;
634 }
635
636 // setup request
637 Property.Set = KSPROPSETID_Clock;
638 Property.Id = KSPROPERTY_CLOCK_TIME;
639 Property.Flags = KSPROPERTY_TYPE_GET;
640
641 // perform request
642 hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pTime, sizeof(REFERENCE_TIME), &BytesReturned);
643
644 // TODO
645 // increment value
646 //
647
648 return hr;
649 }
650
651 HRESULT
652 STDMETHODCALLTYPE
653 CKsProxy::AdviseTime(
654 REFERENCE_TIME baseTime,
655 REFERENCE_TIME streamTime,
656 HEVENT hEvent,
657 DWORD_PTR *pdwAdviseCookie)
658 {
659 HRESULT hr;
660 KSEVENT Property;
661 ULONG BytesReturned;
662 PKSEVENT_TIME_MARK Event;
663
664 #ifdef KSPROXY_TRACE
665 OutputDebugStringW(L"CKsProxy::AdviseTime\n");
666 #endif
667
668 //
669 //FIXME locks
670 //
671
672 if (!pdwAdviseCookie)
673 return E_POINTER;
674
675 if (!m_hClock)
676 {
677 // create clock
678 hr = CreateClockInstance();
679 if (FAILED(hr))
680 return hr;
681 }
682
683 // allocate event entry
684 Event = (PKSEVENT_TIME_MARK)CoTaskMemAlloc(sizeof(KSEVENT_TIME_MARK));
685 if (Event)
686 {
687 // setup request
688 Property.Set = KSEVENTSETID_Clock;
689 Property.Id = KSEVENT_CLOCK_POSITION_MARK;
690 Property.Flags = KSEVENT_TYPE_ENABLE;
691
692 Event->EventData.NotificationType = KSEVENTF_EVENT_HANDLE;
693 Event->EventData.EventHandle.Event = (HANDLE)hEvent;
694 Event->EventData.Alignment.Alignment[0] = 0;
695 Event->EventData.Alignment.Alignment[1] = 0;
696 Event->MarkTime = baseTime + streamTime;
697
698 // perform request
699 hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_MARK), &BytesReturned);
700 if (SUCCEEDED(hr))
701 {
702 // store event handle
703 *pdwAdviseCookie = (DWORD_PTR)Event;
704 }
705 else
706 {
707 // failed to enable event
708 CoTaskMemFree(Event);
709 }
710 }
711 else
712 {
713 hr = E_OUTOFMEMORY;
714 }
715
716 return hr;
717 }
718
719 HRESULT
720 STDMETHODCALLTYPE
721 CKsProxy::AdvisePeriodic(
722 REFERENCE_TIME startTime,
723 REFERENCE_TIME periodTime,
724 HSEMAPHORE hSemaphore,
725 DWORD_PTR *pdwAdviseCookie)
726 {
727 HRESULT hr;
728 KSEVENT Property;
729 ULONG BytesReturned;
730 PKSEVENT_TIME_INTERVAL Event;
731
732 #ifdef KSPROXY_TRACE
733 OutputDebugStringW(L"CKsProxy::AdvisePeriodic\n");
734 #endif
735
736 //
737 //FIXME locks
738 //
739
740 if (!pdwAdviseCookie)
741 return E_POINTER;
742
743 if (!m_hClock)
744 {
745 // create clock
746 hr = CreateClockInstance();
747 if (FAILED(hr))
748 return hr;
749 }
750
751 // allocate event entry
752 Event = (PKSEVENT_TIME_INTERVAL)CoTaskMemAlloc(sizeof(KSEVENT_TIME_INTERVAL));
753 if (Event)
754 {
755 // setup request
756 Property.Set = KSEVENTSETID_Clock;
757 Property.Id = KSEVENT_CLOCK_INTERVAL_MARK;
758 Property.Flags = KSEVENT_TYPE_ENABLE;
759
760 Event->EventData.NotificationType = KSEVENTF_SEMAPHORE_HANDLE;
761 Event->EventData.SemaphoreHandle.Semaphore = (HANDLE)hSemaphore;
762 Event->EventData.SemaphoreHandle.Reserved = 0;
763 Event->EventData.SemaphoreHandle.Adjustment = 1;
764 Event->TimeBase = startTime;
765 Event->Interval = periodTime;
766
767 // perform request
768 hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_INTERVAL), &BytesReturned);
769 if (SUCCEEDED(hr))
770 {
771 // store event handle
772 *pdwAdviseCookie = (DWORD_PTR)Event;
773 }
774 else
775 {
776 // failed to enable event
777 CoTaskMemFree(Event);
778 }
779 }
780 else
781 {
782 hr = E_OUTOFMEMORY;
783 }
784
785 return hr;
786 }
787
788 HRESULT
789 STDMETHODCALLTYPE
790 CKsProxy::Unadvise(
791 DWORD_PTR dwAdviseCookie)
792 {
793 HRESULT hr;
794 ULONG BytesReturned;
795
796 #ifdef KSPROXY_TRACE
797 OutputDebugStringW(L"CKsProxy::Unadvise\n");
798 #endif
799
800 if (m_hClock)
801 {
802 //lets disable the event
803 hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_DISABLE_EVENT, (PVOID)dwAdviseCookie, sizeof(KSEVENTDATA), 0, 0, &BytesReturned);
804 if (SUCCEEDED(hr))
805 {
806 // lets free event data
807 CoTaskMemFree((LPVOID)dwAdviseCookie);
808 }
809 }
810 else
811 {
812 // no clock available
813 hr = E_FAIL;
814 }
815
816 return hr;
817 }
818
819 //-------------------------------------------------------------------
820 // IMediaSeeking interface
821 //
822 HRESULT
823 STDMETHODCALLTYPE
824 CKsProxy::GetCapabilities(
825 DWORD *pCapabilities)
826 {
827 KSPROPERTY Property;
828 ULONG BytesReturned, Index;
829 HRESULT hr = S_OK;
830 DWORD TempCaps;
831
832 Property.Set = KSPROPSETID_MediaSeeking;
833 Property.Id = KSPROPERTY_MEDIASEEKING_CAPABILITIES;
834 Property.Flags = KSPROPERTY_TYPE_GET;
835
836 #ifdef KSPROXY_TRACE
837 OutputDebugStringW(L"CKsProxy::GetCapabilities\n");
838 #endif
839
840
841 if (!pCapabilities)
842 return E_POINTER;
843
844
845 *pCapabilities = (KS_SEEKING_CanSeekAbsolute | KS_SEEKING_CanSeekForwards | KS_SEEKING_CanSeekBackwards | KS_SEEKING_CanGetCurrentPos |
846 KS_SEEKING_CanGetStopPos | KS_SEEKING_CanGetDuration | KS_SEEKING_CanPlayBackwards);
847
848 KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pCapabilities, sizeof(KS_SEEKING_CAPABILITIES), &BytesReturned);
849 // check if plugins support it
850 for(Index = 0; Index < m_Plugins.size(); Index++)
851 {
852 // get plugin
853 IUnknown * Plugin = m_Plugins[Index];
854
855 if (!Plugin)
856 continue;
857
858 // query for IMediaSeeking interface
859 IMediaSeeking *pSeek = NULL;
860 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
861 if (FAILED(hr))
862 {
863 *pCapabilities = 0;
864 return hr;
865 }
866
867 TempCaps = 0;
868 // set time format
869 hr = pSeek->GetCapabilities(&TempCaps);
870 if (SUCCEEDED(hr))
871 {
872 // and with supported flags
873 *pCapabilities = (*pCapabilities & TempCaps);
874 }
875 // release IMediaSeeking interface
876 pSeek->Release();
877 }
878 return hr;
879 }
880
881 HRESULT
882 STDMETHODCALLTYPE
883 CKsProxy::CheckCapabilities(
884 DWORD *pCapabilities)
885 {
886 DWORD Capabilities;
887 HRESULT hr;
888
889 #ifdef KSPROXY_TRACE
890 OutputDebugStringW(L"CKsProxy::CheckCapabilities\n");
891 #endif
892
893 if (!pCapabilities)
894 return E_POINTER;
895
896 if (!*pCapabilities)
897 return E_FAIL;
898
899 hr = GetCapabilities(&Capabilities);
900 if (SUCCEEDED(hr))
901 {
902 if ((Capabilities | *pCapabilities) == Capabilities)
903 {
904 // all present
905 return S_OK;
906 }
907
908 Capabilities = (Capabilities & *pCapabilities);
909 if (Capabilities)
910 {
911 // not all present
912 *pCapabilities = Capabilities;
913 return S_FALSE;
914 }
915 // no capabilities are present
916 return E_FAIL;
917 }
918
919 return hr;
920 }
921
922 HRESULT
923 STDMETHODCALLTYPE
924 CKsProxy::GetMediaSeekingFormats(
925 PKSMULTIPLE_ITEM *FormatList)
926 {
927 KSPROPERTY Property;
928 HRESULT hr;
929 ULONG BytesReturned;
930
931 Property.Set = KSPROPSETID_MediaSeeking;
932 Property.Id = KSPROPERTY_MEDIASEEKING_FORMATS;
933 Property.Flags = KSPROPERTY_TYPE_GET;
934
935 // query for format size list
936 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
937
938 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA))
939 {
940 // allocate format list
941 *FormatList = (PKSMULTIPLE_ITEM)CoTaskMemAlloc(BytesReturned);
942 if (!*FormatList)
943 {
944 // not enough memory
945 return E_OUTOFMEMORY;
946 }
947
948 // get format list
949 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)*FormatList, BytesReturned, &BytesReturned);
950 if (FAILED(hr))
951 {
952 // failed to query format list
953 CoTaskMemFree(FormatList);
954 }
955 }
956 return hr;
957 }
958
959 HRESULT
960 STDMETHODCALLTYPE
961 CKsProxy::IsFormatSupported(
962 const GUID *pFormat)
963 {
964 PKSMULTIPLE_ITEM FormatList;
965 LPGUID pGuid;
966 ULONG Index;
967 HRESULT hr = S_FALSE;
968
969 #ifdef KSPROXY_TRACE
970 WCHAR Buffer[100];
971 LPOLESTR pstr;
972 StringFromCLSID(*pFormat, &pstr);
973 swprintf(Buffer, L"CKsProxy::IsFormatSupported %s\n",pstr);
974 OutputDebugStringW(Buffer);
975 #endif
976
977 if (!pFormat)
978 return E_POINTER;
979
980 // get media formats
981 hr = GetMediaSeekingFormats(&FormatList);
982 if (SUCCEEDED(hr))
983 {
984 #ifdef KSPROXY_TRACE
985 swprintf(Buffer, L"CKsProxy::IsFormatSupported NumFormat %lu\n",FormatList->Count);
986 OutputDebugStringW(Buffer);
987 #endif
988
989 //iterate through format list
990 pGuid = (LPGUID)(FormatList + 1);
991 for(Index = 0; Index < FormatList->Count; Index++)
992 {
993 if (IsEqualGUID(*pGuid, *pFormat))
994 {
995 CoTaskMemFree(FormatList);
996 return S_OK;
997 }
998 pGuid++;
999 }
1000 // free format list
1001 CoTaskMemFree(FormatList);
1002 }
1003
1004 // check if all plugins support it
1005 for(Index = 0; Index < m_Plugins.size(); Index++)
1006 {
1007 // get plugin
1008 IUnknown * Plugin = m_Plugins[Index];
1009
1010 if (!Plugin)
1011 continue;
1012
1013 // query for IMediaSeeking interface
1014 IMediaSeeking *pSeek = NULL;
1015 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1016 if (FAILED(hr))
1017 {
1018 // plugin does not support interface
1019 hr = S_FALSE;
1020 #ifdef KSPROXY_TRACE
1021 OutputDebugStringW(L"CKsProxy::IsFormatSupported plugin does not support IMediaSeeking interface\n");
1022 #endif
1023 break;
1024 }
1025
1026 // query if it is supported
1027 hr = pSeek->IsFormatSupported(pFormat);
1028 // release interface
1029 pSeek->Release();
1030
1031 if (FAILED(hr) || hr == S_FALSE)
1032 break;
1033 }
1034
1035 return hr;
1036 }
1037
1038 HRESULT
1039 STDMETHODCALLTYPE
1040 CKsProxy::QueryPreferredFormat(
1041 GUID *pFormat)
1042 {
1043 PKSMULTIPLE_ITEM FormatList;
1044 HRESULT hr;
1045 ULONG Index;
1046
1047 #ifdef KSPROXY_TRACE
1048 OutputDebugStringW(L"CKsProxy::QueryPreferredFormat\n");
1049 #endif
1050
1051 if (!pFormat)
1052 return E_POINTER;
1053
1054 hr = GetMediaSeekingFormats(&FormatList);
1055 if (SUCCEEDED(hr))
1056 {
1057 if (FormatList->Count)
1058 {
1059 CopyMemory(pFormat, (FormatList + 1), sizeof(GUID));
1060 CoTaskMemFree(FormatList);
1061 return S_OK;
1062 }
1063 CoTaskMemFree(FormatList);
1064 }
1065 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1066 {
1067 // check if plugins support it
1068 for(Index = 0; Index < m_Plugins.size(); Index++)
1069 {
1070 // get plugin
1071 IUnknown * Plugin = m_Plugins[Index];
1072
1073 if (!Plugin)
1074 continue;
1075
1076 // query for IMediaSeeking interface
1077 IMediaSeeking *pSeek = NULL;
1078 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1079 if (SUCCEEDED(hr))
1080 {
1081 // get preferred time format
1082 hr = pSeek->QueryPreferredFormat(pFormat);
1083 // release IMediaSeeking interface
1084 pSeek->Release();
1085
1086 if (hr != S_FALSE)
1087 return hr;
1088 }
1089 }
1090 hr = S_FALSE;
1091 }
1092
1093 return hr;
1094 }
1095
1096 HRESULT
1097 STDMETHODCALLTYPE
1098 CKsProxy::GetTimeFormat(
1099 GUID *pFormat)
1100 {
1101 KSPROPERTY Property;
1102 ULONG BytesReturned, Index;
1103 HRESULT hr;
1104
1105 Property.Set = KSPROPSETID_MediaSeeking;
1106 Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT;
1107 Property.Flags = KSPROPERTY_TYPE_GET;
1108
1109 #ifdef KSPROXY_TRACE
1110 OutputDebugStringW(L"CKsProxy::GetTimeFormat\n");
1111 #endif
1112
1113 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned);
1114 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1115 {
1116 // check if plugins support it
1117 for(Index = 0; Index < m_Plugins.size(); Index++)
1118 {
1119 hr = E_NOTIMPL;
1120 // get plugin
1121 IUnknown * Plugin = m_Plugins[Index];
1122
1123 if (!Plugin)
1124 continue;
1125
1126 // query for IMediaSeeking interface
1127 IMediaSeeking *pSeek = NULL;
1128 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1129 if (SUCCEEDED(hr))
1130 {
1131 // set time format
1132 hr = pSeek->GetTimeFormat(pFormat);
1133 // release IMediaSeeking interface
1134 pSeek->Release();
1135
1136 if (hr != S_FALSE)
1137 break;
1138 }
1139 }
1140 }
1141 return hr;
1142 }
1143
1144 HRESULT
1145 STDMETHODCALLTYPE
1146 CKsProxy::IsUsingTimeFormat(
1147 const GUID *pFormat)
1148 {
1149 GUID Format;
1150
1151 #ifdef KSPROXY_TRACE
1152 OutputDebugStringW(L"CKsProxy::IsUsingTimeFormat\n");
1153 #endif
1154
1155 if (FAILED(QueryPreferredFormat(&Format)))
1156 return S_FALSE;
1157
1158 if (IsEqualGUID(Format, *pFormat))
1159 return S_OK;
1160 else
1161 return S_FALSE;
1162 }
1163
1164 HRESULT
1165 STDMETHODCALLTYPE
1166 CKsProxy::SetTimeFormat(
1167 const GUID *pFormat)
1168 {
1169 KSPROPERTY Property;
1170 ULONG BytesReturned, Index;
1171 HRESULT hr;
1172
1173 Property.Set = KSPROPSETID_MediaSeeking;
1174 Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT;
1175 Property.Flags = KSPROPERTY_TYPE_SET;
1176
1177 #ifdef KSPROXY_TRACE
1178 OutputDebugStringW(L"CKsProxy::SetTimeFormat\n");
1179 #endif
1180
1181 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned);
1182 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1183 {
1184 // check if plugins support it
1185 for(Index = 0; Index < m_Plugins.size(); Index++)
1186 {
1187 hr = E_NOTIMPL;
1188 // get plugin
1189 IUnknown * Plugin = m_Plugins[Index];
1190
1191 if (!Plugin)
1192 continue;
1193
1194 // query for IMediaSeeking interface
1195 IMediaSeeking *pSeek = NULL;
1196 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1197 if (FAILED(hr))
1198 {
1199 //not supported
1200 break;
1201 }
1202 // set time format
1203 hr = pSeek->SetTimeFormat(pFormat);
1204 // release IMediaSeeking interface
1205 pSeek->Release();
1206
1207 if (FAILED(hr))
1208 break;
1209 }
1210 }
1211 return hr;
1212 }
1213
1214 HRESULT
1215 STDMETHODCALLTYPE
1216 CKsProxy::GetDuration(
1217 LONGLONG *pDuration)
1218 {
1219 KSPROPERTY Property;
1220 ULONG BytesReturned, Index;
1221 HRESULT hr;
1222
1223 Property.Set = KSPROPSETID_MediaSeeking;
1224 Property.Id = KSPROPERTY_MEDIASEEKING_DURATION;
1225 Property.Flags = KSPROPERTY_TYPE_GET;
1226
1227 #ifdef KSPROXY_TRACE
1228 OutputDebugStringW(L"CKsProxy::GetDuration\n");
1229 #endif
1230
1231 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pDuration, sizeof(LONGLONG), &BytesReturned);
1232 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1233 {
1234 // check if plugins support it
1235 for(Index = 0; Index < m_Plugins.size(); Index++)
1236 {
1237 hr = E_NOTIMPL;
1238 // get plugin
1239 IUnknown * Plugin = m_Plugins[Index];
1240
1241 if (!Plugin)
1242 continue;
1243
1244 // query for IMediaSeeking interface
1245 IMediaSeeking *pSeek = NULL;
1246 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1247 if (SUCCEEDED(hr))
1248 {
1249 // get duration
1250 hr = pSeek->GetStopPosition(pDuration);
1251 // release IMediaSeeking interface
1252 pSeek->Release();
1253
1254 if (hr != S_FALSE) // plugin implements it
1255 break;
1256 }
1257 }
1258 }
1259 return hr;
1260 }
1261
1262 HRESULT
1263 STDMETHODCALLTYPE
1264 CKsProxy::GetStopPosition(
1265 LONGLONG *pStop)
1266 {
1267 KSPROPERTY Property;
1268 ULONG BytesReturned, Index;
1269 HRESULT hr;
1270
1271 Property.Set = KSPROPSETID_MediaSeeking;
1272 Property.Id = KSPROPERTY_MEDIASEEKING_STOPPOSITION;
1273 Property.Flags = KSPROPERTY_TYPE_GET;
1274
1275 #ifdef KSPROXY_TRACE
1276 OutputDebugStringW(L"CKsProxy::GetStopPosition\n");
1277 #endif
1278
1279 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pStop, sizeof(LONGLONG), &BytesReturned);
1280 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1281 {
1282 // check if plugins support it
1283 for(Index = 0; Index < m_Plugins.size(); Index++)
1284 {
1285 hr = E_NOTIMPL;
1286 // get plugin
1287 IUnknown * Plugin = m_Plugins[Index];
1288
1289 if (!Plugin)
1290 continue;
1291
1292 // query for IMediaSeeking interface
1293 IMediaSeeking *pSeek = NULL;
1294 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1295 if (SUCCEEDED(hr))
1296 {
1297 // get stop position
1298 hr = pSeek->GetStopPosition(pStop);
1299 // release IMediaSeeking interface
1300 pSeek->Release();
1301
1302 if (hr != S_FALSE) // plugin implements it
1303 break;
1304 }
1305 }
1306 }
1307 return hr;
1308 }
1309
1310 HRESULT
1311 STDMETHODCALLTYPE
1312 CKsProxy::GetCurrentPosition(
1313 LONGLONG *pCurrent)
1314 {
1315 KSPROPERTY Property;
1316 ULONG BytesReturned, Index;
1317 HRESULT hr;
1318
1319 Property.Set = KSPROPSETID_MediaSeeking;
1320 Property.Id = KSPROPERTY_MEDIASEEKING_POSITION;
1321 Property.Flags = KSPROPERTY_TYPE_GET;
1322
1323 #ifdef KSPROXY_TRACE
1324 OutputDebugStringW(L"CKsProxy::GetCurrentPosition\n");
1325 #endif
1326
1327 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pCurrent, sizeof(LONGLONG), &BytesReturned);
1328 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1329 {
1330 // check if plugins support it
1331 for(Index = 0; Index < m_Plugins.size(); Index++)
1332 {
1333 hr = E_NOTIMPL;
1334 // get plugin
1335 IUnknown * Plugin = m_Plugins[Index];
1336
1337 if (!Plugin)
1338 continue;
1339
1340 // query for IMediaSeeking interface
1341 IMediaSeeking *pSeek = NULL;
1342 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1343 if (SUCCEEDED(hr))
1344 {
1345 // get current position
1346 hr = pSeek->GetCurrentPosition(pCurrent);
1347 // release IMediaSeeking interface
1348 pSeek->Release();
1349
1350 if (hr != S_FALSE) // plugin implements it
1351 break;
1352 }
1353 }
1354 }
1355 return hr;
1356 }
1357
1358 HRESULT
1359 STDMETHODCALLTYPE
1360 CKsProxy::ConvertTimeFormat(
1361 LONGLONG *pTarget,
1362 const GUID *pTargetFormat,
1363 LONGLONG Source,
1364 const GUID *pSourceFormat)
1365 {
1366 KSP_TIMEFORMAT Property;
1367 ULONG BytesReturned, Index;
1368 GUID SourceFormat, TargetFormat;
1369 HRESULT hr;
1370
1371 Property.Property.Set = KSPROPSETID_MediaSeeking;
1372 Property.Property.Id = KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT;
1373 Property.Property.Flags = KSPROPERTY_TYPE_GET;
1374
1375 #ifdef KSPROXY_TRACE
1376 OutputDebugStringW(L"CKsProxy::ConvertTimeFormat\n");
1377 #endif
1378
1379 if (!pTargetFormat)
1380 {
1381 // get current format
1382 hr = GetTimeFormat(&TargetFormat);
1383 if (FAILED(hr))
1384 return hr;
1385
1386 pTargetFormat = &TargetFormat;
1387 }
1388
1389 if (!pSourceFormat)
1390 {
1391 // get current format
1392 hr = GetTimeFormat(&SourceFormat);
1393 if (FAILED(hr))
1394 return hr;
1395
1396 pSourceFormat = &SourceFormat;
1397 }
1398
1399 Property.SourceFormat = *pSourceFormat;
1400 Property.TargetFormat = *pTargetFormat;
1401 Property.Time = Source;
1402
1403
1404 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_TIMEFORMAT), (PVOID)pTarget, sizeof(LONGLONG), &BytesReturned);
1405 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1406 {
1407 //default error
1408 hr = E_NOTIMPL;
1409
1410 // check if plugins support it
1411 for(Index = 0; Index < m_Plugins.size(); Index++)
1412 {
1413 // get plugin
1414 IUnknown * Plugin = m_Plugins[Index];
1415
1416 if (!Plugin)
1417 continue;
1418
1419 // query for IMediaSeeking interface
1420 IMediaSeeking *pSeek = NULL;
1421 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1422 if (SUCCEEDED(hr))
1423 {
1424 // convert time format
1425 hr = pSeek->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
1426 // release IMediaSeeking interface
1427 pSeek->Release();
1428
1429 if (hr != S_FALSE) // plugin implements it
1430 break;
1431 }
1432 }
1433 }
1434
1435 return hr;
1436 }
1437
1438 HRESULT
1439 STDMETHODCALLTYPE
1440 CKsProxy::SetPositions(
1441 LONGLONG *pCurrent,
1442 DWORD dwCurrentFlags,
1443 LONGLONG *pStop,
1444 DWORD dwStopFlags)
1445 {
1446 KSPROPERTY Property;
1447 KSPROPERTY_POSITIONS Positions;
1448 ULONG BytesReturned, Index;
1449 HRESULT hr;
1450
1451 Property.Set = KSPROPSETID_MediaSeeking;
1452 Property.Id = KSPROPERTY_MEDIASEEKING_POSITIONS;
1453 Property.Flags = KSPROPERTY_TYPE_SET;
1454
1455 Positions.Current = *pCurrent;
1456 Positions.CurrentFlags = (KS_SEEKING_FLAGS)dwCurrentFlags;
1457 Positions.Stop = *pStop;
1458 Positions.StopFlags = (KS_SEEKING_FLAGS)dwStopFlags;
1459
1460 #ifdef KSPROXY_TRACE
1461 OutputDebugStringW(L"CKsProxy::SetPositions\n");
1462 #endif
1463
1464 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Positions, sizeof(KSPROPERTY_POSITIONS), &BytesReturned);
1465 if (SUCCEEDED(hr))
1466 {
1467 if (dwCurrentFlags & AM_SEEKING_ReturnTime)
1468 {
1469 // retrieve current position
1470 hr = GetCurrentPosition(pCurrent);
1471 }
1472
1473 if (SUCCEEDED(hr))
1474 {
1475 if (dwStopFlags & AM_SEEKING_ReturnTime)
1476 {
1477 // retrieve current position
1478 hr = GetStopPosition(pStop);
1479 }
1480 }
1481 return hr;
1482 }
1483 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1484 {
1485 hr = E_NOTIMPL;
1486
1487 // check if plugins support it
1488 for(Index = 0; Index < m_Plugins.size(); Index++)
1489 {
1490 // get plugin
1491 IUnknown * Plugin = m_Plugins[Index];
1492
1493 if (!Plugin)
1494 continue;
1495
1496 // query for IMediaSeeking interface
1497 IMediaSeeking *pSeek = NULL;
1498 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1499 if (SUCCEEDED(hr))
1500 {
1501 // set positions
1502 hr = pSeek->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
1503 // release IMediaSeeking interface
1504 pSeek->Release();
1505
1506 if (FAILED(hr))
1507 break;
1508 }
1509 }
1510 }
1511
1512 return hr;
1513 }
1514
1515 HRESULT
1516 STDMETHODCALLTYPE
1517 CKsProxy::GetPositions(
1518 LONGLONG *pCurrent,
1519 LONGLONG *pStop)
1520 {
1521 HRESULT hr;
1522
1523 #ifdef KSPROXY_TRACE
1524 OutputDebugStringW(L"CKsProxy::GetPositions\n");
1525 #endif
1526
1527 hr = GetCurrentPosition(pCurrent);
1528 if (SUCCEEDED(hr))
1529 hr = GetStopPosition(pStop);
1530
1531 return hr;
1532 }
1533
1534 HRESULT
1535 STDMETHODCALLTYPE
1536 CKsProxy::GetAvailable(
1537 LONGLONG *pEarliest,
1538 LONGLONG *pLatest)
1539 {
1540 KSPROPERTY Property;
1541 KSPROPERTY_MEDIAAVAILABLE Media;
1542 ULONG BytesReturned, Index;
1543 HRESULT hr;
1544
1545 Property.Set = KSPROPSETID_MediaSeeking;
1546 Property.Id = KSPROPERTY_MEDIASEEKING_AVAILABLE;
1547 Property.Flags = KSPROPERTY_TYPE_GET;
1548
1549 #ifdef KSPROXY_TRACE
1550 OutputDebugStringW(L"CKsProxy::GetAvailable\n");
1551 #endif
1552
1553 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Media, sizeof(KSPROPERTY_MEDIAAVAILABLE), &BytesReturned);
1554 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1555 {
1556 // check if plugins support it
1557 for(Index = 0; Index < m_Plugins.size(); Index++)
1558 {
1559 hr = E_NOTIMPL;
1560 // get plugin
1561 IUnknown * Plugin = m_Plugins[Index];
1562
1563 if (!Plugin)
1564 continue;
1565
1566 // query for IMediaSeeking interface
1567 IMediaSeeking *pSeek = NULL;
1568 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1569 if (SUCCEEDED(hr))
1570 {
1571 // delegate call
1572 hr = pSeek->GetAvailable(pEarliest, pLatest);
1573 // release IMediaSeeking interface
1574 pSeek->Release();
1575
1576 if (hr != S_FALSE) // plugin implements it
1577 break;
1578 }
1579 }
1580 }
1581 else if (SUCCEEDED(hr))
1582 {
1583 *pEarliest = Media.Earliest;
1584 *pLatest = Media.Latest;
1585 }
1586
1587 return hr;
1588 }
1589
1590 HRESULT
1591 STDMETHODCALLTYPE
1592 CKsProxy::SetRate(
1593 double dRate)
1594 {
1595 #ifdef KSPROXY_TRACE
1596 OutputDebugStringW(L"CKsProxy::SetRate\n");
1597 #endif
1598 return E_NOTIMPL;
1599 }
1600
1601 HRESULT
1602 STDMETHODCALLTYPE
1603 CKsProxy::GetRate(
1604 double *pdRate)
1605 {
1606 #ifdef KSPROXY_TRACE
1607 OutputDebugStringW(L"CKsProxy::GetRate\n");
1608 #endif
1609 return E_NOTIMPL;
1610 }
1611
1612 HRESULT
1613 STDMETHODCALLTYPE
1614 CKsProxy::GetPreroll(
1615 LONGLONG *pllPreroll)
1616 {
1617 KSPROPERTY Property;
1618 ULONG BytesReturned, Index;
1619 HRESULT hr;
1620
1621 Property.Set = KSPROPSETID_MediaSeeking;
1622 Property.Id = KSPROPERTY_MEDIASEEKING_PREROLL;
1623 Property.Flags = KSPROPERTY_TYPE_GET;
1624
1625 #ifdef KSPROXY_TRACE
1626 OutputDebugStringW(L"CKsProxy::GetPreroll\n");
1627 #endif
1628
1629 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pllPreroll, sizeof(LONGLONG), &BytesReturned);
1630 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
1631 {
1632 // check if all plugins support it
1633 for(Index = 0; Index < m_Plugins.size(); Index++)
1634 {
1635 // get plugin
1636 IUnknown * Plugin = m_Plugins[Index];
1637
1638 if (!Plugin)
1639 continue;
1640
1641 // query for IMediaSeeking interface
1642 IMediaSeeking *pSeek = NULL;
1643 hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
1644 if (SUCCEEDED(hr))
1645 {
1646 // get preroll
1647 hr = pSeek->GetPreroll(pllPreroll);
1648 // release IMediaSeeking interface
1649 pSeek->Release();
1650
1651 if (hr != S_FALSE) // plugin implements it
1652 break;
1653 }
1654 }
1655 hr = E_NOTIMPL;
1656 }
1657 return hr;
1658 }
1659
1660 //-------------------------------------------------------------------
1661 // IAMFilterMiscFlags interface
1662 //
1663
1664 ULONG
1665 STDMETHODCALLTYPE
1666 CKsProxy::GetMiscFlags()
1667 {
1668 ULONG Index;
1669 ULONG Flags = 0;
1670 HRESULT hr;
1671 PIN_DIRECTION PinDirection;
1672 KSPIN_COMMUNICATION Communication;
1673
1674
1675 for(Index = 0; Index < m_Pins.size(); Index++)
1676 {
1677 // get current pin
1678 IPin * pin = m_Pins[Index];
1679 // query direction
1680 hr = pin->QueryDirection(&PinDirection);
1681 if (SUCCEEDED(hr))
1682 {
1683 if (PinDirection == PINDIR_INPUT)
1684 {
1685 if (SUCCEEDED(GetPinCommunication(Index, //FIXME verify PinId
1686 &Communication)))
1687 {
1688 if (Communication != KSPIN_COMMUNICATION_NONE && Communication != KSPIN_COMMUNICATION_BRIDGE)
1689 {
1690 Flags |= AM_FILTER_MISC_FLAGS_IS_SOURCE;
1691 }
1692 }
1693 }
1694 }
1695 }
1696
1697 #ifdef KSPROXY_TRACE
1698 WCHAR Buffer[100];
1699 swprintf(Buffer, L"CKsProxy::GetMiscFlags stub Flags %x\n", Flags);
1700 OutputDebugStringW(Buffer);
1701 #endif
1702
1703 return Flags;
1704 }
1705
1706 //-------------------------------------------------------------------
1707 // IKsControl
1708 //
1709 HRESULT
1710 STDMETHODCALLTYPE
1711 CKsProxy::KsProperty(
1712 PKSPROPERTY Property,
1713 ULONG PropertyLength,
1714 LPVOID PropertyData,
1715 ULONG DataLength,
1716 ULONG* BytesReturned)
1717 {
1718 #ifdef KSPROXY_TRACE
1719 OutputDebugStringW(L"CKsProxy::KsProperty\n");
1720 #endif
1721
1722 assert(m_hDevice != 0);
1723 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned);
1724 }
1725
1726 HRESULT
1727 STDMETHODCALLTYPE
1728 CKsProxy::KsMethod(
1729 PKSMETHOD Method,
1730 ULONG MethodLength,
1731 LPVOID MethodData,
1732 ULONG DataLength,
1733 ULONG* BytesReturned)
1734 {
1735 #ifdef KSPROXY_TRACE
1736 OutputDebugStringW(L"CKsProxy::KsMethod\n");
1737 #endif
1738
1739 assert(m_hDevice != 0);
1740 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned);
1741 }
1742
1743 HRESULT
1744 STDMETHODCALLTYPE
1745 CKsProxy::KsEvent(
1746 PKSEVENT Event,
1747 ULONG EventLength,
1748 LPVOID EventData,
1749 ULONG DataLength,
1750 ULONG* BytesReturned)
1751 {
1752 #ifdef KSPROXY_TRACE
1753 OutputDebugStringW(L"CKsProxy::KsEvent\n");
1754 #endif
1755
1756 assert(m_hDevice != 0);
1757 if (EventLength)
1758 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned);
1759 else
1760 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_DISABLE_EVENT, (PVOID)Event, EventLength, NULL, 0, BytesReturned);
1761 }
1762
1763
1764 //-------------------------------------------------------------------
1765 // IKsPropertySet
1766 //
1767 HRESULT
1768 STDMETHODCALLTYPE
1769 CKsProxy::Set(
1770 REFGUID guidPropSet,
1771 DWORD dwPropID,
1772 LPVOID pInstanceData,
1773 DWORD cbInstanceData,
1774 LPVOID pPropData,
1775 DWORD cbPropData)
1776 {
1777 ULONG BytesReturned;
1778
1779 #ifdef KSPROXY_TRACE
1780 OutputDebugStringW(L"CKsProxy::Set\n");
1781 #endif
1782
1783 if (cbInstanceData)
1784 {
1785 PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
1786 if (!Property)
1787 return E_OUTOFMEMORY;
1788
1789 Property->Set = guidPropSet;
1790 Property->Id = dwPropID;
1791 Property->Flags = KSPROPERTY_TYPE_SET;
1792
1793 CopyMemory((Property+1), pInstanceData, cbInstanceData);
1794
1795 HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
1796 CoTaskMemFree(Property);
1797 return hr;
1798 }
1799 else
1800 {
1801 KSPROPERTY Property;
1802
1803 Property.Set = guidPropSet;
1804 Property.Id = dwPropID;
1805 Property.Flags = KSPROPERTY_TYPE_SET;
1806
1807 HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
1808 return hr;
1809 }
1810 }
1811
1812 HRESULT
1813 STDMETHODCALLTYPE
1814 CKsProxy::Get(
1815 REFGUID guidPropSet,
1816 DWORD dwPropID,
1817 LPVOID pInstanceData,
1818 DWORD cbInstanceData,
1819 LPVOID pPropData,
1820 DWORD cbPropData,
1821 DWORD *pcbReturned)
1822 {
1823 ULONG BytesReturned;
1824
1825 #ifdef KSPROXY_TRACE
1826 OutputDebugStringW(L"CKsProxy::Get\n");
1827 #endif
1828
1829 if (cbInstanceData)
1830 {
1831 PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
1832 if (!Property)
1833 return E_OUTOFMEMORY;
1834
1835 Property->Set = guidPropSet;
1836 Property->Id = dwPropID;
1837 Property->Flags = KSPROPERTY_TYPE_GET;
1838
1839 CopyMemory((Property+1), pInstanceData, cbInstanceData);
1840
1841 HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
1842 CoTaskMemFree(Property);
1843 return hr;
1844 }
1845 else
1846 {
1847 KSPROPERTY Property;
1848
1849 Property.Set = guidPropSet;
1850 Property.Id = dwPropID;
1851 Property.Flags = KSPROPERTY_TYPE_GET;
1852
1853 HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
1854 return hr;
1855 }
1856 }
1857
1858 HRESULT
1859 STDMETHODCALLTYPE
1860 CKsProxy::QuerySupported(
1861 REFGUID guidPropSet,
1862 DWORD dwPropID,
1863 DWORD *pTypeSupport)
1864 {
1865 KSPROPERTY Property;
1866 ULONG BytesReturned;
1867
1868 #ifdef KSPROXY_TRACE
1869 OutputDebugStringW(L"CKsProxy::QuerySupported\n");
1870 #endif
1871
1872 Property.Set = guidPropSet;
1873 Property.Id = dwPropID;
1874 Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
1875
1876 return KsProperty(&Property, sizeof(KSPROPERTY), pTypeSupport, sizeof(DWORD), &BytesReturned);
1877 }
1878
1879
1880 //-------------------------------------------------------------------
1881 // IKsTopology interface
1882 //
1883 HRESULT
1884 STDMETHODCALLTYPE
1885 CKsProxy::CreateNodeInstance(
1886 ULONG NodeId,
1887 ULONG Flags,
1888 ACCESS_MASK DesiredAccess,
1889 IUnknown* UnkOuter,
1890 REFGUID InterfaceId,
1891 LPVOID* Interface)
1892 {
1893 HRESULT hr;
1894
1895 #ifdef KSPROXY_TRACE
1896 OutputDebugStringW(L"CKsProxy::CreateNodeInstance\n");
1897 #endif
1898
1899 *Interface = NULL;
1900
1901 if (IsEqualIID(IID_IUnknown, InterfaceId) || !UnkOuter)
1902 {
1903 hr = CKsNode_Constructor(UnkOuter, m_hDevice, NodeId, DesiredAccess, InterfaceId, Interface);
1904 }
1905 else
1906 {
1907 // interface not supported
1908 hr = E_NOINTERFACE;
1909 }
1910
1911 return hr;
1912 }
1913
1914 //-------------------------------------------------------------------
1915 // IKsAggregateControl interface
1916 //
1917 HRESULT
1918 STDMETHODCALLTYPE
1919 CKsProxy::KsAddAggregate(
1920 IN REFGUID AggregateClass)
1921 {
1922 #ifdef KSPROXY_TRACE
1923 OutputDebugStringW(L"CKsProxy::KsAddAggregate NotImplemented\n");
1924 #endif
1925 return E_NOTIMPL;
1926 }
1927
1928 HRESULT
1929 STDMETHODCALLTYPE
1930 CKsProxy::KsRemoveAggregate(
1931 REFGUID AggregateClass)
1932 {
1933 #ifdef KSPROXY_TRACE
1934 OutputDebugStringW(L"CKsProxy::KsRemoveAggregate NotImplemented\n");
1935 #endif
1936
1937 return E_NOTIMPL;
1938 }
1939
1940
1941 //-------------------------------------------------------------------
1942 // IPersistStream interface
1943 //
1944
1945 HRESULT
1946 STDMETHODCALLTYPE
1947 CKsProxy::IsDirty()
1948 {
1949 #ifdef KSPROXY_TRACE
1950 OutputDebugStringW(L"CKsProxy::IsDirty Notimplemented\n");
1951 #endif
1952 return E_NOTIMPL;
1953 }
1954
1955 HRESULT
1956 STDMETHODCALLTYPE
1957 CKsProxy::Load(
1958 IStream *pStm)
1959 {
1960 HRESULT hr;
1961 WCHAR Buffer[1000];
1962 AM_MEDIA_TYPE MediaType;
1963 ULONG BytesReturned;
1964 LONG Length;
1965
1966 ULONG PinId;
1967 LPOLESTR pMajor, pSub, pFormat;
1968
1969 #ifdef KSPROXY_TRACE
1970 OutputDebugStringW(L"CKsProxy::Load\n");
1971 #endif
1972
1973 #if 0
1974 ULONG Version = ReadInt(pStm, hr);
1975 if (Version != 1)
1976 return E_FAIL;
1977 #endif
1978
1979 hr = pStm->Read(&Length, sizeof(ULONG), &BytesReturned);
1980 swprintf(Buffer, L"Length hr %x hr length %lu\n", hr, Length);
1981 OutputDebugStringW(Buffer);
1982
1983 do
1984 {
1985 hr = pStm->Read(&PinId, sizeof(ULONG), &BytesReturned);
1986 swprintf(Buffer, L"Read: hr %08x PinId %lx BytesReturned %lu\n", hr, PinId, BytesReturned);
1987 OutputDebugStringW(Buffer);
1988
1989 if (FAILED(hr) || !BytesReturned)
1990 break;
1991
1992 Length -= BytesReturned;
1993
1994 hr = pStm->Read(&MediaType, sizeof(AM_MEDIA_TYPE), &BytesReturned);
1995 if (FAILED(hr) || BytesReturned != sizeof(AM_MEDIA_TYPE))
1996 {
1997 swprintf(Buffer, L"Read failed with %lx\n", hr);
1998 OutputDebugStringW(Buffer);
1999 break;
2000 }
2001
2002
2003 StringFromIID(MediaType.majortype, &pMajor);
2004 StringFromIID(MediaType.subtype , &pSub);
2005 StringFromIID(MediaType.formattype, &pFormat);
2006
2007 swprintf(Buffer, L"BytesReturned %lu majortype %s subtype %s bFixedSizeSamples %u bTemporalCompression %u lSampleSize %u formattype %s, pUnk %p cbFormat %u pbFormat %p\n", BytesReturned, pMajor, pSub, MediaType.bFixedSizeSamples, MediaType.bTemporalCompression, MediaType.lSampleSize, pFormat, MediaType.pUnk, MediaType.cbFormat, MediaType.pbFormat);
2008 OutputDebugStringW(Buffer);
2009
2010 Length -= BytesReturned;
2011
2012
2013 if (MediaType.cbFormat)
2014 {
2015 MediaType.pbFormat = (BYTE*)CoTaskMemAlloc(MediaType.cbFormat);
2016 if (!MediaType.pbFormat)
2017 return E_OUTOFMEMORY;
2018
2019 hr = pStm->Read(&MediaType.pbFormat, sizeof(MediaType.cbFormat), &BytesReturned);
2020 if (FAILED(hr))
2021 {
2022 swprintf(Buffer, L"ReadFormat failed with %lx\n", hr);
2023 OutputDebugStringW(Buffer);
2024 break;
2025 }
2026 Length -= BytesReturned;
2027 }
2028
2029 }while(Length > 0);
2030
2031 return S_OK;
2032 }
2033
2034 HRESULT
2035 STDMETHODCALLTYPE
2036 CKsProxy::Save(
2037 IStream *pStm,
2038 BOOL fClearDirty)
2039 {
2040 #ifdef KSPROXY_TRACE
2041 OutputDebugStringW(L"CKsProxy::Save Notimplemented\n");
2042 #endif
2043
2044 return E_NOTIMPL;
2045 }
2046
2047 HRESULT
2048 STDMETHODCALLTYPE
2049 CKsProxy::GetSizeMax(
2050 ULARGE_INTEGER *pcbSize)
2051 {
2052 #ifdef KSPROXY_TRACE
2053 OutputDebugStringW(L"CKsProxy::GetSizeMax Notimplemented\n");
2054 #endif
2055
2056 return E_NOTIMPL;
2057 }
2058
2059 //-------------------------------------------------------------------
2060 // IAMDeviceRemoval interface
2061 //
2062
2063 HRESULT
2064 STDMETHODCALLTYPE
2065 CKsProxy::DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink)
2066 {
2067 #ifdef KSPROXY_TRACE
2068 OutputDebugStringW(L"CKsProxy::DeviceInfo\n");
2069 #endif
2070
2071 if (!m_DevicePath)
2072 {
2073 // object not initialized
2074 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
2075 }
2076
2077 // copy device interface guid
2078 CopyMemory(pclsidInterfaceClass, &m_DeviceInterfaceGUID, sizeof(GUID));
2079
2080 if (pwszSymbolicLink)
2081 {
2082 *pwszSymbolicLink = (LPWSTR)CoTaskMemAlloc((wcslen(m_DevicePath)+1) * sizeof(WCHAR));
2083 if (!*pwszSymbolicLink)
2084 return E_OUTOFMEMORY;
2085
2086 wcscpy(*pwszSymbolicLink, m_DevicePath);
2087 }
2088 return S_OK;
2089 }
2090 HRESULT
2091 STDMETHODCALLTYPE
2092 CKsProxy::Reassociate(void)
2093 {
2094 #ifdef KSPROXY_TRACE
2095 OutputDebugStringW(L"CKsProxy::Reassociate\n");
2096 #endif
2097
2098 if (!m_DevicePath || m_hDevice)
2099 {
2100 // file path not available
2101 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
2102 }
2103
2104 m_hDevice = CreateFileW(m_DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
2105 if (!m_hDevice)
2106 {
2107 // failed to open device
2108 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
2109 }
2110
2111 // success
2112 return NOERROR;
2113 }
2114
2115 HRESULT
2116 STDMETHODCALLTYPE
2117 CKsProxy::Disassociate(void)
2118 {
2119 #ifdef KSPROXY_TRACE
2120 OutputDebugStringW(L"CKsProxy::Disassociate\n");
2121 #endif
2122
2123 if (!m_hDevice)
2124 return E_HANDLE;
2125
2126 CloseHandle(m_hDevice);
2127 m_hDevice = NULL;
2128 return NOERROR;
2129 }
2130
2131 //-------------------------------------------------------------------
2132 // IKsClock interface
2133 //
2134
2135 HANDLE
2136 STDMETHODCALLTYPE
2137 CKsProxy::KsGetClockHandle()
2138 {
2139 #ifdef KSPROXY_TRACE
2140 OutputDebugStringW(L"CKsProxy::KsGetClockHandle\n");
2141 #endif
2142
2143 return m_hClock;
2144 }
2145
2146
2147 //-------------------------------------------------------------------
2148 // IKsObject interface
2149 //
2150
2151 HANDLE
2152 STDMETHODCALLTYPE
2153 CKsProxy::KsGetObjectHandle()
2154 {
2155 #ifdef KSPROXY_TRACE
2156 OutputDebugStringW(L"CKsProxy::KsGetObjectHandle\n");
2157 #endif
2158
2159 return m_hDevice;
2160 }
2161
2162 //-------------------------------------------------------------------
2163 // IPersistPropertyBag interface
2164 //
2165 HRESULT
2166 STDMETHODCALLTYPE
2167 CKsProxy::InitNew( void)
2168 {
2169 #ifdef KSPROXY_TRACE
2170 OutputDebugStringW(L"CKsProxy::InitNew\n");
2171 #endif
2172
2173 return S_OK;
2174 }
2175
2176 HRESULT
2177 STDMETHODCALLTYPE
2178 CKsProxy::GetSupportedSets(
2179 LPGUID * pOutGuid,
2180 PULONG NumGuids)
2181 {
2182 KSPROPERTY Property;
2183 LPGUID pGuid;
2184 ULONG NumProperty = 0;
2185 ULONG NumMethods = 0;
2186 ULONG NumEvents = 0;
2187 ULONG Length;
2188 ULONG BytesReturned;
2189 HRESULT hr;
2190
2191 Property.Set = GUID_NULL;
2192 Property.Id = 0;
2193 Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
2194
2195 KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumProperty);
2196 KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumMethods);
2197 KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumEvents);
2198
2199 Length = NumProperty + NumMethods + NumEvents;
2200
2201 // allocate guid buffer
2202 pGuid = (LPGUID)CoTaskMemAlloc(Length);
2203 if (!pGuid)
2204 {
2205 // failed
2206 return E_OUTOFMEMORY;
2207 }
2208
2209 NumProperty /= sizeof(GUID);
2210 NumMethods /= sizeof(GUID);
2211 NumEvents /= sizeof(GUID);
2212
2213 // get all properties
2214 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pGuid, Length, &BytesReturned);
2215 if (FAILED(hr))
2216 {
2217 CoTaskMemFree(pGuid);
2218 return E_FAIL;
2219 }
2220 Length -= BytesReturned;
2221
2222 // get all methods
2223 if (Length)
2224 {
2225 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty], Length, &BytesReturned);
2226 if (FAILED(hr))
2227 {
2228 CoTaskMemFree(pGuid);
2229 return E_FAIL;
2230 }
2231 Length -= BytesReturned;
2232 }
2233
2234 // get all events
2235 if (Length)
2236 {
2237 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty+NumMethods], Length, &BytesReturned);
2238 if (FAILED(hr))
2239 {
2240 CoTaskMemFree(pGuid);
2241 return E_FAIL;
2242 }
2243 Length -= BytesReturned;
2244 }
2245
2246 #ifdef KSPROXY_TRACE
2247 WCHAR Buffer[200];
2248 swprintf(Buffer, L"NumProperty %lu NumMethods %lu NumEvents %lu\n", NumProperty, NumMethods, NumEvents);
2249 OutputDebugStringW(Buffer);
2250 #endif
2251
2252 *pOutGuid = pGuid;
2253 *NumGuids = NumProperty+NumEvents+NumMethods;
2254 return S_OK;
2255 }
2256
2257 HRESULT
2258 STDMETHODCALLTYPE
2259 CKsProxy::LoadProxyPlugins(
2260 LPGUID pGuids,
2261 ULONG NumGuids)
2262 {
2263 ULONG Index;
2264 LPOLESTR pStr;
2265 HKEY hKey, hSubKey;
2266 HRESULT hr;
2267 IUnknown * pUnknown;
2268
2269 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\MediaInterfaces", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2270 {
2271 OutputDebugStringW(L"CKsProxy::LoadProxyPlugins failed to open MediaInterfaces key\n");
2272 return E_FAIL;
2273 }
2274
2275 // enumerate all sets
2276 for(Index = 0; Index < NumGuids; Index++)
2277 {
2278 // convert to string
2279 hr = StringFromCLSID(pGuids[Index], &pStr);
2280 if (FAILED(hr))
2281 return E_FAIL;
2282
2283 // now try open class key
2284 if (RegOpenKeyExW(hKey, pStr, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
2285 {
2286 // no plugin for that set exists
2287 CoTaskMemFree(pStr);
2288 continue;
2289 }
2290
2291 // try load plugin
2292 hr = CoCreateInstance(pGuids[Index], (IBaseFilter*)this, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
2293 if (SUCCEEDED(hr))
2294 {
2295 // store plugin
2296 m_Plugins.push_back(pUnknown);
2297 }
2298 // close key
2299 RegCloseKey(hSubKey);
2300 }
2301
2302 // close media interfaces key
2303 RegCloseKey(hKey);
2304 return S_OK;
2305 }
2306
2307 HRESULT
2308 STDMETHODCALLTYPE
2309 CKsProxy::GetNumberOfPins(
2310 PULONG NumPins)
2311 {
2312 KSPROPERTY Property;
2313 ULONG BytesReturned;
2314
2315 // setup request
2316 Property.Set = KSPROPSETID_Pin;
2317 Property.Id = KSPROPERTY_PIN_CTYPES;
2318 Property.Flags = KSPROPERTY_TYPE_GET;
2319
2320 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)NumPins, sizeof(ULONG), &BytesReturned);
2321 }
2322
2323 HRESULT
2324 STDMETHODCALLTYPE
2325 CKsProxy::GetPinInstanceCount(
2326 ULONG PinId,
2327 PKSPIN_CINSTANCES Instances)
2328 {
2329 KSP_PIN Property;
2330 ULONG BytesReturned;
2331
2332 // setup request
2333 Property.Property.Set = KSPROPSETID_Pin;
2334 Property.Property.Id = KSPROPERTY_PIN_CINSTANCES;
2335 Property.Property.Flags = KSPROPERTY_TYPE_GET;
2336 Property.PinId = PinId;
2337 Property.Reserved = 0;
2338
2339 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)Instances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
2340 }
2341
2342 HRESULT
2343 STDMETHODCALLTYPE
2344 CKsProxy::GetPinCommunication(
2345 ULONG PinId,
2346 KSPIN_COMMUNICATION * Communication)
2347 {
2348 KSP_PIN Property;
2349 ULONG BytesReturned;
2350
2351 // setup request
2352 Property.Property.Set = KSPROPSETID_Pin;
2353 Property.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
2354 Property.Property.Flags = KSPROPERTY_TYPE_GET;
2355 Property.PinId = PinId;
2356 Property.Reserved = 0;
2357
2358 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
2359 }
2360
2361 HRESULT
2362 STDMETHODCALLTYPE
2363 CKsProxy::GetPinDataflow(
2364 ULONG PinId,
2365 KSPIN_DATAFLOW * DataFlow)
2366 {
2367 KSP_PIN Property;
2368 ULONG BytesReturned;
2369
2370 // setup request
2371 Property.Property.Set = KSPROPSETID_Pin;
2372 Property.Property.Id = KSPROPERTY_PIN_DATAFLOW;
2373 Property.Property.Flags = KSPROPERTY_TYPE_GET;
2374 Property.PinId = PinId;
2375 Property.Reserved = 0;
2376
2377 return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
2378 }
2379
2380 HRESULT
2381 STDMETHODCALLTYPE
2382 CKsProxy::GetPinName(
2383 ULONG PinId,
2384 KSPIN_DATAFLOW DataFlow,
2385 ULONG PinCount,
2386 LPWSTR * OutPinName)
2387 {
2388 KSP_PIN Property;
2389 LPWSTR PinName;
2390 ULONG BytesReturned;
2391 HRESULT hr;
2392 WCHAR Buffer[100];
2393
2394 // setup request
2395 Property.Property.Set = KSPROPSETID_Pin;
2396 Property.Property.Id = KSPROPERTY_PIN_NAME;
2397 Property.Property.Flags = KSPROPERTY_TYPE_GET;
2398 Property.PinId = PinId;
2399 Property.Reserved = 0;
2400
2401 // #1 try get it from pin directly
2402 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
2403
2404 if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA))
2405 {
2406 // allocate pin name
2407 PinName = (LPWSTR)CoTaskMemAlloc(BytesReturned);
2408 if (!PinName)
2409 return E_OUTOFMEMORY;
2410
2411 // retry with allocated buffer
2412 hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), PinName, BytesReturned, &BytesReturned);
2413 if (SUCCEEDED(hr))
2414 {
2415 *OutPinName = PinName;
2416 return hr;
2417 }
2418
2419 //free buffer
2420 CoTaskMemFree(PinName);
2421 }
2422
2423 //
2424 // TODO: retrieve pin name from topology node
2425 //
2426
2427 if (DataFlow == KSPIN_DATAFLOW_IN)
2428 {
2429 swprintf(Buffer, L"Input%lu", PinCount);
2430 }
2431 else
2432 {
2433 swprintf(Buffer, L"Output%lu", PinCount);
2434 }
2435
2436 // allocate pin name
2437 PinName = (LPWSTR)CoTaskMemAlloc((wcslen(Buffer)+1) * sizeof(WCHAR));
2438 if (!PinName)
2439 return E_OUTOFMEMORY;
2440
2441 // copy pin name
2442 wcscpy(PinName, Buffer);
2443
2444 // store result
2445 *OutPinName = PinName;
2446 // done
2447 return S_OK;
2448 }
2449
2450 HRESULT
2451 STDMETHODCALLTYPE
2452 CKsProxy::CreatePins()
2453 {
2454 ULONG NumPins, Index;
2455 KSPIN_CINSTANCES Instances;
2456 KSPIN_DATAFLOW DataFlow;
2457 KSPIN_COMMUNICATION Communication;
2458 HRESULT hr;
2459 LPWSTR PinName;
2460 IPin * pPin;
2461 ULONG InputPin = 0;
2462 ULONG OutputPin = 0;
2463
2464 // get number of pins
2465 hr = GetNumberOfPins(&NumPins);
2466 if (FAILED(hr))
2467 return hr;
2468
2469 for(Index = 0; Index < NumPins; Index++)
2470 {
2471 // query current instance count
2472 hr = GetPinInstanceCount(Index, &Instances);
2473 if (FAILED(hr))
2474 {
2475 #ifdef KSPROXY_TRACE
2476 WCHAR Buffer[100];
2477 swprintf(Buffer, L"CKsProxy::CreatePins GetPinInstanceCount failed with %lx\n", hr);
2478 OutputDebugStringW(Buffer);
2479 #endif
2480 continue;
2481 }
2482
2483
2484 // query pin communication;
2485 hr = GetPinCommunication(Index, &Communication);
2486 if (FAILED(hr))
2487 {
2488 #ifdef KSPROXY_TRACE
2489 WCHAR Buffer[100];
2490 swprintf(Buffer, L"CKsProxy::CreatePins GetPinCommunication failed with %lx\n", hr);
2491 OutputDebugStringW(Buffer);
2492 #endif
2493 continue;
2494 }
2495
2496 if (Instances.CurrentCount == Instances.PossibleCount)
2497 {
2498 // already maximum reached for this pin
2499 #ifdef KSPROXY_TRACE
2500 WCHAR Buffer[100];
2501 swprintf(Buffer, L"CKsProxy::CreatePins Instances.CurrentCount == Instances.PossibleCount\n");
2502 OutputDebugStringW(Buffer);
2503 #endif
2504 continue;
2505 }
2506
2507 // get direction of pin
2508 hr = GetPinDataflow(Index, &DataFlow);
2509 if (FAILED(hr))
2510 {
2511 #ifdef KSPROXY_TRACE
2512 WCHAR Buffer[100];
2513 swprintf(Buffer, L"CKsProxy::CreatePins GetPinDataflow failed with %lx\n", hr);
2514 OutputDebugStringW(Buffer);
2515 #endif
2516 continue;
2517 }
2518
2519 if (DataFlow == KSPIN_DATAFLOW_IN)
2520 hr = GetPinName(Index, DataFlow, InputPin, &PinName);
2521 else
2522 hr = GetPinName(Index, DataFlow, OutputPin, &PinName);
2523
2524 if (FAILED(hr))
2525 {
2526 #ifdef KSPROXY_TRACE
2527 WCHAR Buffer[100];
2528 swprintf(Buffer, L"CKsProxy::CreatePins GetPinName failed with %lx\n", hr);
2529 OutputDebugStringW(Buffer);
2530 #endif
2531 continue;
2532 }
2533
2534 // construct the pins
2535 if (DataFlow == KSPIN_DATAFLOW_IN)
2536 {
2537 hr = CInputPin_Constructor((IBaseFilter*)this, PinName, m_hDevice, Index, Communication, IID_IPin, (void**)&pPin);
2538 if (FAILED(hr))
2539 {
2540 #ifdef KSPROXY_TRACE
2541 WCHAR Buffer[100];
2542 swprintf(Buffer, L"CKsProxy::CreatePins CInputPin_Constructor failed with %lx\n", hr);
2543 OutputDebugStringW(Buffer);
2544 #endif
2545 CoTaskMemFree(PinName);
2546 continue;
2547 }
2548 InputPin++;
2549 }
2550 else
2551 {
2552 hr = COutputPin_Constructor((IBaseFilter*)this, PinName, Index, Communication, IID_IPin, (void**)&pPin);
2553 if (FAILED(hr))
2554 {
2555 #ifdef KSPROXY_TRACE
2556 WCHAR Buffer[100];
2557 swprintf(Buffer, L"CKsProxy::CreatePins COutputPin_Constructor failed with %lx\n", hr);
2558 OutputDebugStringW(Buffer);
2559 #endif
2560 CoTaskMemFree(PinName);
2561 continue;
2562 }
2563 OutputPin++;
2564 }
2565
2566 // store pins
2567 m_Pins.push_back(pPin);
2568
2569 #ifdef KSPROXY_TRACE
2570 WCHAR Buffer[100];
2571 swprintf(Buffer, L"Index %lu DataFlow %lu Name %s\n", Index, DataFlow, PinName);
2572 OutputDebugStringW(Buffer);
2573 #endif
2574
2575 }
2576
2577 return S_OK;
2578 }
2579
2580 HRESULT
2581 STDMETHODCALLTYPE
2582 CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
2583 {
2584 HRESULT hr;
2585 VARIANT varName;
2586 LPGUID pGuid;
2587 ULONG NumGuids = 0;
2588 HDEVINFO hList;
2589 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
2590
2591 #ifdef KSPROXY_TRACE
2592 WCHAR Buffer[100];
2593 OutputDebugStringW(L"CKsProxy::Load\n");
2594 #endif
2595
2596 // read device path
2597 varName.vt = VT_BSTR;
2598 hr = pPropBag->Read(L"DevicePath", &varName, pErrorLog);
2599
2600 if (FAILED(hr))
2601 {
2602 #ifdef KSPROXY_TRACE
2603 swprintf(Buffer, L"CKsProxy::Load Read %lx\n", hr);
2604 OutputDebugStringW(Buffer);
2605 #endif
2606 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
2607 }
2608
2609 #ifdef KSPROXY_TRACE
2610 OutputDebugStringW(L"DevicePath: ");
2611 OutputDebugStringW(varName.bstrVal);
2612 OutputDebugStringW(L"\n");
2613 #endif
2614
2615 // create device list
2616 hList = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
2617 if (hList == INVALID_HANDLE_VALUE)
2618 {
2619 // failed to create device list
2620 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
2621 }
2622
2623 DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
2624 if (!SetupDiOpenDeviceInterfaceW(hList, (PCWSTR)varName.bstrVal, 0, &DeviceInterfaceData))
2625 {
2626 // failed to open device interface
2627 SetupDiDestroyDeviceInfoList(hList);
2628 }
2629
2630 // FIXME handle device interface links(aliases)
2631 CopyMemory(&m_DeviceInterfaceGUID, &DeviceInterfaceData.InterfaceClassGuid, sizeof(GUID));
2632
2633 // close device info list
2634 SetupDiDestroyDeviceInfoList(hList);
2635
2636 // open device
2637 m_hDevice = CreateFileW(varName.bstrVal, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
2638
2639 if (m_hDevice == INVALID_HANDLE_VALUE)
2640 {
2641 // failed to open device
2642 #ifdef KSPROXY_TRACE
2643 swprintf(Buffer, L"CKsProxy:: failed to open device with %lx\n", GetLastError());
2644 OutputDebugStringW(Buffer);
2645 #endif
2646 return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
2647 }
2648
2649 // store device path
2650 m_DevicePath = varName.bstrVal;
2651
2652 // get all supported sets
2653 hr = GetSupportedSets(&pGuid, &NumGuids);
2654 if (FAILED(hr))
2655 {
2656 CloseHandle(m_hDevice);
2657 m_hDevice = NULL;
2658 return hr;
2659 }
2660
2661 // load all proxy plugins
2662 hr = LoadProxyPlugins(pGuid, NumGuids);
2663 if (FAILED(hr))
2664 {
2665 #if 0 //HACK
2666 CloseHandle(m_hDevice);
2667 m_hDevice = NULL;
2668 return hr;
2669 #endif
2670 OutputDebugStringW(L"CKsProxy::LoadProxyPlugins failed!\n");
2671 }
2672
2673 // free sets
2674 CoTaskMemFree(pGuid);
2675
2676 // now create the input / output pins
2677 hr = CreatePins();
2678
2679 #ifdef KSPROXY_TRACE
2680 swprintf(Buffer, L"CKsProxy::Load CreatePins %lx\n", hr);
2681 OutputDebugStringW(Buffer);
2682 #endif
2683
2684 //HACK
2685 hr = S_OK;
2686
2687 return hr;
2688 }
2689
2690 HRESULT
2691 STDMETHODCALLTYPE
2692 CKsProxy::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
2693 {
2694 #ifdef KSPROXY_TRACE
2695 OutputDebugStringW(L"CKsProxy::Save\n");
2696 #endif
2697 return E_NOTIMPL;
2698 }
2699
2700 //-------------------------------------------------------------------
2701 // IBaseFilter interface
2702 //
2703
2704 HRESULT
2705 STDMETHODCALLTYPE
2706 CKsProxy::GetClassID(
2707 CLSID *pClassID)
2708 {
2709 #ifdef KSPROXY_TRACE
2710 OutputDebugStringW(L"CKsProxy::GetClassID\n");
2711 #endif
2712 CopyMemory(pClassID, &CLSID_Proxy, sizeof(GUID));
2713
2714 return S_OK;
2715 }
2716
2717 HRESULT
2718 STDMETHODCALLTYPE
2719 CKsProxy::Stop()
2720 {
2721 HRESULT hr;
2722
2723 #ifdef KSPROXY_TRACE
2724 OutputDebugStringW(L"CKsProxy::Stop\n");
2725 #endif
2726
2727 EnterCriticalSection(&m_Lock);
2728
2729 hr = SetPinState(KSSTATE_STOP);
2730 if (SUCCEEDED(hr))
2731 m_FilterState = State_Stopped;
2732
2733 LeaveCriticalSection(&m_Lock);
2734
2735 return hr;
2736 }
2737
2738 HRESULT
2739 STDMETHODCALLTYPE
2740 CKsProxy::Pause()
2741 {
2742 HRESULT hr = S_OK;
2743
2744 #ifdef KSPROXY_TRACE
2745 OutputDebugStringW(L"CKsProxy::Pause\n");
2746 #endif
2747
2748 EnterCriticalSection(&m_Lock);
2749
2750 if (m_FilterState == State_Running)
2751 {
2752 hr = SetPinState(KSSTATE_STOP);
2753 }
2754 if (SUCCEEDED(hr))
2755 {
2756 if (m_FilterState == State_Stopped)
2757 {
2758 hr = SetPinState(KSSTATE_PAUSE);
2759 }
2760 }
2761
2762 if (SUCCEEDED(hr))
2763 m_FilterState = State_Paused;
2764
2765 LeaveCriticalSection(&m_Lock);
2766 return hr;
2767
2768 }
2769
2770 HRESULT
2771 STDMETHODCALLTYPE
2772 CKsProxy::Run(
2773 REFERENCE_TIME tStart)
2774 {
2775 HRESULT hr;
2776
2777 #ifdef KSPROXY_TRACE
2778 OutputDebugStringW(L"CKsProxy::Run\n");
2779 #endif
2780
2781 EnterCriticalSection(&m_Lock);
2782
2783 if (m_FilterState == State_Stopped)
2784 {
2785 LeaveCriticalSection(&m_Lock);
2786 // setting filter state to pause
2787 hr = Pause();
2788 if (FAILED(hr))
2789 return hr;
2790
2791 EnterCriticalSection(&m_Lock);
2792 assert(m_FilterState == State_Paused);
2793 }
2794
2795 hr = SetPinState(KSSTATE_RUN);
2796
2797 if (SUCCEEDED(hr))
2798 {
2799 m_FilterState = State_Running;
2800 }
2801
2802 LeaveCriticalSection(&m_Lock);
2803 return hr;
2804 }
2805
2806 HRESULT
2807 STDMETHODCALLTYPE
2808 CKsProxy::SetPinState(
2809 KSSTATE State)
2810 {
2811 HRESULT hr = S_OK;
2812 ULONG Index;
2813 IKsObject *pObject;
2814 ULONG BytesReturned;
2815 KSPROPERTY Property;
2816 PIN_INFO PinInfo;
2817
2818 Property.Set = KSPROPSETID_Connection;
2819 Property.Id = KSPROPERTY_CONNECTION_STATE;
2820 Property.Flags = KSPROPERTY_TYPE_SET;
2821
2822 // set all pins to running state
2823 for(Index = 0; Index < m_Pins.size(); Index++)
2824 {
2825 IPin * Pin = m_Pins[Index];
2826 if (!Pin)
2827 continue;
2828
2829 //check if the pin is connected
2830 IPin * TempPin;
2831 hr = Pin->ConnectedTo(&TempPin);
2832 if (FAILED(hr))
2833 {
2834 // skip unconnected pins
2835 continue;
2836 }
2837
2838 // release connected pin
2839 TempPin->Release();
2840
2841 // query for the pin info
2842 hr = Pin->QueryPinInfo(&PinInfo);
2843
2844 if (SUCCEEDED(hr))
2845 {
2846 if (PinInfo.pFilter)
2847 PinInfo.pFilter->Release();
2848
2849 if (PinInfo.dir == PINDIR_OUTPUT)
2850 {
2851 hr = COutputPin_SetState(Pin, State);
2852 if (SUCCEEDED(hr))
2853 continue;
2854 }
2855 }
2856
2857 //query IKsObject interface
2858 hr = Pin->QueryInterface(IID_IKsObject, (void**)&pObject);
2859
2860 // get pin handle
2861 HANDLE hPin = pObject->KsGetObjectHandle();
2862
2863 // sanity check
2864 assert(hPin && hPin != INVALID_HANDLE_VALUE);
2865
2866 // now set state
2867 hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
2868
2869 #ifdef KSPROXY_TRACE
2870 WCHAR Buffer[100];
2871 swprintf(Buffer, L"CKsProxy::SetPinState Index %u State %u hr %lx\n", Index, State, hr);
2872 OutputDebugStringW(Buffer);
2873 #endif
2874
2875 if (FAILED(hr))
2876 return hr;
2877 }
2878 return hr;
2879 }
2880
2881 HRESULT
2882 STDMETHODCALLTYPE
2883 CKsProxy::GetState(
2884 DWORD dwMilliSecsTimeout,
2885 FILTER_STATE *State)
2886 {
2887 if (!State)
2888 return E_POINTER;
2889
2890 *State = m_FilterState;
2891 return S_OK;
2892 }
2893
2894 HRESULT
2895 STDMETHODCALLTYPE
2896 CKsProxy::SetSyncSource(
2897 IReferenceClock *pClock)
2898 {
2899 HRESULT hr;
2900 IKsClock *pKsClock;
2901 HANDLE hClock, hPin;
2902 ULONG Index;
2903 IPin * pin;
2904 IKsObject * pObject;
2905 KSPROPERTY Property;
2906 ULONG BytesReturned;
2907 PIN_DIRECTION PinDir;
2908
2909 #ifdef KSPROXY_TRACE
2910 OutputDebugStringW(L"CKsProxy::SetSyncSource\n");
2911 #endif
2912
2913 // FIXME
2914 // need locks
2915
2916 if (pClock)
2917 {
2918 hr = pClock->QueryInterface(IID_IKsClock, (void**)&pKsClock);
2919 if (FAILED(hr))
2920 {
2921 hr = m_ReferenceClock->QueryInterface(IID_IKsClock, (void**)&pKsClock);
2922 if (FAILED(hr))
2923 return hr;
2924 }
2925
2926 // get clock handle
2927 hClock = pKsClock->KsGetClockHandle();
2928
2929 // release IKsClock interface
2930 pKsClock->Release();
2931 m_hClock = hClock;
2932 }
2933 else
2934 {
2935 // no clock handle
2936 m_hClock = NULL;
2937 }
2938
2939
2940 // distribute clock to all pins
2941 for(Index = 0; Index < m_Pins.size(); Index++)
2942 {
2943 // get current pin
2944 pin = m_Pins[Index];
2945 if (!pin)
2946 continue;
2947
2948 // get IKsObject interface
2949 hr = pin->QueryInterface(IID_IKsObject, (void **)&pObject);
2950 if (SUCCEEDED(hr))
2951 {
2952 // get pin handle
2953 hPin = pObject->KsGetObjectHandle();
2954 if (hPin != INVALID_HANDLE_VALUE && hPin)
2955 {
2956 // set clock
2957 Property.Set = KSPROPSETID_Stream;
2958 Property.Id = KSPROPERTY_STREAM_MASTERCLOCK;
2959 Property.Flags = KSPROPERTY_TYPE_SET;
2960
2961 // set master clock
2962 hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&m_hClock, sizeof(HANDLE), &BytesReturned);
2963
2964 if (FAILED(hr))
2965 {
2966 if (hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND) &&
2967 hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND))
2968 {
2969 // failed to set master clock
2970 pObject->Release();
2971 WCHAR Buffer[100];
2972 swprintf(Buffer, L"CKsProxy::SetSyncSource KSPROPERTY_STREAM_MASTERCLOCK failed with %lx\n", hr);
2973 OutputDebugStringW(Buffer);
2974 return hr;
2975 }
2976 }
2977 }
2978 // release IKsObject
2979 pObject->Release();
2980 }
2981
2982 // now get the direction
2983 hr = pin->QueryDirection(&PinDir);
2984 if (SUCCEEDED(hr))
2985 {
2986 if (PinDir == PINDIR_OUTPUT)
2987 {
2988 // notify pin via
2989 //CBaseStreamControl::SetSyncSource(pClock)
2990 }
2991 }
2992 }
2993
2994 if (pClock)
2995 {
2996 pClock->AddRef();
2997 }
2998
2999 if (m_ReferenceClock)
3000 {
3001 m_ReferenceClock->Release();
3002 }
3003
3004 m_ReferenceClock = pClock;
3005 #ifdef KSPROXY_TRACE
3006 OutputDebugStringW(L"CKsProxy::SetSyncSource done\n");
3007 #endif
3008 return S_OK;
3009 }
3010
3011 HRESULT
3012 STDMETHODCALLTYPE
3013 CKsProxy::GetSyncSource(
3014 IReferenceClock **pClock)
3015 {
3016 #ifdef KSPROXY_TRACE
3017 OutputDebugStringW(L"CKsProxy::GetSyncSource\n");
3018 #endif
3019
3020 if (!pClock)
3021 return E_POINTER;
3022
3023 if (m_ReferenceClock)
3024 m_ReferenceClock->AddRef();
3025
3026 *pClock = m_ReferenceClock;
3027 return S_OK;
3028 }
3029
3030 HRESULT
3031 STDMETHODCALLTYPE
3032 CKsProxy::EnumPins(
3033 IEnumPins **ppEnum)
3034 {
3035 return CEnumPins_fnConstructor(m_Pins, IID_IEnumPins, (void**)ppEnum);
3036 }
3037
3038 HRESULT
3039 STDMETHODCALLTYPE
3040 CKsProxy::FindPin(
3041 LPCWSTR Id, IPin **ppPin)
3042 {
3043 ULONG PinId;
3044
3045 #ifdef KSPROXY_TRACE
3046 OutputDebugStringW(L"CKsProxy::FindPin\n");
3047 #endif
3048
3049 if (!ppPin)
3050 return E_POINTER;
3051
3052 // convert to pin
3053 int ret = swscanf(Id, L"%u", &PinId);
3054
3055 if (!ret || ret == EOF)
3056 {
3057 // invalid id
3058 return VFW_E_NOT_FOUND;
3059 }
3060
3061 if (PinId >= m_Pins.size() || m_Pins[PinId] == NULL)
3062 {
3063 // invalid id
3064 return VFW_E_NOT_FOUND;
3065 }
3066
3067 // found pin
3068 *ppPin = m_Pins[PinId];
3069 m_Pins[PinId]->AddRef();
3070
3071 return S_OK;
3072 }
3073
3074
3075 HRESULT
3076 STDMETHODCALLTYPE
3077 CKsProxy::QueryFilterInfo(
3078 FILTER_INFO *pInfo)
3079 {
3080 if (!pInfo)
3081 return E_POINTER;
3082
3083 #ifdef KSPROXY_TRACE
3084 OutputDebugStringW(L"CKsProxy::QueryFilterInfo\n");
3085 #endif
3086
3087 pInfo->achName[0] = L'\0';
3088 pInfo->pGraph = m_pGraph;
3089
3090 if (m_pGraph)
3091 m_pGraph->AddRef();
3092
3093 return S_OK;
3094 }
3095
3096 HRESULT
3097 STDMETHODCALLTYPE
3098 CKsProxy::JoinFilterGraph(
3099 IFilterGraph *pGraph,
3100 LPCWSTR pName)
3101 {
3102 #ifdef KSPROXY_TRACE
3103 WCHAR Buffer[100];
3104 swprintf(Buffer, L"CKsProxy::JoinFilterGraph pName %s pGraph %p m_Ref %u\n", pName, pGraph, m_Ref);
3105 OutputDebugStringW(Buffer);
3106 #endif
3107
3108 if (pGraph)
3109 {
3110 // joining filter graph
3111 m_pGraph = pGraph;
3112 }
3113 else
3114 {
3115 // leaving graph
3116 m_pGraph = 0;
3117 }
3118
3119 return S_OK;
3120 }
3121
3122
3123 HRESULT
3124 STDMETHODCALLTYPE
3125 CKsProxy::QueryVendorInfo(
3126 LPWSTR *pVendorInfo)
3127 {
3128 #ifdef KSPROXY_TRACE
3129 OutputDebugStringW(L"CKsProxy::QueryVendorInfo\n");
3130 #endif
3131 return StringFromCLSID(CLSID_Proxy, pVendorInfo);
3132 }
3133
3134 //-------------------------------------------------------------------
3135 // IAMovieSetup interface
3136 //
3137
3138 HRESULT
3139 STDMETHODCALLTYPE
3140 CKsProxy::Register()
3141 {
3142 #ifdef KSPROXY_TRACE
3143 OutputDebugStringW(L"CKsProxy::Register : NotImplemented\n");
3144 #endif
3145
3146 return E_NOTIMPL;
3147 }
3148
3149 HRESULT
3150 STDMETHODCALLTYPE
3151 CKsProxy::Unregister()
3152 {
3153 #ifdef KSPROXY_TRACE
3154 OutputDebugStringW(L"CKsProxy::Unregister : NotImplemented\n");
3155 #endif
3156 return E_NOTIMPL;
3157 }
3158
3159 HRESULT
3160 WINAPI
3161 CKsProxy_Constructor(
3162 IUnknown * pUnkOuter,
3163 REFIID riid,
3164 LPVOID * ppv)
3165 {
3166 #ifdef KSPROXY_TRACE
3167 WCHAR Buffer[100];
3168 LPOLESTR pstr;
3169 StringFromCLSID(riid, &pstr);
3170 swprintf(Buffer, L"CKsProxy_Constructor pUnkOuter %p riid %s\n", pUnkOuter, pstr);
3171 OutputDebugStringW(Buffer);
3172 #endif
3173
3174 CKsProxy * handler = new CKsProxy();
3175
3176 if (!handler)
3177 return E_OUTOFMEMORY;
3178
3179 if (FAILED(handler->QueryInterface(riid, ppv)))
3180 {
3181 /* not supported */
3182 delete handler;
3183 return E_NOINTERFACE;
3184 }
3185
3186 return S_OK;
3187 }