2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy
4 * FILE: dll/directx/ksproxy/allocator.cpp
5 * PURPOSE: IKsAllocator interface
7 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
11 const GUID IID_IKsAllocatorEx
= {0x091bb63a, 0x603f, 0x11d1, {0xb0, 0x67, 0x00, 0xa0, 0xc9, 0x06, 0x28, 0x02}};
12 const GUID IID_IKsAllocator
= {0x8da64899, 0xc0d9, 0x11d0, {0x84, 0x13, 0x00, 0x00, 0xf8, 0x22, 0xfe, 0x8a}};
14 class CKsAllocator
: public IKsAllocatorEx
,
15 public IMemAllocatorCallbackTemp
18 typedef std::stack
<IMediaSample
*>MediaSampleStack
;
20 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
22 STDMETHODIMP_(ULONG
) AddRef()
24 InterlockedIncrement(&m_Ref
);
27 STDMETHODIMP_(ULONG
) Release()
29 InterlockedDecrement(&m_Ref
);
39 HANDLE STDMETHODCALLTYPE
KsGetAllocatorHandle();
40 KSALLOCATORMODE STDMETHODCALLTYPE
KsGetAllocatorMode();
41 HRESULT STDMETHODCALLTYPE
KsGetAllocatorStatus(PKSSTREAMALLOCATOR_STATUS AllocatorStatus
);
42 VOID STDMETHODCALLTYPE
KsSetAllocatorMode(KSALLOCATORMODE Mode
);
45 PALLOCATOR_PROPERTIES_EX STDMETHODCALLTYPE
KsGetProperties();
46 VOID STDMETHODCALLTYPE
KsSetProperties(PALLOCATOR_PROPERTIES_EX Properties
);
47 VOID STDMETHODCALLTYPE
KsSetAllocatorHandle(HANDLE AllocatorHandle
);
48 HANDLE STDMETHODCALLTYPE
KsCreateAllocatorAndGetHandle(IKsPin
* KsPin
);
51 HRESULT STDMETHODCALLTYPE
SetProperties(ALLOCATOR_PROPERTIES
*pRequest
, ALLOCATOR_PROPERTIES
*pActual
);
52 HRESULT STDMETHODCALLTYPE
GetProperties(ALLOCATOR_PROPERTIES
*pProps
);
53 HRESULT STDMETHODCALLTYPE
Commit();
54 HRESULT STDMETHODCALLTYPE
Decommit();
55 HRESULT STDMETHODCALLTYPE
GetBuffer(IMediaSample
**ppBuffer
, REFERENCE_TIME
*pStartTime
, REFERENCE_TIME
*pEndTime
, DWORD dwFlags
);
56 HRESULT STDMETHODCALLTYPE
ReleaseBuffer(IMediaSample
*pBuffer
);
58 //IMemAllocatorCallbackTemp
59 HRESULT STDMETHODCALLTYPE
SetNotify(IMemAllocatorNotifyCallbackTemp
*pNotify
);
60 HRESULT STDMETHODCALLTYPE
GetFreeCount(LONG
*plBuffersFree
);
64 virtual ~CKsAllocator(){}
65 VOID STDMETHODCALLTYPE
FreeMediaSamples();
69 KSALLOCATORMODE m_Mode
;
70 ALLOCATOR_PROPERTIES_EX m_Properties
;
71 IMemAllocatorNotifyCallbackTemp
*m_Notify
;
78 CRITICAL_SECTION m_CriticalSection
;
79 MediaSampleStack m_FreeList
;
87 CKsAllocator::QueryInterface(
91 if (IsEqualGUID(refiid
, IID_IUnknown
) ||
92 IsEqualGUID(refiid
, IID_IKsAllocator
) ||
93 IsEqualGUID(refiid
, IID_IKsAllocatorEx
))
95 *Output
= PVOID(this);
96 reinterpret_cast<IUnknown
*>(*Output
)->AddRef();
99 if (IsEqualGUID(refiid
, IID_IMemAllocator
) ||
100 IsEqualGUID(refiid
, IID_IMemAllocatorCallbackTemp
))
102 *Output
= (IMemAllocatorCallbackTemp
*)(this);
103 reinterpret_cast<IMemAllocatorCallbackTemp
*>(*Output
)->AddRef();
107 return E_NOINTERFACE
;
110 CKsAllocator::CKsAllocator() : m_Ref(0),
112 m_Mode(KsAllocatorMode_User
),
124 InitializeCriticalSection(&m_CriticalSection
);
128 //-------------------------------------------------------------------
133 CKsAllocator::SetProperties(
134 ALLOCATOR_PROPERTIES
*pRequest
,
135 ALLOCATOR_PROPERTIES
*pActual
)
137 SYSTEM_INFO SystemInfo
;
139 EnterCriticalSection(&m_CriticalSection
);
140 OutputDebugStringW(L
"CKsAllocator::SetProperties\n");
142 if (!pRequest
|| !pActual
)
145 // zero output properties
146 ZeroMemory(pActual
, sizeof(ALLOCATOR_PROPERTIES
));
149 GetSystemInfo(&SystemInfo
);
151 if (!pRequest
->cbAlign
|| (pRequest
->cbAlign
- 1) & SystemInfo
.dwAllocationGranularity
)
154 LeaveCriticalSection(&m_CriticalSection
);
155 return VFW_E_BADALIGN
;
158 if (m_Mode
== KsAllocatorMode_Kernel
)
160 // u can't change a kernel allocator
161 LeaveCriticalSection(&m_CriticalSection
);
162 return VFW_E_ALREADY_COMMITTED
;
167 // need to decommit first
168 LeaveCriticalSection(&m_CriticalSection
);
169 return VFW_E_ALREADY_COMMITTED
;
172 if (m_Allocated
!= m_FreeList
.size())
174 // outstanding buffers
175 LeaveCriticalSection(&m_CriticalSection
);
176 return VFW_E_BUFFERS_OUTSTANDING
;
179 pActual
->cbAlign
= m_cbAlign
= pRequest
->cbAlign
;
180 pActual
->cbBuffer
= m_cbBuffer
= pRequest
->cbBuffer
;
181 pActual
->cbPrefix
= m_cbPrefix
= pRequest
->cbPrefix
;
182 pActual
->cBuffers
= m_cBuffers
= pRequest
->cBuffers
;
184 LeaveCriticalSection(&m_CriticalSection
);
190 CKsAllocator::GetProperties(
191 ALLOCATOR_PROPERTIES
*pProps
)
196 pProps
->cbBuffer
= m_cbBuffer
;
197 pProps
->cBuffers
= m_cBuffers
;
198 pProps
->cbAlign
= m_cbAlign
;
199 pProps
->cbPrefix
= m_cbPrefix
;
206 CKsAllocator::Commit()
209 PUCHAR CurrentBuffer
;
210 IMediaSample
* Sample
;
213 //TODO integer overflow checks
214 EnterCriticalSection(&m_CriticalSection
);
216 OutputDebugStringW(L
"CKsAllocator::Commit\n");
218 if (m_Mode
== KsAllocatorMode_Kernel
)
220 /* no-op for kernel allocator */
221 LeaveCriticalSection(&m_CriticalSection
);
228 LeaveCriticalSection(&m_CriticalSection
);
232 if (m_cbBuffer
< 0 || m_cBuffers
< 0 || m_cbPrefix
< 0)
235 LeaveCriticalSection(&m_CriticalSection
);
236 return E_OUTOFMEMORY
;
239 LONG Size
= m_cbBuffer
+ m_cbPrefix
;
244 LONG Mod
= Size
% m_cbAlign
;
247 // calculate aligned size
248 Size
+= m_cbAlign
- Mod
;
252 LONG TotalSize
= Size
* m_cBuffers
;
258 // now allocate buffer
259 m_Buffer
= VirtualAlloc(NULL
, TotalSize
, MEM_COMMIT
, PAGE_READWRITE
);
262 LeaveCriticalSection(&m_CriticalSection
);
263 return E_OUTOFMEMORY
;
266 ZeroMemory(m_Buffer
, TotalSize
);
268 CurrentBuffer
= (PUCHAR
)m_Buffer
;
270 for (Index
= 0; Index
< m_cBuffers
; Index
++)
272 // construct media sample
273 hr
= CMediaSample_Constructor((IMemAllocator
*)this, CurrentBuffer
+ m_cbPrefix
, m_cbBuffer
, IID_IMediaSample
, (void**)&Sample
);
276 LeaveCriticalSection(&m_CriticalSection
);
277 return E_OUTOFMEMORY
;
281 m_FreeList
.push(Sample
);
285 CurrentBuffer
+= Size
;
288 // we are now commited
291 LeaveCriticalSection(&m_CriticalSection
);
297 CKsAllocator::Decommit()
299 EnterCriticalSection(&m_CriticalSection
);
301 OutputDebugStringW(L
"CKsAllocator::Decommit\n");
303 if (m_Mode
== KsAllocatorMode_Kernel
)
305 /* no-op for kernel allocator */
306 LeaveCriticalSection(&m_CriticalSection
);
312 if (m_Allocated
!= m_FreeList
.size())
314 // outstanding buffers
315 m_FreeSamples
= true;
316 LeaveCriticalSection(&m_CriticalSection
);
321 // no outstanding buffers
326 LeaveCriticalSection(&m_CriticalSection
);
333 CKsAllocator::GetBuffer(
334 IMediaSample
**ppBuffer
,
335 REFERENCE_TIME
*pStartTime
,
336 REFERENCE_TIME
*pEndTime
,
339 IMediaSample
* Sample
= NULL
;
340 OutputDebugStringW(L
"CKsAllocator::GetBuffer\n");
344 EnterCriticalSection(&m_CriticalSection
);
346 if (!m_FreeList
.empty())
348 Sample
= m_FreeList
.top();
352 LeaveCriticalSection(&m_CriticalSection
);
354 if (dwFlags
& AM_GBF_NOWAIT
)
356 // never wait untill a buffer becomes available
360 while(Sample
== NULL
);
364 // no sample acquired
365 return VFW_E_TIMEOUT
;
377 CKsAllocator::ReleaseBuffer(
378 IMediaSample
*pBuffer
)
380 EnterCriticalSection(&m_CriticalSection
);
382 OutputDebugStringW(L
"CKsAllocator::ReleaseBuffer\n");
384 // media sample always 1 ref count in free list
387 // add the sample to the free list
388 m_FreeList
.push(pBuffer
);
393 if (m_FreeList
.size () == m_Allocated
)
401 //notify caller of an available buffer
402 m_Notify
->NotifyRelease();
405 LeaveCriticalSection(&m_CriticalSection
);
409 //-------------------------------------------------------------------
410 // IMemAllocatorCallbackTemp
414 CKsAllocator::SetNotify(
415 IMemAllocatorNotifyCallbackTemp
*pNotify
)
417 EnterCriticalSection(&m_CriticalSection
);
418 OutputDebugStringW(L
"CKsAllocator::SetNotify\n");
428 LeaveCriticalSection(&m_CriticalSection
);
434 CKsAllocator::GetFreeCount(
437 *plBuffersFree
= m_Allocated
- m_FreeList
.size();
441 //-------------------------------------------------------------------
446 CKsAllocator::KsGetAllocatorHandle()
453 CKsAllocator::KsGetAllocatorMode()
460 CKsAllocator::KsGetAllocatorStatus(
461 PKSSTREAMALLOCATOR_STATUS AllocatorStatus
)
467 CKsAllocator::KsSetAllocatorMode(
468 KSALLOCATORMODE Mode
)
473 //-------------------------------------------------------------------
476 PALLOCATOR_PROPERTIES_EX
478 CKsAllocator::KsGetProperties()
480 return &m_Properties
;
485 CKsAllocator::KsSetProperties(
486 PALLOCATOR_PROPERTIES_EX Properties
)
488 CopyMemory(&m_Properties
, Properties
, sizeof(ALLOCATOR_PROPERTIES_EX
));
493 CKsAllocator::KsSetAllocatorHandle(
494 HANDLE AllocatorHandle
)
496 m_hAllocator
= AllocatorHandle
;
502 CKsAllocator::KsCreateAllocatorAndGetHandle(
507 KSALLOCATOR_FRAMING AllocatorFraming
;
510 OutputDebugStringW(L
"CKsAllocator::KsCreateAllocatorAndGetHandle\n");
514 CloseHandle(m_hAllocator
);
518 // get pin IKsObject interface
519 hr
= KsPin
->QueryInterface(IID_IKsObject
, (void**)&pObject
);
524 hPin
= pObject
->KsGetObjectHandle();
526 //release IKsObject interface
529 if (!hPin
|| hPin
== INVALID_HANDLE_VALUE
)
532 //setup allocator framing
533 AllocatorFraming
.Frames
= m_Properties
.cBuffers
;
534 AllocatorFraming
.FrameSize
= m_Properties
.cbBuffer
;
535 AllocatorFraming
.FileAlignment
= (m_Properties
.cbAlign
-1);
536 AllocatorFraming
.OptionsFlags
= KSALLOCATOR_OPTIONF_SYSTEM_MEMORY
;
537 AllocatorFraming
.PoolType
= (m_Properties
.LogicalMemoryType
== KS_MemoryTypeKernelPaged
);
539 DWORD dwError
= KsCreateAllocator(hPin
, &AllocatorFraming
, &m_hAllocator
);
546 //-------------------------------------------------------------------
549 CKsAllocator::FreeMediaSamples()
553 for(Index
= 0; Index
< m_FreeList
.size(); Index
++)
555 IMediaSample
* Sample
= m_FreeList
.top();
560 m_FreeSamples
= false;
566 VirtualFree(m_Buffer
, 0, MEM_RELEASE
);
574 CKsAllocator_Constructor(
575 IUnknown
* pUnkOuter
,
579 OutputDebugStringW(L
"CKsAllocator_Constructor\n");
581 CKsAllocator
* handler
= new CKsAllocator();
584 return E_OUTOFMEMORY
;
586 if (FAILED(handler
->QueryInterface(riid
, ppv
)))
590 return E_NOINTERFACE
;