Reactos
at listview 625 lines 15 kB view raw
1/* 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 6 * 7 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) 8 */ 9#include "precomp.h" 10 11const GUID IID_IKsAllocatorEx = {0x091bb63a, 0x603f, 0x11d1, {0xb0, 0x67, 0x00, 0xa0, 0xc9, 0x06, 0x28, 0x02}}; 12const GUID IID_IKsAllocator = {0x8da64899, 0xc0d9, 0x11d0, {0x84, 0x13, 0x00, 0x00, 0xf8, 0x22, 0xfe, 0x8a}}; 13 14class CKsAllocator : public IKsAllocatorEx, 15 public IMemAllocatorCallbackTemp 16{ 17public: 18 typedef std::stack<IMediaSample *>MediaSampleStack; 19 typedef std::list<IMediaSample *>MediaSampleList; 20 21 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 22 23 STDMETHODIMP_(ULONG) AddRef() 24 { 25 InterlockedIncrement(&m_Ref); 26 return m_Ref; 27 } 28 STDMETHODIMP_(ULONG) Release() 29 { 30 InterlockedDecrement(&m_Ref); 31 32 if (!m_Ref) 33 { 34 delete this; 35 return 0; 36 } 37 return m_Ref; 38 } 39 //IKsAllocator 40 HANDLE STDMETHODCALLTYPE KsGetAllocatorHandle(); 41 KSALLOCATORMODE STDMETHODCALLTYPE KsGetAllocatorMode(); 42 HRESULT STDMETHODCALLTYPE KsGetAllocatorStatus(PKSSTREAMALLOCATOR_STATUS AllocatorStatus); 43 VOID STDMETHODCALLTYPE KsSetAllocatorMode(KSALLOCATORMODE Mode); 44 45 //IKsAllocatorEx 46 PALLOCATOR_PROPERTIES_EX STDMETHODCALLTYPE KsGetProperties(); 47 VOID STDMETHODCALLTYPE KsSetProperties(PALLOCATOR_PROPERTIES_EX Properties); 48 VOID STDMETHODCALLTYPE KsSetAllocatorHandle(HANDLE AllocatorHandle); 49 HANDLE STDMETHODCALLTYPE KsCreateAllocatorAndGetHandle(IKsPin* KsPin); 50 51 //IMemAllocator 52 HRESULT STDMETHODCALLTYPE SetProperties(ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual); 53 HRESULT STDMETHODCALLTYPE GetProperties(ALLOCATOR_PROPERTIES *pProps); 54 HRESULT STDMETHODCALLTYPE Commit(); 55 HRESULT STDMETHODCALLTYPE Decommit(); 56 HRESULT STDMETHODCALLTYPE GetBuffer(IMediaSample **ppBuffer, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags); 57 HRESULT STDMETHODCALLTYPE ReleaseBuffer(IMediaSample *pBuffer); 58 59 //IMemAllocatorCallbackTemp 60 HRESULT STDMETHODCALLTYPE SetNotify(IMemAllocatorNotifyCallbackTemp *pNotify); 61 HRESULT STDMETHODCALLTYPE GetFreeCount(LONG *plBuffersFree); 62 63 64 CKsAllocator(); 65 virtual ~CKsAllocator(){} 66 VOID STDMETHODCALLTYPE FreeMediaSamples(); 67protected: 68 LONG m_Ref; 69 HANDLE m_hAllocator; 70 KSALLOCATORMODE m_Mode; 71 ALLOCATOR_PROPERTIES_EX m_Properties; 72 IMemAllocatorNotifyCallbackTemp *m_Notify; 73 ULONG m_Allocated; 74 LONG m_cbBuffer; 75 LONG m_cBuffers; 76 LONG m_cbAlign; 77 LONG m_cbPrefix; 78 BOOL m_Committed; 79 CRITICAL_SECTION m_CriticalSection; 80 MediaSampleStack m_FreeList; 81 MediaSampleList m_UsedList; 82 LPVOID m_Buffer; 83 BOOL m_FreeSamples; 84}; 85 86 87HRESULT 88STDMETHODCALLTYPE 89CKsAllocator::QueryInterface( 90 IN REFIID refiid, 91 OUT PVOID* Output) 92{ 93 if (IsEqualGUID(refiid, IID_IUnknown) || 94 IsEqualGUID(refiid, IID_IKsAllocator) || 95 IsEqualGUID(refiid, IID_IKsAllocatorEx)) 96 { 97 *Output = PVOID(this); 98 reinterpret_cast<IUnknown*>(*Output)->AddRef(); 99 return NOERROR; 100 } 101 if (IsEqualGUID(refiid, IID_IMemAllocator) || 102 IsEqualGUID(refiid, IID_IMemAllocatorCallbackTemp)) 103 { 104 *Output = (IMemAllocatorCallbackTemp*)(this); 105 reinterpret_cast<IMemAllocatorCallbackTemp*>(*Output)->AddRef(); 106 return NOERROR; 107 } 108 109 return E_NOINTERFACE; 110} 111 112CKsAllocator::CKsAllocator() : m_Ref(0), 113 m_hAllocator(0), 114 m_Mode(KsAllocatorMode_User), 115 m_Notify(0), 116 m_Allocated(0), 117 m_cbBuffer(0), 118 m_cBuffers(0), 119 m_cbAlign(0), 120 m_cbPrefix(0), 121 m_Committed(FALSE), 122 m_FreeList(), 123 m_UsedList(), 124 m_Buffer(0), 125 m_FreeSamples(FALSE) 126{ 127 InitializeCriticalSection(&m_CriticalSection); 128 129} 130 131//------------------------------------------------------------------- 132// IMemAllocator 133// 134HRESULT 135STDMETHODCALLTYPE 136CKsAllocator::SetProperties( 137 ALLOCATOR_PROPERTIES *pRequest, 138 ALLOCATOR_PROPERTIES *pActual) 139{ 140 SYSTEM_INFO SystemInfo; 141 142 EnterCriticalSection(&m_CriticalSection); 143 144#ifdef KSPROXY_TRACE 145 OutputDebugStringW(L"CKsAllocator::SetProperties\n"); 146#endif 147 148 if (!pRequest || !pActual) 149 return E_POINTER; 150 151 // zero output properties 152 ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES)); 153 154 // get system info 155 GetSystemInfo(&SystemInfo); 156 157 if (!pRequest->cbAlign || (pRequest->cbAlign - 1) & SystemInfo.dwAllocationGranularity) 158 { 159 // bad alignment 160 LeaveCriticalSection(&m_CriticalSection); 161 return VFW_E_BADALIGN; 162 } 163 164 if (m_Mode == KsAllocatorMode_Kernel) 165 { 166 // u can't change a kernel allocator 167 LeaveCriticalSection(&m_CriticalSection); 168 return VFW_E_ALREADY_COMMITTED; 169 } 170 171 if (m_Committed) 172 { 173 // need to decommit first 174 LeaveCriticalSection(&m_CriticalSection); 175 return VFW_E_ALREADY_COMMITTED; 176 } 177 178 if (m_Allocated != m_FreeList.size()) 179 { 180 // outstanding buffers 181 LeaveCriticalSection(&m_CriticalSection); 182 return VFW_E_BUFFERS_OUTSTANDING; 183 } 184 185 pActual->cbAlign = m_cbAlign = pRequest->cbAlign; 186 pActual->cbBuffer = m_cbBuffer = pRequest->cbBuffer; 187 pActual->cbPrefix = m_cbPrefix = pRequest->cbPrefix; 188 pActual->cBuffers = m_cBuffers = pRequest->cBuffers; 189 190 LeaveCriticalSection(&m_CriticalSection); 191 return NOERROR; 192} 193 194HRESULT 195STDMETHODCALLTYPE 196CKsAllocator::GetProperties( 197 ALLOCATOR_PROPERTIES *pProps) 198{ 199 if (!pProps) 200 return E_POINTER; 201 202 pProps->cbBuffer = m_cbBuffer; 203 pProps->cBuffers = m_cBuffers; 204 pProps->cbAlign = m_cbAlign; 205 pProps->cbPrefix = m_cbPrefix; 206 207 return NOERROR; 208} 209 210HRESULT 211STDMETHODCALLTYPE 212CKsAllocator::Commit() 213{ 214 LONG Index; 215 PUCHAR CurrentBuffer; 216 IMediaSample * Sample; 217 HRESULT hr; 218 219 //TODO integer overflow checks 220 EnterCriticalSection(&m_CriticalSection); 221 222#ifdef KSPROXY_TRACE 223 OutputDebugStringW(L"CKsAllocator::Commit\n"); 224#endif 225 226 if (m_Mode == KsAllocatorMode_Kernel) 227 { 228 /* no-op for kernel allocator */ 229 LeaveCriticalSection(&m_CriticalSection); 230 return NOERROR; 231 } 232 233 if (m_Committed) 234 { 235 // already committed 236 LeaveCriticalSection(&m_CriticalSection); 237 return NOERROR; 238 } 239 240 if (m_cbBuffer < 0 || m_cBuffers < 0 || m_cbPrefix < 0) 241 { 242 // invalid parameter 243 LeaveCriticalSection(&m_CriticalSection); 244 return E_OUTOFMEMORY; 245 } 246 247 LONG Size = m_cbBuffer + m_cbPrefix; 248 249 if (m_cbAlign > 1) 250 { 251 //check alignment 252 LONG Mod = Size % m_cbAlign; 253 if (Mod) 254 { 255 // calculate aligned size 256 Size += m_cbAlign - Mod; 257 } 258 } 259 260 LONG TotalSize = Size * m_cBuffers; 261 262 assert(TotalSize); 263 assert(m_cBuffers); 264 assert(Size); 265 266 // now allocate buffer 267 m_Buffer = VirtualAlloc(NULL, TotalSize, MEM_COMMIT, PAGE_READWRITE); 268 if (!m_Buffer) 269 { 270 LeaveCriticalSection(&m_CriticalSection); 271 return E_OUTOFMEMORY; 272 } 273 274 ZeroMemory(m_Buffer, TotalSize); 275 276 CurrentBuffer = (PUCHAR)m_Buffer; 277 278 for (Index = 0; Index < m_cBuffers; Index++) 279 { 280 // construct media sample 281 hr = CMediaSample_Constructor((IMemAllocator*)this, CurrentBuffer + m_cbPrefix, m_cbBuffer, IID_IMediaSample, (void**)&Sample); 282 if (FAILED(hr)) 283 { 284 LeaveCriticalSection(&m_CriticalSection); 285 return E_OUTOFMEMORY; 286 } 287 288 // add to free list 289 m_FreeList.push(Sample); 290 m_Allocated++; 291 292 //next sample buffer 293 CurrentBuffer += Size; 294 } 295 296 // we are now committed 297 m_Committed = true; 298 299 LeaveCriticalSection(&m_CriticalSection); 300 return S_OK; 301} 302 303HRESULT 304STDMETHODCALLTYPE 305CKsAllocator::Decommit() 306{ 307 EnterCriticalSection(&m_CriticalSection); 308 309#ifdef KSPROXY_TRACE 310 OutputDebugStringW(L"CKsAllocator::Decommit\n"); 311#endif 312 313 if (m_Mode == KsAllocatorMode_Kernel) 314 { 315 /* no-op for kernel allocator */ 316 LeaveCriticalSection(&m_CriticalSection); 317 return NOERROR; 318 } 319 320 m_Committed = false; 321 322 if (m_Allocated != m_FreeList.size()) 323 { 324 // outstanding buffers 325 m_FreeSamples = true; 326 LeaveCriticalSection(&m_CriticalSection); 327 return NOERROR; 328 } 329 else 330 { 331 // no outstanding buffers 332 // free to free them 333 FreeMediaSamples(); 334 } 335 336 LeaveCriticalSection(&m_CriticalSection); 337 return NOERROR; 338} 339 340 341HRESULT 342STDMETHODCALLTYPE 343CKsAllocator::GetBuffer( 344 IMediaSample **ppBuffer, 345 REFERENCE_TIME *pStartTime, 346 REFERENCE_TIME *pEndTime, 347 DWORD dwFlags) 348{ 349 IMediaSample * Sample = NULL; 350 351 if (!m_Committed) 352 return VFW_E_NOT_COMMITTED; 353 354 do 355 { 356 EnterCriticalSection(&m_CriticalSection); 357 358 if (!m_FreeList.empty()) 359 { 360 OutputDebugStringW(L"CKsAllocator::GetBuffer HACK\n"); 361 Sample = m_FreeList.top(); 362 m_FreeList.pop(); 363 } 364 365 LeaveCriticalSection(&m_CriticalSection); 366 367 if (dwFlags & AM_GBF_NOWAIT) 368 { 369 // never wait untill a buffer becomes available 370 break; 371 } 372 } 373 while(Sample == NULL); 374 375 if (!Sample) 376 { 377 // no sample acquired 378 //HACKKKKKKK 379 Sample = m_UsedList.back(); 380 m_UsedList.pop_back(); 381 382 if (!Sample) 383 return VFW_E_TIMEOUT; 384 } 385 386 // store result 387 *ppBuffer = Sample; 388 389 // store sample in used list 390 m_UsedList.push_front(Sample); 391 392 // done 393 return NOERROR; 394} 395 396HRESULT 397STDMETHODCALLTYPE 398CKsAllocator::ReleaseBuffer( 399 IMediaSample *pBuffer) 400{ 401 EnterCriticalSection(&m_CriticalSection); 402 403#ifdef KSPROXY_TRACE 404 OutputDebugStringW(L"CKsAllocator::ReleaseBuffer\n"); 405#endif 406 407 // media sample always 1 ref count in free list 408 pBuffer->AddRef(); 409 410 // add the sample to the free list 411 m_FreeList.push(pBuffer); 412 413 414 if (m_FreeSamples) 415 { 416 // pending de-commit 417 if (m_FreeList.size () == m_Allocated) 418 { 419 FreeMediaSamples(); 420 } 421 } 422 423 if (m_Notify) 424 { 425 //notify caller of an available buffer 426 m_Notify->NotifyRelease(); 427 } 428 429 LeaveCriticalSection(&m_CriticalSection); 430 return S_OK; 431} 432 433//------------------------------------------------------------------- 434// IMemAllocatorCallbackTemp 435// 436HRESULT 437STDMETHODCALLTYPE 438CKsAllocator::SetNotify( 439 IMemAllocatorNotifyCallbackTemp *pNotify) 440{ 441 EnterCriticalSection(&m_CriticalSection); 442 443#ifdef KSPROXY_TRACE 444 OutputDebugStringW(L"CKsAllocator::SetNotify\n"); 445#endif 446 447 if (pNotify) 448 pNotify->AddRef(); 449 450 if (m_Notify) 451 m_Notify->Release(); 452 453 m_Notify = pNotify; 454 455 LeaveCriticalSection(&m_CriticalSection); 456 return NOERROR; 457} 458 459HRESULT 460STDMETHODCALLTYPE 461CKsAllocator::GetFreeCount( 462 LONG *plBuffersFree) 463{ 464 *plBuffersFree = m_Allocated - m_FreeList.size(); 465 return S_OK; 466} 467 468//------------------------------------------------------------------- 469// IKsAllocator 470// 471HANDLE 472STDMETHODCALLTYPE 473CKsAllocator::KsGetAllocatorHandle() 474{ 475 return m_hAllocator; 476} 477 478KSALLOCATORMODE 479STDMETHODCALLTYPE 480CKsAllocator::KsGetAllocatorMode() 481{ 482 return m_Mode; 483} 484 485HRESULT 486STDMETHODCALLTYPE 487CKsAllocator::KsGetAllocatorStatus( 488 PKSSTREAMALLOCATOR_STATUS AllocatorStatus) 489{ 490 return NOERROR; 491} 492VOID 493STDMETHODCALLTYPE 494CKsAllocator::KsSetAllocatorMode( 495 KSALLOCATORMODE Mode) 496{ 497 m_Mode = Mode; 498} 499 500//------------------------------------------------------------------- 501// IKsAllocatorEx 502// 503PALLOCATOR_PROPERTIES_EX 504STDMETHODCALLTYPE 505CKsAllocator::KsGetProperties() 506{ 507 return &m_Properties; 508} 509 510VOID 511STDMETHODCALLTYPE 512CKsAllocator::KsSetProperties( 513 PALLOCATOR_PROPERTIES_EX Properties) 514{ 515 CopyMemory(&m_Properties, Properties, sizeof(ALLOCATOR_PROPERTIES_EX)); 516} 517 518VOID 519STDMETHODCALLTYPE 520CKsAllocator::KsSetAllocatorHandle( 521 HANDLE AllocatorHandle) 522{ 523 m_hAllocator = AllocatorHandle; 524} 525 526 527HANDLE 528STDMETHODCALLTYPE 529CKsAllocator::KsCreateAllocatorAndGetHandle( 530 IKsPin* KsPin) 531{ 532 HRESULT hr; 533 IKsObject * pObject; 534 KSALLOCATOR_FRAMING AllocatorFraming; 535 HANDLE hPin; 536 537#ifdef KSPROXY_TRACE 538 OutputDebugStringW(L"CKsAllocator::KsCreateAllocatorAndGetHandle\n"); 539#endif 540 541 if (m_hAllocator) 542 { 543 CloseHandle(m_hAllocator); 544 m_hAllocator = NULL; 545 } 546 547 // get pin IKsObject interface 548 hr = KsPin->QueryInterface(IID_IKsObject, (void**)&pObject); 549 if (FAILED(hr)) 550 return NULL; 551 552 // get pin handle 553 hPin = pObject->KsGetObjectHandle(); 554 555 //release IKsObject interface 556 pObject->Release(); 557 558 if (!hPin || hPin == INVALID_HANDLE_VALUE) 559 return NULL; 560 561 //setup allocator framing 562 AllocatorFraming.Frames = m_Properties.cBuffers; 563 AllocatorFraming.FrameSize = m_Properties.cbBuffer; 564 AllocatorFraming.FileAlignment = (m_Properties.cbAlign -1); 565 AllocatorFraming.OptionsFlags = KSALLOCATOR_OPTIONF_SYSTEM_MEMORY; 566 AllocatorFraming.PoolType = (m_Properties.LogicalMemoryType == KS_MemoryTypeKernelPaged); 567 568 DWORD dwError = KsCreateAllocator(hPin, &AllocatorFraming, &m_hAllocator); 569 if (dwError) 570 return NULL; 571 572 return m_hAllocator; 573} 574 575//------------------------------------------------------------------- 576VOID 577STDMETHODCALLTYPE 578CKsAllocator::FreeMediaSamples() 579{ 580 ULONG Index; 581 582 for(Index = 0; Index < m_FreeList.size(); Index++) 583 { 584 IMediaSample * Sample = m_FreeList.top(); 585 m_FreeList.pop(); 586 Sample->Release(); 587 } 588 589 m_FreeSamples = false; 590 m_Allocated = 0; 591 592 if (m_Buffer) 593 { 594 // release buffer 595 VirtualFree(m_Buffer, 0, MEM_RELEASE); 596 597 m_Buffer = NULL; 598 } 599} 600 601HRESULT 602WINAPI 603CKsAllocator_Constructor( 604 IUnknown * pUnkOuter, 605 REFIID riid, 606 LPVOID * ppv) 607{ 608#ifdef KSPROXY_TRACE 609 OutputDebugStringW(L"CKsAllocator_Constructor\n"); 610#endif 611 612 CKsAllocator * handler = new CKsAllocator(); 613 614 if (!handler) 615 return E_OUTOFMEMORY; 616 617 if (FAILED(handler->QueryInterface(riid, ppv))) 618 { 619 /* not supported */ 620 delete handler; 621 return E_NOINTERFACE; 622 } 623 624 return NOERROR; 625}