[KSPROXY]
authorJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 22 Mar 2010 05:03:50 +0000 (05:03 +0000)
committerJohannes Anderwald <johannes.anderwald@reactos.org>
Mon, 22 Mar 2010 05:03:50 +0000 (05:03 +0000)
- Implement IKsAllocator interface
- Implement IMediaSample interface
- Implement querying the output pin for IMemInputPin and determine allocator properties. Currently the allocation strategy is limited to 16 Buffers with a size of 2048 * 188 (MPEG2 TS Payload size). Needs more work to determine a reasonable value
- Implement overriding allocator if properties are not matching
- Implement IPin::BeginFlush, IPin::EndFlush, IPin::EndOfStream, IPin::NewSegment for the OutputPin
- Implement a I/O thread which queues the media sample to the kernel pin via IKsInterfaceHandler and then transmitts it to the connected input pin via IMemInputPin interface.
- Implement setting pin state via a friend function, in order to synchronize the starting / stopping of the I/O thread
- Fix a bug in IAMFilterMiscFlags::GetMiscFlags function
- ksproxy (CLSID_Proxy) is now able to connect to MPEG-2 splitter and deliver samples. Needs more investigation why the render filter is not releasing the samples back to allocator, which causes the I/O thread to hang. WIP

svn path=/trunk/; revision=46339

reactos/dll/directx/ksproxy/allocator.cpp
reactos/dll/directx/ksproxy/interface.cpp
reactos/dll/directx/ksproxy/ksproxy.rbuild
reactos/dll/directx/ksproxy/mediasample.cpp [new file with mode: 0644]
reactos/dll/directx/ksproxy/output_pin.cpp
reactos/dll/directx/ksproxy/precomp.h
reactos/dll/directx/ksproxy/proxy.cpp

index 2b5cd1a..7db5234 100644 (file)
@@ -15,6 +15,8 @@ class CKsAllocator : public IKsAllocatorEx,
                      public IMemAllocatorCallbackTemp
 {
 public:
+    typedef std::stack<IMediaSample *>MediaSampleStack;
+
     STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
 
     STDMETHODIMP_(ULONG) AddRef()
@@ -58,9 +60,9 @@ public:
     HRESULT STDMETHODCALLTYPE GetFreeCount(LONG *plBuffersFree);
 
 
-    CKsAllocator() : m_Ref(0), m_hAllocator(0), m_Mode(KsAllocatorMode_User), m_Notify(0), m_Allocated(0), m_FreeCount(0), m_cbBuffer(0), m_cBuffers(0), m_cbAlign(0), m_cbPrefix(0){}
+    CKsAllocator();
     virtual ~CKsAllocator(){}
-
+    VOID STDMETHODCALLTYPE FreeMediaSamples();
 protected:
     LONG m_Ref;
     HANDLE m_hAllocator;
@@ -68,11 +70,15 @@ protected:
     ALLOCATOR_PROPERTIES_EX m_Properties;
     IMemAllocatorNotifyCallbackTemp *m_Notify;
     ULONG m_Allocated;
-    ULONG m_FreeCount;
-    ULONG m_cbBuffer;
-    ULONG m_cBuffers;
-    ULONG m_cbAlign;
-    ULONG m_cbPrefix;
+    LONG m_cbBuffer;
+    LONG m_cBuffers;
+    LONG m_cbAlign;
+    LONG m_cbPrefix;
+    BOOL m_Commited;
+    CRITICAL_SECTION m_CriticalSection;
+    MediaSampleStack m_FreeList;
+    LPVOID m_Buffer;
+    BOOL m_FreeSamples;
 };
 
 
@@ -93,14 +99,32 @@ CKsAllocator::QueryInterface(
     if (IsEqualGUID(refiid, IID_IMemAllocator) ||
         IsEqualGUID(refiid, IID_IMemAllocatorCallbackTemp))
     {
-        *Output = (IDistributorNotify*)(this);
-        reinterpret_cast<IDistributorNotify*>(*Output)->AddRef();
+        *Output = (IMemAllocatorCallbackTemp*)(this);
+        reinterpret_cast<IMemAllocatorCallbackTemp*>(*Output)->AddRef();
         return NOERROR;
     }
 
     return E_NOINTERFACE;
 }
 
+CKsAllocator::CKsAllocator() : m_Ref(0), 
+                               m_hAllocator(0), 
+                               m_Mode(KsAllocatorMode_User),
+                               m_Notify(0),
+                               m_Allocated(0),
+                               m_cbBuffer(0),
+                               m_cBuffers(0),
+                               m_cbAlign(0),
+                               m_cbPrefix(0),
+                               m_Commited(FALSE),
+                               m_FreeList(),
+                               m_Buffer(0),
+                               m_FreeSamples(FALSE)
+{
+   InitializeCriticalSection(&m_CriticalSection);
+
+}
+
 //-------------------------------------------------------------------
 // IMemAllocator
 //
