xref: /reactos/dll/directx/ksproxy/output_pin.cpp (revision d6eebaa4)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS WDM Streaming ActiveMovie Proxy
4  * FILE:            dll/directx/ksproxy/output_pin.cpp
5  * PURPOSE:         OutputPin of Proxy Filter
6  *
7  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 #include "precomp.h"
10 
11 class COutputPin : public IPin,
12                    public IKsObject,
13                    public IKsPropertySet,
14                    public IStreamBuilder,
15                    public IKsPinFactory,
16                    public ISpecifyPropertyPages,
17                    public IKsPinEx,
18                    public IKsPinPipe,
19                    public IKsControl,
20                    public IKsAggregateControl,
21                    public IQualityControl,
22                    public IMediaSeeking,
23                    public IAMBufferNegotiation,
24                    public IAMStreamConfig,
25                    public IMemAllocatorNotifyCallbackTemp
26 
27 {
28 public:
29     typedef std::vector<IUnknown *>ProxyPluginVector;
30 
31     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
32 
33     STDMETHODIMP_(ULONG) AddRef()
34     {
35         InterlockedIncrement(&m_Ref);
36         return m_Ref;
37     }
38     STDMETHODIMP_(ULONG) Release()
39     {
40         InterlockedDecrement(&m_Ref);
41         if (!m_Ref)
42         {
43             //delete this;
44             return 0;
45         }
46         return m_Ref;
47     }
48 
49     //IKsPin
50     HRESULT STDMETHODCALLTYPE KsQueryMediums(PKSMULTIPLE_ITEM* MediumList);
51     HRESULT STDMETHODCALLTYPE KsQueryInterfaces(PKSMULTIPLE_ITEM* InterfaceList);
52     HRESULT STDMETHODCALLTYPE KsCreateSinkPinHandle(KSPIN_INTERFACE& Interface, KSPIN_MEDIUM& Medium);
53     HRESULT STDMETHODCALLTYPE KsGetCurrentCommunication(KSPIN_COMMUNICATION *Communication, KSPIN_INTERFACE *Interface, KSPIN_MEDIUM *Medium);
54     HRESULT STDMETHODCALLTYPE KsPropagateAcquire();
55     HRESULT STDMETHODCALLTYPE KsDeliver(IMediaSample* Sample, ULONG Flags);
56     HRESULT STDMETHODCALLTYPE KsMediaSamplesCompleted(PKSSTREAM_SEGMENT StreamSegment);
57     IMemAllocator * STDMETHODCALLTYPE KsPeekAllocator(KSPEEKOPERATION Operation);
58     HRESULT STDMETHODCALLTYPE KsReceiveAllocator(IMemAllocator *MemAllocator);
59     HRESULT STDMETHODCALLTYPE KsRenegotiateAllocator();
60     LONG STDMETHODCALLTYPE KsIncrementPendingIoCount();
61     LONG STDMETHODCALLTYPE KsDecrementPendingIoCount();
62     HRESULT STDMETHODCALLTYPE KsQualityNotify(ULONG Proportion, REFERENCE_TIME TimeDelta);
63     // IKsPinEx
64     VOID STDMETHODCALLTYPE KsNotifyError(IMediaSample* Sample, HRESULT hr);
65 
66     //IKsPinPipe
67     HRESULT STDMETHODCALLTYPE KsGetPinFramingCache(PKSALLOCATOR_FRAMING_EX *FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option);
68     HRESULT STDMETHODCALLTYPE KsSetPinFramingCache(PKSALLOCATOR_FRAMING_EX FramingEx, PFRAMING_PROP FramingProp, FRAMING_CACHE_OPS Option);
69     IPin* STDMETHODCALLTYPE KsGetConnectedPin();
70     IKsAllocatorEx* STDMETHODCALLTYPE KsGetPipe(KSPEEKOPERATION Operation);
71     HRESULT STDMETHODCALLTYPE KsSetPipe(IKsAllocatorEx *KsAllocator);
72     ULONG STDMETHODCALLTYPE KsGetPipeAllocatorFlag();
73     HRESULT STDMETHODCALLTYPE KsSetPipeAllocatorFlag(ULONG Flag);
74     GUID STDMETHODCALLTYPE KsGetPinBusCache();
75     HRESULT STDMETHODCALLTYPE KsSetPinBusCache(GUID Bus);
76     PWCHAR STDMETHODCALLTYPE KsGetPinName();
77     PWCHAR STDMETHODCALLTYPE KsGetFilterName();
78 
79     //IPin methods
80     HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt);
81     HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt);
82     HRESULT STDMETHODCALLTYPE Disconnect();
83     HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **pPin);
84     HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt);
85     HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo);
86     HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir);
87     HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id);
88     HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt);
89     HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum);
90     HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin);
91     HRESULT STDMETHODCALLTYPE EndOfStream();
92     HRESULT STDMETHODCALLTYPE BeginFlush();
93     HRESULT STDMETHODCALLTYPE EndFlush();
94     HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
95 
96     // ISpecifyPropertyPages
97     HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages);
98 
99     //IKsObject methods
100     HANDLE STDMETHODCALLTYPE KsGetObjectHandle();
101 
102     //IKsPropertySet
103     HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData);
104     HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD *pcbReturned);
105     HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport);
106 
107     //IKsControl
108     HRESULT STDMETHODCALLTYPE KsProperty(PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData, ULONG DataLength, ULONG* BytesReturned);
109     HRESULT STDMETHODCALLTYPE KsMethod(PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData, ULONG DataLength, ULONG* BytesReturned);
110     HRESULT STDMETHODCALLTYPE KsEvent(PKSEVENT Event, ULONG EventLength, LPVOID EventData, ULONG DataLength, ULONG* BytesReturned);
111 
112     //IStreamBuilder
113     HRESULT STDMETHODCALLTYPE Render(IPin *ppinOut, IGraphBuilder *pGraph);
114     HRESULT STDMETHODCALLTYPE Backout(IPin *ppinOut, IGraphBuilder *pGraph);
115 
116     //IKsPinFactory
117     HRESULT STDMETHODCALLTYPE KsPinFactory(ULONG* PinFactory);
118 
119     //IKsAggregateControl
120     HRESULT STDMETHODCALLTYPE KsAddAggregate(IN REFGUID AggregateClass);
121     HRESULT STDMETHODCALLTYPE KsRemoveAggregate(REFGUID AggregateClass);
122 
123     //IQualityControl
124     HRESULT STDMETHODCALLTYPE Notify(IBaseFilter *pSelf, Quality q);
125     HRESULT STDMETHODCALLTYPE SetSink(IQualityControl *piqc);
126 
127     //IMediaSeeking
128     HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities);
129     HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities);
130     HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat);
131     HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat);
132     HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat);
133     HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat);
134     HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat);
135     HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration);
136     HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop);
137     HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent);
138     HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat);
139     HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags);
140     HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop);
141     HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest);
142     HRESULT STDMETHODCALLTYPE SetRate(double dRate);
143     HRESULT STDMETHODCALLTYPE GetRate(double *pdRate);
144     HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll);
145 
146     //IAMBufferNegotiation
147     HRESULT STDMETHODCALLTYPE SuggestAllocatorProperties(const ALLOCATOR_PROPERTIES *pprop);
148     HRESULT STDMETHODCALLTYPE GetAllocatorProperties(ALLOCATOR_PROPERTIES *pprop);
149 
150     //IAMStreamConfig
151     HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE *pmt);
152     HRESULT STDMETHODCALLTYPE GetFormat(AM_MEDIA_TYPE **ppmt);
153     HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities(int *piCount, int *piSize);
154     HRESULT STDMETHODCALLTYPE GetStreamCaps(int iIndex, AM_MEDIA_TYPE **ppmt, BYTE *pSCC);
155 
156     //IMemAllocatorNotifyCallbackTemp
157     HRESULT STDMETHODCALLTYPE NotifyRelease();
158 
159     //---------------------------------------------------------------
160     COutputPin(IBaseFilter * ParentFilter, LPCWSTR PinName, ULONG PinId, KSPIN_COMMUNICATION Communication);
161     virtual ~COutputPin();
162     HRESULT STDMETHODCALLTYPE CheckFormat(const AM_MEDIA_TYPE *pmt);
163     HRESULT STDMETHODCALLTYPE CreatePin(const AM_MEDIA_TYPE *pmt);
164     HRESULT STDMETHODCALLTYPE CreatePinHandle(PKSPIN_MEDIUM Medium, PKSPIN_INTERFACE Interface, const AM_MEDIA_TYPE *pmt);
165     HRESULT WINAPI IoProcessRoutine();
166     HRESULT WINAPI InitializeIOThread();
167     HRESULT STDMETHODCALLTYPE GetSupportedSets(LPGUID * pOutGuid, PULONG NumGuids);
168     HRESULT STDMETHODCALLTYPE LoadProxyPlugins(LPGUID pGuids, ULONG NumGuids);
169 
170     friend DWORD WINAPI COutputPin_IoThreadStartup(LPVOID lpParameter);
171     friend HRESULT STDMETHODCALLTYPE COutputPin_SetState(IPin * Pin, KSSTATE State);
172 
173 protected:
174     LONG m_Ref;
175     IBaseFilter * m_ParentFilter;
176     LPCWSTR m_PinName;
177     HANDLE m_hPin;
178     ULONG m_PinId;
179     IPin * m_Pin;
180     IKsAllocatorEx * m_KsAllocatorEx;
181     ULONG m_PipeAllocatorFlag;
182     BOOL m_bPinBusCacheInitialized;
183     GUID m_PinBusCache;
184     LPWSTR m_FilterName;
185     FRAMING_PROP m_FramingProp[4];
186     PKSALLOCATOR_FRAMING_EX m_FramingEx[4];
187 
188     IMemAllocator * m_MemAllocator;
189     IMemInputPin * m_MemInputPin;
190     LONG m_IoCount;
191     KSPIN_COMMUNICATION m_Communication;
192     KSPIN_INTERFACE m_Interface;
193     KSPIN_MEDIUM m_Medium;
194     AM_MEDIA_TYPE m_MediaFormat;
195     ALLOCATOR_PROPERTIES m_Properties;
196     IKsInterfaceHandler * m_InterfaceHandler;
197 
198     HANDLE m_hStartEvent;
199     HANDLE m_hBufferAvailable;
200     HANDLE m_hStopEvent;
201     BOOL m_StopInProgress;
202     BOOL m_IoThreadStarted;
203 
204     KSSTATE m_State;
205     CRITICAL_SECTION m_Lock;
206 
207     ProxyPluginVector m_Plugins;
208 };
209 
210 COutputPin::~COutputPin()
211 {
212 }
213 
214 COutputPin::COutputPin(
215     IBaseFilter * ParentFilter,
216     LPCWSTR PinName,
217     ULONG PinId,
218     KSPIN_COMMUNICATION Communication) : m_Ref(0),
219                                          m_ParentFilter(ParentFilter),
220                                          m_PinName(PinName),
221                                          m_hPin(INVALID_HANDLE_VALUE),
222                                          m_PinId(PinId),
223                                          m_Pin(0),
224                                          m_KsAllocatorEx(0),
225                                          m_PipeAllocatorFlag(0),
226                                          m_bPinBusCacheInitialized(0),
227                                          m_FilterName(0),
228                                          m_MemAllocator(0),
229                                          m_MemInputPin(0),
230                                          m_IoCount(0),
231                                          m_Communication(Communication),
232                                          m_InterfaceHandler(0),
233                                          m_hStartEvent(0),
234                                          m_hBufferAvailable(0),
235                                          m_hStopEvent(0),
236                                          m_StopInProgress(0),
237                                          m_IoThreadStarted(0),
238                                          m_State(KSSTATE_STOP),
239                                          m_Plugins()
240 {
241     HRESULT hr;
242     IKsObject * KsObjectParent;
243 
244     hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
245     assert(hr == S_OK);
246 
247     ZeroMemory(m_FramingProp, sizeof(m_FramingProp));
248     ZeroMemory(m_FramingEx, sizeof(m_FramingEx));
249     ZeroMemory(&m_MediaFormat, sizeof(AM_MEDIA_TYPE));
250 
251     hr = KsGetMediaType(0, &m_MediaFormat, KsObjectParent->KsGetObjectHandle(), m_PinId);
252 
253 #ifdef KSPROXY_TRACE
254     WCHAR Buffer[100];
255     swprintf(Buffer, L"COutputPin::COutputPin Format %p pbFormat %lu\n", &m_MediaFormat, m_MediaFormat.cbFormat);
256     OutputDebugStringW(Buffer);
257 #endif
258 
259     assert(hr == S_OK);
260 
261     InitializeCriticalSection(&m_Lock);
262 
263     KsObjectParent->Release();
264 };
265 
266 HRESULT
267 STDMETHODCALLTYPE
268 COutputPin::QueryInterface(
269     IN  REFIID refiid,
270     OUT PVOID* Output)
271 {
272     *Output = NULL;
273     if (IsEqualGUID(refiid, IID_IUnknown) ||
274         IsEqualGUID(refiid, IID_IPin))
275     {
276 #ifdef KSPROXY_TRACE
277         OutputDebugStringW(L"COutputPin::QueryInterface IID_IPin\n");
278 #endif
279         *Output = PVOID(this);
280         reinterpret_cast<IUnknown*>(*Output)->AddRef();
281         return NOERROR;
282     }
283     else if (IsEqualGUID(refiid, IID_IKsObject))
284     {
285         if (m_hPin == INVALID_HANDLE_VALUE)
286         {
287             HRESULT hr = CreatePin(&m_MediaFormat);
288             if (FAILED(hr))
289                 return hr;
290         }
291 #ifdef KSPROXY_TRACE
292         OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsObject\n");
293 #endif
294         *Output = (IKsObject*)(this);
295         reinterpret_cast<IKsObject*>(*Output)->AddRef();
296         return NOERROR;
297     }
298     else if (IsEqualGUID(refiid, IID_IKsPin) || IsEqualGUID(refiid, IID_IKsPinEx))
299     {
300         *Output = (IKsPinEx*)(this);
301         reinterpret_cast<IKsPinEx*>(*Output)->AddRef();
302         return NOERROR;
303     }
304     else if (IsEqualGUID(refiid, IID_IKsPinPipe))
305     {
306         *Output = (IKsPinPipe*)(this);
307         reinterpret_cast<IKsPinPipe*>(*Output)->AddRef();
308         return NOERROR;
309     }
310     else if (IsEqualGUID(refiid, IID_IKsAggregateControl))
311     {
312         *Output = (IKsAggregateControl*)(this);
313         reinterpret_cast<IKsAggregateControl*>(*Output)->AddRef();
314         return NOERROR;
315     }
316     else if (IsEqualGUID(refiid, IID_IQualityControl))
317     {
318         *Output = (IQualityControl*)(this);
319         reinterpret_cast<IQualityControl*>(*Output)->AddRef();
320         return NOERROR;
321     }
322     else if (IsEqualGUID(refiid, IID_IKsPropertySet))
323     {
324         if (m_hPin == INVALID_HANDLE_VALUE)
325         {
326             HRESULT hr = CreatePin(&m_MediaFormat);
327             if (FAILED(hr))
328                 return hr;
329         }
330 #ifdef KSPROXY_TRACE
331         OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsPropertySet\n");
332 #endif
333         *Output = (IKsPropertySet*)(this);
334         reinterpret_cast<IKsPropertySet*>(*Output)->AddRef();
335         return NOERROR;
336     }
337     else if (IsEqualGUID(refiid, IID_IKsControl))
338     {
339 #ifdef KSPROXY_TRACE
340         OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsControl\n");
341 #endif
342         *Output = (IKsControl*)(this);
343         reinterpret_cast<IKsControl*>(*Output)->AddRef();
344         return NOERROR;
345     }
346 #if 0
347     else if (IsEqualGUID(refiid, IID_IStreamBuilder))
348     {
349         *Output = (IStreamBuilder*)(this);
350         reinterpret_cast<IStreamBuilder*>(*Output)->AddRef();
351         return NOERROR;
352     }
353 #endif
354     else if (IsEqualGUID(refiid, IID_IKsPinFactory))
355     {
356 #ifdef KSPROXY_TRACE
357         OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsPinFactory\n");
358 #endif
359         *Output = (IKsPinFactory*)(this);
360         reinterpret_cast<IKsPinFactory*>(*Output)->AddRef();
361         return NOERROR;
362     }
363     else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages))
364     {
365 #ifdef KSPROXY_TRACE
366         OutputDebugStringW(L"COutputPin::QueryInterface IID_ISpecifyPropertyPages\n");
367 #endif
368         *Output = (ISpecifyPropertyPages*)(this);
369         reinterpret_cast<ISpecifyPropertyPages*>(*Output)->AddRef();
370         return NOERROR;
371     }
372     else if (IsEqualGUID(refiid, IID_IMediaSeeking))
373     {
374         *Output = (IMediaSeeking*)(this);
375         reinterpret_cast<IMediaSeeking*>(*Output)->AddRef();
376         return NOERROR;
377     }
378     else if (IsEqualGUID(refiid, IID_IAMBufferNegotiation))
379     {
380         *Output = (IAMBufferNegotiation*)(this);
381         reinterpret_cast<IAMBufferNegotiation*>(*Output)->AddRef();
382         return NOERROR;
383     }
384     else if (IsEqualGUID(refiid, IID_IAMStreamConfig))
385     {
386         *Output = (IAMStreamConfig*)(this);
387         reinterpret_cast<IAMStreamConfig*>(*Output)->AddRef();
388         return NOERROR;
389     }
390     else if (IsEqualGUID(refiid, IID_IMemAllocatorNotifyCallbackTemp))
391     {
392         *Output = (IMemAllocatorNotifyCallbackTemp*)(this);
393         reinterpret_cast<IMemAllocatorNotifyCallbackTemp*>(*Output)->AddRef();
394         return NOERROR;
395     }
396 
397 #ifdef KSPROXY_TRACE
398     WCHAR Buffer[MAX_PATH];
399     LPOLESTR lpstr;
400     StringFromCLSID(refiid, &lpstr);
401     swprintf(Buffer, L"COutputPin::QueryInterface: NoInterface for %s PinId %u PinName %s\n", lpstr, m_PinId, m_PinName);
402     OutputDebugStringW(Buffer);
403     CoTaskMemFree(lpstr);
404 #endif
405 
406     return E_NOINTERFACE;
407 }
408 
409 //-------------------------------------------------------------------
410 // IAMBufferNegotiation interface
411 //
412 HRESULT
413 STDMETHODCALLTYPE
414 COutputPin::SuggestAllocatorProperties(
415     const ALLOCATOR_PROPERTIES *pprop)
416 {
417 #ifdef KSPROXY_TRACE
418     OutputDebugStringW(L"COutputPin::SuggestAllocatorProperties\n");
419 #endif
420 
421     if (m_Pin)
422     {
423         // pin is already connected
424         return VFW_E_ALREADY_CONNECTED;
425     }
426 
427     CopyMemory(&m_Properties, pprop, sizeof(ALLOCATOR_PROPERTIES));
428     return NOERROR;
429 }
430 
431 HRESULT
432 STDMETHODCALLTYPE
433 COutputPin::GetAllocatorProperties(
434     ALLOCATOR_PROPERTIES *pprop)
435 {
436 #ifdef KSPROXY_TRACE
437     OutputDebugStringW(L"COutputPin::GetAllocatorProperties\n");
438 #endif
439 
440     if (!m_Pin)
441     {
442         // you should call this method AFTER you connected
443         return E_UNEXPECTED;
444     }
445 
446     if (!m_KsAllocatorEx)
447     {
448         // something went wrong while creating the allocator
449         return E_FAIL;
450     }
451 
452     CopyMemory(pprop, &m_Properties, sizeof(ALLOCATOR_PROPERTIES));
453     return NOERROR;
454 }
455 
456 //-------------------------------------------------------------------
457 // IAMStreamConfig interface
458 //
459 HRESULT
460 STDMETHODCALLTYPE
461 COutputPin::SetFormat(
462     AM_MEDIA_TYPE *pmt)
463 {
464 #ifdef KSPROXY_TRACE
465     OutputDebugStringW(L"COutputPin::SetFormat NotImplemented\n");
466 #endif
467     return E_NOTIMPL;
468 }
469 
470 HRESULT
471 STDMETHODCALLTYPE
472 COutputPin::GetFormat(AM_MEDIA_TYPE **ppmt)
473 {
474 #ifdef KSPROXY_TRACE
475     OutputDebugStringW(L"COutputPin::GetFormat NotImplemented\n");
476 #endif
477     return E_NOTIMPL;
478 }
479 
480 HRESULT
481 STDMETHODCALLTYPE
482 COutputPin::GetNumberOfCapabilities(
483     int *piCount,
484     int *piSize)
485 {
486 #ifdef KSPROXY_TRACE
487     OutputDebugStringW(L"COutputPin::GetNumberOfCapabilities NotImplemented\n");
488 #endif
489     return E_NOTIMPL;
490 }
491 
492 HRESULT
493 STDMETHODCALLTYPE
494 COutputPin::GetStreamCaps(
495     int iIndex,
496     AM_MEDIA_TYPE **ppmt,
497     BYTE *pSCC)
498 {
499 #ifdef KSPROXY_TRACE
500     OutputDebugStringW(L"COutputPin::GetStreamCaps NotImplemented\n");
501 #endif
502     return E_NOTIMPL;
503 }
504 
505 //-------------------------------------------------------------------
506 // IMemAllocatorNotifyCallbackTemp interface
507 //
508 HRESULT
509 STDMETHODCALLTYPE
510 COutputPin::NotifyRelease()
511 {
512 #ifdef KSPROXY_TRACE
513     OutputDebugStringW(L"COutputPin::NotifyRelease\n");
514 #endif
515 
516     // notify thread of new available sample
517     SetEvent(m_hBufferAvailable);
518 
519     return NOERROR;
520 }
521 
522 //-------------------------------------------------------------------
523 // IMediaSeeking interface
524 //
525 HRESULT
526 STDMETHODCALLTYPE
527 COutputPin::GetCapabilities(
528     DWORD *pCapabilities)
529 {
530     IMediaSeeking * FilterMediaSeeking;
531     HRESULT hr;
532 
533     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
534     if (FAILED(hr))
535         return hr;
536 
537     hr = FilterMediaSeeking->GetCapabilities(pCapabilities);
538 
539     FilterMediaSeeking->Release();
540     return hr;
541 }
542 
543 HRESULT
544 STDMETHODCALLTYPE
545 COutputPin::CheckCapabilities(
546     DWORD *pCapabilities)
547 {
548     IMediaSeeking * FilterMediaSeeking;
549     HRESULT hr;
550 
551     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
552     if (FAILED(hr))
553         return hr;
554 
555     hr = FilterMediaSeeking->CheckCapabilities(pCapabilities);
556 
557     FilterMediaSeeking->Release();
558     return hr;
559 }
560 
561 HRESULT
562 STDMETHODCALLTYPE
563 COutputPin::IsFormatSupported(
564     const GUID *pFormat)
565 {
566     IMediaSeeking * FilterMediaSeeking;
567     HRESULT hr;
568 
569     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
570     if (FAILED(hr))
571         return hr;
572 
573     hr = FilterMediaSeeking->IsFormatSupported(pFormat);
574 
575     FilterMediaSeeking->Release();
576     return hr;
577 }
578 
579 HRESULT
580 STDMETHODCALLTYPE
581 COutputPin::QueryPreferredFormat(
582     GUID *pFormat)
583 {
584     IMediaSeeking * FilterMediaSeeking;
585     HRESULT hr;
586 
587     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
588     if (FAILED(hr))
589         return hr;
590 
591     hr = FilterMediaSeeking->QueryPreferredFormat(pFormat);
592 
593     FilterMediaSeeking->Release();
594     return hr;
595 }
596 
597 HRESULT
598 STDMETHODCALLTYPE
599 COutputPin::GetTimeFormat(
600     GUID *pFormat)
601 {
602     IMediaSeeking * FilterMediaSeeking;
603     HRESULT hr;
604 
605     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
606     if (FAILED(hr))
607         return hr;
608 
609     hr = FilterMediaSeeking->GetTimeFormat(pFormat);
610 
611     FilterMediaSeeking->Release();
612     return hr;
613 }
614 
615 HRESULT
616 STDMETHODCALLTYPE
617 COutputPin::IsUsingTimeFormat(
618     const GUID *pFormat)
619 {
620     IMediaSeeking * FilterMediaSeeking;
621     HRESULT hr;
622 
623     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
624     if (FAILED(hr))
625         return hr;
626 
627     hr = FilterMediaSeeking->IsUsingTimeFormat(pFormat);
628 
629     FilterMediaSeeking->Release();
630     return hr;
631 }
632 
633 HRESULT
634 STDMETHODCALLTYPE
635 COutputPin::SetTimeFormat(
636     const GUID *pFormat)
637 {
638     IMediaSeeking * FilterMediaSeeking;
639     HRESULT hr;
640 
641     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
642     if (FAILED(hr))
643         return hr;
644 
645     hr = FilterMediaSeeking->SetTimeFormat(pFormat);
646 
647     FilterMediaSeeking->Release();
648     return hr;
649 }
650 
651 HRESULT
652 STDMETHODCALLTYPE
653 COutputPin::GetDuration(
654     LONGLONG *pDuration)
655 {
656     IMediaSeeking * FilterMediaSeeking;
657     HRESULT hr;
658 
659     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
660     if (FAILED(hr))
661         return hr;
662 
663     hr = FilterMediaSeeking->GetDuration(pDuration);
664 
665     FilterMediaSeeking->Release();
666     return hr;
667 }
668 
669 HRESULT
670 STDMETHODCALLTYPE
671 COutputPin::GetStopPosition(
672     LONGLONG *pStop)
673 {
674     IMediaSeeking * FilterMediaSeeking;
675     HRESULT hr;
676 
677     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
678     if (FAILED(hr))
679         return hr;
680 
681     hr = FilterMediaSeeking->GetStopPosition(pStop);
682 
683     FilterMediaSeeking->Release();
684     return hr;
685 }
686 
687 
688 HRESULT
689 STDMETHODCALLTYPE
690 COutputPin::GetCurrentPosition(
691     LONGLONG *pCurrent)
692 {
693     IMediaSeeking * FilterMediaSeeking;
694     HRESULT hr;
695 
696     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
697     if (FAILED(hr))
698         return hr;
699 
700     hr = FilterMediaSeeking->GetCurrentPosition(pCurrent);
701 
702     FilterMediaSeeking->Release();
703     return hr;
704 }
705 
706 HRESULT
707 STDMETHODCALLTYPE
708 COutputPin::ConvertTimeFormat(
709     LONGLONG *pTarget,
710     const GUID *pTargetFormat,
711     LONGLONG Source,
712     const GUID *pSourceFormat)
713 {
714     IMediaSeeking * FilterMediaSeeking;
715     HRESULT hr;
716 
717     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
718     if (FAILED(hr))
719         return hr;
720 
721     hr = FilterMediaSeeking->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
722 
723     FilterMediaSeeking->Release();
724     return hr;
725 }
726 
727 HRESULT
728 STDMETHODCALLTYPE
729 COutputPin::SetPositions(
730     LONGLONG *pCurrent,
731     DWORD dwCurrentFlags,
732     LONGLONG *pStop,
733     DWORD dwStopFlags)
734 {
735     IMediaSeeking * FilterMediaSeeking;
736     HRESULT hr;
737 
738     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
739     if (FAILED(hr))
740         return hr;
741 
742     hr = FilterMediaSeeking->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
743 
744     FilterMediaSeeking->Release();
745     return hr;
746 }
747 
748 HRESULT
749 STDMETHODCALLTYPE
750 COutputPin::GetPositions(
751     LONGLONG *pCurrent,
752     LONGLONG *pStop)
753 {
754     IMediaSeeking * FilterMediaSeeking;
755     HRESULT hr;
756 
757     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
758     if (FAILED(hr))
759         return hr;
760 
761     hr = FilterMediaSeeking->GetPositions(pCurrent, pStop);
762 
763     FilterMediaSeeking->Release();
764     return hr;
765 }
766 
767 HRESULT
768 STDMETHODCALLTYPE
769 COutputPin::GetAvailable(
770     LONGLONG *pEarliest,
771     LONGLONG *pLatest)
772 {
773     IMediaSeeking * FilterMediaSeeking;
774     HRESULT hr;
775 
776     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
777     if (FAILED(hr))
778         return hr;
779 
780     hr = FilterMediaSeeking->GetAvailable(pEarliest, pLatest);
781 
782     FilterMediaSeeking->Release();
783     return hr;
784 }
785 
786 HRESULT
787 STDMETHODCALLTYPE
788 COutputPin::SetRate(
789     double dRate)
790 {
791     IMediaSeeking * FilterMediaSeeking;
792     HRESULT hr;
793 
794     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
795     if (FAILED(hr))
796         return hr;
797 
798     hr = FilterMediaSeeking->SetRate(dRate);
799 
800     FilterMediaSeeking->Release();
801     return hr;
802 }
803 
804 HRESULT
805 STDMETHODCALLTYPE
806 COutputPin::GetRate(
807     double *pdRate)
808 {
809     IMediaSeeking * FilterMediaSeeking;
810     HRESULT hr;
811 
812     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
813     if (FAILED(hr))
814         return hr;
815 
816     hr = FilterMediaSeeking->GetRate(pdRate);
817 
818     FilterMediaSeeking->Release();
819     return hr;
820 }
821 
822 HRESULT
823 STDMETHODCALLTYPE
824 COutputPin::GetPreroll(
825     LONGLONG *pllPreroll)
826 {
827     IMediaSeeking * FilterMediaSeeking;
828     HRESULT hr;
829 
830     hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
831     if (FAILED(hr))
832         return hr;
833 
834     hr = FilterMediaSeeking->GetPreroll(pllPreroll);
835 
836     FilterMediaSeeking->Release();
837     return hr;
838 }
839 
840 //-------------------------------------------------------------------
841 // IQualityControl interface
842 //
843 HRESULT
844 STDMETHODCALLTYPE
845 COutputPin::Notify(
846     IBaseFilter *pSelf,
847     Quality q)
848 {
849 #ifdef KSPROXY_TRACE
850     OutputDebugStringW(L"COutputPin::Notify NotImplemented\n");
851 #endif
852     return E_NOTIMPL;
853 }
854 
855 HRESULT
856 STDMETHODCALLTYPE
857 COutputPin::SetSink(
858     IQualityControl *piqc)
859 {
860 #ifdef KSPROXY_TRACE
861     OutputDebugStringW(L"COutputPin::SetSink NotImplemented\n");
862 #endif
863     return E_NOTIMPL;
864 }
865 
866 
867 //-------------------------------------------------------------------
868 // IKsAggregateControl interface
869 //
870 HRESULT
871 STDMETHODCALLTYPE
872 COutputPin::KsAddAggregate(
873     IN REFGUID AggregateClass)
874 {
875 #ifdef KSPROXY_TRACE
876     OutputDebugStringW(L"COutputPin::KsAddAggregate NotImplemented\n");
877 #endif
878     return E_NOTIMPL;
879 }
880 
881 HRESULT
882 STDMETHODCALLTYPE
883 COutputPin::KsRemoveAggregate(
884     REFGUID AggregateClass)
885 {
886 #ifdef KSPROXY_TRACE
887     OutputDebugStringW(L"COutputPin::KsRemoveAggregate NotImplemented\n");
888 #endif
889     return E_NOTIMPL;
890 }
891 
892 
893 //-------------------------------------------------------------------
894 // IKsPin
895 //
896 
897 HRESULT
898 STDMETHODCALLTYPE
899 COutputPin::KsQueryMediums(
900     PKSMULTIPLE_ITEM* MediumList)
901 {
902     HRESULT hr;
903     HANDLE hFilter;
904     IKsObject * KsObjectParent;
905 
906     hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
907     if (FAILED(hr))
908         return E_NOINTERFACE;
909 
910     hFilter = KsObjectParent->KsGetObjectHandle();
911 
912     if (hFilter)
913         hr = KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_MEDIUMS, (PVOID*)MediumList);
914     else
915         hr = E_HANDLE;
916 
917     KsObjectParent->Release();
918 
919     return hr;
920 }
921 
922 HRESULT
923 STDMETHODCALLTYPE
924 COutputPin::KsQueryInterfaces(
925     PKSMULTIPLE_ITEM* InterfaceList)
926 {
927     HRESULT hr;
928     HANDLE hFilter;
929     IKsObject * KsObjectParent;
930 
931     hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
932     if (FAILED(hr))
933         return hr;
934 
935     hFilter = KsObjectParent->KsGetObjectHandle();
936 
937     if (hFilter)
938         hr = KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_INTERFACES, (PVOID*)InterfaceList);
939     else
940         hr = E_HANDLE;
941 
942     KsObjectParent->Release();
943 
944     return hr;
945 }
946 
947 HRESULT
948 STDMETHODCALLTYPE
949 COutputPin::KsCreateSinkPinHandle(
950     KSPIN_INTERFACE& Interface,
951     KSPIN_MEDIUM& Medium)
952 {
953 #ifdef KSPROXY_TRACE
954     OutputDebugStringW(L"COutputPin::KsCreateSinkPinHandle NotImplemented\n");
955 #endif
956     return E_NOTIMPL;
957 }
958 
959 HRESULT
960 STDMETHODCALLTYPE
961 COutputPin::KsGetCurrentCommunication(
962     KSPIN_COMMUNICATION *Communication,
963     KSPIN_INTERFACE *Interface,
964     KSPIN_MEDIUM *Medium)
965 {
966     if (Communication)
967     {
968         *Communication = m_Communication;
969     }
970 
971     if (Interface)
972     {
973         if (!m_hPin)
974             return VFW_E_NOT_CONNECTED;
975 
976         CopyMemory(Interface, &m_Interface, sizeof(KSPIN_INTERFACE));
977     }
978 
979     if (Medium)
980     {
981         if (!m_hPin)
982             return VFW_E_NOT_CONNECTED;
983 
984         CopyMemory(Medium, &m_Medium, sizeof(KSPIN_MEDIUM));
985     }
986     return NOERROR;
987 }
988 
989 HRESULT
990 STDMETHODCALLTYPE
991 COutputPin::KsPropagateAcquire()
992 {
993     KSPROPERTY Property;
994     KSSTATE State;
995     ULONG BytesReturned;
996     HRESULT hr;
997 
998 #ifdef KSPROXY_TRACE
999     OutputDebugStringW(L"COutputPin::KsPropagateAcquire\n");
1000 #endif
1001 
1002     assert(m_hPin != INVALID_HANDLE_VALUE);
1003 
1004     Property.Set = KSPROPSETID_Connection;
1005     Property.Id = KSPROPERTY_CONNECTION_STATE;
1006     Property.Flags = KSPROPERTY_TYPE_SET;
1007 
1008     State = KSSTATE_ACQUIRE;
1009 
1010     hr = KsProperty(&Property, sizeof(KSPROPERTY), (LPVOID)&State, sizeof(KSSTATE), &BytesReturned);
1011     if (SUCCEEDED(hr))
1012     {
1013         m_State = State;
1014     }
1015 
1016     //TODO
1017     //propagate to connected pin on the pipe
1018 
1019     return hr;
1020 }
1021 
1022 HRESULT
1023 STDMETHODCALLTYPE
1024 COutputPin::KsDeliver(
1025     IMediaSample* Sample,
1026     ULONG Flags)
1027 {
1028     return E_FAIL;
1029 }
1030 
1031 HRESULT
1032 STDMETHODCALLTYPE
1033 COutputPin::KsMediaSamplesCompleted(PKSSTREAM_SEGMENT StreamSegment)
1034 {
1035     return NOERROR;
1036 }
1037 
1038 IMemAllocator *
1039 STDMETHODCALLTYPE
1040 COutputPin::KsPeekAllocator(KSPEEKOPERATION Operation)
1041 {
1042     if (Operation == KsPeekOperation_AddRef)
1043     {
1044         // add reference on allocator
1045         m_MemAllocator->AddRef();
1046     }
1047 
1048     return m_MemAllocator;
1049 }
1050 
1051 HRESULT
1052 STDMETHODCALLTYPE
1053 COutputPin::KsReceiveAllocator(IMemAllocator *MemAllocator)
1054 {
1055     if (MemAllocator)
1056     {
1057         MemAllocator->AddRef();
1058     }
1059 
1060     if (m_MemAllocator)
1061     {
1062         m_MemAllocator->Release();
1063     }
1064 
1065     m_MemAllocator = MemAllocator;
1066     return NOERROR;
1067 }
1068 
1069 HRESULT
1070 STDMETHODCALLTYPE
1071 COutputPin::KsRenegotiateAllocator()
1072 {
1073     return E_FAIL;
1074 }
1075 
1076 LONG
1077 STDMETHODCALLTYPE
1078 COutputPin::KsIncrementPendingIoCount()
1079 {
1080     return InterlockedIncrement((volatile LONG*)&m_IoCount);
1081 }
1082 
1083 LONG
1084 STDMETHODCALLTYPE
1085 COutputPin::KsDecrementPendingIoCount()
1086 {
1087     return InterlockedDecrement((volatile LONG*)&m_IoCount);
1088 }
1089 
1090 HRESULT
1091 STDMETHODCALLTYPE
1092 COutputPin::KsQualityNotify(
1093     ULONG Proportion,
1094     REFERENCE_TIME TimeDelta)
1095 {
1096 #ifdef KSPROXY_TRACE
1097     OutputDebugStringW(L"COutputPin::KsQualityNotify NotImplemented\n");
1098 #endif
1099     return E_NOTIMPL;
1100 }
1101 
1102 //-------------------------------------------------------------------
1103 // IKsPinEx
1104 //
1105 
1106 VOID
1107 STDMETHODCALLTYPE
1108 COutputPin::KsNotifyError(
1109     IMediaSample* Sample,
1110     HRESULT hr)
1111 {
1112 #ifdef KSPROXY_TRACE
1113     OutputDebugStringW(L"COutputPin::KsNotifyError NotImplemented\n");
1114 #endif
1115 }
1116 
1117 
1118 //-------------------------------------------------------------------
1119 // IKsPinPipe
1120 //
1121 
1122 HRESULT
1123 STDMETHODCALLTYPE
1124 COutputPin::KsGetPinFramingCache(
1125     PKSALLOCATOR_FRAMING_EX *FramingEx,
1126     PFRAMING_PROP FramingProp,
1127     FRAMING_CACHE_OPS Option)
1128 {
1129     if (Option > Framing_Cache_Write || Option < Framing_Cache_ReadLast)
1130     {
1131         // invalid argument
1132         return E_INVALIDARG;
1133     }
1134 
1135     // get framing properties
1136     *FramingProp = m_FramingProp[Option];
1137     *FramingEx = m_FramingEx[Option];
1138 
1139     return NOERROR;
1140 }
1141 
1142 HRESULT
1143 STDMETHODCALLTYPE
1144 COutputPin::KsSetPinFramingCache(
1145     PKSALLOCATOR_FRAMING_EX FramingEx,
1146     PFRAMING_PROP FramingProp,
1147     FRAMING_CACHE_OPS Option)
1148 {
1149     ULONG Index;
1150     ULONG RefCount = 0;
1151 
1152     if (m_FramingEx[Option])
1153     {
1154         for(Index = 1; Index < 4; Index++)
1155         {
1156             if (m_FramingEx[Index] == m_FramingEx[Option])
1157                 RefCount++;
1158         }
1159 
1160         if (RefCount == 1)
1161         {
1162             // existing framing is only used once
1163             CoTaskMemFree(m_FramingEx[Option]);
1164         }
1165     }
1166 
1167     // store framing
1168     m_FramingEx[Option] = FramingEx;
1169     m_FramingProp[Option] = *FramingProp;
1170 
1171     return S_OK;
1172 }
1173 
1174 IPin*
1175 STDMETHODCALLTYPE
1176 COutputPin::KsGetConnectedPin()
1177 {
1178     return m_Pin;
1179 }
1180 
1181 IKsAllocatorEx*
1182 STDMETHODCALLTYPE
1183 COutputPin::KsGetPipe(
1184     KSPEEKOPERATION Operation)
1185 {
1186     if (Operation == KsPeekOperation_AddRef)
1187     {
1188         if (m_KsAllocatorEx)
1189             m_KsAllocatorEx->AddRef();
1190     }
1191     return m_KsAllocatorEx;
1192 }
1193 
1194 HRESULT
1195 STDMETHODCALLTYPE
1196 COutputPin::KsSetPipe(
1197     IKsAllocatorEx *KsAllocator)
1198 {
1199     if (KsAllocator)
1200         KsAllocator->AddRef();
1201 
1202     if (m_KsAllocatorEx)
1203         m_KsAllocatorEx->Release();
1204 
1205     m_KsAllocatorEx = KsAllocator;
1206     return NOERROR;
1207 }
1208 
1209 ULONG
1210 STDMETHODCALLTYPE
1211 COutputPin::KsGetPipeAllocatorFlag()
1212 {
1213     return m_PipeAllocatorFlag;
1214 }
1215 
1216 
1217 HRESULT
1218 STDMETHODCALLTYPE
1219 COutputPin::KsSetPipeAllocatorFlag(
1220     ULONG Flag)
1221 {
1222     m_PipeAllocatorFlag = Flag;
1223     return NOERROR;
1224 }
1225 
1226 GUID
1227 STDMETHODCALLTYPE
1228 COutputPin::KsGetPinBusCache()
1229 {
1230     if (!m_bPinBusCacheInitialized)
1231     {
1232         CopyMemory(&m_PinBusCache, &m_Medium.Set, sizeof(GUID));
1233         m_bPinBusCacheInitialized = TRUE;
1234     }
1235 
1236     return m_PinBusCache;
1237 }
1238 
1239 HRESULT
1240 STDMETHODCALLTYPE
1241 COutputPin::KsSetPinBusCache(
1242     GUID Bus)
1243 {
1244     CopyMemory(&m_PinBusCache, &Bus, sizeof(GUID));
1245     return NOERROR;
1246 }
1247 
1248 PWCHAR
1249 STDMETHODCALLTYPE
1250 COutputPin::KsGetPinName()
1251 {
1252     return (PWCHAR)m_PinName;
1253 }
1254 
1255 
1256 PWCHAR
1257 STDMETHODCALLTYPE
1258 COutputPin::KsGetFilterName()
1259 {
1260     return m_FilterName;
1261 }
1262 
1263 //-------------------------------------------------------------------
1264 // ISpecifyPropertyPages
1265 //
1266 
1267 HRESULT
1268 STDMETHODCALLTYPE
1269 COutputPin::GetPages(CAUUID *pPages)
1270 {
1271 #ifdef KSPROXY_TRACE
1272     OutputDebugStringW(L"COutputPin::GetPages NotImplemented\n");
1273 #endif
1274 
1275     if (!pPages)
1276         return E_POINTER;
1277 
1278     pPages->cElems = 0;
1279     pPages->pElems = NULL;
1280 
1281     return S_OK;
1282 }
1283 
1284 //-------------------------------------------------------------------
1285 // IKsPinFactory
1286 //
1287 
1288 HRESULT
1289 STDMETHODCALLTYPE
1290 COutputPin::KsPinFactory(
1291     ULONG* PinFactory)
1292 {
1293 #ifdef KSPROXY_TRACE
1294     OutputDebugStringW(L"COutputPin::KsPinFactory\n");
1295 #endif
1296 
1297     *PinFactory = m_PinId;
1298     return S_OK;
1299 }
1300 
1301 
1302 //-------------------------------------------------------------------
1303 // IStreamBuilder
1304 //
1305 
1306 HRESULT
1307 STDMETHODCALLTYPE
1308 COutputPin::Render(
1309     IPin *ppinOut,
1310     IGraphBuilder *pGraph)
1311 {
1312 #ifdef KSPROXY_TRACE
1313     OutputDebugStringW(L"COutputPin::Render\n");
1314 #endif
1315     return S_OK;
1316 }
1317 
1318 HRESULT
1319 STDMETHODCALLTYPE
1320 COutputPin::Backout(
1321     IPin *ppinOut,
1322     IGraphBuilder *pGraph)
1323 {
1324 #ifdef KSPROXY_TRACE
1325     OutputDebugStringW(L"COutputPin::Backout\n");
1326 #endif
1327 
1328     return S_OK;
1329 }
1330 //-------------------------------------------------------------------
1331 // IKsObject
1332 //
1333 HANDLE
1334 STDMETHODCALLTYPE
1335 COutputPin::KsGetObjectHandle()
1336 {
1337 #ifdef KSPROXY_TRACE
1338     OutputDebugStringW(L"COutputPin::KsGetObjectHandle\n");
1339 #endif
1340 
1341     assert(m_hPin != INVALID_HANDLE_VALUE);
1342     return m_hPin;
1343 }
1344 
1345 //-------------------------------------------------------------------
1346 // IKsControl
1347 //
1348 HRESULT
1349 STDMETHODCALLTYPE
1350 COutputPin::KsProperty(
1351     PKSPROPERTY Property,
1352     ULONG PropertyLength,
1353     LPVOID PropertyData,
1354     ULONG DataLength,
1355     ULONG* BytesReturned)
1356 {
1357     HRESULT hr;
1358 
1359     assert(m_hPin != INVALID_HANDLE_VALUE);
1360 
1361     hr = KsSynchronousDeviceControl(m_hPin, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned);
1362 #ifdef KSPROXY_TRACE
1363     WCHAR Buffer[100];
1364     LPOLESTR pstr;
1365     StringFromCLSID(Property->Set, &pstr);
1366     swprintf(Buffer, L"COutputPin::KsProperty Set %s Id %lu Flags %x hr %x\n", pstr, Property->Id, Property->Flags, hr);
1367     OutputDebugStringW(Buffer);
1368 #endif
1369 
1370     return hr;
1371 }
1372 
1373 HRESULT
1374 STDMETHODCALLTYPE
1375 COutputPin::KsMethod(
1376     PKSMETHOD Method,
1377     ULONG MethodLength,
1378     LPVOID MethodData,
1379     ULONG DataLength,
1380     ULONG* BytesReturned)
1381 {
1382     assert(m_hPin != INVALID_HANDLE_VALUE);
1383 #ifdef KSPROXY_TRACE
1384     OutputDebugStringW(L"COutputPin::KsMethod\n");
1385 #endif
1386     return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned);
1387 }
1388 
1389 HRESULT
1390 STDMETHODCALLTYPE
1391 COutputPin::KsEvent(
1392     PKSEVENT Event,
1393     ULONG EventLength,
1394     LPVOID EventData,
1395     ULONG DataLength,
1396     ULONG* BytesReturned)
1397 {
1398     assert(m_hPin != INVALID_HANDLE_VALUE);
1399 
1400 #ifdef KSPROXY_TRACE
1401     OutputDebugStringW(L"COutputPin::KsEvent\n");
1402 #endif
1403 
1404     if (EventLength)
1405         return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned);
1406     else
1407         return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_DISABLE_EVENT, (PVOID)Event, EventLength, NULL, 0, BytesReturned);
1408 }
1409 
1410 
1411 //-------------------------------------------------------------------
1412 // IKsPropertySet
1413 //
1414 HRESULT
1415 STDMETHODCALLTYPE
1416 COutputPin::Set(
1417     REFGUID guidPropSet,
1418     DWORD dwPropID,
1419     LPVOID pInstanceData,
1420     DWORD cbInstanceData,
1421     LPVOID pPropData,
1422     DWORD cbPropData)
1423 {
1424     ULONG BytesReturned;
1425 
1426     if (cbInstanceData)
1427     {
1428         PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
1429         if (!Property)
1430             return E_OUTOFMEMORY;
1431 
1432         Property->Set = guidPropSet;
1433         Property->Id = dwPropID;
1434         Property->Flags = KSPROPERTY_TYPE_SET;
1435 
1436         CopyMemory((Property+1), pInstanceData, cbInstanceData);
1437 
1438         HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
1439         CoTaskMemFree(Property);
1440         return hr;
1441     }
1442     else
1443     {
1444         KSPROPERTY Property;
1445 
1446         Property.Set = guidPropSet;
1447         Property.Id = dwPropID;
1448         Property.Flags = KSPROPERTY_TYPE_SET;
1449 
1450         HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
1451         return hr;
1452     }
1453 }
1454 
1455 HRESULT
1456 STDMETHODCALLTYPE
1457 COutputPin::Get(
1458     REFGUID guidPropSet,
1459     DWORD dwPropID,
1460     LPVOID pInstanceData,
1461     DWORD cbInstanceData,
1462     LPVOID pPropData,
1463     DWORD cbPropData,
1464     DWORD *pcbReturned)
1465 {
1466     ULONG BytesReturned;
1467 
1468     if (cbInstanceData)
1469     {
1470         PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
1471         if (!Property)
1472             return E_OUTOFMEMORY;
1473 
1474         Property->Set = guidPropSet;
1475         Property->Id = dwPropID;
1476         Property->Flags = KSPROPERTY_TYPE_GET;
1477 
1478         CopyMemory((Property+1), pInstanceData, cbInstanceData);
1479 
1480         HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
1481         CoTaskMemFree(Property);
1482         return hr;
1483     }
1484     else
1485     {
1486         KSPROPERTY Property;
1487 
1488         Property.Set = guidPropSet;
1489         Property.Id = dwPropID;
1490         Property.Flags = KSPROPERTY_TYPE_GET;
1491 
1492         HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
1493         return hr;
1494     }
1495 }
1496 
1497 HRESULT
1498 STDMETHODCALLTYPE
1499 COutputPin::QuerySupported(
1500     REFGUID guidPropSet,
1501     DWORD dwPropID,
1502     DWORD *pTypeSupport)
1503 {
1504     KSPROPERTY Property;
1505     ULONG BytesReturned;
1506 
1507 #ifdef KSPROXY_TRACE
1508     OutputDebugStringW(L"COutputPin::QuerySupported\n");
1509 #endif
1510 
1511     Property.Set = guidPropSet;
1512     Property.Id = dwPropID;
1513     Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
1514 
1515     return KsProperty(&Property, sizeof(KSPROPERTY), pTypeSupport, sizeof(DWORD), &BytesReturned);
1516 }
1517 
1518 
1519 //-------------------------------------------------------------------
1520 // IPin interface
1521 //
1522 HRESULT
1523 STDMETHODCALLTYPE
1524 COutputPin::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
1525 {
1526     HRESULT hr;
1527     ALLOCATOR_PROPERTIES Properties;
1528     IMemAllocatorCallbackTemp *pMemCallback;
1529     LPGUID pGuid;
1530     ULONG NumGuids = 0;
1531 
1532 #ifdef KSPROXY_TRACE
1533     WCHAR Buffer[200];
1534     OutputDebugStringW(L"COutputPin::Connect called\n");
1535 #endif
1536 
1537     if (pmt)
1538     {
1539         hr = pReceivePin->QueryAccept(pmt);
1540         if (FAILED(hr))
1541             return hr;
1542     }
1543     else
1544     {
1545         // query accept
1546         hr = pReceivePin->QueryAccept(&m_MediaFormat);
1547         if (FAILED(hr))
1548             return hr;
1549 
1550          pmt = &m_MediaFormat;
1551     }
1552 
1553     if (m_hPin == INVALID_HANDLE_VALUE)
1554     {
1555         hr = CreatePin(pmt);
1556         if (FAILED(hr))
1557         {
1558 #ifdef KSPROXY_TRACE
1559             swprintf(Buffer, L"COutputPin::Connect CreatePin handle failed with %lx\n", hr);
1560             OutputDebugStringW(Buffer);
1561 #endif
1562             return hr;
1563         }
1564     }
1565 
1566 
1567     // query for IMemInput interface
1568     hr = pReceivePin->QueryInterface(IID_IMemInputPin, (void**)&m_MemInputPin);
1569     if (FAILED(hr))
1570     {
1571 #ifdef KSPROXY_TRACE
1572         OutputDebugStringW(L"COutputPin::Connect no IMemInputPin interface\n");
1573 #endif
1574 
1575         return hr;
1576     }
1577 
1578     // get input pin allocator properties
1579     ZeroMemory(&Properties, sizeof(ALLOCATOR_PROPERTIES));
1580     m_MemInputPin->GetAllocatorRequirements(&Properties);
1581 
1582     //FIXME determine allocator properties
1583     Properties.cBuffers = 32;
1584     Properties.cbBuffer = 2048 * 188; //2048 frames * MPEG2 TS Payload size
1585     Properties.cbAlign = 4;
1586 
1587     // get input pin allocator
1588 #if 0
1589     hr = m_MemInputPin->GetAllocator(&m_MemAllocator);
1590     if (SUCCEEDED(hr))
1591     {
1592         // set allocator properties
1593         hr = m_MemAllocator->SetProperties(&Properties, &m_Properties);
1594         if (FAILED(hr))
1595             m_MemAllocator->Release();
1596     }
1597 #endif
1598 
1599     if (1)
1600     {
1601         hr = CKsAllocator_Constructor(NULL, IID_IMemAllocator, (void**)&m_MemAllocator);
1602         if (FAILED(hr))
1603             return hr;
1604 
1605         // set allocator properties
1606         hr = m_MemAllocator->SetProperties(&Properties, &m_Properties);
1607         if (FAILED(hr))
1608         {
1609 #ifdef KSPROXY_TRACE
1610             swprintf(Buffer, L"COutputPin::Connect IMemAllocator::SetProperties failed with hr %lx\n", hr);
1611             OutputDebugStringW(Buffer);
1612 #endif
1613             m_MemAllocator->Release();
1614             m_MemInputPin->Release();
1615             return hr;
1616         }
1617     }
1618 
1619     // commit property changes
1620     hr = m_MemAllocator->Commit();
1621     if (FAILED(hr))
1622     {
1623 #ifdef KSPROXY_TRACE
1624         swprintf(Buffer, L"COutputPin::Connect IMemAllocator::Commit failed with hr %lx\n", hr);
1625         OutputDebugStringW(Buffer);
1626 #endif
1627         m_MemAllocator->Release();
1628         m_MemInputPin->Release();
1629         return hr;
1630     }
1631 
1632     // get callback interface
1633     hr = m_MemAllocator->QueryInterface(IID_IMemAllocatorCallbackTemp, (void**)&pMemCallback);
1634     if (FAILED(hr))
1635     {
1636 #ifdef KSPROXY_TRACE
1637         swprintf(Buffer, L"COutputPin::Connect No IMemAllocatorCallbackTemp interface hr %lx\n", hr);
1638         OutputDebugStringW(Buffer);
1639 #endif
1640         m_MemAllocator->Release();
1641         m_MemInputPin->Release();
1642         return hr;
1643     }
1644 
1645     // set notification routine
1646     hr = pMemCallback->SetNotify((IMemAllocatorNotifyCallbackTemp*)this);
1647 
1648     // release IMemAllocatorNotifyCallbackTemp interface
1649     pMemCallback->Release();
1650 
1651     if (FAILED(hr))
1652     {
1653 #ifdef KSPROXY_TRACE
1654         swprintf(Buffer, L"COutputPin::Connect IMemAllocatorNotifyCallbackTemp::SetNotify failed hr %lx\n", hr);
1655         OutputDebugStringW(Buffer);
1656 #endif
1657         m_MemAllocator->Release();
1658         m_MemInputPin->Release();
1659         return hr;
1660     }
1661 
1662     // now set allocator
1663     hr = m_MemInputPin->NotifyAllocator(m_MemAllocator, TRUE);
1664     if (FAILED(hr))
1665     {
1666 #ifdef KSPROXY_TRACE
1667         swprintf(Buffer, L"COutputPin::Connect IMemInputPin::NotifyAllocator failed with hr %lx\n", hr);
1668         OutputDebugStringW(Buffer);
1669 #endif
1670         m_MemAllocator->Release();
1671         m_MemInputPin->Release();
1672         return hr;
1673     }
1674 
1675 
1676     assert(m_hPin != INVALID_HANDLE_VALUE);
1677 
1678     // get all supported sets
1679     if (m_Plugins.empty())
1680     {
1681         if (GetSupportedSets(&pGuid, &NumGuids))
1682         {
1683             // load all proxy plugins
1684             if (FAILED(LoadProxyPlugins(pGuid, NumGuids)))
1685             {
1686 #ifdef KSPROXY_TRACE
1687                 OutputDebugStringW(L"COutputPin::Connect LoadProxyPlugins failed\n");
1688 #endif
1689             }
1690             // free sets
1691             CoTaskMemFree(pGuid);
1692         }
1693     }
1694 
1695     // receive connection;
1696     hr = pReceivePin->ReceiveConnection((IPin*)this, pmt);
1697     if (SUCCEEDED(hr))
1698     {
1699         // increment reference count
1700         pReceivePin->AddRef();
1701         m_Pin = pReceivePin;
1702 #ifdef KSPROXY_TRACE
1703         OutputDebugStringW(L"COutputPin::Connect success\n");
1704 #endif
1705     }
1706     else
1707     {
1708         m_MemInputPin->Release();
1709         m_MemAllocator->Release();
1710     }
1711 
1712     return hr;
1713 }
1714 
1715 HRESULT
1716 STDMETHODCALLTYPE
1717 COutputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
1718 {
1719     return E_UNEXPECTED;
1720 }
1721 HRESULT
1722 STDMETHODCALLTYPE
1723 COutputPin::Disconnect( void)
1724 {
1725 #ifdef KSPROXY_TRACE
1726    OutputDebugStringW(L"COutputPin::Disconnect\n");
1727 #endif
1728 
1729     if (!m_Pin)
1730     {
1731         // pin was not connected
1732         return S_FALSE;
1733     }
1734 
1735     //FIXME
1736     //check if filter is active
1737 
1738     m_Pin->Release();
1739     m_Pin = NULL;
1740     m_MemInputPin->Release();
1741     m_MemAllocator->Release();
1742 
1743     CloseHandle(m_hPin);
1744     m_hPin = INVALID_HANDLE_VALUE;
1745 
1746 #ifdef KSPROXY_TRACE
1747     OutputDebugStringW(L"COutputPin::Disconnect\n");
1748 #endif
1749     return S_OK;
1750 }
1751 HRESULT
1752 STDMETHODCALLTYPE
1753 COutputPin::ConnectedTo(IPin **pPin)
1754 {
1755 #ifdef KSPROXY_TRACE
1756    OutputDebugStringW(L"COutputPin::ConnectedTo\n");
1757 #endif
1758 
1759     if (!pPin)
1760         return E_POINTER;
1761 
1762     if (m_Pin)
1763     {
1764         // increment reference count
1765         m_Pin->AddRef();
1766         *pPin = m_Pin;
1767         return S_OK;
1768     }
1769 
1770     *pPin = NULL;
1771     return VFW_E_NOT_CONNECTED;
1772 }
1773 HRESULT
1774 STDMETHODCALLTYPE
1775 COutputPin::ConnectionMediaType(AM_MEDIA_TYPE *pmt)
1776 {
1777 #ifdef KSPROXY_TRACE
1778     OutputDebugStringW(L"COutputPin::ConnectionMediaType called\n");
1779 #endif
1780 
1781     return E_NOTIMPL;
1782 }
1783 HRESULT
1784 STDMETHODCALLTYPE
1785 COutputPin::QueryPinInfo(PIN_INFO *pInfo)
1786 {
1787     wcscpy(pInfo->achName, m_PinName);
1788     pInfo->dir = PINDIR_OUTPUT;
1789     pInfo->pFilter = m_ParentFilter;
1790     m_ParentFilter->AddRef();
1791 
1792     return S_OK;
1793 }
1794 HRESULT
1795 STDMETHODCALLTYPE
1796 COutputPin::QueryDirection(PIN_DIRECTION *pPinDir)
1797 {
1798     if (pPinDir)
1799     {
1800         *pPinDir = PINDIR_OUTPUT;
1801         return S_OK;
1802     }
1803 
1804     return E_POINTER;
1805 }
1806 HRESULT
1807 STDMETHODCALLTYPE
1808 COutputPin::QueryId(LPWSTR *Id)
1809 {
1810     *Id = (LPWSTR)CoTaskMemAlloc((wcslen(m_PinName)+1)*sizeof(WCHAR));
1811     if (!*Id)
1812         return E_OUTOFMEMORY;
1813 
1814     wcscpy(*Id, m_PinName);
1815     return S_OK;
1816 }
1817 HRESULT
1818 STDMETHODCALLTYPE
1819 COutputPin::QueryAccept(const AM_MEDIA_TYPE *pmt)
1820 {
1821 #ifdef KSPROXY_TRACE
1822     OutputDebugStringW(L"COutputPin::QueryAccept called\n");
1823 #endif
1824 
1825     return E_NOTIMPL;
1826 }
1827 HRESULT
1828 STDMETHODCALLTYPE
1829 COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum)
1830 {
1831     HRESULT hr;
1832     ULONG MediaTypeCount = 0, Index;
1833     AM_MEDIA_TYPE * MediaTypes;
1834     HANDLE hFilter;
1835     IKsObject * KsObjectParent;
1836 
1837     hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
1838     if (FAILED(hr))
1839         return hr;
1840 
1841     // get parent filter handle
1842     hFilter = KsObjectParent->KsGetObjectHandle();
1843 
1844     // release IKsObject
1845     KsObjectParent->Release();
1846 
1847     // query media type count
1848     hr = KsGetMediaTypeCount(hFilter, m_PinId, &MediaTypeCount);
1849     if (FAILED(hr) || !MediaTypeCount)
1850     {
1851         return hr;
1852     }
1853 
1854     // allocate media types
1855     MediaTypes = (AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * MediaTypeCount);
1856     if (!MediaTypes)
1857     {
1858         // not enough memory
1859         return E_OUTOFMEMORY;
1860     }
1861 
1862     // zero media types
1863     ZeroMemory(MediaTypes, sizeof(AM_MEDIA_TYPE) * MediaTypeCount);
1864 
1865     for(Index = 0; Index < MediaTypeCount; Index++)
1866     {
1867         // get media type
1868         hr = KsGetMediaType(Index, &MediaTypes[Index], hFilter, m_PinId);
1869         if (FAILED(hr))
1870         {
1871             // failed
1872             CoTaskMemFree(MediaTypes);
1873             return hr;
1874         }
1875     }
1876 
1877     return CEnumMediaTypes_fnConstructor(MediaTypeCount, MediaTypes, IID_IEnumMediaTypes, (void**)ppEnum);
1878 }
1879 HRESULT
1880 STDMETHODCALLTYPE
1881 COutputPin::QueryInternalConnections(IPin **apPin, ULONG *nPin)
1882 {
1883     return E_NOTIMPL;
1884 }
1885 HRESULT
1886 STDMETHODCALLTYPE
1887 COutputPin::EndOfStream( void)
1888 {
1889     /* should be called only on input pins */
1890     return E_UNEXPECTED;
1891 }
1892 HRESULT
1893 STDMETHODCALLTYPE
1894 COutputPin::BeginFlush( void)
1895 {
1896     /* should be called only on input pins */
1897     return E_UNEXPECTED;
1898 }
1899 HRESULT
1900 STDMETHODCALLTYPE
1901 COutputPin::EndFlush( void)
1902 {
1903     /* should be called only on input pins */
1904     return E_UNEXPECTED;
1905 }
1906 HRESULT
1907 STDMETHODCALLTYPE
1908 COutputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1909 {
1910     if (!m_Pin)
1911     {
1912         // we are not connected
1913         return VFW_E_NOT_CONNECTED;
1914     }
1915 
1916     return m_Pin->NewSegment(tStart, tStop, dRate);
1917 }
1918 
1919 //-------------------------------------------------------------------
1920 HRESULT
1921 STDMETHODCALLTYPE
1922 COutputPin::CheckFormat(
1923     const AM_MEDIA_TYPE *pmt)
1924 {
1925     PKSMULTIPLE_ITEM MultipleItem;
1926     PKSDATAFORMAT DataFormat;
1927     HRESULT hr;
1928     IKsObject * KsObjectParent;
1929     HANDLE hFilter;
1930 
1931     if (!pmt)
1932         return E_POINTER;
1933 
1934     // get IKsObject interface
1935     hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
1936     if (FAILED(hr))
1937         return hr;
1938 
1939     // get parent filter handle
1940     hFilter = KsObjectParent->KsGetObjectHandle();
1941 
1942     // release IKsObject
1943     KsObjectParent->Release();
1944 
1945     if (!hFilter)
1946         return E_HANDLE;
1947 
1948 
1949     hr = KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_DATARANGES, (PVOID*)&MultipleItem);
1950     if (FAILED(hr))
1951         return S_FALSE;
1952 
1953     DataFormat = (PKSDATAFORMAT)(MultipleItem + 1);
1954     for(ULONG Index = 0; Index < MultipleItem->Count; Index++)
1955     {
1956         if (IsEqualGUID(pmt->majortype, DataFormat->MajorFormat) &&
1957             IsEqualGUID(pmt->subtype, DataFormat->SubFormat) &&
1958             IsEqualGUID(pmt->formattype, DataFormat->Specifier))
1959         {
1960             // format is supported
1961             CoTaskMemFree(MultipleItem);
1962             return S_OK;
1963         }
1964         DataFormat = (PKSDATAFORMAT)((ULONG_PTR)DataFormat + DataFormat->FormatSize);
1965     }
1966     //format is not supported
1967     CoTaskMemFree(MultipleItem);
1968     return S_FALSE;
1969 }
1970 
1971 HRESULT
1972 STDMETHODCALLTYPE
1973 COutputPin::CreatePin(
1974     const AM_MEDIA_TYPE *pmt)
1975 {
1976     PKSMULTIPLE_ITEM MediumList;
1977     PKSMULTIPLE_ITEM InterfaceList;
1978     PKSPIN_MEDIUM Medium;
1979     PKSPIN_INTERFACE Interface;
1980     IKsInterfaceHandler * InterfaceHandler;
1981     HRESULT hr;
1982 
1983     // query for pin medium
1984     hr = KsQueryMediums(&MediumList);
1985     if (FAILED(hr))
1986     {
1987 #ifdef KSPROXY_TRACE
1988         WCHAR Buffer[100];
1989         swprintf(Buffer, L"COutputPin::CreatePin KsQueryMediums failed %lx\n", hr);
1990         OutputDebugStringW(Buffer);
1991 #endif
1992         return hr;
1993     }
1994 
1995     // query for pin interface
1996     hr = KsQueryInterfaces(&InterfaceList);
1997     if (FAILED(hr))
1998     {
1999         // failed
2000 #ifdef KSPROXY_TRACE
2001         WCHAR Buffer[100];
2002         swprintf(Buffer, L"COutputPin::CreatePin KsQueryInterfaces failed %lx\n", hr);
2003         OutputDebugStringW(Buffer);
2004 #endif
2005 
2006         CoTaskMemFree(MediumList);
2007         return hr;
2008     }
2009 
2010     if (MediumList->Count)
2011     {
2012         //use first available medium
2013         Medium = (PKSPIN_MEDIUM)(MediumList + 1);
2014     }
2015     else
2016     {
2017         // default to standard medium
2018         Medium = &StandardPinMedium;
2019     }
2020 
2021     if (InterfaceList->Count)
2022     {
2023         //use first available interface
2024         Interface = (PKSPIN_INTERFACE)(InterfaceList + 1);
2025     }
2026     else
2027     {
2028         // default to standard interface
2029         Interface = &StandardPinInterface;
2030     }
2031 
2032     if (m_Communication != KSPIN_COMMUNICATION_BRIDGE && m_Communication != KSPIN_COMMUNICATION_NONE)
2033     {
2034         // now create pin
2035         hr = CreatePinHandle(Medium, Interface, pmt);
2036         if (FAILED(hr))
2037         {
2038 #ifdef KSPROXY_TRACE
2039             WCHAR Buffer[100];
2040             swprintf(Buffer, L"COutputPin::CreatePinHandle failed with %lx\n", hr);
2041             OutputDebugStringW(Buffer);
2042 #endif
2043             return hr;
2044         }
2045 
2046         if (!m_InterfaceHandler)
2047         {
2048             // now load the IKsInterfaceHandler plugin
2049             hr = CoCreateInstance(Interface->Set, NULL, CLSCTX_INPROC_SERVER, IID_IKsInterfaceHandler, (void**)&InterfaceHandler);
2050             if (FAILED(hr))
2051             {
2052                 // failed to load interface handler plugin
2053                 CoTaskMemFree(MediumList);
2054                 CoTaskMemFree(InterfaceList);
2055 
2056 #ifdef KSPROXY_TRACE
2057                 WCHAR Buffer[100];
2058                 swprintf(Buffer, L"COutputPin::CreatePin failed to create interface handler %lx\n", hr);
2059                 OutputDebugStringW(Buffer);
2060 #endif
2061 
2062                 return hr;
2063             }
2064 
2065             // now set the pin
2066             hr = InterfaceHandler->KsSetPin((IKsPin*)this);
2067             if (FAILED(hr))
2068             {
2069                 // failed to initialize interface handler plugin
2070 #ifdef KSPROXY_TRACE
2071                 WCHAR Buffer[100];
2072                 swprintf(Buffer, L"COutputPin::CreatePin failed to initialize interface handler %lx\n", hr);
2073                 OutputDebugStringW(Buffer);
2074 #endif
2075                 InterfaceHandler->Release();
2076                 CoTaskMemFree(MediumList);
2077                 CoTaskMemFree(InterfaceList);
2078                 return hr;
2079             }
2080 
2081             // store interface handler
2082             m_InterfaceHandler = InterfaceHandler;
2083         }
2084     }
2085     else
2086     {
2087 #ifdef KSPROXY_TRACE
2088         WCHAR Buffer[100];
2089         swprintf(Buffer, L"COutputPin::CreatePin unexpected communication %u %s\n", m_Communication, m_PinName);
2090         OutputDebugStringW(Buffer);
2091 #endif
2092 
2093         hr = E_FAIL;
2094     }
2095 
2096     // free medium / interface / dataformat
2097     CoTaskMemFree(MediumList);
2098     CoTaskMemFree(InterfaceList);
2099 
2100 #ifdef KSPROXY_TRACE
2101     WCHAR Buffer[100];
2102     swprintf(Buffer, L"COutputPin::CreatePin Result %lx\n", hr);
2103     OutputDebugStringW(Buffer);
2104 #endif
2105 
2106     return hr;
2107 }
2108 
2109 HRESULT
2110 STDMETHODCALLTYPE
2111 COutputPin::CreatePinHandle(
2112     PKSPIN_MEDIUM Medium,
2113     PKSPIN_INTERFACE Interface,
2114     const AM_MEDIA_TYPE *pmt)
2115 {
2116     PKSPIN_CONNECT PinConnect;
2117     PKSDATAFORMAT DataFormat;
2118     ULONG Length;
2119     HRESULT hr;
2120     HANDLE hFilter;
2121     IKsObject * KsObjectParent;
2122 
2123     //KSALLOCATOR_FRAMING Framing;
2124     //KSPROPERTY Property;
2125     //ULONG BytesReturned;
2126 
2127     OutputDebugStringW(L"COutputPin::CreatePinHandle\n");
2128 
2129     if (m_hPin != INVALID_HANDLE_VALUE)
2130     {
2131         // pin already exists
2132         //CloseHandle(m_hPin);
2133         //m_hPin = INVALID_HANDLE_VALUE;
2134         OutputDebugStringW(L"COutputPin::CreatePinHandle pin already exists\n");
2135         return S_OK;
2136     }
2137 
2138 
2139     // calc format size
2140     Length = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT) + pmt->cbFormat;
2141 
2142     // allocate pin connect
2143     PinConnect = (PKSPIN_CONNECT)CoTaskMemAlloc(Length);
2144     if (!PinConnect)
2145     {
2146         // failed
2147         OutputDebugStringW(L"COutputPin::CreatePinHandle out of memory\n");
2148         return E_OUTOFMEMORY;
2149     }
2150         OutputDebugStringW(L"COutputPin::CreatePinHandle copy pinconnect\n");
2151     // setup request
2152     CopyMemory(&PinConnect->Interface, Interface, sizeof(KSPIN_INTERFACE));
2153     CopyMemory(&PinConnect->Medium, Medium, sizeof(KSPIN_MEDIUM));
2154     PinConnect->PinId = m_PinId;
2155     PinConnect->PinToHandle = NULL;
2156     PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
2157     PinConnect->Priority.PrioritySubClass = KSPRIORITY_NORMAL;
2158 
2159     // get dataformat offset
2160     DataFormat = (PKSDATAFORMAT)(PinConnect + 1);
2161         OutputDebugStringW(L"COutputPin::CreatePinHandle copy format\n");
2162     // copy data format
2163     DataFormat->FormatSize = sizeof(KSDATAFORMAT) + pmt->cbFormat;
2164     DataFormat->Flags = 0;
2165     DataFormat->SampleSize = pmt->lSampleSize;
2166     DataFormat->Reserved = 0;
2167     CopyMemory(&DataFormat->MajorFormat, &pmt->majortype, sizeof(GUID));
2168     CopyMemory(&DataFormat->SubFormat,  &pmt->subtype, sizeof(GUID));
2169     CopyMemory(&DataFormat->Specifier, &pmt->formattype, sizeof(GUID));
2170 
2171     if (pmt->cbFormat)
2172     {
2173         // copy extended format
2174         WCHAR Buffer[100];
2175         swprintf(Buffer, L"COutputPin::CreatePinHandle copy format %p pbFormat %lu\n", pmt, pmt->cbFormat);
2176         OutputDebugStringW(Buffer);
2177         CopyMemory((DataFormat + 1), pmt->pbFormat, pmt->cbFormat);
2178     }
2179 
2180     // get IKsObject interface
2181     hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
2182     if (FAILED(hr))
2183     {
2184         OutputDebugStringW(L"COutputPin::CreatePinHandle no IID_IKsObject interface\n");
2185         return hr;
2186     }
2187 
2188     // get parent filter handle
2189     hFilter = KsObjectParent->KsGetObjectHandle();
2190 
2191     // release IKsObject
2192     KsObjectParent->Release();
2193 
2194     if (!hFilter)
2195     {
2196         OutputDebugStringW(L"COutputPin::CreatePinHandle no filter handle\n");
2197         return E_HANDLE;
2198     }
2199 
2200     OutputDebugStringW(L"COutputPin::CreatePinHandle before creating pin\n");
2201     // create pin
2202     DWORD dwError = KsCreatePin(hFilter, PinConnect, GENERIC_READ, &m_hPin);
2203 
2204     if (dwError == ERROR_SUCCESS)
2205     {
2206         OutputDebugStringW(L"COutputPin::CreatePinHandle created pin\n");
2207 
2208         // store current interface / medium
2209         CopyMemory(&m_Medium, Medium, sizeof(KSPIN_MEDIUM));
2210         CopyMemory(&m_Interface, Interface, sizeof(KSPIN_INTERFACE));
2211         CopyMemory(&m_MediaFormat, pmt, sizeof(AM_MEDIA_TYPE));
2212 
2213 #ifdef KSPROXY_TRACE
2214         LPOLESTR pMajor, pSub, pFormat;
2215         StringFromIID(m_MediaFormat.majortype, &pMajor);
2216         StringFromIID(m_MediaFormat.subtype , &pSub);
2217         StringFromIID(m_MediaFormat.formattype, &pFormat);
2218         WCHAR Buffer[200];
2219         swprintf(Buffer, L"COutputPin::CreatePinHandle Major %s SubType %s Format %s pbFormat %p cbFormat %u\n", pMajor, pSub, pFormat, pmt->pbFormat, pmt->cbFormat);
2220         CoTaskMemFree(pMajor);
2221         CoTaskMemFree(pSub);
2222         CoTaskMemFree(pFormat);
2223         OutputDebugStringW(Buffer);
2224 #endif
2225 
2226         if (pmt->cbFormat)
2227         {
2228             m_MediaFormat.pbFormat = (BYTE*)CoTaskMemAlloc(pmt->cbFormat);
2229             if (!m_MediaFormat.pbFormat)
2230             {
2231                 CoTaskMemFree(PinConnect);
2232                 m_MediaFormat.pbFormat = NULL;
2233                 m_MediaFormat.cbFormat = 0;
2234                 return E_OUTOFMEMORY;
2235             }
2236             CopyMemory(m_MediaFormat.pbFormat, pmt->pbFormat, pmt->cbFormat);
2237         }
2238 #if 0
2239         Property.Set = KSPROPSETID_Connection;
2240         Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING;
2241         Property.Flags = KSPROPERTY_TYPE_GET;
2242 
2243         ZeroMemory(&Framing, sizeof(KSALLOCATOR_FRAMING));
2244         hr = KsProperty(&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned);
2245         if (SUCCEEDED(hr))
2246         {
2247             m_Properties.cbAlign = (Framing.FileAlignment + 1);
2248             m_Properties.cbBuffer = Framing.FrameSize;
2249             m_Properties.cbPrefix = 0; //FIXME
2250             m_Properties.cBuffers = Framing.Frames;
2251         }
2252         hr = S_OK;
2253 #endif
2254 
2255         if (FAILED(InitializeIOThread()))
2256         {
2257             OutputDebugStringW(L"COutputPin::CreatePinHandle failed to initialize i/o thread\n");
2258         }
2259 
2260         //TODO
2261         // connect pin pipes
2262 
2263     }
2264     else
2265         OutputDebugStringW(L"COutputPin::CreatePinHandle failed to create pin\n");
2266     // free pin connect
2267      CoTaskMemFree(PinConnect);
2268 
2269     return hr;
2270 }
2271 
2272 HRESULT
2273 STDMETHODCALLTYPE
2274 COutputPin::GetSupportedSets(
2275     LPGUID * pOutGuid,
2276     PULONG NumGuids)
2277 {
2278     KSPROPERTY Property;
2279     LPGUID pGuid;
2280     ULONG NumProperty = 0;
2281     ULONG NumMethods = 0;
2282     ULONG NumEvents = 0;
2283     ULONG Length;
2284     ULONG BytesReturned;
2285     HRESULT hr;
2286 
2287     Property.Set = GUID_NULL;
2288     Property.Id = 0;
2289     Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
2290 
2291     KsSynchronousDeviceControl(m_hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumProperty);
2292     KsSynchronousDeviceControl(m_hPin, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumMethods);
2293     KsSynchronousDeviceControl(m_hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumEvents);
2294 
2295     Length = NumProperty + NumMethods + NumEvents;
2296 
2297     assert(Length);
2298 
2299     // allocate guid buffer
2300     pGuid = (LPGUID)CoTaskMemAlloc(Length);
2301     if (!pGuid)
2302     {
2303         // failed
2304         return E_OUTOFMEMORY;
2305     }
2306 
2307     NumProperty /= sizeof(GUID);
2308     NumMethods /= sizeof(GUID);
2309     NumEvents /= sizeof(GUID);
2310 
2311     // get all properties
2312     hr = KsSynchronousDeviceControl(m_hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pGuid, Length, &BytesReturned);
2313     if (FAILED(hr))
2314     {
2315         CoTaskMemFree(pGuid);
2316         return E_FAIL;
2317     }
2318     Length -= BytesReturned;
2319 
2320     // get all methods
2321     if (Length && NumMethods)
2322     {
2323         hr = KsSynchronousDeviceControl(m_hPin, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty], Length, &BytesReturned);
2324         if (FAILED(hr))
2325         {
2326             CoTaskMemFree(pGuid);
2327             return E_FAIL;
2328         }
2329         Length -= BytesReturned;
2330     }
2331 
2332     // get all events
2333     if (Length && NumEvents)
2334     {
2335         hr = KsSynchronousDeviceControl(m_hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty+NumMethods], Length, &BytesReturned);
2336         if (FAILED(hr))
2337         {
2338             CoTaskMemFree(pGuid);
2339             return E_FAIL;
2340         }
2341         Length -= BytesReturned;
2342     }
2343 
2344 #ifdef KSPROXY_TRACE
2345     WCHAR Buffer[200];
2346     swprintf(Buffer, L"NumProperty %lu NumMethods %lu NumEvents %lu\n", NumProperty, NumMethods, NumEvents);
2347     OutputDebugStringW(Buffer);
2348 #endif
2349 
2350     *pOutGuid = pGuid;
2351     *NumGuids = NumProperty+NumEvents+NumMethods;
2352     return S_OK;
2353 }
2354 
2355 HRESULT
2356 STDMETHODCALLTYPE
2357 COutputPin::LoadProxyPlugins(
2358     LPGUID pGuids,
2359     ULONG NumGuids)
2360 {
2361     ULONG Index;
2362     LPOLESTR pStr;
2363     HKEY hKey, hSubKey;
2364     HRESULT hr;
2365     IUnknown * pUnknown;
2366 
2367     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\MediaInterfaces", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
2368     {
2369         OutputDebugStringW(L"CKsProxy::LoadProxyPlugins failed to open MediaInterfaces key\n");
2370         return E_FAIL;
2371     }
2372 
2373     // enumerate all sets
2374     for(Index = 0; Index < NumGuids; Index++)
2375     {
2376         // convert to string
2377         hr = StringFromCLSID(pGuids[Index], &pStr);
2378         if (FAILED(hr))
2379             return E_FAIL;
2380 
2381         // now try open class key
2382         if (RegOpenKeyExW(hKey, pStr, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
2383         {
2384             // no plugin for that set exists
2385             CoTaskMemFree(pStr);
2386             continue;
2387         }
2388 
2389         // try load plugin
2390         hr = CoCreateInstance(pGuids[Index], (IBaseFilter*)this, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
2391         if (SUCCEEDED(hr))
2392         {
2393             // store plugin
2394             m_Plugins.push_back(pUnknown);
2395         }
2396         // close key
2397         RegCloseKey(hSubKey);
2398     }
2399 
2400     // close media interfaces key
2401     RegCloseKey(hKey);
2402     return S_OK;
2403 }
2404 
2405 
2406 HRESULT
2407 WINAPI
2408 COutputPin::IoProcessRoutine()
2409 {
2410     IMediaSample *Sample;
2411     LONG SampleCount;
2412     HRESULT hr;
2413     PKSSTREAM_SEGMENT * StreamSegment;
2414     HANDLE hEvent;
2415     IMediaSample ** Samples;
2416     LONG NumHandles;
2417     DWORD dwStatus;
2418 
2419 #ifdef KSPROXY_TRACE
2420     WCHAR Buffer[200];
2421 #endif
2422 
2423     NumHandles = m_Properties.cBuffers / 2;
2424 
2425     if (!NumHandles)
2426         NumHandles = 8;
2427 
2428     assert(NumHandles);
2429 
2430     //allocate stream segment array
2431     StreamSegment = (PKSSTREAM_SEGMENT*)CoTaskMemAlloc(sizeof(PVOID) * NumHandles);
2432     if (!StreamSegment)
2433     {
2434         OutputDebugStringW(L"COutputPin::IoProcessRoutine out of memory\n");
2435         return E_FAIL;
2436     }
2437 
2438     // allocate handle array
2439     Samples = (IMediaSample**)CoTaskMemAlloc(sizeof(IMediaSample*) * NumHandles);
2440     if (!Samples)
2441     {
2442         OutputDebugStringW(L"COutputPin::IoProcessRoutine out of memory\n");
2443         return E_FAIL;
2444     }
2445 
2446     // zero handles array
2447     ZeroMemory(StreamSegment, sizeof(PVOID) * NumHandles);
2448     ZeroMemory(Samples, sizeof(IMediaSample*) * NumHandles);
2449 
2450     // first wait for the start event to signal
2451     WaitForSingleObject(m_hStartEvent, INFINITE);
2452 
2453     m_IoCount = 0;
2454 
2455     assert(m_InterfaceHandler);
2456     do
2457     {
2458         if (m_StopInProgress)
2459         {
2460             // stop io thread
2461             break;
2462         }
2463 
2464         assert(m_State == KSSTATE_RUN);
2465         assert(m_MemAllocator);
2466 
2467         // get buffer
2468         hr = m_MemAllocator->GetBuffer(&Sample, NULL, NULL, AM_GBF_NOWAIT);
2469 
2470         if (FAILED(hr))
2471         {
2472             WaitForSingleObject(m_hBufferAvailable, INFINITE);
2473             // now retry again
2474             continue;
2475         }
2476 
2477         // fill buffer
2478         SampleCount = 1;
2479         Samples[m_IoCount] = Sample;
2480 
2481         Sample->SetTime(NULL, NULL);
2482         hr = m_InterfaceHandler->KsProcessMediaSamples(NULL, /* FIXME */
2483                                                        &Samples[m_IoCount],
2484                                                        &SampleCount,
2485                                                        KsIoOperation_Read,
2486                                                        &StreamSegment[m_IoCount]);
2487         if (FAILED(hr) || !StreamSegment)
2488         {
2489 #ifdef KSPROXY_TRACE
2490             swprintf(Buffer, L"COutputPin::IoProcessRoutine KsProcessMediaSamples FAILED PinName %s hr %lx\n", m_PinName, hr);
2491             OutputDebugStringW(Buffer);
2492 #endif
2493             break;
2494         }
2495 
2496         // interface handle should increment pending i/o count
2497         assert(m_IoCount >= 1);
2498 
2499         swprintf(Buffer, L"COutputPin::IoProcessRoutine m_IoCount %lu NumHandles %lu\n", m_IoCount, NumHandles);
2500         OutputDebugStringW(Buffer);
2501 
2502         if (m_IoCount != NumHandles)
2503             continue;
2504 
2505         // get completion handle
2506         hEvent = StreamSegment[0]->CompletionEvent;
2507 
2508         // wait for i/o completion
2509         dwStatus = WaitForSingleObject(hEvent, INFINITE);
2510 
2511         swprintf(Buffer, L"COutputPin::IoProcessRoutine dwStatus %lx Error %lx NumHandles %lu\n", dwStatus, GetLastError(), NumHandles);
2512         OutputDebugStringW(Buffer);
2513 
2514         // perform completion
2515         m_InterfaceHandler->KsCompleteIo(StreamSegment[0]);
2516 
2517         // close completion event
2518         CloseHandle(hEvent);
2519 
2520         if (SUCCEEDED(hr))
2521         {
2522             assert(m_MemInputPin);
2523 
2524             // now deliver the sample
2525             hr = m_MemInputPin->Receive(Samples[0]);
2526 
2527 #ifdef KSPROXY_TRACE
2528             swprintf(Buffer, L"COutputPin::IoProcessRoutine PinName %s IMemInputPin::Receive hr %lx Sample %p m_MemAllocator %p\n", m_PinName, hr, Sample, m_MemAllocator);
2529             OutputDebugStringW(Buffer);
2530 #endif
2531 
2532              if (FAILED(hr))
2533                  break;
2534 
2535             Sample = NULL;
2536         }
2537 
2538         //circular stream segment array
2539         RtlMoveMemory(StreamSegment, &StreamSegment[1], sizeof(PVOID) * (NumHandles - 1));
2540         RtlMoveMemory(Samples, &Samples[1], sizeof(IMediaSample*) * (NumHandles - 1));
2541 
2542     }while(TRUE);
2543 
2544     // signal end of i/o thread
2545     SetEvent(m_hStopEvent);
2546 
2547     m_IoThreadStarted = false;
2548 
2549     return NOERROR;
2550 }
2551 
2552 DWORD
2553 WINAPI
2554 COutputPin_IoThreadStartup(
2555     LPVOID lpParameter)
2556 {
2557     COutputPin * Pin = (COutputPin*)lpParameter;
2558     assert(Pin);
2559 
2560     return Pin->IoProcessRoutine();
2561 }
2562 
2563 
2564 HRESULT
2565 WINAPI
2566 COutputPin::InitializeIOThread()
2567 {
2568     HANDLE hThread;
2569 
2570     if (m_IoThreadStarted)
2571         return NOERROR;
2572 
2573     if (!m_hStartEvent)
2574         m_hStartEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2575 
2576     if (!m_hStartEvent)
2577         return E_OUTOFMEMORY;
2578 
2579     if (!m_hStopEvent)
2580         m_hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
2581 
2582     if (!m_hStopEvent)
2583         return E_OUTOFMEMORY;
2584 
2585     if (!m_hBufferAvailable)
2586         m_hBufferAvailable = CreateEventW(NULL, FALSE, FALSE, NULL);
2587 
2588     if (!m_hBufferAvailable)
2589         return E_OUTOFMEMORY;
2590 
2591     m_StopInProgress = false;
2592     m_IoThreadStarted = true;
2593 
2594     // now create the startup thread
2595     hThread = CreateThread(NULL, 0, COutputPin_IoThreadStartup, (LPVOID)this, 0, NULL);
2596     if (!hThread)
2597         return E_OUTOFMEMORY;
2598 
2599 
2600     // close thread handle
2601     CloseHandle(hThread);
2602     return NOERROR;
2603 }
2604 
2605 HRESULT
2606 STDMETHODCALLTYPE
2607 COutputPin_SetState(
2608     IPin * Pin,
2609     KSSTATE State)
2610 {
2611     HRESULT hr = S_OK;
2612     KSPROPERTY Property;
2613     KSSTATE CurState;
2614     ULONG BytesReturned;
2615     COutputPin * pPin = (COutputPin*)Pin;
2616 
2617 #ifdef KSPROXY_TRACE
2618     WCHAR Buffer[200];
2619 #endif
2620 
2621     Property.Set = KSPROPSETID_Connection;
2622     Property.Id = KSPROPERTY_CONNECTION_STATE;
2623     Property.Flags = KSPROPERTY_TYPE_SET;
2624 
2625     EnterCriticalSection(&pPin->m_Lock);
2626 
2627     if (pPin->m_State <= State)
2628     {
2629         if (pPin->m_State == KSSTATE_STOP)
2630         {
2631             hr = pPin->InitializeIOThread();
2632             if (FAILED(hr))
2633             {
2634                 // failed to initialize I/O thread
2635 #ifdef KSPROXY_TRACE
2636                 OutputDebugStringW(L"Failed to initialize I/O Thread\n");
2637 #endif
2638                 LeaveCriticalSection(&pPin->m_Lock);
2639                 return hr;
2640             }
2641             CurState = KSSTATE_ACQUIRE;
2642             hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
2643 
2644 #ifdef KSPROXY_TRACE
2645             swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_STOP KSSTATE_ACQUIRE PinName %s hr %lx\n", pPin->m_PinName, hr);
2646             OutputDebugStringW(Buffer);
2647 #endif
2648 
2649             if (FAILED(hr))
2650             {
2651                 LeaveCriticalSection(&pPin->m_Lock);
2652                 return hr;
2653             }
2654 
2655             pPin->m_State = CurState;
2656 
2657             if (pPin->m_State == State)
2658             {
2659                 LeaveCriticalSection(&pPin->m_Lock);
2660                 return hr;
2661             }
2662         }
2663         if (pPin->m_State == KSSTATE_ACQUIRE)
2664         {
2665             CurState = KSSTATE_PAUSE;
2666             hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
2667 
2668 #ifdef KSPROXY_TRACE
2669             swprintf(Buffer, L"COutputPin_SetState Setting State CurState KSSTATE_ACQUIRE KSSTATE_PAUSE PinName %s hr %lx\n", pPin->m_PinName, hr);
2670             OutputDebugStringW(Buffer);
2671 #endif
2672 
2673             if (FAILED(hr))
2674             {
2675                 LeaveCriticalSection(&pPin->m_Lock);
2676                 return hr;
2677             }
2678 
2679             pPin->m_State = CurState;
2680 
2681             if (pPin->m_State == State)
2682             {
2683                 LeaveCriticalSection(&pPin->m_Lock);
2684                 return hr;
2685             }
2686         }
2687         if (State == KSSTATE_RUN && pPin->m_State == KSSTATE_PAUSE)
2688         {
2689             CurState = KSSTATE_RUN;
2690             hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
2691 
2692 #ifdef KSPROXY_TRACE
2693             swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_PAUSE KSSTATE_RUN PinName %s hr %lx\n", pPin->m_PinName, hr);
2694             OutputDebugStringW(Buffer);
2695 #endif
2696 
2697             if (SUCCEEDED(hr))
2698             {
2699                 pPin->m_State = CurState;
2700                 // signal start event
2701                 SetEvent(pPin->m_hStartEvent);
2702             }
2703         }
2704 
2705         LeaveCriticalSection(&pPin->m_Lock);
2706         return hr;
2707     }
2708     else
2709     {
2710         if (pPin->m_State == KSSTATE_RUN)
2711         {
2712             // setting pending stop flag
2713             pPin->m_StopInProgress = true;
2714 
2715             // release any waiting threads
2716             SetEvent(pPin->m_hBufferAvailable);
2717 
2718             // wait until i/o thread is done
2719             WaitForSingleObject(pPin->m_hStopEvent, INFINITE);
2720 
2721             CurState = KSSTATE_PAUSE;
2722             hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
2723 
2724 #ifdef KSPROXY_TRACE
2725             swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_RUN KSSTATE_PAUSE PinName %s hr %lx\n", pPin->m_PinName, hr);
2726             OutputDebugStringW(Buffer);
2727 #endif
2728 
2729             if (FAILED(hr))
2730             {
2731                 LeaveCriticalSection(&pPin->m_Lock);
2732                 return hr;
2733             }
2734 
2735             pPin->m_State = CurState;
2736 
2737             if (FAILED(hr))
2738             {
2739                 LeaveCriticalSection(&pPin->m_Lock);
2740                 return hr;
2741             }
2742         }
2743         if (pPin->m_State == KSSTATE_PAUSE)
2744         {
2745             CurState = KSSTATE_ACQUIRE;
2746             hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
2747 
2748 #ifdef KSPROXY_TRACE
2749             swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_PAUSE KSSTATE_ACQUIRE PinName %s hr %lx\n", pPin->m_PinName, hr);
2750             OutputDebugStringW(Buffer);
2751 #endif
2752 
2753             if (FAILED(hr))
2754             {
2755                 LeaveCriticalSection(&pPin->m_Lock);
2756                 return hr;
2757             }
2758 
2759             pPin->m_State = CurState;
2760 
2761             if (pPin->m_State == State)
2762             {
2763                 LeaveCriticalSection(&pPin->m_Lock);
2764                 return hr;
2765             }
2766         }
2767 
2768         CloseHandle(pPin->m_hStopEvent);
2769         CloseHandle(pPin->m_hStartEvent);
2770         CloseHandle(pPin->m_hBufferAvailable);
2771 
2772         /* close event handles */
2773         pPin->m_hStopEvent = NULL;
2774         pPin->m_hStartEvent = NULL;
2775         pPin->m_hBufferAvailable = NULL;
2776 
2777         CurState = KSSTATE_STOP;
2778         hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
2779 
2780 #ifdef KSPROXY_TRACE
2781         swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_ACQUIRE KSSTATE_STOP PinName %s hr %lx\n", pPin->m_PinName, hr);
2782         OutputDebugStringW(Buffer);
2783 #endif
2784 
2785         if (SUCCEEDED(hr))
2786         {
2787             // store state
2788             pPin->m_State = CurState;
2789         }
2790 
2791         // unset pending stop flag
2792         pPin->m_StopInProgress = false;
2793 
2794         LeaveCriticalSection(&pPin->m_Lock);
2795         return hr;
2796     }
2797 }
2798 
2799 HRESULT
2800 WINAPI
2801 COutputPin_Constructor(
2802     IBaseFilter * ParentFilter,
2803     LPCWSTR PinName,
2804     ULONG PinId,
2805     KSPIN_COMMUNICATION Communication,
2806     REFIID riid,
2807     LPVOID * ppv)
2808 {
2809     COutputPin * handler = new COutputPin(ParentFilter, PinName, PinId, Communication);
2810 
2811     if (!handler)
2812         return E_OUTOFMEMORY;
2813 
2814     if (FAILED(handler->QueryInterface(riid, ppv)))
2815     {
2816         /* not supported */
2817         delete handler;
2818         return E_NOINTERFACE;
2819     }
2820 
2821     return S_OK;
2822 }
2823