sync with trunk r46493
[reactos.git] / dll / directx / ksproxy / output_pin.cpp
index c5d897c..17f0780 100644 (file)
@@ -26,6 +26,8 @@ class COutputPin : public IPin,
 
 {
 public:
+    typedef std::vector<IUnknown *>ProxyPluginVector;
+
     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
 
     STDMETHODIMP_(ULONG) AddRef()
@@ -160,6 +162,13 @@ 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();
+    HRESULT STDMETHODCALLTYPE GetSupportedSets(LPGUID * pOutGuid, PULONG NumGuids);
+    HRESULT STDMETHODCALLTYPE LoadProxyPlugins(LPGUID pGuids, ULONG NumGuids);
+
+    friend DWORD WINAPI COutputPin_IoThreadStartup(LPVOID lpParameter);
+    friend HRESULT STDMETHODCALLTYPE COutputPin_SetState(IPin * Pin, KSSTATE State);
 
 protected:
     LONG m_Ref;
@@ -167,7 +176,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 +186,29 @@ 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;
+
+    ProxyPluginVector m_Plugins;
 };
 
 COutputPin::~COutputPin()
 {
-    if (m_KsObjectParent)
-        m_KsObjectParent->Release();
 }
 
 COutputPin::COutputPin(
@@ -204,31 +220,39 @@ 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),
+                                         m_Plugins()
 {
     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 +265,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 +280,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 +319,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 +345,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 +386,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 +406,9 @@ STDMETHODCALLTYPE
 COutputPin::SuggestAllocatorProperties(
     const ALLOCATOR_PROPERTIES *pprop)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::SuggestAllocatorProperties\n");
+#endif
 
     if (m_Pin)
     {
@@ -386,7 +425,9 @@ STDMETHODCALLTYPE
 COutputPin::GetAllocatorProperties(
     ALLOCATOR_PROPERTIES *pprop)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetAllocatorProperties\n");
+#endif
 
     if (!m_Pin)
     {
@@ -412,7 +453,9 @@ STDMETHODCALLTYPE
 COutputPin::SetFormat(
     AM_MEDIA_TYPE *pmt)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::SetFormat NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -420,7 +463,9 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::GetFormat(AM_MEDIA_TYPE **ppmt)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetFormat NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -430,7 +475,9 @@ COutputPin::GetNumberOfCapabilities(
     int *piCount,
     int *piSize)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetNumberOfCapabilities NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -441,7 +488,9 @@ COutputPin::GetStreamCaps(
     AM_MEDIA_TYPE **ppmt,
     BYTE *pSCC)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetStreamCaps NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -452,8 +501,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 +519,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 +537,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 +555,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 +573,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 +591,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 +609,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 +627,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 +645,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 +663,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 +682,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 +703,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 +724,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 +743,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 +762,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 +780,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 +798,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 +816,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 +838,9 @@ COutputPin::Notify(
     IBaseFilter *pSelf,
     Quality q)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::Notify NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -622,7 +849,9 @@ STDMETHODCALLTYPE
 COutputPin::SetSink(
     IQualityControl *piqc)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::SetSink NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -635,7 +864,9 @@ STDMETHODCALLTYPE
 COutputPin::KsAddAggregate(
     IN REFGUID AggregateClass)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsAddAggregate NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -644,7 +875,9 @@ STDMETHODCALLTYPE
 COutputPin::KsRemoveAggregate(
     REFGUID AggregateClass)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsRemoveAggregate NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -658,8 +891,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 +916,24 @@ STDMETHODCALLTYPE
 COutputPin::KsQueryInterfaces(
     PKSMULTIPLE_ITEM* InterfaceList)
 {
-    HANDLE hFilter = m_KsObjectParent->KsGetObjectHandle();
+    HRESULT hr;
+    HANDLE hFilter;
+    IKsObject * KsObjectParent;
+
+    hr = m_ParentFilter->QueryInterface(IID_IKsObject, (LPVOID*)&KsObjectParent);
+    if (FAILED(hr))
+        return hr;
 
-    return KsGetMultiplePinFactoryItems(hFilter, m_PinId, KSPROPERTY_PIN_INTERFACES, (PVOID*)InterfaceList);
+    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 +942,9 @@ COutputPin::KsCreateSinkPinHandle(
     KSPIN_INTERFACE& Interface,
     KSPIN_MEDIUM& Medium)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsCreateSinkPinHandle NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -721,7 +987,9 @@ COutputPin::KsPropagateAcquire()
     ULONG BytesReturned;
     HRESULT hr;
 
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsPropagateAcquire\n");
+#endif
 
     assert(m_hPin != INVALID_HANDLE_VALUE);
 
@@ -732,6 +1000,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 +1085,9 @@ COutputPin::KsQualityNotify(
     ULONG Proportion,
     REFERENCE_TIME TimeDelta)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsQualityNotify NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -827,7 +1101,9 @@ COutputPin::KsNotifyError(
     IMediaSample* Sample,
     HRESULT hr)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsNotifyError NotImplemented\n");
+#endif
 }
 
 
@@ -984,7 +1260,9 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::GetPages(CAUUID *pPages)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::GetPages NotImplemented\n");
+#endif
 
     if (!pPages)
         return E_POINTER;
@@ -1004,7 +1282,10 @@ STDMETHODCALLTYPE
 COutputPin::KsPinFactory(
     ULONG* PinFactory)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::KsPinFactory\n");
+#endif
+
     *PinFactory = m_PinId;
     return S_OK;
 }
@@ -1020,7 +1301,9 @@ COutputPin::Render(
     IPin *ppinOut,
     IGraphBuilder *pGraph)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::Render\n");
+#endif
     return S_OK;
 }
 
@@ -1030,7 +1313,10 @@ COutputPin::Backout(
     IPin *ppinOut, 
     IGraphBuilder *pGraph)
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::Backout\n");
+#endif
+
     return S_OK;
 }
 //-------------------------------------------------------------------