@@ -112,7 +136,8 @@ CKsAllocator::SetProperties(
 {
     SYSTEM_INFO SystemInfo;
 
-    OutputDebugStringW(L"CKsAllocator::SetProperties Stub\n");
+    EnterCriticalSection(&m_CriticalSection);
+    OutputDebugStringW(L"CKsAllocator::SetProperties\n");
 
     if (!pRequest || !pActual)
         return E_POINTER;
@@ -126,18 +151,28 @@ CKsAllocator::SetProperties(
     if (!pRequest->cbAlign || (pRequest->cbAlign - 1) & SystemInfo.dwAllocationGranularity)
     {
         // bad alignment
+        LeaveCriticalSection(&m_CriticalSection);
         return VFW_E_BADALIGN;
     }
 
     if (m_Mode == KsAllocatorMode_Kernel)
     {
-        // u cannt change a kernel allocator
+        // u can't change a kernel allocator
+        LeaveCriticalSection(&m_CriticalSection);
         return VFW_E_ALREADY_COMMITTED;
     }
 
-    if (m_Allocated != m_FreeCount)
+    if (m_Commited)
+    {
+        // need to decommit first
+        LeaveCriticalSection(&m_CriticalSection);
+        return VFW_E_ALREADY_COMMITTED;
+    }
+
+    if (m_Allocated != m_FreeList.size())
     {
         // outstanding buffers
+        LeaveCriticalSection(&m_CriticalSection);
         return VFW_E_BUFFERS_OUTSTANDING;
     }
 
@@ -146,6 +181,7 @@ CKsAllocator::SetProperties(
     pActual->cbPrefix = m_cbPrefix = pRequest->cbPrefix;
     pActual->cBuffers = m_cBuffers = pRequest->cBuffers;
 
+    LeaveCriticalSection(&m_CriticalSection);
     return NOERROR;
 }
 
@@ -169,28 +205,126 @@ HRESULT
 STDMETHODCALLTYPE
 CKsAllocator::Commit()
 {
+    LONG Index;
+    PUCHAR CurrentBuffer;
+    IMediaSample * Sample;
+    HRESULT hr;
+
+    //TODO integer overflow checks
+    EnterCriticalSection(&m_CriticalSection);
+
+    OutputDebugStringW(L"CKsAllocator::Commit\n");
+
     if (m_Mode == KsAllocatorMode_Kernel)
     {
         /* no-op for kernel allocator */
+       LeaveCriticalSection(&m_CriticalSection);
        return NOERROR;
     }
 
-    OutputDebugStringW(L"CKsAllocator::Commit NotImplemented\n");
-    return E_NOTIMPL;
+    if (m_Commited)
+    {
+        // already commited
+        LeaveCriticalSection(&m_CriticalSection);
+        return NOERROR;
+    }
+
+    if (m_cbBuffer < 0 || m_cBuffers < 0 || m_cbPrefix < 0)
+    {
+        // invalid parameter
+        LeaveCriticalSection(&m_CriticalSection);
+        return E_OUTOFMEMORY;
+    }
+
+    LONG Size = m_cbBuffer + m_cbPrefix;
+
+    if (m_cbAlign > 1)
+    {
+        //check alignment
+        LONG Mod = Size % m_cbAlign;
+        if (Mod)
+        {
+            // calculate aligned size
+            Size += m_cbAlign - Mod;
+        }
+    }
+
+    LONG TotalSize = Size * m_cBuffers;
+
+    assert(TotalSize);
+    assert(m_cBuffers);
+    assert(Size);
+
+    // now allocate buffer
+    m_Buffer = VirtualAlloc(NULL, TotalSize, MEM_COMMIT, PAGE_READWRITE);
+    if (!m_Buffer)
+    {
+        LeaveCriticalSection(&m_CriticalSection);
+        return E_OUTOFMEMORY;
+    }
+
+    ZeroMemory(m_Buffer, TotalSize);
+
+    CurrentBuffer = (PUCHAR)m_Buffer;
+
+    for (Index = 0; Index < m_cBuffers; Index++)
+    {
+        // construct media sample
+        hr = CMediaSample_Constructor((IMemAllocator*)this, CurrentBuffer + m_cbPrefix, m_cbBuffer, IID_IMediaSample, (void**)&Sample);
+        if (FAILED(hr))
+        {
+            LeaveCriticalSection(&m_CriticalSection);
+            return E_OUTOFMEMORY;
+        }
+
+        // add to free list
+        m_FreeList.push(Sample);
+        m_Allocated++;
+
+        //next sample buffer
+        CurrentBuffer += Size;
+    }
+
+    // we are now commited
+    m_Commited = true;
+
+    LeaveCriticalSection(&m_CriticalSection);
+    return S_OK;
 }
 
 HRESULT
 STDMETHODCALLTYPE
 CKsAllocator::Decommit()
 {
+    EnterCriticalSection(&m_CriticalSection);
+
+    OutputDebugStringW(L"CKsAllocator::Decommit\n");
+
     if (m_Mode == KsAllocatorMode_Kernel)
     {
         /* no-op for kernel allocator */
-       return NOERROR;
+        LeaveCriticalSection(&m_CriticalSection);
+        return NOERROR;
     }
 
-    OutputDebugStringW(L"CKsAllocator::Decommit NotImplemented\n");
-    return E_NOTIMPL;
+    m_Commited = false;
+
+    if (m_Allocated != m_FreeList.size())
+    {
+        // outstanding buffers
+        m_FreeSamples = true;
+        LeaveCriticalSection(&m_CriticalSection);
+        return NOERROR;
+    }
+    else
+    {
+        // no outstanding buffers
+        // free to free them
+        FreeMediaSamples();
+    }
+
+    LeaveCriticalSection(&m_CriticalSection);
+    return NOERROR;
 }
 
 
@@ -202,8 +336,40 @@ CKsAllocator::GetBuffer(
     REFERENCE_TIME *pEndTime,
     DWORD dwFlags)
 {
-    OutputDebugStringW(L"CKsAllocator::GetBuffer NotImplemented\n");
-    return E_NOTIMPL;
+    IMediaSample * Sample = NULL;
+    OutputDebugStringW(L"CKsAllocator::GetBuffer\n");
+
+    do
+    {
+        EnterCriticalSection(&m_CriticalSection);
+
+        if (!m_FreeList.empty())
+        {
+            Sample = m_FreeList.top();
+            m_FreeList.pop();
+        }
+
+        LeaveCriticalSection(&m_CriticalSection);
+
+        if (dwFlags & AM_GBF_NOWAIT)
+        {
+            // never wait untill a buffer becomes available
+            break;
+        }
+    }
+    while(Sample == NULL);
+
+    if (!Sample)
+    {
+        // no sample acquired
+        return VFW_E_TIMEOUT;
+    }
+
+    // store result
+    *ppBuffer = Sample;
+
+    // done
+    return NOERROR;
 }
 
 HRESULT
@@ -211,8 +377,33 @@ STDMETHODCALLTYPE
 CKsAllocator::ReleaseBuffer(
     IMediaSample *pBuffer)
 {
-    OutputDebugStringW(L"CKsAllocator::ReleaseBuffer NotImplemented\n");
-    return E_NOTIMPL;
+    EnterCriticalSection(&m_CriticalSection);
+
+    OutputDebugStringW(L"CKsAllocator::ReleaseBuffer\n");
+
+    // media sample always 1 ref count in free list
+    pBuffer->AddRef();
+
+    // add the sample to the free list
+    m_FreeList.push(pBuffer);
+
+    if (m_FreeSamples)
+    {
+        // pending de-commit
+        if (m_FreeList.size () == m_Allocated)
+        {
+            FreeMediaSamples();
+        }
+    }
+
+    if (m_Notify)
+    {
+        //notify caller of an available buffer
+        m_Notify->NotifyRelease();
+    }
+
+    LeaveCriticalSection(&m_CriticalSection);
+    return S_OK;
 }
 
 //-------------------------------------------------------------------
@@ -223,6 +414,7 @@ STDMETHODCALLTYPE
 CKsAllocator::SetNotify(
     IMemAllocatorNotifyCallbackTemp *pNotify)
 {
+    EnterCriticalSection(&m_CriticalSection);
     OutputDebugStringW(L"CKsAllocator::SetNotify\n");
 
     if (pNotify)
@@ -232,6 +424,8 @@ CKsAllocator::SetNotify(
         m_Notify->Release();
 
     m_Notify = pNotify;
+
+    LeaveCriticalSection(&m_CriticalSection);
     return NOERROR;
 }
 
@@ -240,8 +434,8 @@ STDMETHODCALLTYPE
 CKsAllocator::GetFreeCount(
     LONG *plBuffersFree)
 {
-    OutputDebugStringW(L"CKsAllocator::GetFreeCount NotImplemented\n");
-    return E_NOTIMPL;
+    *plBuffersFree = m_Allocated - m_FreeList.size();
+    return S_OK;
 }
 
 //-------------------------------------------------------------------
@@ -349,6 +543,32 @@ CKsAllocator::KsCreateAllocatorAndGetHandle(
     return m_hAllocator;
 }
 
+//-------------------------------------------------------------------
+VOID
+STDMETHODCALLTYPE
+CKsAllocator::FreeMediaSamples()
+{
+    ULONG Index;
+
+    for(Index = 0; Index < m_FreeList.size(); Index++)
+    {
+        IMediaSample * Sample = m_FreeList.top();
+        m_FreeList.pop();
+        delete Sample;
+    }
+
+    m_FreeSamples = false;
+    m_Allocated = 0;
+
+    if (m_Buffer)
+    {
+        // release buffer
+        VirtualFree(m_Buffer, 0, MEM_RELEASE);
+
+        m_Buffer = NULL;
+    }
+}
+
 HRESULT
 WINAPI
 CKsAllocator_Constructor(
index 930f7e0..dffed7d 100644 (file)
@@ -35,24 +35,25 @@ public:
     HRESULT STDMETHODCALLTYPE KsProcessMediaSamples(IKsDataTypeHandler *KsDataTypeHandler, IMediaSample** SampleList, PLONG SampleCount, KSIOOPERATION IoOperation, PKSSTREAM_SEGMENT *StreamSegment);
     HRESULT STDMETHODCALLTYPE KsCompleteIo(PKSSTREAM_SEGMENT StreamSegment);
 
-    CKsInterfaceHandler() : m_Ref(0), m_Handle(NULL), m_Pin(0){};
+    CKsInterfaceHandler() : m_Ref(0), m_Handle(NULL), m_Pin(0) {m_PinName[0] = L'\0';};
     virtual ~CKsInterfaceHandler(){};
 
 protected:
     LONG m_Ref;
     HANDLE m_Handle;
     IKsPinEx * m_Pin;
+    WCHAR m_PinName[129];
 };
 
 typedef struct
 {
     KSSTREAM_SEGMENT StreamSegment;
+    OVERLAPPED Overlapped;
     IMediaSample * MediaSample[64];
 
     ULONG SampleCount;
     ULONG ExtendedSize;
     PKSSTREAM_HEADER StreamHeader;
-    OVERLAPPED Overlapped;
 }KSSTREAM_SEGMENT_EXT, *PKSSTREAM_SEGMENT_EXT;
 
 
@@ -118,6 +119,38 @@ CKsInterfaceHandler::KsSetPin(
             Pin->Release();
         }
     }
+#if 1
+    //DBG code
+    PIN_INFO PinInfo;
+    IPin * pPin;
+    if (SUCCEEDED(KsPin->QueryInterface(IID_IPin, (void**)&pPin)))
+    {
+        if (SUCCEEDED(pPin->QueryPinInfo(&PinInfo)))
+        {
+            if (PinInfo.pFilter)
+                PinInfo.pFilter->Release();
+
+            wcscpy(m_PinName, PinInfo.achName);
+        }
+        pPin->Release();
+    }
+
+    IKsAllocatorEx * Allocator;
+
+    if (SUCCEEDED(KsPin->QueryInterface(IID_IKsAllocatorEx, (void**)&Allocator)))
+    {
+        PALLOCATOR_PROPERTIES_EX Properties = Allocator->KsGetProperties();
+
+        if (Properties)
+        {
+            WCHAR Buffer[100];
+            swprintf(Buffer, L"CKsInterfaceHandler::KsSetPin PinName %s Properties.cbAlign %u cbBuffer %u cbPrefix %u cBuffers %u\n", m_PinName, Properties->cbAlign, Properties->cbBuffer, Properties->cbPrefix, Properties->cBuffers);
+            OutputDebugStringW(Buffer);
+        }
+        Allocator->Release();
+    }
+
+#endif
 
     // done
     return hr;
@@ -136,8 +169,6 @@ CKsInterfaceHandler::KsProcessMediaSamples(
     ULONG ExtendedSize, Index, BytesReturned;
     HRESULT hr = S_OK;
 
-    OutputDebugString("CKsInterfaceHandler::KsProcessMediaSamples\n");
-
     // sanity check
     assert(*SampleCount);
 
@@ -256,6 +287,9 @@ CKsInterfaceHandler::KsProcessMediaSamples(
              hr = SampleList[Index]->GetTime(&Properties.tStart, &Properties.tStop);
              assert(hr == NOERROR);
 
+             Properties.cbBuffer = SampleList[Index]->GetSize();
+             assert(Properties.cbBuffer);
+
              Properties.dwSampleFlags = 0;
 
              if (SampleList[Index]->IsDiscontinuity() == S_OK)
@@ -268,9 +302,9 @@ CKsInterfaceHandler::KsProcessMediaSamples(
                  Properties.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
          }
 
-         WCHAR Buffer[100];
-         swprintf(Buffer, L"BufferLength %lu Property Buffer %p ExtendedSize %u lActual %u\n", Properties.cbBuffer, Properties.pbBuffer, ExtendedSize, Properties.lActual);
-         OutputDebugStringW(Buffer);
+         WCHAR Buffer[200];
+         swprintf(Buffer, L"CKsInterfaceHandler::KsProcessMediaSamples PinName %s BufferLength %lu Property Buffer %p ExtendedSize %u lActual %u\n", m_PinName, Properties.cbBuffer, Properties.pbBuffer, ExtendedSize, Properties.lActual);
+         //OutputDebugStringW(Buffer);
 
          CurStreamHeader->Size = sizeof(KSSTREAM_HEADER) + ExtendedSize;
          CurStreamHeader->PresentationTime.Denominator = 1;
@@ -336,8 +370,6 @@ CKsInterfaceHandler::KsCompleteIo(
     AM_SAMPLE2_PROPERTIES Properties;
     REFERENCE_TIME Start, Stop;
 
-    OutputDebugStringW(L"CKsInterfaceHandler::KsCompleteIo\n");
-
     // get private stream segment
     StreamSegment = (PKSSTREAM_SEGMENT_EXT)InStreamSegment;
 
@@ -347,6 +379,10 @@ CKsInterfaceHandler::KsCompleteIo(
 
     CurStreamHeader = StreamSegment->StreamHeader;
 
+    WCHAR Buffer[100];
+    swprintf(Buffer, L"CKsInterfaceHandler::KsCompleteIo PinName %s bOverlapped %u hr %lx\n", m_PinName, bOverlapped, dwError);
+    //OutputDebugStringW(Buffer);
+
     //iterate through all stream headers
     for(Index = 0; Index < StreamSegment->SampleCount; Index++)
     {
index 269d986..86cd50a 100644 (file)
@@ -33,6 +33,7 @@
        <file>interface.cpp</file>
        <file>ksproxy.cpp</file>
        <file>ksproxy.rc</file>
+       <file>mediasample.cpp</file>
        <file>node.cpp</file>
        <file>output_pin.cpp</file>
        <file>proxy.cpp</file>
diff --git a/reactos/dll/directx/ksproxy/mediasample.cpp b/reactos/dll/directx/ksproxy/mediasample.cpp
new file mode 100644 (file)
index 0000000..c9cb4cd
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS WDM Streaming ActiveMovie Proxy
+ * FILE:            dll/directx/ksproxy/mediasample.cpp
+ * PURPOSE:         IMediaSample interface
+ *
+ * PROGRAMMERS:     Johannes Anderwald (janderwald@reactos.org)
+ */
+#include "precomp.h"
+
+class CMediaSample : public IMediaSample
+{
+public:
+    STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
+
+    STDMETHODIMP_(ULONG) AddRef()
+    {
+        InterlockedIncrement(&m_Ref);
+        return m_Ref;
+    }
+    STDMETHODIMP_(ULONG) Release()
+    {
+        InterlockedDecrement(&m_Ref);
+        DebugBreak();
+        if (!m_Ref)
+        {
+            if (m_Allocator)
+            {
+                m_Allocator->ReleaseBuffer((IMediaSample*)this);
+                return 0;
+            }
+            delete this;
+            return 0;
+        }
+        return m_Ref;
+    }
+
+    HRESULT STDMETHODCALLTYPE GetPointer(BYTE **ppBuffer);
+    long STDMETHODCALLTYPE GetSize(void);
+    HRESULT STDMETHODCALLTYPE GetTime(REFERENCE_TIME *pTimeStart, REFERENCE_TIME *pTimeEnd);
+    HRESULT STDMETHODCALLTYPE SetTime(REFERENCE_TIME *pTimeStart, REFERENCE_TIME *pTimeEnd);
+    HRESULT STDMETHODCALLTYPE IsSyncPoint();
+    HRESULT STDMETHODCALLTYPE SetSyncPoint(BOOL bIsSyncPoint);
+    HRESULT STDMETHODCALLTYPE IsPreroll();
+    HRESULT STDMETHODCALLTYPE SetPreroll(BOOL bIsPreroll);
+    long STDMETHODCALLTYPE GetActualDataLength();
+    HRESULT STDMETHODCALLTYPE SetActualDataLength(long Length);
+    HRESULT STDMETHODCALLTYPE GetMediaType(AM_MEDIA_TYPE **ppMediaType);
+    HRESULT STDMETHODCALLTYPE SetMediaType(AM_MEDIA_TYPE *pMediaType);
+    HRESULT STDMETHODCALLTYPE IsDiscontinuity();
+    HRESULT STDMETHODCALLTYPE SetDiscontinuity(BOOL bDiscontinuity);
+    HRESULT STDMETHODCALLTYPE GetMediaTime(LONGLONG *pTimeStart, LONGLONG *pTimeEnd);
+    HRESULT STDMETHODCALLTYPE SetMediaTime(LONGLONG *pTimeStart, LONGLONG *pTimeEnd);
+
+    CMediaSample(IMemAllocator * Allocator, BYTE * Buffer, LONG BufferSize);
+    virtual ~CMediaSample(){}
+
+protected:
+    LONG m_Ref;
+    IMemAllocator * m_Allocator;
+    BYTE * m_Buffer;
+    LONG m_BufferSize;
+    LONG m_ActualLength;
+    REFERENCE_TIME m_StartTime;
+    REFERENCE_TIME m_StopTime;
+    ULONG m_Flags;
+    BOOL m_bMediaTimeValid;
+    LONGLONG m_MediaStart;
+    LONGLONG m_MediaStop;
+
+};
+
+CMediaSample::CMediaSample(
+    IMemAllocator * Allocator,
+    BYTE * Buffer,
+    LONG BufferSize) : m_Ref(0),
+                       m_Allocator(Allocator),
+                       m_Buffer(Buffer),
+                       m_BufferSize(BufferSize),
+                       m_ActualLength(BufferSize),
+                       m_StartTime(0),
+                       m_StopTime(0),
+                       m_Flags(0),
+                       m_bMediaTimeValid(0),
+                       m_MediaStart(0),
+                       m_MediaStop(0)
+{
+}
+
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::QueryInterface(
+    IN  REFIID refiid,
+    OUT PVOID* Output)
+{
+    if (IsEqualGUID(refiid, IID_IUnknown) ||
+        IsEqualGUID(refiid, IID_IMediaSample))
+    {
+        *Output = PVOID(this);
+        reinterpret_cast<IMediaSample*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    if (IsEqualGUID(refiid, IID_IMediaSample2))
+    {
+
+        OutputDebugStringW(L"CMediaSample::QueryInterface requested IMediaSample2 interface\n");
+#if 0
+        *Output = (IMediaSample2*)(this);
+        reinterpret_cast<IMediaSample2*>(*Output)->AddRef();
+        return NOERROR;
+#endif
+    }
+
+    return E_NOINTERFACE;
+}
+
+//-------------------------------------------------------------------
+// IMediaSample interface
+//
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::GetPointer(
+    BYTE **ppBuffer)
+{
+    if (!ppBuffer)
+        return E_POINTER;
+
+    *ppBuffer = m_Buffer;
+    return S_OK;
+}
+
+long
+STDMETHODCALLTYPE
+CMediaSample::GetSize()
+{
+    return m_BufferSize;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::GetTime(
+    REFERENCE_TIME *pTimeStart,
+    REFERENCE_TIME *pTimeEnd)
+{
+    HRESULT hr;
+
+    if (!pTimeStart || !pTimeEnd)
+        return E_POINTER;
+
+    if (!(m_Flags & (AM_SAMPLE_TIMEVALID | AM_SAMPLE_STOPVALID)))
+    {
+        // no time is set
+        return VFW_E_SAMPLE_TIME_NOT_SET;
+    }
+
+    *pTimeStart = m_StartTime;
+
+    if (m_Flags & AM_SAMPLE_STOPVALID)
+    {
+        *pTimeEnd = m_StopTime;
+        hr = NOERROR;
+    }
+    else
+    {
+        *pTimeEnd = m_StartTime + 1;
+        hr = VFW_S_NO_STOP_TIME;
+    }
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::SetTime(REFERENCE_TIME *pTimeStart, REFERENCE_TIME *pTimeEnd)
+{
+    if (!pTimeStart)
+    {
+        m_Flags &= ~(AM_SAMPLE_TIMEVALID | AM_SAMPLE_STOPVALID);
+        return NOERROR;
+    }
+
+    if (!pTimeEnd)
+    {
+        m_Flags &= ~(AM_SAMPLE_STOPVALID);
+        m_Flags |= AM_SAMPLE_TIMEVALID;
+        m_StartTime = *pTimeStart;
+        return NOERROR;
+    }
+
+
+    m_Flags |= (AM_SAMPLE_TIMEVALID | AM_SAMPLE_STOPVALID);
+    m_StartTime = *pTimeStart;
+    m_StopTime = *pTimeEnd;
+
+    return NOERROR;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::IsSyncPoint()
+{
+    return (m_Flags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE;
+}
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::SetSyncPoint(BOOL bIsSyncPoint)
+{
+    if (bIsSyncPoint)
+        m_Flags |= AM_SAMPLE_SPLICEPOINT;
+    else
+        m_Flags &= ~AM_SAMPLE_SPLICEPOINT;
+
+    return NOERROR;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::IsPreroll()
+{
+    return (m_Flags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::SetPreroll(BOOL bIsPreroll)
+{
+    if (bIsPreroll)
+        m_Flags |= AM_SAMPLE_PREROLL;
+    else
+        m_Flags &= ~AM_SAMPLE_PREROLL;
+
+    return NOERROR;
+}
+
+long
+STDMETHODCALLTYPE
+CMediaSample::GetActualDataLength()
+{
+    return m_ActualLength;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::SetActualDataLength(long Length)
+{
+    if (Length > m_BufferSize)
+        return VFW_E_BUFFER_OVERFLOW;
+
+    m_ActualLength = Length;
+    return NOERROR;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::GetMediaType(AM_MEDIA_TYPE **ppMediaType)
+{
+    OutputDebugStringW(L"CMediaSample::GetMediaType NotImplemented\n");
+    DebugBreak();
+    return E_NOTIMPL;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::SetMediaType(AM_MEDIA_TYPE *pMediaType)
+{
+    OutputDebugStringW(L"CMediaSample::SetMediaType NotImplemented\n");
+    DebugBreak();
+    return E_NOTIMPL;
+}
+
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::IsDiscontinuity()
+{
+    return (m_Flags & AM_SAMPLE_DATADISCONTINUITY) ? S_OK : S_FALSE;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::SetDiscontinuity(BOOL bDiscontinuity)
+{
+    if (bDiscontinuity)
+        m_Flags |= AM_SAMPLE_DATADISCONTINUITY;
+    else
+        m_Flags &= ~AM_SAMPLE_DATADISCONTINUITY;
+
+    return NOERROR;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::GetMediaTime(LONGLONG *pTimeStart, LONGLONG *pTimeEnd)
+{
+    if (!pTimeStart || !pTimeEnd)
+        return E_POINTER;
+
+    if (!m_bMediaTimeValid)
+        return VFW_E_MEDIA_TIME_NOT_SET;
+
+    m_MediaStart = *pTimeStart;
+    m_MediaStop = *pTimeEnd;
+
+    return NOERROR;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CMediaSample::SetMediaTime(LONGLONG *pTimeStart, LONGLONG *pTimeEnd)
+{
+    if (!pTimeStart || !pTimeEnd)
+    {
+        m_bMediaTimeValid = false;
+        return NOERROR;
+    }
+
+    m_MediaStart = *pTimeStart;
+    m_MediaStop = *pTimeEnd;
+
+    return NOERROR;
+}
+
+
+
+
+HRESULT
+WINAPI
+CMediaSample_Constructor(
+    IMemAllocator* Allocator, 
+    BYTE* pBuffer,
+    ULONG BufferSize,
+    REFIID riid,
+    LPVOID * ppv)
+{
+    OutputDebugStringW(L"CMediaSample_Constructor\n");
+
+    CMediaSample * handler = new CMediaSample(Allocator, pBuffer, BufferSize);
+
+    if (!handler)
+        return E_OUTOFMEMORY;
+
+    if (FAILED(handler->QueryInterface(riid, ppv)))
+    {
+        /* not supported */
+        delete handler;
+        return E_NOINTERFACE;
+    }
+
+    return NOERROR;
+}
index c5d897c..e3d620e 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;
@@ -178,6 +183,7 @@ protected:
     PKSALLOCATOR_FRAMING_EX m_FramingEx[4];
 
     IMemAllocator * m_MemAllocator;
+    IMemInputPin * m_MemInputPin;
     LONG m_IoCount;
     KSPIN_COMMUNICATION m_Communication;
     KSPIN_INTERFACE m_Interface;
@@ -187,6 +193,14 @@ protected:
     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;
 };
 
 COutputPin::~COutputPin()
@@ -211,10 +225,17 @@ COutputPin::COutputPin(
                                          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;
 
@@ -452,8 +473,12 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::NotifyRelease()
 {
-    OutputDebugStringW(L"COutputPin::NotifyRelease NotImplemented\n");
-    return E_NOTIMPL;
+    OutputDebugStringW(L"COutputPin::NotifyRelease\n");
+
+    // notify thread of new available sample
+    SetEvent(m_hBufferAvailable);
+
+    return NOERROR;
 }
 
 //-------------------------------------------------------------------
@@ -1220,6 +1245,9 @@ STDMETHODCALLTYPE
 COutputPin::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
 {
     HRESULT hr;
+    ALLOCATOR_PROPERTIES Properties;
+    IMemAllocatorCallbackTemp *pMemCallback;
+    WCHAR Buffer[200];
 
     OutputDebugStringW(L"COutputPin::Connect called\n");
     if (pmt)
@@ -1238,7 +1266,105 @@ 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))
+    {
+        OutputDebugStringW(L"COutputPin::Connect no IMemInputPin interface\n");
+        DebugBreak();
+        return hr;
+    }
+
+    // get input pin allocator properties
+    ZeroMemory(&Properties, sizeof(ALLOCATOR_PROPERTIES));
+    m_MemInputPin->GetAllocatorRequirements(&Properties);
+
+    //FIXME determine allocator properties
+    Properties.cBuffers = 16;
+    Properties.cbBuffer = 2048 * 188; //2048 frames * MPEG2 TS Payload size
+    Properties.cbAlign = 4;
+
+    // get input pin allocator
+    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();
+    }
+
+    if (FAILED(hr))
+    {
+        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))
+        {
+            swprintf(Buffer, L"COutputPin::Connect IMemAllocator::SetProperties failed with hr %lx\n", hr);
+            OutputDebugStringW(Buffer);
+            m_MemAllocator->Release();
+            m_MemInputPin->Release();
+            return hr;
+        }
+    }
+
+    // commit property changes
+    hr = m_MemAllocator->Commit();
+    if (FAILED(hr))
+    {
+        swprintf(Buffer, L"COutputPin::Connect IMemAllocator::Commit failed with hr %lx\n", hr);
+        OutputDebugStringW(Buffer);
+        m_MemAllocator->Release();
+        m_MemInputPin->Release();
+        return hr;
+    }
+
+    // get callback interface
+    hr = m_MemAllocator->QueryInterface(IID_IMemAllocatorCallbackTemp, (void**)&pMemCallback);
+    if (FAILED(hr))
+    {
+        swprintf(Buffer, L"COutputPin::Connect No IMemAllocatorCallbackTemp interface hr %lx\n", hr);
+        OutputDebugStringW(Buffer);
+        m_MemAllocator->Release();
+        m_MemInputPin->Release();
+        return hr;
+    }
+
+    // set notification routine
+    hr = pMemCallback->SetNotify((IMemAllocatorNotifyCallbackTemp*)this);
+
+    // release IMemAllocatorNotifyCallbackTemp interface
+    pMemCallback->Release();
+
+    if (FAILED(hr))
+    {
+        swprintf(Buffer, L"COutputPin::Connect IMemAllocatorNotifyCallbackTemp::SetNotify failed hr %lx\n", hr);
+        OutputDebugStringW(Buffer);
+        m_MemAllocator->Release();
+        m_MemInputPin->Release();
+        return hr;
+    }
+
+    // now set allocator
+    hr = m_MemInputPin->NotifyAllocator(m_MemAllocator, TRUE);
+    if (FAILED(hr))
+    {
+        swprintf(Buffer, L"COutputPin::Connect IMemInputPin::NotifyAllocator failed with hr %lx\n", hr);
+        OutputDebugStringW(Buffer);
+        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);
@@ -1249,6 +1375,11 @@ COutputPin::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
         m_Pin = pReceivePin;
         OutputDebugStringW(L"COutputPin::Connect success\n");
     }
+    else
+    {
+        m_MemInputPin->Release();
+        m_MemAllocator->Release();
+    }
 
     return hr;
 }
@@ -1257,7 +1388,6 @@ HRESULT
 STDMETHODCALLTYPE
 COutputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
 {
-    OutputDebugStringW(L"COutputPin::ReceiveConnection\n");
     return E_UNEXPECTED;
 }
 HRESULT
@@ -1277,6 +1407,8 @@ COutputPin::Disconnect( void)
 
     m_Pin->Release();
     m_Pin = NULL;
+    m_MemInputPin->Release();
+    m_MemAllocator->Release();
 
     OutputDebugStringW(L"COutputPin::Disconnect\n");
     return S_OK;
@@ -1421,29 +1553,34 @@ 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);
 }
 
 //-------------------------------------------------------------------
@@ -1600,6 +1737,9 @@ COutputPin::CreatePinHandle(
     PKSDATAFORMAT DataFormat;
     ULONG Length;
     HRESULT hr;
+    //KSALLOCATOR_FRAMING Framing;
+    //KSPROPERTY Property;
+    //ULONG BytesReturned;
 
     if (m_hPin != INVALID_HANDLE_VALUE)
     {
@@ -1651,7 +1791,7 @@ COutputPin::CreatePinHandle(
     assert(hFilter != NULL);
 
     // create pin
-    hr = KsCreatePin(hFilter, PinConnect, GENERIC_WRITE, &m_hPin);
+    hr = KsCreatePin(hFilter, PinConnect, GENERIC_READ, &m_hPin);
 
     if (SUCCEEDED(hr))
     {
@@ -1683,6 +1823,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 +1856,277 @@ COutputPin::CreatePinHandle(
     return hr;
 }
 
+HRESULT
+WINAPI
+COutputPin::IoProcessRoutine()
+{
+    IMediaSample *Sample;
+    LONG SampleCount;
+    HRESULT hr;
+    PKSSTREAM_SEGMENT StreamSegment;
+    HANDLE hEvent;
+    WCHAR Buffer[100];
+    IMediaSample * Samples[1];
+
+    // first wait for the start event to signal
+    WaitForSingleObject(m_hStartEvent, INFINITE);
+
+    assert(m_InterfaceHandler);
+    REFERENCE_TIME Start = 0;
+    REFERENCE_TIME Stop = 1;
+    do
+    {
+        if (m_StopInProgress)
+        {
+            // stop io thread
+            break;
+        }
+
+        // get buffer
+        hr = m_MemAllocator->GetBuffer(&Sample, NULL, NULL, AM_GBF_NOWAIT);
+
+        if (FAILED(hr))
+        {
+            m_Pin->BeginFlush();
+            OutputDebugStringW(L"Beginning flushing...\n");
+            WaitForSingleObject(m_hBufferAvailable, INFINITE);
+            m_Pin->EndFlush();
+            // now retry again
+            continue;
+        }
+
+        // fill buffer
+        SampleCount = 1;
+        Samples[0] = Sample;
+
+
+        Sample->SetTime(&Start, &Stop);
+        hr = m_InterfaceHandler->KsProcessMediaSamples(NULL, /* FIXME */
+                                                       Samples,
+                                                       &SampleCount,
+                                                       KsIoOperation_Read,
+                                                       &StreamSegment);
+        if (FAILED(hr) || !StreamSegment)
+        {
+            swprintf(Buffer, L"COutputPin::IoProcessRoutine KsProcessMediaSamples PinName %s hr %lx StreamSegment %p\n", m_PinName, hr, StreamSegment);
+            OutputDebugStringW(Buffer);
+            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))
+        {
+            Sample->GetTime(&Start, &Stop);
+            Start = Stop;
+            Stop++;
+
+            // now deliver the sample
+            hr = m_MemInputPin->Receive(Sample);
+
+            swprintf(Buffer, L"COutputPin::IoProcessRoutine IMemInputPin::Receive hr %lx Start %I64u Stop %I64u\n", hr, Start, Stop);
+            OutputDebugStringW(Buffer);
+        }
+    }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);
+    else
+        ResetEvent(m_hStartEvent);
+
+    if (!m_hStartEvent)
+        return E_OUTOFMEMORY;
+
+    if (!m_hStopEvent)
+        m_hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+    else
+        ResetEvent(m_hStopEvent);
+
+    if (!m_hStopEvent)
+        return E_OUTOFMEMORY;
+
+    if (!m_hBufferAvailable)
+        m_hBufferAvailable = CreateEventW(NULL, FALSE, FALSE, NULL);
+    else
+        ResetEvent(m_hBufferAvailable);
+
+    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;
+    WCHAR Buffer[100];
+    ULONG BytesReturned;
+
+    COutputPin * pPin = (COutputPin*)Pin;
+
+
+    Property.Set = KSPROPSETID_Connection;
+    Property.Id = KSPROPERTY_CONNECTION_STATE;
+    Property.Flags = KSPROPERTY_TYPE_SET;
+
+
+    if (pPin->m_State < State)
+    {
+        if (pPin->m_State == KSSTATE_STOP)
+        {
+            CurState = KSSTATE_ACQUIRE;
+            hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+            swprintf(Buffer, L"COutputPin_SetState Setting State KSSTATE_ACQUIRE PinName %s hr %lx\n", pPin->m_PinName, hr);
+            OutputDebugStringW(Buffer);
+            if (FAILED(hr))
+                return hr;
+
+            pPin->m_State = CurState;
+
+            if (pPin->m_State == State)
+                return hr;
+        }
+        if (pPin->m_State == KSSTATE_ACQUIRE)
+        {
+            CurState = KSSTATE_PAUSE;
+            hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+            swprintf(Buffer, L"COutputPin_SetState Setting State KSSTATE_PAUSE PinName %s hr %lx\n", pPin->m_PinName, hr);
+            OutputDebugStringW(Buffer);
+            if (FAILED(hr))
+                return hr;
+
+            pPin->m_State = CurState;
+
+            if (pPin->m_State == State)
+                return hr;
+        }
+
+        CurState = KSSTATE_RUN;
+        hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+        swprintf(Buffer, L"COutputPin_SetState Setting State KSSTATE_RUN PinName %s hr %lx\n", pPin->m_PinName, hr);
+        OutputDebugStringW(Buffer);
+        if (FAILED(hr))
+            return hr;
+
+        // signal start event
+        SetEvent(pPin->m_hStartEvent);
+
+
+        pPin->m_State = CurState;
+        return hr;
+    }
+    else
+    {
+        if (pPin->m_State == KSSTATE_RUN)
+        {
+            CurState = KSSTATE_PAUSE;
+            hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+            swprintf(Buffer, L"COutputPin_SetState Setting State KSSTATE_PAUSE PinName %u hr %lx\n", pPin->m_PinName, hr);
+            OutputDebugStringW(Buffer);
+            if (FAILED(hr))
+                return hr;
+
+            pPin->m_State = CurState;
+
+            if (pPin->m_State == State)
+                return hr;
+        }
+        if (pPin->m_State == KSSTATE_PAUSE)
+        {
+            CurState = KSSTATE_ACQUIRE;
+            hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+            swprintf(Buffer, L"COutputPin_SetState Setting State KSSTATE_ACQUIRE PinName %u hr %lx\n", pPin->m_PinName, hr);
+            OutputDebugStringW(Buffer);
+            if (FAILED(hr))
+                return hr;
+
+            pPin->m_State = CurState;
+
+            if (pPin->m_State == State)
+                return hr;
+        }
+
+        // setting pending stop flag
+        pPin->m_StopInProgress = true;
+
+        CurState = KSSTATE_STOP;
+        hr = pPin->KsProperty(&Property, sizeof(KSPROPERTY), &CurState, sizeof(KSSTATE), &BytesReturned);
+
+        swprintf(Buffer, L"COutputPin_SetState Setting State KSSTATE_STOP PinName %s hr %lx\n", pPin->m_PinName, hr);
+        OutputDebugStringW(Buffer);
+        if (FAILED(hr))
+            return hr;
+
+        // wait until i/o thread is done
+        WaitForSingleObject(pPin->m_hStopEvent, INFINITE);
+
+        pPin->m_State = CurState;
+        return hr;
+    }
+}
+
+
 HRESULT
 WINAPI
 COutputPin_Constructor(
index 6df3ddf..335ae19 100644 (file)
@@ -18,6 +18,7 @@
 #include <setupapi.h>
 #include <stdio.h>
 #include <vector>
+#include <stack>
 #include <assert.h>
 #include <ksmedia.h>
 //#include <debug.h>
@@ -138,6 +139,12 @@ COutputPin_Constructor(
     REFIID riid,
     LPVOID * ppv);
 
+HRESULT
+STDMETHODCALLTYPE
+COutputPin_SetState(
+    IPin * Pin,
+    KSSTATE State);
+
 /* enumpins.cpp */
 HRESULT
 WINAPI
@@ -166,10 +173,30 @@ CKsNode_Constructor(
     REFIID riid,
     LPVOID * ppv);
 
+/* allocator.cpp */
+HRESULT
+WINAPI
+CKsAllocator_Constructor(
+    IUnknown * pUnkOuter,
+    REFIID riid,
+    LPVOID * ppv);
+
+/* mediasample.cpp */
+HRESULT
+WINAPI
+CMediaSample_Constructor(
+    IMemAllocator* Allocator, 
+    BYTE* pBuffer,
+    ULONG BufferSize,
+    REFIID riid,
+    LPVOID * ppv);
+
+
 extern const GUID IID_IKsObject;
 extern const GUID IID_IKsPinEx;
 extern const GUID IID_IKsAggregateControl;
 extern const GUID IID_IKsPinPipe;
 extern const GUID IID_IKsPinFactory;
+extern const GUID IID_IKsAllocatorEx;
 extern KSPIN_INTERFACE StandardPinInterface;
 extern KSPIN_MEDIUM StandardPinMedium;
index 549307c..41d543f 100644 (file)
@@ -1599,7 +1599,7 @@ CKsProxy::GetMiscFlags()
                 if (SUCCEEDED(GetPinCommunication(Index, //FIXME verify PinId
                                         &Communication)))
                 {
-                    if (Communication == KSPIN_COMMUNICATION_NONE || Communication == KSPIN_COMMUNICATION_BRIDGE)
+                    if (Communication != KSPIN_COMMUNICATION_NONE && Communication != KSPIN_COMMUNICATION_BRIDGE)
                     {
                         Flags |= AM_FILTER_MISC_FLAGS_IS_SOURCE;
                     }
@@ -2578,6 +2578,7 @@ CKsProxy::SetPinState(
     IKsObject *pObject;
     ULONG BytesReturned;
     KSPROPERTY Property;
+    PIN_INFO PinInfo;
 
     Property.Set = KSPROPSETID_Connection;
     Property.Id = KSPROPERTY_CONNECTION_STATE;
@@ -2602,6 +2603,22 @@ CKsProxy::SetPinState(
         // release connected pin
         TempPin->Release();
 
+        // query for the pin info
+        hr = Pin->QueryPinInfo(&PinInfo);
+
+        if (SUCCEEDED(hr))
+        {
+            if (PinInfo.pFilter)
+                PinInfo.pFilter->Release();
+
+            if (PinInfo.dir == PINDIR_OUTPUT)
+            {
+                hr = COutputPin_SetState(Pin, State);
+                if (SUCCEEDED(hr))
+                    continue;
+            }
+        }
+
         //query IKsObject interface
         hr = Pin->QueryInterface(IID_IKsObject, (void**)&pObject);