mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-03 04:13:31 +00:00
[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:
@@ -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(
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user