Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy * FILE: dll/directx/ksproxy/allocator.cpp * PURPOSE: IKsAllocator interface * * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) */#include "precomp.h"
const GUID IID_IKsAllocatorEx = {0x091bb63a, 0x603f, 0x11d1, {0xb0, 0x67, 0x00, 0xa0, 0xc9, 0x06, 0x28, 0x02}};const GUID IID_IKsAllocator = {0x8da64899, 0xc0d9, 0x11d0, {0x84, 0x13, 0x00, 0x00, 0xf8, 0x22, 0xfe, 0x8a}};
class CKsAllocator : public IKsAllocatorEx, public IMemAllocatorCallbackTemp{public: typedef std::stack<IMediaSample *>MediaSampleStack; typedef std::list<IMediaSample *>MediaSampleList;
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
STDMETHODIMP_(ULONG) AddRef() { InterlockedIncrement(&m_Ref); return m_Ref; } STDMETHODIMP_(ULONG) Release() { InterlockedDecrement(&m_Ref);
if (!m_Ref) { delete this; return 0; } return m_Ref; } //IKsAllocator HANDLE STDMETHODCALLTYPE KsGetAllocatorHandle(); KSALLOCATORMODE STDMETHODCALLTYPE KsGetAllocatorMode(); HRESULT STDMETHODCALLTYPE KsGetAllocatorStatus(PKSSTREAMALLOCATOR_STATUS AllocatorStatus); VOID STDMETHODCALLTYPE KsSetAllocatorMode(KSALLOCATORMODE Mode);
//IKsAllocatorEx PALLOCATOR_PROPERTIES_EX STDMETHODCALLTYPE KsGetProperties(); VOID STDMETHODCALLTYPE KsSetProperties(PALLOCATOR_PROPERTIES_EX Properties); VOID STDMETHODCALLTYPE KsSetAllocatorHandle(HANDLE AllocatorHandle); HANDLE STDMETHODCALLTYPE KsCreateAllocatorAndGetHandle(IKsPin* KsPin);
//IMemAllocator HRESULT STDMETHODCALLTYPE SetProperties(ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual); HRESULT STDMETHODCALLTYPE GetProperties(ALLOCATOR_PROPERTIES *pProps); HRESULT STDMETHODCALLTYPE Commit(); HRESULT STDMETHODCALLTYPE Decommit(); HRESULT STDMETHODCALLTYPE GetBuffer(IMediaSample **ppBuffer, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags); HRESULT STDMETHODCALLTYPE ReleaseBuffer(IMediaSample *pBuffer);
//IMemAllocatorCallbackTemp HRESULT STDMETHODCALLTYPE SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); HRESULT STDMETHODCALLTYPE GetFreeCount(LONG *plBuffersFree);
CKsAllocator(); virtual ~CKsAllocator(){} VOID STDMETHODCALLTYPE FreeMediaSamples();protected: LONG m_Ref; HANDLE m_hAllocator; KSALLOCATORMODE m_Mode; ALLOCATOR_PROPERTIES_EX m_Properties; IMemAllocatorNotifyCallbackTemp *m_Notify; ULONG m_Allocated; LONG m_cbBuffer; LONG m_cBuffers; LONG m_cbAlign; LONG m_cbPrefix; BOOL m_Committed; CRITICAL_SECTION m_CriticalSection; MediaSampleStack m_FreeList; MediaSampleList m_UsedList; LPVOID m_Buffer; BOOL m_FreeSamples;};
HRESULTSTDMETHODCALLTYPECKsAllocator::QueryInterface( IN REFIID refiid, OUT PVOID* Output){ if (IsEqualGUID(refiid, IID_IUnknown) || IsEqualGUID(refiid, IID_IKsAllocator) || IsEqualGUID(refiid, IID_IKsAllocatorEx)) { *Output = PVOID(this); reinterpret_cast<IUnknown*>(*Output)->AddRef(); return NOERROR; } if (IsEqualGUID(refiid, IID_IMemAllocator) || IsEqualGUID(refiid, IID_IMemAllocatorCallbackTemp)) { *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_Committed(FALSE), m_FreeList(), m_UsedList(), m_Buffer(0), m_FreeSamples(FALSE){ InitializeCriticalSection(&m_CriticalSection);
}
//-------------------------------------------------------------------// IMemAllocator//HRESULTSTDMETHODCALLTYPECKsAllocator::SetProperties( ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual){ SYSTEM_INFO SystemInfo;
EnterCriticalSection(&m_CriticalSection);
#ifdef KSPROXY_TRACE OutputDebugStringW(L"CKsAllocator::SetProperties\n");#endif
if (!pRequest || !pActual) return E_POINTER;
// zero output properties ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
// get system info GetSystemInfo(&SystemInfo);
if (!pRequest->cbAlign || (pRequest->cbAlign - 1) & SystemInfo.dwAllocationGranularity) { // bad alignment LeaveCriticalSection(&m_CriticalSection); return VFW_E_BADALIGN; }
if (m_Mode == KsAllocatorMode_Kernel) { // u can't change a kernel allocator LeaveCriticalSection(&m_CriticalSection); return VFW_E_ALREADY_COMMITTED; }
if (m_Committed) { // 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->cbAlign = m_cbAlign = pRequest->cbAlign; pActual->cbBuffer = m_cbBuffer = pRequest->cbBuffer; pActual->cbPrefix = m_cbPrefix = pRequest->cbPrefix; pActual->cBuffers = m_cBuffers = pRequest->cBuffers;
LeaveCriticalSection(&m_CriticalSection); return NOERROR;}
HRESULTSTDMETHODCALLTYPECKsAllocator::GetProperties( ALLOCATOR_PROPERTIES *pProps){ if (!pProps) return E_POINTER;
pProps->cbBuffer = m_cbBuffer; pProps->cBuffers = m_cBuffers; pProps->cbAlign = m_cbAlign; pProps->cbPrefix = m_cbPrefix;
return NOERROR;}
HRESULTSTDMETHODCALLTYPECKsAllocator::Commit(){ LONG Index; PUCHAR CurrentBuffer; IMediaSample * Sample; HRESULT hr;
//TODO integer overflow checks EnterCriticalSection(&m_CriticalSection);
#ifdef KSPROXY_TRACE OutputDebugStringW(L"CKsAllocator::Commit\n");#endif
if (m_Mode == KsAllocatorMode_Kernel) { /* no-op for kernel allocator */ LeaveCriticalSection(&m_CriticalSection); return NOERROR; }
if (m_Committed) { // already committed 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 committed m_Committed = true;
LeaveCriticalSection(&m_CriticalSection); return S_OK;}
HRESULTSTDMETHODCALLTYPECKsAllocator::Decommit(){ EnterCriticalSection(&m_CriticalSection);
#ifdef KSPROXY_TRACE OutputDebugStringW(L"CKsAllocator::Decommit\n");#endif
if (m_Mode == KsAllocatorMode_Kernel) { /* no-op for kernel allocator */ LeaveCriticalSection(&m_CriticalSection); return NOERROR; }
m_Committed = 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;}
HRESULTSTDMETHODCALLTYPECKsAllocator::GetBuffer( IMediaSample **ppBuffer, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags){ IMediaSample * Sample = NULL;
if (!m_Committed) return VFW_E_NOT_COMMITTED;
do { EnterCriticalSection(&m_CriticalSection);
if (!m_FreeList.empty()) { OutputDebugStringW(L"CKsAllocator::GetBuffer HACK\n"); 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 //HACKKKKKKK Sample = m_UsedList.back(); m_UsedList.pop_back();
if (!Sample) return VFW_E_TIMEOUT; }
// store result *ppBuffer = Sample;
// store sample in used list m_UsedList.push_front(Sample);
// done return NOERROR;}
HRESULTSTDMETHODCALLTYPECKsAllocator::ReleaseBuffer( IMediaSample *pBuffer){ EnterCriticalSection(&m_CriticalSection);
#ifdef KSPROXY_TRACE OutputDebugStringW(L"CKsAllocator::ReleaseBuffer\n");#endif
// 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;}
//-------------------------------------------------------------------// IMemAllocatorCallbackTemp//HRESULTSTDMETHODCALLTYPECKsAllocator::SetNotify( IMemAllocatorNotifyCallbackTemp *pNotify){ EnterCriticalSection(&m_CriticalSection);
#ifdef KSPROXY_TRACE OutputDebugStringW(L"CKsAllocator::SetNotify\n");#endif
if (pNotify) pNotify->AddRef();
if (m_Notify) m_Notify->Release();
m_Notify = pNotify;
LeaveCriticalSection(&m_CriticalSection); return NOERROR;}
HRESULTSTDMETHODCALLTYPECKsAllocator::GetFreeCount( LONG *plBuffersFree){ *plBuffersFree = m_Allocated - m_FreeList.size(); return S_OK;}
//-------------------------------------------------------------------// IKsAllocator//HANDLESTDMETHODCALLTYPECKsAllocator::KsGetAllocatorHandle(){ return m_hAllocator;}
KSALLOCATORMODESTDMETHODCALLTYPECKsAllocator::KsGetAllocatorMode(){ return m_Mode;}
HRESULTSTDMETHODCALLTYPECKsAllocator::KsGetAllocatorStatus( PKSSTREAMALLOCATOR_STATUS AllocatorStatus){ return NOERROR;}VOIDSTDMETHODCALLTYPECKsAllocator::KsSetAllocatorMode( KSALLOCATORMODE Mode){ m_Mode = Mode;}
//-------------------------------------------------------------------// IKsAllocatorEx//PALLOCATOR_PROPERTIES_EXSTDMETHODCALLTYPECKsAllocator::KsGetProperties(){ return &m_Properties;}
VOIDSTDMETHODCALLTYPECKsAllocator::KsSetProperties( PALLOCATOR_PROPERTIES_EX Properties){ CopyMemory(&m_Properties, Properties, sizeof(ALLOCATOR_PROPERTIES_EX));}
VOIDSTDMETHODCALLTYPECKsAllocator::KsSetAllocatorHandle( HANDLE AllocatorHandle){ m_hAllocator = AllocatorHandle;}
HANDLESTDMETHODCALLTYPECKsAllocator::KsCreateAllocatorAndGetHandle( IKsPin* KsPin){ HRESULT hr; IKsObject * pObject; KSALLOCATOR_FRAMING AllocatorFraming; HANDLE hPin;
#ifdef KSPROXY_TRACE OutputDebugStringW(L"CKsAllocator::KsCreateAllocatorAndGetHandle\n");#endif
if (m_hAllocator) { CloseHandle(m_hAllocator); m_hAllocator = NULL; }
// get pin IKsObject interface hr = KsPin->QueryInterface(IID_IKsObject, (void**)&pObject); if (FAILED(hr)) return NULL;
// get pin handle hPin = pObject->KsGetObjectHandle();
//release IKsObject interface pObject->Release();
if (!hPin || hPin == INVALID_HANDLE_VALUE) return NULL;
//setup allocator framing AllocatorFraming.Frames = m_Properties.cBuffers; AllocatorFraming.FrameSize = m_Properties.cbBuffer; AllocatorFraming.FileAlignment = (m_Properties.cbAlign -1); AllocatorFraming.OptionsFlags = KSALLOCATOR_OPTIONF_SYSTEM_MEMORY; AllocatorFraming.PoolType = (m_Properties.LogicalMemoryType == KS_MemoryTypeKernelPaged);
DWORD dwError = KsCreateAllocator(hPin, &AllocatorFraming, &m_hAllocator); if (dwError) return NULL;
return m_hAllocator;}
//-------------------------------------------------------------------VOIDSTDMETHODCALLTYPECKsAllocator::FreeMediaSamples(){ ULONG Index;
for(Index = 0; Index < m_FreeList.size(); Index++) { IMediaSample * Sample = m_FreeList.top(); m_FreeList.pop(); Sample->Release(); }
m_FreeSamples = false; m_Allocated = 0;
if (m_Buffer) { // release buffer VirtualFree(m_Buffer, 0, MEM_RELEASE);
m_Buffer = NULL; }}
HRESULTWINAPICKsAllocator_Constructor( IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv){#ifdef KSPROXY_TRACE OutputDebugStringW(L"CKsAllocator_Constructor\n");#endif
CKsAllocator * handler = new CKsAllocator();
if (!handler) return E_OUTOFMEMORY;
if (FAILED(handler->QueryInterface(riid, ppv))) { /* not supported */ delete handler; return E_NOINTERFACE; }
return NOERROR;}