convert line ends
[canaan.git] / prj / tech / libsrc / actmovie / amalloc.cpp
blobd52fa7561968c55e0e0f81499814961cb92d694d
1 ///////////////////////////////////////////////////////////////////////////////
2 // $Source: x:/prj/tech/libsrc/actmovie/RCS/amalloc.cpp $
3 // $Author: JON $
4 // $Date: 1996/09/18 11:32:28 $
5 // $Revision: 1.3 $
6 //
8 #include <windows.h>
9 #include <lg.h>
11 #include <comtools.h>
13 #include <actmovie.h>
15 #include <control.h>
16 #include <strmif.h>
17 #include <evcode.h>
18 #include <uuids.h>
19 #include <vfwmsgs.h>
21 #include <amalloc.h>
23 ///////////////////////////////////////////////////////////////////////////////
25 // @Note (toml 09-06-96): The following are HACKS to get this file to compiler
28 // @TBD (toml 09-06-96): Thse macros are placeholders for things in mtype.*, which needs to be imported (?)
29 #define DeleteMediaType(p)
30 #define CreateMediaType(p) (p)
32 // @TBD (toml 09-06-96): these are things from wxutil
33 #define ValidateReadPtr(p,cb)
34 #define ValidateWritePtr(p,cb)
35 #define ValidateReadWritePtr(p,cb)
36 #define ValidateStringPtr(p)
37 #define ValidateStringPtrA(p)
38 #define ValidateStringPtrW(p)
40 // @TBD (toml 09-06-96): From wxdebug
41 #define CheckPointer(p,ret) {if((p)==NULL) return (ret);}
43 #undef DbgLog
44 #define DbgLog(x)
46 #define NAME(s) NULL
48 ///////////////////////////////////////////////////////////////////////////////
50 // CLASS: cMediaSample
52 // Memory allocation class, implements cMediaSample
55 ///////////////////////////////////////
57 // Pre-fab COM implementations
60 IMPLEMENT_UNAGGREGATABLE(cMediaSample, IMediaSample);
62 ///////////////////////////////////////
64 #pragma off(unreferenced)
65 cMediaSample::cMediaSample(char *pName,
66 cBaseAllocator * pAllocator,
67 HRESULT * phr,
68 BYTE * pBuffer,
69 long length)
70 : m_pBuffer(pBuffer), // Initialise the buffer
71 m_cbBuffer(length), // And it's length
72 m_lActual(length), // By default, actual = length
73 m_pMediaType(NULL), // No media type change
74 m_dwFlags(0) // Nothing set
76 /* We must have an owner and it must also be derived from class cBaseAllocator BUT we do not hold a reference count on it */
77 m_pAllocator = pAllocator;
78 Assert_(pAllocator);
80 if (pAllocator == NULL)
82 *phr = VFW_E_NEED_OWNER;
85 #pragma on(unreferenced)
88 ///////////////////////////////////////
90 cMediaSample::~cMediaSample()
92 if (m_pMediaType)
94 DeleteMediaType(m_pMediaType);
95 m_pMediaType = NULL;
100 ///////////////////////////////////////
102 // On final release of this sample buffer it is not deleted but
103 // returned to the freelist of the owning memory allocator
105 // The allocator may be waiting for the last buffer to be placed on the free
106 // list in order to decommit all the memory, so the ReleaseBuffer() call may
107 // result in this sample being deleted. We also need to hold a refcount on
108 // the allocator to stop that going away until we have finished with this.
109 // However, we cannot release the allocator before the ReleaseBuffer, as the
110 // release may cause us to be deleted. Similarly we can't do it afterwards.
112 // Thus we must leave it to the allocator to hold an addref on our behalf.
113 // When he issues us in GetBuffer, he addref's himself. When ReleaseBuffer
114 // is called, he releases himself, possibly causing us and him to be deleted.
116 void cMediaSample::OnFinalRelease()
118 /* Free all resources */
119 SetMediaType(NULL);
120 m_dwFlags = 0;
122 /* This may cause us to be deleted */
123 // Our refcount is reliably 0 thus no-one will mess with us
124 m_pAllocator->ReleaseBuffer(this);
128 ///////////////////////////////////////
130 // set the buffer pointer and length. Used by allocators that
131 // want variable sized pointers or pointers into already-read data.
132 // This is only available through a cMediaSample* not an IMediaSample*
133 // and so cannot be changed by clients.
136 HRESULT cMediaSample::SetPointer(BYTE * ptr, long cBytes)
138 m_pBuffer = ptr; // new buffer area (could be null)
139 m_cbBuffer = cBytes; // length of buffer
140 m_lActual = cBytes; // length of data in buffer (assume full)
142 return S_OK;
146 ///////////////////////////////////////
148 // get me a read/write pointer to this buffer's memory. I will actually
149 // want to use sizeUsed bytes.
152 STDMETHODIMP cMediaSample::GetPointer(BYTE ** ppBuffer)
154 CheckPointer(ppBuffer, E_POINTER);
155 ValidateReadWritePtr(ppBuffer, sizeof(BYTE *));
157 // creator must have set pointer either during
158 // constructor or by SetPointer
159 Assert_(m_pBuffer);
160 if (m_pBuffer == 0)
162 return VFW_E_BUFFER_NOTSET;
165 *ppBuffer = m_pBuffer;
166 return NOERROR;
170 ///////////////////////////////////////
172 // return the size in bytes of this buffer
175 STDMETHODIMP_(long) cMediaSample::GetSize(void)
177 return m_cbBuffer;
181 ///////////////////////////////////////
183 // get the stream time at which this sample should start and finish.
186 STDMETHODIMP cMediaSample::GetTime(REFERENCE_TIME * pTimeStart, // put time here
187 REFERENCE_TIME * pTimeEnd)
189 CheckPointer(pTimeStart, E_POINTER);
190 CheckPointer(pTimeEnd, E_POINTER);
191 ValidateReadWritePtr(pTimeStart, sizeof(REFERENCE_TIME));
192 ValidateReadWritePtr(pTimeEnd, sizeof(REFERENCE_TIME));
194 if (!(m_dwFlags & Sample_TimeValid))
196 return VFW_E_SAMPLE_TIME_NOT_SET;
199 *pTimeStart = m_Start;
200 *pTimeEnd = m_End;
201 return NOERROR;
205 ///////////////////////////////////////
207 // Set the stream time at which this sample should start and finish.
209 STDMETHODIMP cMediaSample::SetTime(REFERENCE_TIME * pTimeStart,
210 REFERENCE_TIME * pTimeEnd)
212 if (!pTimeStart || !pTimeEnd)
214 if (!pTimeStart && !pTimeEnd)
216 m_dwFlags &= ~Sample_TimeValid;
218 else
220 CheckPointer(pTimeStart, E_POINTER);
221 CheckPointer(pTimeEnd, E_POINTER);
224 else
226 ValidateReadPtr(pTimeStart, sizeof(REFERENCE_TIME));
227 ValidateReadPtr(pTimeEnd, sizeof(REFERENCE_TIME));
228 Assert_(*pTimeEnd >= *pTimeStart);
230 m_Start = *pTimeStart;
231 m_End = *pTimeEnd;
232 m_dwFlags |= Sample_TimeValid;
234 return NOERROR;
238 ///////////////////////////////////////
240 // get the media times (eg bytes) for this sample
243 STDMETHODIMP cMediaSample::GetMediaTime(LONGLONG * pTimeStart,
244 LONGLONG * pTimeEnd)
246 CheckPointer(pTimeStart, E_POINTER);
247 CheckPointer(pTimeEnd, E_POINTER);
248 ValidateReadWritePtr(pTimeStart, sizeof(LONGLONG));
249 ValidateReadWritePtr(pTimeEnd, sizeof(LONGLONG));
251 if (!(m_dwFlags & Sample_MediaTimeValid))
253 return VFW_E_MEDIA_TIME_NOT_SET;
256 *pTimeStart = m_MediaStart;
257 *pTimeEnd = (m_MediaStart + m_MediaEnd);
258 return NOERROR;
262 ///////////////////////////////////////
264 // Set the media times for this sample
267 STDMETHODIMP cMediaSample::SetMediaTime(LONGLONG * pTimeStart,
268 LONGLONG * pTimeEnd)
270 if (!pTimeStart && !pTimeEnd)
272 m_dwFlags &= ~Sample_MediaTimeValid;
274 else
276 CheckPointer(pTimeStart, E_POINTER);
277 CheckPointer(pTimeEnd, E_POINTER);
278 ValidateReadPtr(pTimeStart, sizeof(LONGLONG));
279 ValidateReadPtr(pTimeEnd, sizeof(LONGLONG));
280 Assert_(*pTimeEnd >= *pTimeStart);
282 m_MediaStart = *pTimeStart;
283 m_MediaEnd = (long) (*pTimeEnd - *pTimeStart);
284 m_dwFlags |= Sample_MediaTimeValid;
286 return NOERROR;
290 ///////////////////////////////////////
292 STDMETHODIMP cMediaSample::IsSyncPoint(void)
294 if (m_dwFlags & Sample_SyncPoint)
296 return S_OK;
298 else
300 return S_FALSE;
305 ///////////////////////////////////////
307 STDMETHODIMP cMediaSample::SetSyncPoint(BOOL bIsSyncPoint)
309 if (bIsSyncPoint)
311 m_dwFlags |= Sample_SyncPoint;
313 else
315 m_dwFlags &= ~Sample_SyncPoint;
317 return NOERROR;
320 ///////////////////////////////////////
322 // returns S_OK if there is a discontinuity in the data (this same is
323 // not a continuation of the previous stream of data
324 // - there has been a seek).
327 STDMETHODIMP cMediaSample::IsDiscontinuity(void)
329 if (m_dwFlags & Sample_Discontinuity)
331 return S_OK;
333 else
335 return S_FALSE;
339 ///////////////////////////////////////
341 // set the discontinuity property - TRUE if this sample is not a
342 // continuation, but a new sample after a seek.
345 STDMETHODIMP cMediaSample::SetDiscontinuity(BOOL bDiscont)
347 // should be TRUE or FALSE
348 if (bDiscont)
350 m_dwFlags |= Sample_Discontinuity;
352 else
354 m_dwFlags &= ~Sample_Discontinuity;
356 return S_OK;
359 ///////////////////////////////////////
361 STDMETHODIMP cMediaSample::IsPreroll(void)
363 if (m_dwFlags & Sample_Preroll)
365 return S_OK;
367 else
369 return S_FALSE;
374 ///////////////////////////////////////
376 STDMETHODIMP cMediaSample::SetPreroll(BOOL bIsPreroll)
378 if (bIsPreroll)
380 m_dwFlags |= Sample_Preroll;
382 else
384 m_dwFlags &= ~Sample_Preroll;
386 return NOERROR;
389 ///////////////////////////////////////
391 STDMETHODIMP_(long) cMediaSample::GetActualDataLength(void)
393 return m_lActual;
397 ///////////////////////////////////////
399 STDMETHODIMP cMediaSample::SetActualDataLength(long lActual)
401 if (lActual > GetSize())
403 Assert_(lActual <= GetSize());
404 return VFW_E_BUFFER_OVERFLOW;
406 m_lActual = lActual;
407 return NOERROR;
411 ///////////////////////////////////////
413 STDMETHODIMP cMediaSample::GetMediaType(AM_MEDIA_TYPE ** ppMediaType)
415 CheckPointer(ppMediaType, E_POINTER);
416 ValidateReadWritePtr(ppMediaType, sizeof(AM_MEDIA_TYPE *));
417 Assert_(ppMediaType);
419 /* Do we have a new media type for them */
421 if (!(m_dwFlags & Sample_TypeChanged))
423 Assert_(m_pMediaType == NULL);
424 *ppMediaType = NULL;
425 return S_FALSE;
428 Assert_(m_pMediaType);
430 /* Create a copy of our media type */
432 *ppMediaType = CreateMediaType(m_pMediaType);
433 if (*ppMediaType == NULL)
435 return E_OUTOFMEMORY;
437 return NOERROR;
441 ///////////////////////////////////////
443 STDMETHODIMP cMediaSample::SetMediaType(AM_MEDIA_TYPE * pMediaType)
445 /* Delete the current media type */
447 if (m_pMediaType)
449 DeleteMediaType(m_pMediaType);
450 m_pMediaType = NULL;
453 /* Mechanism for resetting the format type */
455 if (pMediaType == NULL)
457 m_dwFlags &= ~Sample_TypeChanged;
458 return NOERROR;
461 Assert_(pMediaType);
462 ValidateReadPtr(pMediaType, sizeof(AM_MEDIA_TYPE));
464 /* Take a copy of the media type */
466 m_pMediaType = CreateMediaType(pMediaType);
467 if (m_pMediaType == NULL)
469 m_dwFlags &= ~Sample_TypeChanged;
470 return E_OUTOFMEMORY;
473 m_dwFlags |= Sample_TypeChanged;
474 return NOERROR;
477 ///////////////////////////////////////////////////////////////////////////////
479 // CLASS: cBaseAllocator
482 ///////////////////////////////////////
484 // Pre-fab COM implementations
487 IMPLEMENT_UNAGGREGATABLE_SELF_DELETE(cBaseAllocator, IMemAllocator);
489 ///////////////////////////////////////
491 #pragma off(unreferenced)
492 cBaseAllocator::cBaseAllocator(char *pName, LPUNKNOWN pUnk, HRESULT * phr, BOOL bEvent)
493 : m_lAllocated(0),
494 m_bChanged(FALSE),
495 m_bCommitted(FALSE),
496 m_bDecommitInProgress(FALSE),
497 m_lSize(0),
498 m_lCount(0),
499 m_lAlignment(0),
500 m_lPrefix(0),
501 m_hSem(NULL),
502 m_lWaiting(0)
504 AssertMsg(!pUnk, "Aggregation of cBaseAllocator not implemented!");
505 if (bEvent)
507 m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
508 if (m_hSem == NULL)
510 *phr = E_OUTOFMEMORY;
511 return;
515 #pragma on(unreferenced)
518 ///////////////////////////////////////
520 cBaseAllocator::~cBaseAllocator()
522 // we can't call Decommit here since that would mean a call to a
523 // pure virtual in destructor.
524 // We must assume that the derived class has gone into decommit state in
525 // its destructor.
526 Assert_(!m_bCommitted);
527 if (m_hSem != NULL)
529 Verify(CloseHandle(m_hSem));
534 ///////////////////////////////////////
536 /* This sets the size and count of the required samples. The memory isn't
537 actually allocated until Commit() is called, if memory has already been
538 allocated then assuming no samples are outstanding the user may call us
539 to change the buffering, the memory will be released in Commit() */
541 STDMETHODIMP cBaseAllocator::SetProperties(ALLOCATOR_PROPERTIES * pRequest,
542 ALLOCATOR_PROPERTIES * pActual)
544 CheckPointer(pRequest, E_POINTER);
545 CheckPointer(pActual, E_POINTER);
546 ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES));
547 cAutoLock lock(m_Lock);
548 ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
550 Assert_(pRequest->cbBuffer > 0);
552 /* Check the alignment requested */
553 if (pRequest->cbAlign != 1)
555 DbgLog((LOG_ERROR, 2, TEXT("Alignment requested was 0x%x, not 1"),
556 pRequest->cbAlign));
557 return VFW_E_BADALIGN;
560 /* Can't do this if already committed, there is an argument that says we should not reject the SetProperties call if there
561 are buffers still active. However this is called by the source filter, which is the same person who is holding the
562 samples. Therefore it is not unreasonable for them to free all their samples before changing the requirements */
564 if (m_bCommitted)
566 return VFW_E_ALREADY_COMMITTED;
569 /* Must be no outstanding buffers */
571 if (m_lAllocated != m_lFree.GetCount())
573 return VFW_E_BUFFERS_OUTSTANDING;
576 /* There isn't any real need to check the parameters as they will just be rejected when the user finally calls Commit */
578 pActual->cbBuffer = m_lSize = pRequest->cbBuffer;
579 pActual->cBuffers = m_lCount = pRequest->cBuffers;
580 pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
581 pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
583 m_bChanged = TRUE;
584 return NOERROR;
587 ///////////////////////////////////////
589 STDMETHODIMP cBaseAllocator::GetProperties(ALLOCATOR_PROPERTIES * pActual)
591 CheckPointer(pActual, E_POINTER);
592 ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES));
594 cAutoLock lock(m_Lock);
595 pActual->cbBuffer = m_lSize;
596 pActual->cBuffers = m_lCount;
597 pActual->cbAlign = m_lAlignment;
598 pActual->cbPrefix = m_lPrefix;
599 return NOERROR;
602 ///////////////////////////////////////
603 // get container for a sample. Blocking, synchronous call to get the
604 // next free buffer (as represented by an IMediaSample interface).
605 // on return, the time etc properties will be invalid, but the buffer
606 // pointer and size will be correct.
608 HRESULT cBaseAllocator::GetBuffer(IMediaSample ** ppBuffer,
609 REFERENCE_TIME * /* pStartTime */,
610 REFERENCE_TIME * /*pEndTime */,
611 DWORD /* dwFlags */)
613 cMediaSample *pSample;
614 *ppBuffer = NULL;
615 for (;;)
617 { // scope for lock
618 cAutoLock lock(m_Lock);
619 /* Check we are committed */
620 if (!m_bCommitted)
622 return VFW_E_NOT_COMMITTED;
624 pSample = (cMediaSample *) m_lFree.RemoveHead();
625 if (pSample == NULL)
627 SetWaiting();
631 /* If we didn't get a sample then wait for the list to signal */
633 if (pSample)
635 break;
637 Assert_(m_hSem != NULL);
638 WaitForSingleObject(m_hSem, INFINITE);
641 /* This QueryInterface should addref the buffer up to one. On release back to zero instead of being deleted, it will
642 requeue itself by calling the ReleaseBuffer member function. NOTE the owner of a media sample must always be derived
643 from cBaseAllocator */
645 HRESULT hr = pSample->QueryInterface(IID_IMediaSample, (void **) ppBuffer);
646 /* For each sample outstanding, we need to AddRef ourselves on his behalf he cannot do it, as there is no correct ordering
647 of his release and his call to ReleaseBuffer as both could destroy him. We release this count in ReleaseBuffer, called
648 when the sample's count drops to zero */
650 AddRef();
651 return NOERROR;
655 ///////////////////////////////////////
657 /* Final release of a cMediaSample will call this */
659 STDMETHODIMP cBaseAllocator::ReleaseBuffer(IMediaSample * pSample)
661 CheckPointer(pSample, E_POINTER);
662 ValidateReadPtr(pSample, sizeof(IMediaSample));
664 cAutoLock lock(m_Lock);
665 /* Put back on the free list */
667 m_lFree.Add((cMediaSample *) pSample);
668 NotifySample();
670 // if there is a pending Decommit, then we need to complete it by
671 // calling Free() when the last buffer is placed on the free list
673 long l1 = m_lFree.GetCount();
674 if (m_bDecommitInProgress && (l1 == m_lAllocated))
676 Free();
677 m_bDecommitInProgress = FALSE;
681 /* For each buffer there is one AddRef, made in GetBuffer and released here. This may cause the allocator and all samples
682 to be deleted */
684 Release();
685 return NOERROR;
688 ///////////////////////////////////////
690 void cBaseAllocator::NotifySample()
692 if (m_lWaiting != 0)
694 Assert_(m_hSem != NULL);
695 ReleaseSemaphore(m_hSem, m_lWaiting, 0);
696 m_lWaiting = 0;
700 ///////////////////////////////////////
702 STDMETHODIMP cBaseAllocator::Commit()
704 /* Check we are not decommitted */
705 cAutoLock lock(m_Lock);
706 // cannot need to alloc or re-alloc if we are committed
707 if (m_bCommitted)
709 return NOERROR;
712 /* Allow GetBuffer calls */
714 m_bCommitted = TRUE;
716 // is there a pending decommit ? if so, just cancel it
717 if (m_bDecommitInProgress)
719 m_bDecommitInProgress = FALSE;
721 // don't call Alloc at this point. He cannot allow SetProperties
722 // between Decommit and the last free, so the buffer size cannot have
723 // changed. And because some of the buffers are not free yet, he
724 // cannot re-alloc anyway.
725 return NOERROR;
728 DbgLog((LOG_MEMORY, 1, TEXT("Allocating: %ldx%ld"), m_lCount, m_lSize));
730 // actually need to allocate the samples
731 HRESULT hr = Alloc();
732 if (FAILED(hr))
734 m_bCommitted = FALSE;
735 return hr;
737 return NOERROR;
741 ///////////////////////////////////////
743 STDMETHODIMP cBaseAllocator::Decommit()
745 /* Check we are not already decommitted */
746 cAutoLock lock(m_Lock);
747 if (m_bCommitted == FALSE)
749 if (m_bDecommitInProgress == FALSE)
751 return NOERROR;
755 /* No more GetBuffer calls will succeed */
756 m_bCommitted = FALSE;
758 // are any buffers outstanding?
759 if (m_lFree.GetCount() < m_lAllocated)
761 // please complete the decommit when last buffer is freed
762 m_bDecommitInProgress = TRUE;
764 else
766 m_bDecommitInProgress = FALSE;
768 // need to complete the decommit here as there are no
769 // outstanding buffers
771 Free();
774 // Tell anyone whose waiting that they can go now so we can
775 // reject their call
776 NotifySample();
778 return NOERROR;
782 ///////////////////////////////////////
784 /* Base definition of allocation which checks we are ok to go ahead and do
785 the full allocation. We return S_FALSE if the requirements are the same */
787 HRESULT cBaseAllocator::Alloc(void)
789 /* Error if he hasn't set the size yet */
790 if (m_lCount <= 0 || m_lSize <= 0 || m_lAlignment <= 0)
792 return VFW_E_SIZENOTSET;
795 /* should never get here while buffers outstanding */
796 Assert_(m_lFree.GetCount() == m_lAllocated);
798 /* If the requirements haven't changed then don't reallocate */
799 if (m_bChanged == FALSE)
801 return S_FALSE;
804 return NOERROR;
807 ///////////////////////////////////////
809 /* Implement cBaseAllocator::cSampleList::Remove(pSample)
810 Removes pSample from the list
812 void cBaseAllocator::cSampleList::Remove(cMediaSample * pSample)
814 cMediaSample **pSearch;
815 for (pSearch = &m_List;
816 *pSearch != NULL;
817 pSearch = &(cBaseAllocator::NextSample(*pSearch)))
819 if (*pSearch == pSample)
821 *pSearch = cBaseAllocator::NextSample(pSample);
822 cBaseAllocator::NextSample(pSample) = NULL;
823 m_nOnList--;
824 return;
828 CriticalMsg("Couldn't find sample in list");
831 ///////////////////////////////////////////////////////////////////////////////
833 // CLASS: cMemAllocator
837 cMemAllocator::cMemAllocator(char *pName,
838 LPUNKNOWN pUnk,
839 HRESULT * phr)
840 : cBaseAllocator(pName, pUnk, phr),
841 m_pBuffer(NULL)
845 ///////////////////////////////////////
847 /* This sets the size and count of the required samples. The memory isn't
848 actually allocated until Commit() is called, if memory has already been
849 allocated then assuming no samples are outstanding the user may call us
850 to change the buffering, the memory will be released in Commit() */
851 STDMETHODIMP cMemAllocator::SetProperties(ALLOCATOR_PROPERTIES * pRequest,
852 ALLOCATOR_PROPERTIES * pActual)
854 CheckPointer(pActual, E_POINTER);
855 ValidateReadWritePtr(pActual, sizeof(ALLOCATOR_PROPERTIES));
856 cAutoLock lock(m_Lock);
857 ZeroMemory(pActual, sizeof(ALLOCATOR_PROPERTIES));
859 Assert_(pRequest->cbBuffer > 0);
861 SYSTEM_INFO SysInfo;
862 GetSystemInfo(&SysInfo);
864 /* Check the alignment request is a power of 2 */
865 if ((-pRequest->cbAlign & pRequest->cbAlign) != pRequest->cbAlign)
867 DbgLog((LOG_ERROR, 1, TEXT("Alignment requested 0x%x not a power of 2!"),
868 pRequest->cbAlign));
870 /* Check the alignment requested */
871 if (pRequest->cbAlign == 0 ||
872 SysInfo.dwAllocationGranularity & (pRequest->cbAlign - 1) != 0)
874 DbgLog((LOG_ERROR, 1, TEXT("Invalid alignment 0x%x requested - granularity = 0x%x"),
875 pRequest->cbAlign, SysInfo.dwAllocationGranularity));
876 return VFW_E_BADALIGN;
879 /* Can't do this if already committed, there is an argument that says we should not reject the SetProperties call if there
880 are buffers still active. However this is called by the source filter, which is the same person who is holding the
881 samples. Therefore it is not unreasonable for them to free all their samples before changing the requirements */
883 if (m_bCommitted == TRUE)
885 return VFW_E_ALREADY_COMMITTED;
888 /* Must be no outstanding buffers */
890 if (m_lFree.GetCount() < m_lAllocated)
892 return VFW_E_BUFFERS_OUTSTANDING;
895 /* There isn't any real need to check the parameters as they will just be rejected when the user finally calls Commit */
897 // round length up to alignment - remember that prefix is included in
898 // the alignment
899 long lSize = pRequest->cbBuffer + pRequest->cbPrefix;
900 long lRemainder = lSize % pRequest->cbAlign;
901 if (lRemainder != 0)
903 lSize = lSize - lRemainder + pRequest->cbAlign;
905 pActual->cbBuffer = m_lSize = (lSize - pRequest->cbPrefix);
907 pActual->cBuffers = m_lCount = pRequest->cBuffers;
908 pActual->cbAlign = m_lAlignment = pRequest->cbAlign;
909 pActual->cbPrefix = m_lPrefix = pRequest->cbPrefix;
911 m_bChanged = TRUE;
912 return NOERROR;
915 ///////////////////////////////////////
916 // override this to allocate our resources when Commit is called.
918 // note that our resources may be already allocated when this is called,
919 // since we don't free them on Decommit. We will only be called when in
920 // decommit state with all buffers free.
922 // object locked by caller
924 HRESULT cMemAllocator::Alloc(void)
926 cAutoLock lock(m_Lock);
927 /* Check he has called SetProperties */
928 HRESULT hr = cBaseAllocator::Alloc();
929 if (FAILED(hr))
931 return hr;
934 /* If the requirements haven't changed then don't reallocate */
935 if (hr == S_FALSE)
937 Assert_(m_pBuffer);
938 return NOERROR;
940 Assert_(hr == S_OK); // we use this fact in the loop below
942 /* Free the old resources */
943 if (m_pBuffer)
945 ReallyFree();
948 /* Create the contiguous memory block for the samples making sure it's properly aligned (64K should be enough!) */
949 Assert_(m_lAlignment != 0 &&
950 (m_lSize + m_lPrefix) % m_lAlignment == 0);
952 m_pBuffer = (PBYTE) VirtualAlloc(NULL,
953 m_lCount * (m_lSize + m_lPrefix),
954 MEM_COMMIT,
955 PAGE_READWRITE);
957 if (m_pBuffer == NULL)
959 return E_OUTOFMEMORY;
962 BYTE *pNext = m_pBuffer;
963 cMediaSample *pSample;
964 Assert_(m_lAllocated == 0);
966 // Create the new samples - we have allocated m_lSize bytes for each sample
967 // plus m_lPrefix bytes per sample as a prefix. We set the pointer to
968 // the memory after the prefix - so that GetPointer() will return a pointer
969 // to m_lSize bytes.
970 for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += (m_lSize + m_lPrefix))
974 pSample = new cMediaSample(NAME("Default memory media sample"),
975 this,
976 &hr,
977 pNext + m_lPrefix, // GetPointer() value
978 m_lSize); // not including prefix
980 if (FAILED(hr) || pSample == NULL)
982 delete pSample;
983 return E_OUTOFMEMORY;
986 // This CANNOT fail
987 // m_lFree.Add(pSample);
988 // Our new results in a 1 reference count not zero, so we start by releasing the sample
989 // (which decrements the reference count and then adds it to the free list anyway).
990 // This should fix things so that media samples are actually released when we're finished with them.
991 pSample->Release();
994 m_bChanged = FALSE;
995 return NOERROR;
999 ///////////////////////////////////////
1000 // override this to free up any resources we have allocated.
1001 // called from the base class on Decommit when all buffers have been
1002 // returned to the free list.
1004 // caller has already locked the object.
1006 // in our case, we keep the memory until we are deleted, so
1007 // we do nothing here. The memory is deleted in the destructor by
1008 // calling ReallyFree()
1010 void cMemAllocator::Free(void)
1012 return;
1016 ///////////////////////////////////////
1017 // called from the destructor (and from Alloc if changing size/count) to
1018 // actually free up the memory
1020 void cMemAllocator::ReallyFree(void)
1022 /* Should never be deleting this unless all buffers are freed */
1024 Assert_(m_lAllocated == m_lFree.GetCount());
1026 /* Free up all the cMediaSamples */
1028 cMediaSample *pSample;
1029 for (;;)
1031 pSample = m_lFree.RemoveHead();
1032 if (pSample != NULL)
1034 delete pSample;
1036 else
1038 break;
1042 m_lAllocated = 0;
1044 // free the block of buffer memory
1045 if (m_pBuffer)
1047 Verify(VirtualFree(m_pBuffer, 0, MEM_RELEASE));
1048 m_pBuffer = NULL;
1053 ///////////////////////////////////////
1055 /* Destructor frees our memory resources */
1057 cMemAllocator::~cMemAllocator()
1059 Decommit();
1060 ReallyFree();
1063 ///////////////////////////////////////////////////////////////////////////////
1065 #pragma off(unreferenced)
1066 cDDSample::cDDSample(
1067 TCHAR *pName,
1068 cBaseAllocator *pAllocator,
1069 HRESULT *phr,
1070 LPDIRECTDRAWSURFACE pDDSurface,
1071 IDirectDrawSurface *pIDDSurface,
1072 LPDDSURFACEDESC pDDSurfaceDesc,
1073 LONG length):
1074 cMediaSample(pName, pAllocator, phr, (BYTE*)pDDSurfaceDesc->lpSurface, length),
1075 m_pDDSurface(pDDSurface),
1076 m_pDDSurfaceDesc(pDDSurfaceDesc),
1077 m_pIDDSurface(pIDDSurface)
1081 #pragma on(unreferenced)
1083 LPDIRECTDRAWSURFACE cDDSample::GetDDSurface()
1085 return m_pDDSurface;
1088 IDirectDrawSurface *cDDSample::GetIDDSurface()
1090 return m_pIDDSurface;
1093 LPDDSURFACEDESC cDDSample::GetDDSurfaceDesc()
1095 return m_pDDSurfaceDesc;
1098 #pragma off(unreferenced)
1099 cBitmapSample::cBitmapSample(
1100 TCHAR *pName,
1101 cBaseAllocator *pAllocator,
1102 HRESULT *phr,
1103 grs_bitmap *pBitmap,
1104 LONG length):
1105 cMediaSample(pName, pAllocator, phr, (BYTE*)pBitmap->bits, length),
1106 m_pBitmap(pBitmap)
1109 #pragma on(unreferenced)
1111 grs_bitmap *cBitmapSample::GetBitmap()
1113 return m_pBitmap;