[KSPROXY]
[reactos.git] / reactos / dll / directx / ksproxy / output_pin.cpp
index c5d897c..594788a 100644 (file)
@@ -160,6 +160,11 @@ public:
     HRESULT STDMETHODCALLTYPE CheckFormat(const AM_MEDIA_TYPE *pmt);
     HRESULT STDMETHODCALLTYPE CreatePin(const AM_MEDIA_TYPE *pmt);
     HRESULT STDMETHODCALLTYPE CreatePinHandle(PKSPIN_MEDIUM Medium, PKSPIN_INTERFACE Interface, const AM_MEDIA_TYPE *pmt);
+    HRESULT WINAPI IoProcessRoutine();
+    HRESULT WINAPI InitializeIOThread();
+
+    friend DWORD WINAPI COutputPin_IoThreadStartup(LPVOID lpParameter);
+    friend HRESULT STDMETHODCALLTYPE COutputPin_SetState(IPin * Pin, KSSTATE State);
 
 protected:
     LONG m_Ref;
@@ -167,7 +172,6 @@ protected:
     LPCWSTR m_PinName;
     HANDLE m_hPin;
     ULONG m_PinId;
-    IKsObject * m_KsObjectParent;
     IPin * m_Pin;
     IKsAllocatorEx * m_KsAllocatorEx;
     ULONG m_PipeAllocatorFlag;
@@ -178,21 +182,27 @@ protected:
     PKSALLOCATOR_FRAMING_EX m_FramingEx[4];
 
     IMemAllocator * m_MemAllocator;
+    IMemInputPin * m_MemInputPin;
     LONG m_IoCount;
     KSPIN_COMMUNICATION m_Communication;
     KSPIN_INTERFACE m_Interface;
     KSPIN_MEDIUM m_Medium;
     AM_MEDIA_TYPE m_MediaFormat;
-
-    IMediaSeeking * m_FilterMediaSeeking;
     ALLOCATOR_PROPERTIES m_Properties;
     IKsInterfaceHandler * m_InterfaceHandler;
+
+    HANDLE m_hStartEvent;
+    HANDLE m_hBufferAvailable;
+    HANDLE m_hStopEvent;
+    BOOL m_StopInProgress;
+    BOOL m_IoThreadStarted;
+
+    KSSTATE m_State;
+    CRITICAL_SECTION m_Lock;
 };
 
 COutputPin::~COutputPin()
 {
-    if (m_KsObjectParent)
-        m_KsObjectParent->Release();
 }
 
 COutputPin::COutputPin(
@@ -204,31 +214,38 @@ COutputPin::COutputPin(
                                          m_PinName(PinName),
                                          m_hPin(INVALID_HANDLE_VALUE),
                                          m_PinId(PinId),
-                                         m_KsObjectParent(0),
                                          m_Pin(0),
                                          m_KsAllocatorEx(0),
                                          m_PipeAllocatorFlag(0),
                                          m_bPinBusCacheInitialized(0),
                                          m_FilterName(0),
                                          m_MemAllocator(0),
+                                         m_MemInputPin(0),
                                          m_IoCount(0),
                                          m_Communication(Communication),
-                                         m_FilterMediaSeeking(0),
-                                         m_InterfaceHandler(0)
+                                         m_InterfaceHandler(0),
+                                         m_hStartEvent(0),
+                                         m_hBufferAvailable(0),
+                                         m_hStopEvent(0),
+                                         m_StopInProgress(0),
+                                         m_IoThreadStarted(0),
+                                         m_State(KSSTATE_STOP)
 {
     HRESULT hr;
+    IKsObject * KsObjectParent;
 
-    hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&m_KsObjectParent);
-    assert(hr == S_OK);
-
-    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&m_FilterMediaSeeking);
+    hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
     assert(hr == S_OK);
 
     ZeroMemory(m_FramingProp, sizeof(m_FramingProp));
     ZeroMemory(m_FramingEx, sizeof(m_FramingEx));
 
-    hr = KsGetMediaType(0, &m_MediaFormat, m_KsObjectParent->KsGetObjectHandle(), m_PinId);
+    hr = KsGetMediaType(0, &m_MediaFormat, KsObjectParent->KsGetObjectHandle(), m_PinId);
     assert(hr == S_OK);
+
+    InitializeCriticalSection(&m_Lock);
+
+    KsObjectParent->Release();
 };
 
 HRESULT
