public IMemAllocatorCallbackTemp
{
public:
+ typedef std::stack<IMediaSample *>MediaSampleStack;
+
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
STDMETHODIMP_(ULONG) AddRef()
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;
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;
};
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
//
{
SYSTEM_INFO SystemInfo;
- OutputDebugStringW(L"CKsAllocator::SetProperties Stub\n");
+ EnterCriticalSection(&m_CriticalSection);
+ OutputDebugStringW(L"CKsAllocator::SetProperties\n");
if (!pRequest || !pActual)
return E_POINTER;
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;
}
pActual->cbPrefix = m_cbPrefix = pRequest->cbPrefix;
pActual->cBuffers = m_cBuffers = pRequest->cBuffers;
+ LeaveCriticalSection(&m_CriticalSection);
return NOERROR;
}
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;
}
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
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;
}
//-------------------------------------------------------------------
CKsAllocator::SetNotify(
IMemAllocatorNotifyCallbackTemp *pNotify)
{
+ EnterCriticalSection(&m_CriticalSection);
OutputDebugStringW(L"CKsAllocator::SetNotify\n");
if (pNotify)
m_Notify->Release();
m_Notify = pNotify;
+
+ LeaveCriticalSection(&m_CriticalSection);
return NOERROR;
}
CKsAllocator::GetFreeCount(
LONG *plBuffersFree)
{
- OutputDebugStringW(L"CKsAllocator::GetFreeCount NotImplemented\n");
- return E_NOTIMPL;
+ *plBuffersFree = m_Allocated - m_FreeList.size();
+ return S_OK;
}
//-------------------------------------------------------------------
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(
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;
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;
ULONG ExtendedSize, Index, BytesReturned;
HRESULT hr = S_OK;
- OutputDebugString("CKsInterfaceHandler::KsProcessMediaSamples\n");
-
// sanity check
assert(*SampleCount);
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)
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;
AM_SAMPLE2_PROPERTIES Properties;
REFERENCE_TIME Start, Stop;
- OutputDebugStringW(L"CKsInterfaceHandler::KsCompleteIo\n");
-
// get private stream segment
StreamSegment = (PKSSTREAM_SEGMENT_EXT)InStreamSegment;
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++)
{
<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>
--- /dev/null
+/*
+ * 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;
+}
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;
PKSALLOCATOR_FRAMING_EX m_FramingEx[4];
IMemAllocator * m_MemAllocator;
+ IMemInputPin * m_MemInputPin;
LONG m_IoCount;
KSPIN_COMMUNICATION m_Communication;
KSPIN_INTERFACE m_Interface;
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()
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;
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;
}
//-------------------------------------------------------------------
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)
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);
m_Pin = pReceivePin;
OutputDebugStringW(L"COutputPin::Connect success\n");
}
+ else
+ {
+ m_MemInputPin->Release();
+ m_MemAllocator->Release();
+ }
return hr;
}
STDMETHODCALLTYPE
COutputPin::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
{
- OutputDebugStringW(L"COutputPin::ReceiveConnection\n");
return E_UNEXPECTED;
}
HRESULT
m_Pin->Release();
m_Pin = NULL;
+ m_MemInputPin->Release();
+ m_MemAllocator->Release();
OutputDebugStringW(L"COutputPin::Disconnect\n");
return S_OK;
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);
}
//-------------------------------------------------------------------
PKSDATAFORMAT DataFormat;
ULONG Length;
HRESULT hr;
+ //KSALLOCATOR_FRAMING Framing;
+ //KSPROPERTY Property;
+ //ULONG BytesReturned;
if (m_hPin != INVALID_HANDLE_VALUE)
{
assert(hFilter != NULL);
// create pin
- hr = KsCreatePin(hFilter, PinConnect, GENERIC_WRITE, &m_hPin);
+ hr = KsCreatePin(hFilter, PinConnect, GENERIC_READ, &m_hPin);
if (SUCCEEDED(hr))
{
}
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
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(
#include <setupapi.h>
#include <stdio.h>
#include <vector>
+#include <stack>
#include <assert.h>
#include <ksmedia.h>
//#include <debug.h>
REFIID riid,
LPVOID * ppv);
+HRESULT
+STDMETHODCALLTYPE
+COutputPin_SetState(
+ IPin * Pin,
+ KSSTATE State);
+
/* enumpins.cpp */
HRESULT
WINAPI
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;
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;
}
IKsObject *pObject;
ULONG BytesReturned;
KSPROPERTY Property;
+ PIN_INFO PinInfo;
Property.Set = KSPROPSETID_Connection;
Property.Id = KSPROPERTY_CONNECTION_STATE;
// 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);