@@ -1040,7 +1326,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 +1347,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 +1372,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 +1389,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 +1496,9 @@ COutputPin::QuerySupported(
     KSPROPERTY Property;
     ULONG BytesReturned;
 
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"COutputPin::QuerySupported\n");
+#endif
 
     Property.Set = guidPropSet;
     Property.Id = dwPropID;
@@ -1220,8 +1516,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,54 +1540,184 @@ 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;
+    }
 
-    // receive connection;
-    hr = pReceivePin->ReceiveConnection((IPin*)this, pmt);
+    // 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))
     {
-        // increment reference count
-        pReceivePin->AddRef();
-        m_Pin = pReceivePin;
-        OutputDebugStringW(L"COutputPin::Connect success\n");
+        // set allocator properties
+        hr = m_MemAllocator->SetProperties(&Properties, &m_Properties);
+        if (FAILED(hr))
+            m_MemAllocator->Release();
     }
+#endif
 
-    return hr;
-}
+    if (1)
+    {
+        hr = CKsAllocator_Constructor(NULL, IID_IMemAllocator, (void**)&m_MemAllocator);
+        if (FAILED(hr))
+            return hr;
 
-HRESULT
-STDMETHODCALLTYPE
-COutputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
-{
-    OutputDebugStringW(L"COutputPin::ReceiveConnection\n");
-    return E_UNEXPECTED;
-}
-HRESULT
-STDMETHODCALLTYPE
-COutputPin::Disconnect( void)
-{
-   OutputDebugStringW(L"COutputPin::Disconnect\n");
+        // 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;
+        }
+    }
 
-    if (!m_Pin)
+    // commit property changes
+    hr = m_MemAllocator->Commit();
+    if (FAILED(hr))
     {
-        // pin was not connected
-        return S_FALSE;
+#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;
     }
 