@@ -241,7 +258,9 @@ COutputPin::QueryInterface(
     if (IsEqualGUID(refiid, IID_IUnknown) ||
         IsEqualGUID(refiid, IID_IPin))
     {
+#ifdef KSPROXY_TRACE
         OutputDebugStringW(L"COutputPin::QueryInterface IID_IPin\n");
+#endif
         *Output = PVOID(this);
         reinterpret_cast<IUnknown*>(*Output)->AddRef();
         return NOERROR;
@@ -254,8 +273,9 @@ COutputPin::QueryInterface(
             if (FAILED(hr))
                 return hr;
         }
-
+#ifdef KSPROXY_TRACE
         OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsObject\n");
+#endif
         *Output = (IKsObject*)(this);
         reinterpret_cast<IKsObject*>(*Output)->AddRef();
         return NOERROR;
@@ -292,14 +312,18 @@ COutputPin::QueryInterface(
             if (FAILED(hr))
                 return hr;
         }
+#ifdef KSPROXY_TRACE
         OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsPropertySet\n");
+#endif
         *Output = (IKsPropertySet*)(this);
         reinterpret_cast<IKsPropertySet*>(*Output)->AddRef();
         return NOERROR;
     }
     else if (IsEqualGUID(refiid, IID_IKsControl))
     {
+#ifdef KSPROXY_TRACE
         OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsControl\n");
+#endif
         *Output = (IKsControl*)(this);
         reinterpret_cast<IKsControl*>(*Output)->AddRef();
         return NOERROR;
@@ -314,14 +338,18 @@ COutputPin::QueryInterface(
 #endif
     else if (IsEqualGUID(refiid, IID_IKsPinFactory))
     {
+#ifdef KSPROXY_TRACE
         OutputDebugStringW(L"COutputPin::QueryInterface IID_IKsPinFactory\n");
+#endif
         *Output = (IKsPinFactory*)(this);
         reinterpret_cast<IKsPinFactory*>(*Output)->AddRef();
         return NOERROR;
     }
     else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages))
     {
+#ifdef KSPROXY_TRACE
         OutputDebugStringW(L"COutputPin::QueryInterface IID_ISpecifyPropertyPages\n");
+#endif
         *Output = (ISpecifyPropertyPages*)(this);
         reinterpret_cast<ISpecifyPropertyPages*>(*Output)->AddRef();
         return NOERROR;
@@ -351,12 +379,14 @@ COutputPin::QueryInterface(
         return NOERROR;
     }
 
+#ifdef KSPROXY_TRACE
     WCHAR Buffer[MAX_PATH];
     LPOLESTR lpstr;
     StringFromCLSID(refiid, &lpstr);
     swprintf(Buffer, L"COutputPin::QueryInterface: NoInterface for %s PinId %u PinName %s\n", lpstr, m_PinId, m_PinName);
     OutputDebugStringW(Buffer);
     CoTaskMemFree(lpstr);
+#endif
 
     return E_NOINTERFACE;
 }
@@ -369,7 +399,9 @@ STDMETHODCALLTYPE
 COutputPin::SuggestAllocatorProperties(
     const ALLOCATOR_PROPERTIES *pprop)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::SuggestAllocatorProperties\n");
+#endif
 
     if (m_Pin)
     {
@@ -386,7 +418,9 @@ STDMETHODCALLTYPE
 COutputPin::GetAllocatorProperties(
     ALLOCATOR_PROPERTIES *pprop)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetAllocatorProperties\n");
+#endif
 
     if (!m_Pin)
     {
@@ -412,7 +446,9 @@ STDMETHODCALLTYPE
 COutputPin::SetFormat(
     AM_MEDIA_TYPE *pmt)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::SetFormat NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -420,7 +456,9 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::GetFormat(AM_MEDIA_TYPE **ppmt)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetFormat NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -430,7 +468,9 @@ COutputPin::GetNumberOfCapabilities(
     int *piCount,
     int *piSize)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetNumberOfCapabilities NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -441,7 +481,9 @@ COutputPin::GetStreamCaps(
     AM_MEDIA_TYPE **ppmt,
     BYTE *pSCC)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetStreamCaps NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -452,8 +494,14 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::NotifyRelease()
 {
-    OutputDebugStringW(L"COutputPin::NotifyRelease NotImplemented\n");
-    return E_NOTIMPL;
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"COutputPin::NotifyRelease\n");
+#endif
+
+    // notify thread of new available sample
+    SetEvent(m_hBufferAvailable);
+
+    return NOERROR;
 }
 
 //-------------------------------------------------------------------
@@ -464,7 +512,17 @@ STDMETHODCALLTYPE
 COutputPin::GetCapabilities(
     DWORD *pCapabilities)
 {
-    return m_FilterMediaSeeking->GetCapabilities(pCapabilities);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->GetCapabilities(pCapabilities);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -472,7 +530,17 @@ STDMETHODCALLTYPE
 COutputPin::CheckCapabilities(
     DWORD *pCapabilities)
 {
-    return m_FilterMediaSeeking->CheckCapabilities(pCapabilities);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->CheckCapabilities(pCapabilities);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -480,7 +548,17 @@ STDMETHODCALLTYPE
 COutputPin::IsFormatSupported(
     const GUID *pFormat)
 {
-    return m_FilterMediaSeeking->IsFormatSupported(pFormat);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->IsFormatSupported(pFormat);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -488,7 +566,17 @@ STDMETHODCALLTYPE
 COutputPin::QueryPreferredFormat(
     GUID *pFormat)
 {
-    return m_FilterMediaSeeking->QueryPreferredFormat(pFormat);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->QueryPreferredFormat(pFormat);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -496,7 +584,17 @@ STDMETHODCALLTYPE
 COutputPin::GetTimeFormat(
     GUID *pFormat)
 {
-    return m_FilterMediaSeeking->GetTimeFormat(pFormat);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->GetTimeFormat(pFormat);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -504,7 +602,17 @@ STDMETHODCALLTYPE
 COutputPin::IsUsingTimeFormat(
     const GUID *pFormat)
 {
-    return m_FilterMediaSeeking->IsUsingTimeFormat(pFormat);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->IsUsingTimeFormat(pFormat);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -512,7 +620,17 @@ STDMETHODCALLTYPE
 COutputPin::SetTimeFormat(
     const GUID *pFormat)
 {
-    return m_FilterMediaSeeking->SetTimeFormat(pFormat);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->SetTimeFormat(pFormat);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -520,7 +638,17 @@ STDMETHODCALLTYPE
 COutputPin::GetDuration(
     LONGLONG *pDuration)
 {
-    return m_FilterMediaSeeking->GetDuration(pDuration);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->GetDuration(pDuration);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -528,7 +656,17 @@ STDMETHODCALLTYPE
 COutputPin::GetStopPosition(
     LONGLONG *pStop)
 {
-    return m_FilterMediaSeeking->GetStopPosition(pStop);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->GetStopPosition(pStop);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 
@@ -537,7 +675,17 @@ STDMETHODCALLTYPE
 COutputPin::GetCurrentPosition(
     LONGLONG *pCurrent)
 {
-    return m_FilterMediaSeeking->GetCurrentPosition(pCurrent);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->GetCurrentPosition(pCurrent);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -548,7 +696,17 @@ COutputPin::ConvertTimeFormat(
     LONGLONG Source,
     const GUID *pSourceFormat)
 {
-    return m_FilterMediaSeeking->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -559,7 +717,17 @@ COutputPin::SetPositions(
     LONGLONG *pStop,
     DWORD dwStopFlags)
 {
-    return m_FilterMediaSeeking->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -568,7 +736,17 @@ COutputPin::GetPositions(
     LONGLONG *pCurrent,
     LONGLONG *pStop)
 {
-    return m_FilterMediaSeeking->GetPositions(pCurrent, pStop);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->GetPositions(pCurrent, pStop);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -577,7 +755,17 @@ COutputPin::GetAvailable(
     LONGLONG *pEarliest,
     LONGLONG *pLatest)
 {
-    return m_FilterMediaSeeking->GetAvailable(pEarliest, pLatest);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->GetAvailable(pEarliest, pLatest);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -585,7 +773,17 @@ STDMETHODCALLTYPE
 COutputPin::SetRate(
     double dRate)
 {
-    return m_FilterMediaSeeking->SetRate(dRate);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->SetRate(dRate);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -593,7 +791,17 @@ STDMETHODCALLTYPE
 COutputPin::GetRate(
     double *pdRate)
 {
-    return m_FilterMediaSeeking->GetRate(pdRate);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->GetRate(pdRate);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 HRESULT
@@ -601,7 +809,17 @@ STDMETHODCALLTYPE
 COutputPin::GetPreroll(
     LONGLONG *pllPreroll)
 {
-    return m_FilterMediaSeeking->GetPreroll(pllPreroll);
+    IMediaSeeking * FilterMediaSeeking;
+    HRESULT hr;
+
+    hr = m_ParentFilter->QueryInterface(IID_IMediaSeeking, (LPVOID*)&FilterMediaSeeking);
+    if (FAILED(hr))
+        return hr;
+
+    hr = FilterMediaSeeking->GetPreroll(pllPreroll);
+
+    FilterMediaSeeking->Release();
+    return hr;
 }
 
 //-------------------------------------------------------------------
@@ -613,7 +831,9 @@ COutputPin::Notify(
     IBaseFilter *pSelf,
     Quality q)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::Notify NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -622,7 +842,9 @@ STDMETHODCALLTYPE
 COutputPin::SetSink(
     IQualityControl *piqc)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::SetSink NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -635,7 +857,9 @@ STDMETHODCALLTYPE
 COutputPin::KsAddAggregate(
     IN REFGUID AggregateClass)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsAddAggregate NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -644,7 +868,9 @@ STDMETHODCALLTYPE
 COutputPin::KsRemoveAggregate(
     REFGUID AggregateClass)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsRemoveAggregate NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -658,8 +884,24 @@ STDMETHODCALLTYPE
 COutputPin::KsQueryMediums(
     PKSMULTIPLE_ITEM* MediumList)
 {
-    HANDLE hFilter = m_KsObjectParent->KsGetObjectHandle();
-    return KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_MEDIUMS, (PVOID*)MediumList);
+    HRESULT hr;
+    HANDLE hFilter;
+    IKsObject * KsObjectParent;
+
+    hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
+    if (FAILED(hr))
+        return E_NOINTERFACE;
+
+    hFilter = KsObjectParent->KsGetObjectHandle();
+
+    if (hFilter)
+        hr = KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_MEDIUMS, (PVOID*)MediumList);
+    else
+        hr = E_HANDLE;
+
+    KsObjectParent->Release();
+
+    return hr;
 }
 
 HRESULT
@@ -667,9 +909,24 @@ STDMETHODCALLTYPE
 COutputPin::KsQueryInterfaces(
     PKSMULTIPLE_ITEM* InterfaceList)
 {
-    HANDLE hFilter = m_KsObjectParent->KsGetObjectHandle();
+    HRESULT hr;
+    HANDLE hFilter;
+    IKsObject * KsObjectParent;
 
-    return KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_INTERFACES, (PVOID*)InterfaceList);
+    hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
+    if (FAILED(hr))
+        return hr;
+
+    hFilter = KsObjectParent->KsGetObjectHandle();
+
+    if (hFilter)
+        hr = KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_INTERFACES, (PVOID*)InterfaceList);
+    else
+        hr = E_HANDLE;
+
+    KsObjectParent->Release();
+
+    return hr;
 }
 
 HRESULT
@@ -678,7 +935,9 @@ COutputPin::KsCreateSinkPinHandle(
     KSPIN_INTERFACE& Interface,
     KSPIN_MEDIUM& Medium)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsCreateSinkPinHandle NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -721,7 +980,9 @@ COutputPin::KsPropagateAcquire()
     ULONG BytesReturned;
     HRESULT hr;
 
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsPropagateAcquire\n");
+#endif
 
     assert(m_hPin != INVALID_HANDLE_VALUE);
 
@@ -732,6 +993,10 @@ COutputPin::KsPropagateAcquire()
     State = KSSTATE_ACQUIRE;
 
     hr = KsProperty(&Property, sizeof(KSPROPERTY), (LPVOID)&State, sizeof(KSSTATE), &BytesReturned);
+    if (SUCCEEDED(hr))
+    {
+        m_State = State;
+    }
 
     //TODO
     //propagate to connected pin on the pipe
@@ -813,7 +1078,9 @@ COutputPin::KsQualityNotify(
     ULONG Proportion,
     REFERENCE_TIME TimeDelta)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsQualityNotify NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -827,7 +1094,9 @@ COutputPin::KsNotifyError(
     IMediaSample* Sample,
     HRESULT hr)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsNotifyError NotImplemented\n");
+#endif
 }
 
 
@@ -984,7 +1253,9 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::GetPages(CAUUID *pPages)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetPages NotImplemented\n");
+#endif
 
     if (!pPages)
         return E_POINTER;
@@ -1004,7 +1275,10 @@ STDMETHODCALLTYPE
 COutputPin::KsPinFactory(
     ULONG* PinFactory)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsPinFactory\n");
+#endif
+
     *PinFactory = m_PinId;
     return S_OK;
 }
@@ -1020,7 +1294,9 @@ COutputPin::Render(
     IPin *ppinOut,
     IGraphBuilder *pGraph)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::Render\n");
+#endif
     return S_OK;
 }
 
@@ -1030,7 +1306,10 @@ COutputPin::Backout(
     IPin *ppinOut, 
     IGraphBuilder *pGraph)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::Backout\n");
+#endif
+
     return S_OK;
 }
 //-------------------------------------------------------------------
@@ -1040,7 +1319,10 @@ HANDLE
 STDMETHODCALLTYPE
 COutputPin::KsGetObjectHandle()
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsGetObjectHandle\n");
+#endif
+
     assert(m_hPin != INVALID_HANDLE_VALUE);
     return m_hPin;
 }
@@ -1058,16 +1340,17 @@ COutputPin::KsProperty(
     ULONG* BytesReturned)
 {
     HRESULT hr;
-    WCHAR Buffer[100];
-    LPOLESTR pstr;
 
     assert(m_hPin != INVALID_HANDLE_VALUE);
 
     hr = KsSynchronousDeviceControl(m_hPin, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned);
-
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[100];
+    LPOLESTR pstr;
     StringFromCLSID(Property->Set, &pstr);
     swprintf(Buffer, L"COutputPin::KsProperty Set %s Id %lu Flags %x hr %x\n", pstr, Property->Id, Property->Flags, hr);
     OutputDebugStringW(Buffer);
+#endif
 
     return hr;
 }
@@ -1082,7 +1365,9 @@ COutputPin::KsMethod(
     ULONG* BytesReturned)
 {
     assert(m_hPin != INVALID_HANDLE_VALUE);
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsMethod\n");
+#endif
     return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned);
 }
 
@@ -1097,7 +1382,9 @@ COutputPin::KsEvent(
 {
     assert(m_hPin != INVALID_HANDLE_VALUE);
 
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsEvent\n");
+#endif
 
     if (EventLength)
         return KsSynchronousDeviceControl(m_hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned);
@@ -1202,7 +1489,9 @@ COutputPin::QuerySupported(
     KSPROPERTY Property;
     ULONG BytesReturned;
 
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::QuerySupported\n");
+#endif
 
     Property.Set = guidPropSet;
     Property.Id = dwPropID;
@@ -1220,8 +1509,14 @@ STDMETHODCALLTYPE
 COutputPin::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
 {
     HRESULT hr;
+    ALLOCATOR_PROPERTIES Properties;
+    IMemAllocatorCallbackTemp *pMemCallback;
 
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[200];
     OutputDebugStringW(L"COutputPin::Connect called\n");
+#endif
+
     if (pmt)
     {
         hr = pReceivePin->QueryAccept(pmt);
@@ -1238,7 +1533,120 @@ COutputPin::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
          pmt = &m_MediaFormat;
     }
 
-    //FIXME create pin handle
+    // query for IMemInput interface
+    hr = pReceivePin->QueryInterface(IID_IMemInputPin, (void**)&m_MemInputPin);
+    if (FAILED(hr))
+    {
+#ifdef KSPROXY_TRACE
+        OutputDebugStringW(L"COutputPin::Connect no IMemInputPin interface\n");
+#endif
+
+        DebugBreak();
+        return hr;
+    }
+
+    // get input pin allocator properties
+    ZeroMemory(&Properties, sizeof(ALLOCATOR_PROPERTIES));
+    m_MemInputPin->GetAllocatorRequirements(&Properties);
+
+    //FIXME determine allocator properties
+    Properties.cBuffers = 32;
+    Properties.cbBuffer = 2048 * 188; //2048 frames * MPEG2 TS Payload size
+    Properties.cbAlign = 4;
+
+    // get input pin allocator
+#if 0
+    hr = m_MemInputPin->GetAllocator(&m_MemAllocator);
+    if (SUCCEEDED(hr))
+    {
+        // set allocator properties
+        hr = m_MemAllocator->SetProperties(&Properties, &m_Properties);
+        if (FAILED(hr))
+            m_MemAllocator->Release();
+    }
+#endif
+
+    if (1)
+    {
+        hr = CKsAllocator_Constructor(NULL, IID_IMemAllocator, (void**)&m_MemAllocator);
+        if (FAILED(hr))
+            return hr;
+
+        // set allocator properties
+        hr = m_MemAllocator->SetProperties(&Properties, &m_Properties);
+        if (FAILED(hr))
+        {
+#ifdef KSPROXY_TRACE
+            swprintf(Buffer, L"COutputPin::Connect IMemAllocator::SetProperties failed with hr %lx\n", hr);
+            OutputDebugStringW(Buffer);
+#endif
+            m_MemAllocator->Release();
+            m_MemInputPin->Release();
+            return hr;
+        }
+    }
+
+    // commit property changes
+    hr = m_MemAllocator->Commit();
+    if (FAILED(hr))
+    {
+#ifdef KSPROXY_TRACE
+        swprintf(Buffer, L"COutputPin::Connect IMemAllocator::Commit failed with hr %lx\n", hr);
+        OutputDebugStringW(Buffer);
+#endif
+        m_MemAllocator->Release();
+        m_MemInputPin->Release();
+        return hr;
+    }
+
+    // get callback interface
+    hr = m_MemAllocator->QueryInterface(IID_IMemAllocatorCallbackTemp, (void**)&pMemCallback);
+    if (FAILED(hr))
+    {
+#ifdef KSPROXY_TRACE
+        swprintf(Buffer, L"COutputPin::Connect No IMemAllocatorCallbackTemp interface hr %lx\n", hr);
+        OutputDebugStringW(Buffer);
+#endif
+        m_MemAllocator->Release();
+        m_MemInputPin->Release();
+        return hr;
+    }
+
+    // set notification routine
+    hr = pMemCallback->SetNotify((IMemAllocatorNotifyCallbackTemp*)this);
+
+    // release IMemAllocatorNotifyCallbackTemp interface
+    pMemCallback->Release();
+
+    if (FAILED(hr))
+    {
+#ifdef KSPROXY_TRACE
+        swprintf(Buffer, L"COutputPin::Connect IMemAllocatorNotifyCallbackTemp::SetNotify failed hr %lx\n", hr);
+        OutputDebugStringW(Buffer);
+#endif
+        m_MemAllocator->Release();
+        m_MemInputPin->Release();
+        return hr;
+    }
+
+    // now set allocator
+    hr = m_MemInputPin->NotifyAllocator(m_MemAllocator, TRUE);
+    if (FAILED(hr))
+    {
+#ifdef KSPROXY_TRACE
+        swprintf(Buffer, L"COutputPin::Connect IMemInputPin::NotifyAllocator failed with hr %lx\n", hr);
+        OutputDebugStringW(Buffer);
+#endif
+        m_MemAllocator->Release();
+        m_MemInputPin->Release();
+        return hr;
+    }
+
+    if (!m_hPin)
+    {
+        //FIXME create pin handle
+        assert(0);
+    }
 
     // receive connection;
     hr = pReceivePin->ReceiveConnection((IPin*)this, pmt);
@@ -1247,7 +1655,14 @@ COutputPin::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
         // increment reference count
         pReceivePin->AddRef();
         m_Pin = pReceivePin;
+#ifdef KSPROXY_TRACE
         OutputDebugStringW(L"COutputPin::Connect success\n");
+#endif
+    }
+    else
+    {
+        m_MemInputPin->Release();
+        m_MemAllocator->Release();
     }
 
     return hr;
@@ -1257,14 +1672,15 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
 {
-    OutputDebugStringW(L"COutputPin::ReceiveConnection\n");
     return E_UNEXPECTED;
 }
 HRESULT
 STDMETHODCALLTYPE
 COutputPin::Disconnect( void)
 {
+#ifdef KSPROXY_TRACE
    OutputDebugStringW(L"COutputPin::Disconnect\n");
+#endif
 
     if (!m_Pin)
     {
@@ -1277,15 +1693,24 @@ COutputPin::Disconnect( void)
 
     m_Pin->Release();
     m_Pin = NULL;
+    m_MemInputPin->Release();
+    m_MemAllocator->Release();
+
+    CloseHandle(m_hPin);
+    m_hPin = INVALID_HANDLE_VALUE;
 
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::Disconnect\n");
+#endif
     return S_OK;
 }
 HRESULT
 STDMETHODCALLTYPE
 COutputPin::ConnectedTo(IPin **pPin)
 {
+#ifdef KSPROXY_TRACE
    OutputDebugStringW(L"COutputPin::ConnectedTo\n");
+#endif
 
     if (!pPin)
         return E_POINTER;
@@ -1305,15 +1730,16 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::ConnectionMediaType(AM_MEDIA_TYPE *pmt)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::ConnectionMediaType called\n");
+#endif
+
     return E_NOTIMPL;
 }
 HRESULT
 STDMETHODCALLTYPE
 COutputPin::QueryPinInfo(PIN_INFO *pInfo)
 {
-    OutputDebugStringW(L"COutputPin::QueryPinInfo\n");
-
     wcscpy(pInfo->achName, m_PinName);
     pInfo->dir = PINDIR_OUTPUT;
     pInfo->pFilter = m_ParentFilter;
@@ -1325,8 +1751,6 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::QueryDirection(PIN_DIRECTION *pPinDir)
 {
-    OutputDebugStringW(L"COutputPin::QueryDirection\n");
-
     if (pPinDir)
     {
         *pPinDir = PINDIR_OUTPUT;
@@ -1339,8 +1763,6 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::QueryId(LPWSTR *Id)
 {
-    OutputDebugStringW(L"COutputPin::QueryId\n");
-
     *Id = (LPWSTR)CoTaskMemAlloc((wcslen(m_PinName)+1)*sizeof(WCHAR));
     if (!*Id)
         return E_OUTOFMEMORY;
@@ -1352,7 +1774,10 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::QueryAccept(const AM_MEDIA_TYPE *pmt)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::QueryAccept called\n");
+#endif
+
     return E_NOTIMPL;
 }
 HRESULT
@@ -1363,23 +1788,22 @@ COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum)
     ULONG MediaTypeCount = 0, Index;
     AM_MEDIA_TYPE * MediaTypes;
     HANDLE hFilter;
+    IKsObject * KsObjectParent;
 
-    OutputDebugStringW(L"COutputPin::EnumMediaTypes called\n");
-
-    if (!m_KsObjectParent)
-    {
-        // no interface
-        return E_NOINTERFACE;
-    }
+    hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
+    if (FAILED(hr))
+        return hr;
 
     // get parent filter handle
-    hFilter = m_KsObjectParent->KsGetObjectHandle();
+    hFilter = KsObjectParent->KsGetObjectHandle();
+
+    // release IKsObject
+    KsObjectParent->Release();
 
     // query media type count
     hr = KsGetMediaTypeCount(hFilter, m_PinId, &MediaTypeCount);
     if (FAILED(hr) || !MediaTypeCount)
     {
-        OutputDebugStringW(L"COutputPin::EnumMediaTypes failed1\n");
         return hr;
     }
 
@@ -1388,7 +1812,6 @@ COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum)
     if (!MediaTypes)
     {
         // not enough memory
-        OutputDebugStringW(L"COutputPin::EnumMediaTypes CoTaskMemAlloc\n");
         return E_OUTOFMEMORY;
     }
 
@@ -1403,7 +1826,6 @@ COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum)
         {
             // failed
             CoTaskMemFree(MediaTypes);
-            OutputDebugStringW(L"COutputPin::EnumMediaTypes failed\n");
             return hr;
         }
     }
@@ -1414,36 +1836,40 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::QueryInternalConnections(IPin **apPin, ULONG *nPin)
 {
-    OutputDebugStringW(L"COutputPin::QueryInternalConnections called\n");
     return E_NOTIMPL;
 }
 HRESULT
 STDMETHODCALLTYPE
 COutputPin::EndOfStream( void)
 {
-    OutputDebugStringW(L"COutputPin::EndOfStream called\n");
-    return E_NOTIMPL;
+    /* should be called only on input pins */
+    return E_UNEXPECTED;
 }
 HRESULT
 STDMETHODCALLTYPE
 COutputPin::BeginFlush( void)
 {
-    OutputDebugStringW(L"COutputPin::BeginFlush called\n");
-    return E_NOTIMPL;
+    /* should be called only on input pins */
+    return E_UNEXPECTED;
 }
 HRESULT
 STDMETHODCALLTYPE
 COutputPin::EndFlush( void)
 {
-    OutputDebugStringW(L"COutputPin::EndFlush called\n");
-    return E_NOTIMPL;
+    /* should be called only on input pins */
+    return E_UNEXPECTED;
 }
 HRESULT
 STDMETHODCALLTYPE
 COutputPin::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
 {
-    OutputDebugStringW(L"COutputPin::NewSegment called\n");
-    return E_NOTIMPL;
+    if (!m_Pin)
+    {
+        // we are not connected
+        return VFW_E_NOT_CONNECTED;
+    }
+
+    return m_Pin->NewSegment(tStart, tStop, dRate);
 }
 
 //-------------------------------------------------------------------
@@ -1455,12 +1881,26 @@ COutputPin::CheckFormat(
     PKSMULTIPLE_ITEM MultipleItem;
     PKSDATAFORMAT DataFormat;
     HRESULT hr;
+    IKsObject * KsObjectParent;
+    HANDLE hFilter;
 
     if (!pmt)
         return E_POINTER;
 
-    HANDLE hFilter = m_KsObjectParent->KsGetObjectHandle();
-    assert(hFilter != NULL);
+    // get IKsObject interface
+    hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
+    if (FAILED(hr))
+        return hr;
+
+    // get parent filter handle
+    hFilter = KsObjectParent->KsGetObjectHandle();
+
+    // release IKsObject
+    KsObjectParent->Release();
+
+    if (!hFilter)
+        return E_HANDLE;
+
 
     hr = KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_DATARANGES, (PVOID*)&MultipleItem);
     if (FAILED(hr))
@@ -1475,7 +1915,6 @@ COutputPin::CheckFormat(
         {
             // format is supported
             CoTaskMemFree(MultipleItem);
-            OutputDebugStringW(L"COutputPin::CheckFormat format OK\n");
             return S_OK;
         }
         DataFormat = (PKSDATAFORMAT)((ULONG_PTR)DataFormat + DataFormat->FormatSize);
@@ -1550,7 +1989,6 @@ COutputPin::CreatePin(
             if (FAILED(hr))
             {
                 // failed to load interface handler plugin
-                OutputDebugStringW(L"COutputPin::CreatePin failed to load InterfaceHandlerPlugin\n");
                 CoTaskMemFree(MediumList);
                 CoTaskMemFree(InterfaceList);
 
@@ -1562,7 +2000,6 @@ COutputPin::CreatePin(
             if (FAILED(hr))
             {
                 // failed to load interface handler plugin
-                OutputDebugStringW(L"COutputPin::CreatePin failed to initialize InterfaceHandlerPlugin\n");
                 InterfaceHandler->Release();
                 CoTaskMemFree(MediumList);
                 CoTaskMemFree(InterfaceList);
@@ -1575,10 +2012,13 @@ COutputPin::CreatePin(
     }
     else
     {
+#ifdef KSPROXY_TRACE
         WCHAR Buffer[100];
         swprintf(Buffer, L"COutputPin::CreatePin unexpected communication %u %s\n", m_Communication, m_PinName);
         OutputDebugStringW(Buffer);
         DebugBreak();
+#endif
+
         hr = E_FAIL;
     }
 
@@ -1600,6 +2040,12 @@ COutputPin::CreatePinHandle(
     PKSDATAFORMAT DataFormat;
     ULONG Length;
     HRESULT hr;
+    HANDLE hFilter;
+    IKsObject * KsObjectParent;
+
+    //KSALLOCATOR_FRAMING Framing;
+    //KSPROPERTY Property;
+    //ULONG BytesReturned;
 
     if (m_hPin != INVALID_HANDLE_VALUE)
     {
@@ -1647,11 +2093,22 @@ COutputPin::CreatePinHandle(
         CopyMemory((DataFormat + 1), pmt->pbFormat, pmt->cbFormat);
     }
 
-    HANDLE hFilter = m_KsObjectParent->KsGetObjectHandle();
-    assert(hFilter != NULL);
+    // get IKsObject interface
+    hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
+    if (FAILED(hr))
+        return hr;
+
+    // get parent filter handle
+    hFilter = KsObjectParent->KsGetObjectHandle();
+
+    // release IKsObject
+    KsObjectParent->Release();
+
+    if (!hFilter)
+        return E_HANDLE;
 
     // create pin
-    hr = KsCreatePin(hFilter, PinConnect, GENERIC_WRITE, &m_hPin);
+    hr = KsCreatePin(hFilter, PinConnect, GENERIC_READ, &m_hPin);
 
     if (SUCCEEDED(hr))
     {
@@ -1660,6 +2117,7 @@ COutputPin::CreatePinHandle(
         CopyMemory(&m_Interface, Interface, sizeof(KSPIN_INTERFACE));
         CopyMemory(&m_MediaFormat, pmt, sizeof(AM_MEDIA_TYPE));
 
+#ifdef KSPROXY_TRACE
         LPOLESTR pMajor, pSub, pFormat;
         StringFromIID(m_MediaFormat.majortype, &pMajor);
         StringFromIID(m_MediaFormat.subtype , &pSub);
@@ -1670,6 +2128,7 @@ COutputPin::CreatePinHandle(
         CoTaskMemFree(pSub);
         CoTaskMemFree(pFormat);
         OutputDebugStringW(Buffer);
+#endif
 
         if (pmt->cbFormat)
         {
@@ -1683,6 +2142,28 @@ COutputPin::CreatePinHandle(
             }
             CopyMemory(m_MediaFormat.pbFormat, pmt->pbFormat, pmt->cbFormat);
         }
+#if 0
+        Property.Set = KSPROPSETID_Connection;
+        Property.Id = KSPROPERTY_CONNECTION_ALLOCATORFRAMING;
+        Property.Flags = KSPROPERTY_TYPE_GET;
+
+        ZeroMemory(&Framing, sizeof(KSALLOCATOR_FRAMING));
+        hr = KsProperty(&Property, sizeof(KSPROPERTY), (PVOID)&Framing, sizeof(KSALLOCATOR_FRAMING), &BytesReturned);
+        if (SUCCEEDED(hr))
+        {
+            m_Properties.cbAlign = (Framing.FileAlignment + 1);
+            m_Properties.cbBuffer = Framing.FrameSize;
+            m_Properties.cbPrefix = 0; //FIXME
+            m_Properties.cBuffers = Framing.Frames;
+        }
+        hr = S_OK;
+#endif
+
+        if (FAILED(InitializeIOThread()))
+        {
+            OutputDebugStringW(L"COutputPin::CreatePinHandle failed to initialize i/o thread\n");
+            DebugBreak();
+        }
 
         //TODO
         // connect pin pipes
@@ -1694,6 +2175,351 @@ COutputPin::CreatePinHandle(
     return hr;
 }
 
+HRESULT
+WINAPI
+COutputPin::IoProcessRoutine()
+{
+    IMediaSample *Sample;
+    LONG SampleCount;
+    HRESULT hr;
+    PKSSTREAM_SEGMENT StreamSegment;
+    HANDLE hEvent;
+    IMediaSample * Samples[1];
+
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[200];
+#endif
+
+    // first wait for the start event to signal
+    WaitForSingleObject(m_hStartEvent, INFINITE);
+
+    assert(m_InterfaceHandler);
+    do
+    {
+        if (m_StopInProgress)
+        {
+            // stop io thread
+            break;
+        }
+
+        assert(m_State == KSSTATE_RUN);
+        assert(m_MemAllocator);
+
+        // get buffer
+        hr = m_MemAllocator->GetBuffer(&Sample, NULL, NULL, AM_GBF_NOWAIT);
+
+        if (FAILED(hr))
+        {
+            WaitForSingleObject(m_hBufferAvailable, INFINITE);
+            // now retry again
+            continue;
+        }
+
+        // fill buffer
+        SampleCount = 1;
+        Samples[0] = Sample;
+
+        Sample->SetTime(NULL, NULL);
+        hr = m_InterfaceHandler->KsProcessMediaSamples(NULL, /* FIXME */
+                                                       Samples,
+                                                       &SampleCount,
+                                                       KsIoOperation_Read,
+                                                       &StreamSegment);
+        if (FAILED(hr) || !StreamSegment)
+        {
+#ifdef KSPROXY_TRACE
+            swprintf(Buffer, L"COutputPin::IoProcessRoutine KsProcessMediaSamples FAILED PinName %s hr %lx\n", m_PinName, hr);
+            OutputDebugStringW(Buffer);
+#endif
+            break;
+        }
+
+        // get completion event
+        hEvent = StreamSegment->CompletionEvent;
+
+        // wait for i/o completion
+        WaitForSingleObject(hEvent, INFINITE);
+
+        // perform completion
+        m_InterfaceHandler->KsCompleteIo(StreamSegment);
+
+        // close completion event
+        CloseHandle(hEvent);
+
+        if (SUCCEEDED(hr))
+        {
+            assert(m_MemInputPin);
+
+            // now deliver the sample
+            hr = m_MemInputPin->Receive(Sample);
+
+#ifdef KSPROXY_TRACE
+            swprintf(Buffer, L"COutputPin::IoProcessRoutine PinName %s IMemInputPin::Receive hr %lx Sample %p m_MemAllocator %p\n", m_PinName, hr, Sample, m_MemAllocator);
+            OutputDebugStringW(Buffer);
+#endif
+
+             if (FAILED(hr))
+                 break;
+
+            Sample = NULL;
+        }
+    }while(TRUE);
+
+    // signal end of i/o thread
+    SetEvent(m_hStopEvent);
+
+    m_IoThreadStarted = false;
+
+    return NOERROR;
+}
+
+DWORD
+WINAPI
+COutputPin_IoThreadStartup(
+    LPVOID lpParameter)
+{
+    COutputPin * Pin = (COutputPin*)lpParameter;
+    assert(Pin);
+
+    return Pin->IoProcessRoutine();
+}
+
+
+HRESULT
+WINAPI
+COutputPin::InitializeIOThread()
+{
+    HANDLE hThread;
+
+    if (m_IoThreadStarted)
+        return NOERROR;
+
+    if (!m_hStartEvent)
+        m_hStartEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+    if (!m_hStartEvent)
+        return E_OUTOFMEMORY;
+
+    if (!m_hStopEvent)
+        m_hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+    if (!m_hStopEvent)
+        return E_OUTOFMEMORY;
+
+    if (!m_hBufferAvailable)
+        m_hBufferAvailable = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+    if (!m_hBufferAvailable)
+        return E_OUTOFMEMORY;
+
+    m_StopInProgress = false;
+    m_IoThreadStarted = true;
+
+    // now create the startup thread
+    hThread = CreateThread(NULL, 0, COutputPin_IoThreadStartup, (LPVOID)this, 0, NULL);
+    if (!hThread)
+        return E_OUTOFMEMORY;
+
+
+    // close thread handle
+    CloseHandle(hThread);
+    return NOERROR;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+COutputPin_SetState(
+    IPin * Pin,
+    KSSTATE State)
+{
+    HRESULT hr = S_OK;
+    KSPROPERTY Property;
+    KSSTATE CurState;
+    ULONG BytesReturned;
+    COutputPin * pPin = (COutputPin*)Pin;
+
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[200];
+#endif
+
+    Property.Set = KSPROPSETID_Connection;
+    Property.Id = KSPROPERTY_CONNECTION_STATE;
+    Property.Flags = KSPROPERTY_TYPE_SET;
+
+    EnterCriticalSection(&pPin->m_Lock);
+
+    if (pPin->m_State <= State)
+    {
+        if (pPin->m_State == KSSTATE_STOP)
+        {
+            hr = pPin->InitializeIOThread();
+            if (FAILED(hr))
+            {
+                // failed to initialize I/O thread
+#ifdef KSPROXY_TRACE
+                OutputDebugStringW(L"Failed to initialize I/O Thread\n");
+#endif
+                LeaveCriticalSection(&pPin->m_Lock);
+                return hr;
+            }
+            CurState = KSSTATE_ACQUIRE;
+            hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+#ifdef KSPROXY_TRACE
+            swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_STOP KSSTATE_ACQUIRE PinName %s hr %lx\n", pPin->m_PinName, hr);
+            OutputDebugStringW(Buffer);
+#endif
+
+            if (FAILED(hr))
+            {
+                LeaveCriticalSection(&pPin->m_Lock);
+                return hr;
+            }
+
+            pPin->m_State = CurState;
+
+            if (pPin->m_State == State)
+            {
+                LeaveCriticalSection(&pPin->m_Lock);
+                return hr;
+            }
+        }
+        if (pPin->m_State == KSSTATE_ACQUIRE)
+        {
+            CurState = KSSTATE_PAUSE;
+            hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+#ifdef KSPROXY_TRACE
+            swprintf(Buffer, L"COutputPin_SetState Setting State CurState KSSTATE_ACQUIRE KSSTATE_PAUSE PinName %s hr %lx\n", pPin->m_PinName, hr);
+            OutputDebugStringW(Buffer);
+#endif
+
+            if (FAILED(hr))
+            {
+                LeaveCriticalSection(&pPin->m_Lock);
+                return hr;
+            }
+
+            pPin->m_State = CurState;
+
+            if (pPin->m_State == State)
+            {
+                LeaveCriticalSection(&pPin->m_Lock);
+                return hr;
+            }
+        }
+        if (State == KSSTATE_RUN && pPin->m_State == KSSTATE_PAUSE)
+        {
+            CurState = KSSTATE_RUN;
+            hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+#ifdef KSPROXY_TRACE
+            swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_PAUSE KSSTATE_RUN PinName %s hr %lx\n", pPin->m_PinName, hr);
+            OutputDebugStringW(Buffer);
+#endif
+
+            if (SUCCEEDED(hr))
+            {
+                pPin->m_State = CurState;
+                // signal start event
+                SetEvent(pPin->m_hStartEvent);
+            }
+        }
+
+        LeaveCriticalSection(&pPin->m_Lock);
+        return hr;
+    }
+    else
+    {
+        if (pPin->m_State == KSSTATE_RUN)
+        {
+            // setting pending stop flag
+            pPin->m_StopInProgress = true;
+
+            // release any waiting threads
+            SetEvent(pPin->m_hBufferAvailable);
+
+            // wait until i/o thread is done
+            WaitForSingleObject(pPin->m_hStopEvent, INFINITE);
+
+            CurState = KSSTATE_PAUSE;
+            hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+#ifdef KSPROXY_TRACE
+            swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_RUN KSSTATE_PAUSE PinName %s hr %lx\n", pPin->m_PinName, hr);
+            OutputDebugStringW(Buffer);
+#endif
+
+            if (FAILED(hr))
+            {
+                LeaveCriticalSection(&pPin->m_Lock);
+                return hr;
+            }
+
+            pPin->m_State = CurState;
+
+            if (FAILED(hr))
+            {
+                LeaveCriticalSection(&pPin->m_Lock);
+                return hr;
+            }
+        }
+        if (pPin->m_State == KSSTATE_PAUSE)
+        {
+            CurState = KSSTATE_ACQUIRE;
+            hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+#ifdef KSPROXY_TRACE
+            swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_PAUSE KSSTATE_ACQUIRE PinName %s hr %lx\n", pPin->m_PinName, hr);
+            OutputDebugStringW(Buffer);
+#endif
+
+            if (FAILED(hr))
+            {
+                LeaveCriticalSection(&pPin->m_Lock);
+                return hr;
+            }
+
+            pPin->m_State = CurState;
+
+            if (pPin->m_State == State)
+            {
+                LeaveCriticalSection(&pPin->m_Lock);
+                return hr;
+            }
+        }
+
+        CloseHandle(pPin->m_hStopEvent);
+        CloseHandle(pPin->m_hStartEvent);
+        CloseHandle(pPin->m_hBufferAvailable);
+
+        /* close event handles */
+        pPin->m_hStopEvent = NULL;
+        pPin->m_hStartEvent = NULL;
+        pPin->m_hBufferAvailable = NULL;
+
+        CurState = KSSTATE_STOP;
+        hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+#ifdef KSPROXY_TRACE
+        swprintf(Buffer, L"COutputPin_SetState Setting State CurState: KSSTATE_ACQUIRE KSSTATE_STOP PinName %s hr %lx\n", pPin->m_PinName, hr);
+        OutputDebugStringW(Buffer);
+#endif
+
+        if (SUCCEEDED(hr))
+        {
+            // store state
+            pPin->m_State = CurState;
+        }
+
+        // unset pending stop flag
+        pPin->m_StopInProgress = false;
+
+        LeaveCriticalSection(&pPin->m_Lock);
+        return hr;
+    }
+}
+
 HRESULT
 WINAPI
 COutputPin_Constructor(