Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenallocator.cpp
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS WDM Streaming ActiveMovie Proxy 00004 * FILE: dll/directx/ksproxy/allocator.cpp 00005 * PURPOSE: IKsAllocator interface 00006 * 00007 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org) 00008 */ 00009 #include "precomp.h" 00010 00011 const GUID IID_IKsAllocatorEx = {0x091bb63a, 0x603f, 0x11d1, {0xb0, 0x67, 0x00, 0xa0, 0xc9, 0x06, 0x28, 0x02}}; 00012 const GUID IID_IKsAllocator = {0x8da64899, 0xc0d9, 0x11d0, {0x84, 0x13, 0x00, 0x00, 0xf8, 0x22, 0xfe, 0x8a}}; 00013 00014 class CKsAllocator : public IKsAllocatorEx, 00015 public IMemAllocatorCallbackTemp 00016 { 00017 public: 00018 typedef std::stack<IMediaSample *>MediaSampleStack; 00019 typedef std::list<IMediaSample *>MediaSampleList; 00020 00021 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 00022 00023 STDMETHODIMP_(ULONG) AddRef() 00024 { 00025 InterlockedIncrement(&m_Ref); 00026 return m_Ref; 00027 } 00028 STDMETHODIMP_(ULONG) Release() 00029 { 00030 InterlockedDecrement(&m_Ref); 00031 00032 if (!m_Ref) 00033 { 00034 delete this; 00035 return 0; 00036 } 00037 return m_Ref; 00038 } 00039 //IKsAllocator 00040 HANDLE STDMETHODCALLTYPE KsGetAllocatorHandle(); 00041 KSALLOCATORMODE STDMETHODCALLTYPE KsGetAllocatorMode(); 00042 HRESULT STDMETHODCALLTYPE KsGetAllocatorStatus(PKSSTREAMALLOCATOR_STATUS AllocatorStatus); 00043 VOID STDMETHODCALLTYPE KsSetAllocatorMode(KSALLOCATORMODE Mode); 00044 00045 //IKsAllocatorEx 00046 PALLOCATOR_PROPERTIES_EX STDMETHODCALLTYPE KsGetProperties(); 00047 VOID STDMETHODCALLTYPE KsSetProperties(PALLOCATOR_PROPERTIES_EX Properties); 00048 VOID STDMETHODCALLTYPE KsSetAllocatorHandle(HANDLE AllocatorHandle); 00049 HANDLE STDMETHODCALLTYPE KsCreateAllocatorAndGetHandle(IKsPin* KsPin); 00050 00051 //IMemAllocator 00052 HRESULT STDMETHODCALLTYPE SetProperties(ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual); 00053 HRESULT STDMETHODCALLTYPE GetProperties(ALLOCATOR_PROPERTIES *pProps); 00054 HRESULT STDMETHODCALLTYPE Commit(); 00055 HRESULT STDMETHODCALLTYPE Decommit(); 00056 HRESULT STDMETHODCALLTYPE GetBuffer(IMediaSample **ppBuffer, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags); 00057 HRESULT STDMETHODCALLTYPE ReleaseBuffer(IMediaSample *pBuffer); 00058 00059 //IMemAllocatorCallbackTemp 00060 HRESULT STDMETHODCALLTYPE SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); 00061 HRESULT STDMETHODCALLTYPE GetFreeCount(LONG *plBuffersFree); 00062 00063 00064 CKsAllocator(); 00065 virtual ~CKsAllocator(){} 00066 VOID STDMETHODCALLTYPE FreeMediaSamples(); 00067 protected: 00068 LONG m_Ref; 00069 HANDLE m_hAllocator; 00070 KSALLOCATORMODE m_Mode; 00071 ALLOCATOR_PROPERTIES_EX m_Properties; 00072 IMemAllocatorNotifyCallbackTemp *m_Notify; 00073 ULONG m_Allocated; 00074 LONG m_cbBuffer; 00075 LONG m_cBuffers; 00076 LONG m_cbAlign; 00077 LONG m_cbPrefix; 00078 BOOL m_Commited; 00079 CRITICAL_SECTION m_CriticalSection; 00080 MediaSampleStack m_FreeList; 00081 MediaSampleList m_UsedList; 00082 LPVOID m_Buffer; 00083 BOOL m_FreeSamples; 00084 }; 00085 00086 00087 HRESULT 00088 STDMETHODCALLTYPE 00089 CKsAllocator::QueryInterface( 00090 IN REFIID refiid, 00091 OUT PVOID* Output) 00092 { 00093 if (IsEqualGUID(refiid, IID_IUnknown) || 00094 IsEqualGUID(refiid, IID_IKsAllocator) || 00095 IsEqualGUID(refiid, IID_IKsAllocatorEx)) 00096 { 00097 *Output = PVOID(this); 00098 reinterpret_cast<IUnknown*>(*Output)->AddRef(); 00099 return NOERROR; 00100 } 00101 if (IsEqualGUID(refiid, IID_IMemAllocator) || 00102 IsEqualGUID(refiid, IID_IMemAllocatorCallbackTemp)) 00103 { 00104 *Output = (IMemAllocatorCallbackTemp*)(this); 00105 reinterpret_cast<IMemAllocatorCallbackTemp*>(*Output)->AddRef(); 00106 return NOERROR; 00107 } 00108 00109 return E_NOINTERFACE; 00110 } 00111 00112 CKsAllocator::CKsAllocator() : m_Ref(0), 00113 m_hAllocator(0), 00114 m_Mode(KsAllocatorMode_User), 00115 m_Notify(0), 00116 m_Allocated(0), 00117 m_cbBuffer(0), 00118 m_cBuffers(0), 00119 m_cbAlign(0), 00120 m_cbPrefix(0), 00121 m_Commited(FALSE), 00122 m_FreeList(), 00123 m_UsedList(), 00124 m_Buffer(0), 00125 m_FreeSamples(FALSE) 00126 { 00127 InitializeCriticalSection(&m_CriticalSection); 00128 00129 } 00130 00131 //------------------------------------------------------------------- 00132 // IMemAllocator 00133 // 00134 HRESULT 00135 STDMETHODCALLTYPE 00136 CKsAllocator::SetProperties( 00137 ALLOCATOR_PROPERTIES *pRequest, 00138 ALLOCATOR_PROPERTIES *pActual) 00139 { 00140 SYSTEM_INFO SystemInfo; 00141 00142 EnterCriticalSection(&m_CriticalSection); 00143 00144 #ifdef KSPROXY_TRACE 00145 OutputDebugStringW(L"CKsAllocator::SetProperties\n"); 00146 #endif 00147 00148 if (!pRequest || !pActual) 00149 return E_POINTER; 00150 00151 // zero output properties 00152 ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); 00153 00154 // get system info 00155 GetSystemInfo(&SystemInfo); 00156 00157 if (!pRequest->cbAlign || (pRequest->cbAlign - 1) & SystemInfo.dwAllocationGranularity) 00158 { 00159 // bad alignment 00160 LeaveCriticalSection(&m_CriticalSection); 00161 return VFW_E_BADALIGN; 00162 } 00163 00164 if (m_Mode == KsAllocatorMode_Kernel) 00165 { 00166 // u can't change a kernel allocator 00167 LeaveCriticalSection(&m_CriticalSection); 00168 return VFW_E_ALREADY_COMMITTED; 00169 } 00170 00171 if (m_Commited) 00172 { 00173 // need to decommit first 00174 LeaveCriticalSection(&m_CriticalSection); 00175 return VFW_E_ALREADY_COMMITTED; 00176 } 00177 00178 if (m_Allocated != m_FreeList.size()) 00179 { 00180 // outstanding buffers 00181 LeaveCriticalSection(&m_CriticalSection); 00182 return VFW_E_BUFFERS_OUTSTANDING; 00183 } 00184 00185 pActual->cbAlign = m_cbAlign = pRequest->cbAlign; 00186 pActual->cbBuffer = m_cbBuffer = pRequest->cbBuffer; 00187 pActual->cbPrefix = m_cbPrefix = pRequest->cbPrefix; 00188 pActual->cBuffers = m_cBuffers = pRequest->cBuffers; 00189 00190 LeaveCriticalSection(&m_CriticalSection); 00191 return NOERROR; 00192 } 00193 00194 HRESULT 00195 STDMETHODCALLTYPE 00196 CKsAllocator::GetProperties( 00197 ALLOCATOR_PROPERTIES *pProps) 00198 { 00199 if (!pProps) 00200 return E_POINTER; 00201 00202 pProps->cbBuffer = m_cbBuffer; 00203 pProps->cBuffers = m_cBuffers; 00204 pProps->cbAlign = m_cbAlign; 00205 pProps->cbPrefix = m_cbPrefix; 00206 00207 return NOERROR; 00208 } 00209 00210 HRESULT 00211 STDMETHODCALLTYPE 00212 CKsAllocator::Commit() 00213 { 00214 LONG Index; 00215 PUCHAR CurrentBuffer; 00216 IMediaSample * Sample; 00217 HRESULT hr; 00218 00219 //TODO integer overflow checks 00220 EnterCriticalSection(&m_CriticalSection); 00221 00222 #ifdef KSPROXY_TRACE 00223 OutputDebugStringW(L"CKsAllocator::Commit\n"); 00224 #endif 00225 00226 if (m_Mode == KsAllocatorMode_Kernel) 00227 { 00228 /* no-op for kernel allocator */ 00229 LeaveCriticalSection(&m_CriticalSection); 00230 return NOERROR; 00231 } 00232 00233 if (m_Commited) 00234 { 00235 // already commited 00236 LeaveCriticalSection(&m_CriticalSection); 00237 return NOERROR; 00238 } 00239 00240 if (m_cbBuffer < 0 || m_cBuffers < 0 || m_cbPrefix < 0) 00241 { 00242 // invalid parameter 00243 LeaveCriticalSection(&m_CriticalSection); 00244 return E_OUTOFMEMORY; 00245 } 00246 00247 LONG Size = m_cbBuffer + m_cbPrefix; 00248 00249 if (m_cbAlign > 1) 00250 { 00251 //check alignment 00252 LONG Mod = Size % m_cbAlign; 00253 if (Mod) 00254 { 00255 // calculate aligned size 00256 Size += m_cbAlign - Mod; 00257 } 00258 } 00259 00260 LONG TotalSize = Size * m_cBuffers; 00261 00262 assert(TotalSize); 00263 assert(m_cBuffers); 00264 assert(Size); 00265 00266 // now allocate buffer 00267 m_Buffer = VirtualAlloc(NULL, TotalSize, MEM_COMMIT, PAGE_READWRITE); 00268 if (!m_Buffer) 00269 { 00270 LeaveCriticalSection(&m_CriticalSection); 00271 return E_OUTOFMEMORY; 00272 } 00273 00274 ZeroMemory(m_Buffer, TotalSize); 00275 00276 CurrentBuffer = (PUCHAR)m_Buffer; 00277 00278 for (Index = 0; Index < m_cBuffers; Index++) 00279 { 00280 // construct media sample 00281 hr = CMediaSample_Constructor((IMemAllocator*)this, CurrentBuffer + m_cbPrefix, m_cbBuffer, IID_IMediaSample, (void**)&Sample); 00282 if (FAILED(hr)) 00283 { 00284 LeaveCriticalSection(&m_CriticalSection); 00285 return E_OUTOFMEMORY; 00286 } 00287 00288 // add to free list 00289 m_FreeList.push(Sample); 00290 m_Allocated++; 00291 00292 //next sample buffer 00293 CurrentBuffer += Size; 00294 } 00295 00296 // we are now commited 00297 m_Commited = true; 00298 00299 LeaveCriticalSection(&m_CriticalSection); 00300 return S_OK; 00301 } 00302 00303 HRESULT 00304 STDMETHODCALLTYPE 00305 CKsAllocator::Decommit() 00306 { 00307 EnterCriticalSection(&m_CriticalSection); 00308 00309 #ifdef KSPROXY_TRACE 00310 OutputDebugStringW(L"CKsAllocator::Decommit\n"); 00311 #endif 00312 00313 if (m_Mode == KsAllocatorMode_Kernel) 00314 { 00315 /* no-op for kernel allocator */ 00316 LeaveCriticalSection(&m_CriticalSection); 00317 return NOERROR; 00318 } 00319 00320 m_Commited = false; 00321 00322 if (m_Allocated != m_FreeList.size()) 00323 { 00324 // outstanding buffers 00325 m_FreeSamples = true; 00326 LeaveCriticalSection(&m_CriticalSection); 00327 return NOERROR; 00328 } 00329 else 00330 { 00331 // no outstanding buffers 00332 // free to free them 00333 FreeMediaSamples(); 00334 } 00335 00336 LeaveCriticalSection(&m_CriticalSection); 00337 return NOERROR; 00338 } 00339 00340 00341 HRESULT 00342 STDMETHODCALLTYPE 00343 CKsAllocator::GetBuffer( 00344 IMediaSample **ppBuffer, 00345 REFERENCE_TIME *pStartTime, 00346 REFERENCE_TIME *pEndTime, 00347 DWORD dwFlags) 00348 { 00349 IMediaSample * Sample = NULL; 00350 00351 if (!m_Commited) 00352 return VFW_E_NOT_COMMITTED; 00353 00354 do 00355 { 00356 EnterCriticalSection(&m_CriticalSection); 00357 00358 if (!m_FreeList.empty()) 00359 { 00360 OutputDebugStringW(L"CKsAllocator::GetBuffer HACK\n"); 00361 Sample = m_FreeList.top(); 00362 m_FreeList.pop(); 00363 } 00364 00365 LeaveCriticalSection(&m_CriticalSection); 00366 00367 if (dwFlags & AM_GBF_NOWAIT) 00368 { 00369 // never wait untill a buffer becomes available 00370 break; 00371 } 00372 } 00373 while(Sample == NULL); 00374 00375 if (!Sample) 00376 { 00377 // no sample acquired 00378 //HACKKKKKKK 00379 Sample = m_UsedList.back(); 00380 m_UsedList.pop_back(); 00381 00382 if (!Sample) 00383 return VFW_E_TIMEOUT; 00384 } 00385 00386 // store result 00387 *ppBuffer = Sample; 00388 00389 // store sample in used list 00390 m_UsedList.push_front(Sample); 00391 00392 // done 00393 return NOERROR; 00394 } 00395 00396 HRESULT 00397 STDMETHODCALLTYPE 00398 CKsAllocator::ReleaseBuffer( 00399 IMediaSample *pBuffer) 00400 { 00401 EnterCriticalSection(&m_CriticalSection); 00402 00403 #ifdef KSPROXY_TRACE 00404 OutputDebugStringW(L"CKsAllocator::ReleaseBuffer\n"); 00405 #endif 00406 00407 // media sample always 1 ref count in free list 00408 pBuffer->AddRef(); 00409 00410 // add the sample to the free list 00411 m_FreeList.push(pBuffer); 00412 00413 00414 if (m_FreeSamples) 00415 { 00416 // pending de-commit 00417 if (m_FreeList.size () == m_Allocated) 00418 { 00419 FreeMediaSamples(); 00420 } 00421 } 00422 00423 if (m_Notify) 00424 { 00425 //notify caller of an available buffer 00426 m_Notify->NotifyRelease(); 00427 } 00428 00429 LeaveCriticalSection(&m_CriticalSection); 00430 return S_OK; 00431 } 00432 00433 //------------------------------------------------------------------- 00434 // IMemAllocatorCallbackTemp 00435 // 00436 HRESULT 00437 STDMETHODCALLTYPE 00438 CKsAllocator::SetNotify( 00439 IMemAllocatorNotifyCallbackTemp *pNotify) 00440 { 00441 EnterCriticalSection(&m_CriticalSection); 00442 00443 #ifdef KSPROXY_TRACE 00444 OutputDebugStringW(L"CKsAllocator::SetNotify\n"); 00445 #endif 00446 00447 if (pNotify) 00448 pNotify->AddRef(); 00449 00450 if (m_Notify) 00451 m_Notify->Release(); 00452 00453 m_Notify = pNotify; 00454 00455 LeaveCriticalSection(&m_CriticalSection); 00456 return NOERROR; 00457 } 00458 00459 HRESULT 00460 STDMETHODCALLTYPE 00461 CKsAllocator::GetFreeCount( 00462 LONG *plBuffersFree) 00463 { 00464 *plBuffersFree = m_Allocated - m_FreeList.size(); 00465 return S_OK; 00466 } 00467 00468 //------------------------------------------------------------------- 00469 // IKsAllocator 00470 // 00471 HANDLE 00472 STDMETHODCALLTYPE 00473 CKsAllocator::KsGetAllocatorHandle() 00474 { 00475 return m_hAllocator; 00476 } 00477 00478 KSALLOCATORMODE 00479 STDMETHODCALLTYPE 00480 CKsAllocator::KsGetAllocatorMode() 00481 { 00482 return m_Mode; 00483 } 00484 00485 HRESULT 00486 STDMETHODCALLTYPE 00487 CKsAllocator::KsGetAllocatorStatus( 00488 PKSSTREAMALLOCATOR_STATUS AllocatorStatus) 00489 { 00490 return NOERROR; 00491 } 00492 VOID 00493 STDMETHODCALLTYPE 00494 CKsAllocator::KsSetAllocatorMode( 00495 KSALLOCATORMODE Mode) 00496 { 00497 m_Mode = Mode; 00498 } 00499 00500 //------------------------------------------------------------------- 00501 // IKsAllocatorEx 00502 // 00503 PALLOCATOR_PROPERTIES_EX 00504 STDMETHODCALLTYPE 00505 CKsAllocator::KsGetProperties() 00506 { 00507 return &m_Properties; 00508 } 00509 00510 VOID 00511 STDMETHODCALLTYPE 00512 CKsAllocator::KsSetProperties( 00513 PALLOCATOR_PROPERTIES_EX Properties) 00514 { 00515 CopyMemory(&m_Properties, Properties, sizeof(ALLOCATOR_PROPERTIES_EX)); 00516 } 00517 00518 VOID 00519 STDMETHODCALLTYPE 00520 CKsAllocator::KsSetAllocatorHandle( 00521 HANDLE AllocatorHandle) 00522 { 00523 m_hAllocator = AllocatorHandle; 00524 } 00525 00526 00527 HANDLE 00528 STDMETHODCALLTYPE 00529 CKsAllocator::KsCreateAllocatorAndGetHandle( 00530 IKsPin* KsPin) 00531 { 00532 HRESULT hr; 00533 IKsObject * pObject; 00534 KSALLOCATOR_FRAMING AllocatorFraming; 00535 HANDLE hPin; 00536 00537 #ifdef KSPROXY_TRACE 00538 OutputDebugStringW(L"CKsAllocator::KsCreateAllocatorAndGetHandle\n"); 00539 #endif 00540 00541 if (m_hAllocator) 00542 { 00543 CloseHandle(m_hAllocator); 00544 m_hAllocator = NULL; 00545 } 00546 00547 // get pin IKsObject interface 00548 hr = KsPin->QueryInterface(IID_IKsObject, (void**)&pObject); 00549 if (FAILED(hr)) 00550 return NULL; 00551 00552 // get pin handle 00553 hPin = pObject->KsGetObjectHandle(); 00554 00555 //release IKsObject interface 00556 pObject->Release(); 00557 00558 if (!hPin || hPin == INVALID_HANDLE_VALUE) 00559 return NULL; 00560 00561 //setup allocator framing 00562 AllocatorFraming.Frames = m_Properties.cBuffers; 00563 AllocatorFraming.FrameSize = m_Properties.cbBuffer; 00564 AllocatorFraming.FileAlignment = (m_Properties.cbAlign -1); 00565 AllocatorFraming.OptionsFlags = KSALLOCATOR_OPTIONF_SYSTEM_MEMORY; 00566 AllocatorFraming.PoolType = (m_Properties.LogicalMemoryType == KS_MemoryTypeKernelPaged); 00567 00568 DWORD dwError = KsCreateAllocator(hPin, &AllocatorFraming, &m_hAllocator); 00569 if (dwError) 00570 return NULL; 00571 00572 return m_hAllocator; 00573 } 00574 00575 //------------------------------------------------------------------- 00576 VOID 00577 STDMETHODCALLTYPE 00578 CKsAllocator::FreeMediaSamples() 00579 { 00580 ULONG Index; 00581 00582 for(Index = 0; Index < m_FreeList.size(); Index++) 00583 { 00584 IMediaSample * Sample = m_FreeList.top(); 00585 m_FreeList.pop(); 00586 delete Sample; 00587 } 00588 00589 m_FreeSamples = false; 00590 m_Allocated = 0; 00591 00592 if (m_Buffer) 00593 { 00594 // release buffer 00595 VirtualFree(m_Buffer, 0, MEM_RELEASE); 00596 00597 m_Buffer = NULL; 00598 } 00599 } 00600 00601 HRESULT 00602 WINAPI 00603 CKsAllocator_Constructor( 00604 IUnknown * pUnkOuter, 00605 REFIID riid, 00606 LPVOID * ppv) 00607 { 00608 #ifdef KSPROXY_TRACE 00609 OutputDebugStringW(L"CKsAllocator_Constructor\n"); 00610 #endif 00611 00612 CKsAllocator * handler = new CKsAllocator(); 00613 00614 if (!handler) 00615 return E_OUTOFMEMORY; 00616 00617 if (FAILED(handler->QueryInterface(riid, ppv))) 00618 { 00619 /* not supported */ 00620 delete handler; 00621 return E_NOINTERFACE; 00622 } 00623 00624 return NOERROR; 00625 } Generated on Sat May 26 2012 04:20:21 for ReactOS by
1.7.6.1
|