[KSPROXY]

- 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
This commit is contained in:
Johannes Anderwald
2010-03-22 05:03:50 +00:00
parent db734f6736
commit 15a94d994c
7 changed files with 1131 additions and 47 deletions
+243 -23
View 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(
+45 -9
View 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++)
{
@@ -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>
+350
View File
@@ -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 ([email protected])
*/
#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;
}
+447 -14
View 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(
+27
View 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;
+18 -1
View 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);