-    //FIXME
-    //check if filter is active
+    // 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);
+    if (SUCCEEDED(hr))
+    {
+        // 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;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+COutputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
+{
+    return E_UNEXPECTED;
+}
+HRESULT
+STDMETHODCALLTYPE
+COutputPin::Disconnect( void)
+{
+#ifdef KSPROXY_TRACE
+   OutputDebugStringW(L"COutputPin::Disconnect\n");
+#endif
+
+    if (!m_Pin)
+    {
+        // pin was not connected
+        return S_FALSE;
+    }
+
+    //FIXME
+    //check if filter is active
 
     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 +1737,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 +1758,6 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::QueryDirection(PIN_DIRECTION *pPinDir)
 {
-    OutputDebugStringW(L"COutputPin::QueryDirection\n");
-
     if (pPinDir)
     {
         *pPinDir = PINDIR_OUTPUT;
@@ -1339,8 +1770,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 +1781,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 +1795,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 +1819,6 @@ COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum)
     if (!MediaTypes)
     {
         // not enough memory
-        OutputDebugStringW(L"COutputPin::EnumMediaTypes CoTaskMemAlloc\n");
         return E_OUTOFMEMORY;
     }
 
@@ -1403,7 +1833,6 @@ COutputPin::EnumMediaTypes(IEnumMediaTypes **ppEnum)
         {
             // failed
             CoTaskMemFree(MediaTypes);
-            OutputDebugStringW(L"COutputPin::EnumMediaTypes failed\n");
             return hr;
         }
     }
@@ -1414,36 +1843,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 +1888,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 +1922,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);
@@ -1539,8 +1985,12 @@ COutputPin::CreatePin(
         hr = CreatePinHandle(Medium, Interface, pmt);
         if (FAILED(hr))
         {
-            m_InterfaceHandler->Release();
-            m_InterfaceHandler = InterfaceHandler;
+#ifdef KSPROXY_TRACE
+            WCHAR Buffer[100];
+            swprintf(Buffer, L"COutputPin::CreatePinHandle failed with %lx\n", hr);
+            OutputDebugStringW(Buffer);
+#endif
+            return hr;
         }
 
         if (!m_InterfaceHandler)
@@ -1550,7 +2000,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 +2011,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 +2023,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 +2051,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 +2104,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 +2128,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 +2139,7 @@ COutputPin::CreatePinHandle(
         CoTaskMemFree(pSub);
         CoTaskMemFree(pFormat);
         OutputDebugStringW(Buffer);
+#endif
 
         if (pmt->cbFormat)
         {
@@ -1683,6 +2153,57 @@ 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();
+        }
+
+        LPGUID pGuid;
+        ULONG NumGuids = 0;
+
+        // get all supported sets
+        hr = GetSupportedSets(&pGuid, &NumGuids);
+        if (FAILED(hr))
+        {
+#ifdef KSPROXY_TRACE
+            OutputDebugStringW(L"CInputPin::CreatePinHandle GetSupportedSets failed\n");
+            DebugBreak();
+#endif
+            return hr;
+        }
+
+        // load all proxy plugins
+        hr = LoadProxyPlugins(pGuid, NumGuids);
+        if (FAILED(hr))
+        {
+#ifdef KSPROXY_TRACE
+            OutputDebugStringW(L"CInputPin::CreatePinHandle LoadProxyPlugins failed\n");
+            DebugBreak();
+#endif
+            return hr;
+        }
+
+        // free sets
+        CoTaskMemFree(pGuid);
+
 
         //TODO
         // connect pin pipes
@@ -1694,6 +2215,486 @@ COutputPin::CreatePinHandle(
     return hr;
 }
 
+HRESULT
+STDMETHODCALLTYPE
+COutputPin::GetSupportedSets(
+    LPGUID * pOutGuid,
+    PULONG NumGuids)
+{
+    KSPROPERTY Property;
+    LPGUID pGuid;
+    ULONG NumProperty = 0;
+    ULONG NumMethods = 0;
+    ULONG NumEvents = 0;
+    ULONG Length;
+    ULONG BytesReturned;
+    HRESULT hr;
+
+    Property.Set = GUID_NULL;
+    Property.Id = 0;
+    Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
+
+    KsSynchronousDeviceControl(m_hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumProperty);
+    KsSynchronousDeviceControl(m_hPin, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumMethods);
+    KsSynchronousDeviceControl(m_hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &NumEvents);
+
+    Length = NumProperty + NumMethods + NumEvents;
+
+    assert(Length);
+
+    // allocate guid buffer
+    pGuid = (LPGUID)CoTaskMemAlloc(Length);
+    if (!pGuid)
+    {
+        // failed
+        return E_OUTOFMEMORY;
+    }
+
+    NumProperty /= sizeof(GUID);
+    NumMethods /= sizeof(GUID);
+    NumEvents /= sizeof(GUID);
+
+    // get all properties
+    hr = KsSynchronousDeviceControl(m_hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pGuid, Length, &BytesReturned);
+    if (FAILED(hr))
+    {
+        CoTaskMemFree(pGuid);
+        return E_FAIL;
+    }
+    Length -= BytesReturned;
+
+    // get all methods
+    if (Length && NumMethods)
+    {
+        hr = KsSynchronousDeviceControl(m_hPin, IOCTL_KS_METHOD, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty], Length, &BytesReturned);
+        if (FAILED(hr))
+        {
+            CoTaskMemFree(pGuid);
+            return E_FAIL;
+        }
+        Length -= BytesReturned;
+    }
+
+    // get all events
+    if (Length && NumEvents)
+    {
+        hr = KsSynchronousDeviceControl(m_hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pGuid[NumProperty+NumMethods], Length, &BytesReturned);
+        if (FAILED(hr))
+        {
+            CoTaskMemFree(pGuid);
+            return E_FAIL;
+        }
+        Length -= BytesReturned;
+    }
+
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[200];
+    swprintf(Buffer, L"NumProperty %lu NumMethods %lu NumEvents %lu\n", NumProperty, NumMethods, NumEvents);
+    OutputDebugStringW(Buffer);
+#endif
+
+    *pOutGuid = pGuid;
+    *NumGuids = NumProperty+NumEvents+NumMethods;
+    return S_OK;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+COutputPin::LoadProxyPlugins(
+    LPGUID pGuids,
+    ULONG NumGuids)
+{
+    ULONG Index;
+    LPOLESTR pStr;
+    HKEY hKey, hSubKey;
+    HRESULT hr;
+    IUnknown * pUnknown;
+
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\MediaInterfaces", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+    {
+        OutputDebugStringW(L"CKsProxy::LoadProxyPlugins failed to open MediaInterfaces key\n");
+        return E_FAIL;
+    }
+
+    // enumerate all sets
+    for(Index = 0; Index < NumGuids; Index++)
+    {
+        // convert to string
+        hr = StringFromCLSID(pGuids[Index], &pStr);
+        if (FAILED(hr))
+            return E_FAIL;
+
+        // now try open class key
+        if (RegOpenKeyExW(hKey, pStr, 0, KEY_READ, &hSubKey) != ERROR_SUCCESS)
+        {
+            // no plugin for that set exists
+            CoTaskMemFree(pStr);
+            continue;
+        }
+
+        // try load plugin
+        hr = CoCreateInstance(pGuids[Index], (IBaseFilter*)this, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
+        if (SUCCEEDED(hr))
+        {
+            // store plugin
+            m_Plugins.push_back(pUnknown);
+DebugBreak();
+        }
+        // close key
+        RegCloseKey(hSubKey);
+    }
+
+    // close media interfaces key
+    RegCloseKey(hKey);
+    return S_OK;
+}
+
+
+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(