alloc.cpp
上传用户:sunbaby
上传日期:2013-05-31
资源大小:242k
文件大小:8k
源码类别:

mpeg/mp3

开发平台:

Visual C++

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1996 - 1997  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. /*  Sequential allocator methods */
  12. #include "stdafx.h"
  13. #include <streams.h>
  14. #include "alloc.h"
  15. CSequentialAllocator::CSequentialAllocator(
  16.     LPUNKNOWN  pUnk,
  17.     HRESULT   *phr
  18. ) : CMemAllocator(TEXT("CSequential Allocator"), pUnk, phr),
  19.     m_pbNext(m_pBuffer),
  20.     m_parSamples(NULL),
  21.     m_lValid(0),
  22.     m_pbStartValid(NULL)
  23. {
  24. }
  25. CSequentialAllocator::~CSequentialAllocator()
  26. {
  27.     if (m_parSamples != NULL) {
  28.         delete [] m_parSamples;
  29.     }
  30. }
  31. STDMETHODIMP CSequentialAllocator::GetBuffer(
  32.     IMediaSample **ppBuffer,
  33.     REFERENCE_TIME * pStartTime,
  34.     REFERENCE_TIME * pEndTime,
  35.     DWORD dwFlags
  36. )
  37. {
  38.     /*  Like the normal version except we will only allocate the NEXT
  39.         buffer
  40.     */
  41.     UNREFERENCED_PARAMETER(pStartTime);
  42.     UNREFERENCED_PARAMETER(pEndTime);
  43.     UNREFERENCED_PARAMETER(dwFlags);
  44.     CMediaSample *pSample = NULL;
  45.     *ppBuffer = NULL;
  46.     for (;;)
  47.     {
  48. {  // scope for lock
  49.     CAutoLock cObjectLock(this);
  50.     /* Check we are committed */
  51.     if (!m_bCommitted) {
  52. return VFW_E_NOT_COMMITTED;
  53.     }
  54.             /* Check if the one we want is there */
  55.             CMediaSample *pSearch = m_lFree.Head();
  56.             while (pSearch) {
  57.                 PBYTE pbBuffer;
  58.                 pSearch->GetPointer(&pbBuffer);
  59.                 if (pbBuffer == m_pbNext) {
  60.                     m_lFree.Remove(pSearch);
  61.                     pSample = pSearch;
  62.                     ASSERT(m_lSize == pSample->GetSize());
  63.                     m_pbNext += m_lSize;
  64.                     if (m_pbNext == m_pBuffer + m_lSize * m_lCount) {
  65.                         m_pbNext = m_pBuffer;
  66.                     }
  67.                     break;
  68.                 } else {
  69.                     pSearch = m_lFree.Next(pSearch);
  70.                 }
  71.             }
  72.             if (pSample == NULL) {
  73.                 /*  If there were some samples but just not ours someone
  74.                     else may be waiting
  75.                 */
  76.                 if (m_lFree.GetCount() != 0) {
  77.                     NotifySample();
  78.                 }
  79.                 SetWaiting();
  80.             }
  81. }
  82. /* If we didn't get a sample then wait for the list to signal */
  83. if (pSample) {
  84.     break;
  85. }
  86.         ASSERT(m_hSem != NULL);
  87.         DbgLog((LOG_TRACE, 4, TEXT("Waiting - %d buffers available"),
  88.                 m_lFree.GetCount()));
  89. WaitForSingleObject(m_hSem, INFINITE);
  90.     }
  91. #ifdef VFW_S_CANT_CUE
  92.     /* Addref the buffer up to one. On release
  93.        back to zero instead of being deleted, it will requeue itself by
  94.        calling the ReleaseBuffer member function. NOTE the owner of a
  95.        media sample must always be derived from CBaseAllocator */
  96.     ASSERT(pSample->m_cRef == 0);
  97.     pSample->m_cRef = 1;
  98.     *ppBuffer = pSample;
  99. #else
  100.     /* This QueryInterface should addref the buffer up to one. On release
  101.        back to zero instead of being deleted, it will requeue itself by
  102.        calling the ReleaseBuffer member function. NOTE the owner of a
  103.        media sample must always be derived from CBaseAllocator */
  104.     HRESULT hr = pSample->QueryInterface(IID_IMediaSample, (void **)ppBuffer);
  105.     /* For each sample outstanding, we need to AddRef ourselves on his behalf
  106.        he cannot do it, as there is no correct ordering of his release and his
  107.        call to ReleaseBuffer as both could destroy him. We release this count
  108.        in ReleaseBuffer, called when the sample's count drops to zero */
  109.     AddRef();
  110. #endif
  111.     return NOERROR;
  112. }
  113. HRESULT CSequentialAllocator::Alloc()
  114. {
  115.     CAutoLock lck(this);
  116.     if (m_parSamples != NULL) {
  117.         delete [] m_parSamples;
  118.     }
  119.     m_parSamples = new LPCMEDIASAMPLE[m_lCount];
  120.     if (m_parSamples == NULL) {
  121.         return E_OUTOFMEMORY;
  122.     }
  123.     HRESULT hr = CMemAllocator::Alloc();
  124.     if (S_OK == hr) {
  125.         ASSERT(m_lCount == m_lFree.GetCount());
  126.         /* Find the smallest */
  127.         CMediaSample *pSample = m_lFree.Head();
  128.         m_pBuffer = (PBYTE)(DWORD)-1;
  129.         for (; pSample != NULL; pSample = m_lFree.Next(pSample)) {
  130.             PBYTE pbTemp;
  131.             pSample->GetPointer(&pbTemp);
  132.             if (m_pBuffer > pbTemp) {
  133.                 m_pBuffer = pbTemp;
  134.             }
  135.         }
  136.         pSample = m_lFree.Head();
  137.         for ( ;pSample != NULL; pSample = m_lFree.Next(pSample)) {
  138.             PBYTE pbTemp;
  139.             pSample->GetPointer(&pbTemp);
  140.             m_parSamples[BufferIndex(pbTemp)] = pSample;
  141.         }
  142.     }
  143.     m_pbStartValid = m_pBuffer;
  144.     m_pbNext       = m_pBuffer;
  145.     ASSERT(m_lValid == 0);
  146.     return hr;
  147. }
  148. /*  Get buffer index */
  149. int CSequentialAllocator::BufferIndex(PBYTE pbBuffer)
  150. {
  151.     int iPos = (pbBuffer - m_pBuffer) / m_lSize;
  152.     // xxx
  153.     /*ASSERT(iPos < m_lCount);*/
  154.     return iPos;
  155. }
  156. /*  Given an address get the IMediaSample pointer -
  157.     NB needs optimizing
  158. */
  159. CMediaSample *CSequentialAllocator::SampleFromBuffer(PBYTE pBuffer)
  160. {
  161.     return m_parSamples[BufferIndex(pBuffer)];
  162. }
  163. /*  Add a buffer to the valid list */
  164. void CSequentialAllocator::AddBuffer(CMediaSample *pSample)
  165. {
  166.     /*  Don't get fooled by 0 length buffers ! */
  167.     if (pSample->GetActualDataLength() == 0) {
  168.         return;
  169.     }
  170.     pSample->AddRef();
  171. #ifdef DEBUG
  172.     PBYTE pbBuffer;
  173.     pSample->GetPointer(&pbBuffer);
  174.     ASSERT(m_pbStartValid + m_lValid == pbBuffer);
  175. #endif
  176.     m_lValid += pSample->GetActualDataLength();
  177. }
  178. /*  Step through valid data */
  179. HRESULT CSequentialAllocator::Advance(LONG lAdvance)
  180. {
  181.     /*  For every sample boundary we step over we should Release()
  182.         a buffer
  183.     */
  184.     int iStart = BufferIndex(m_pbStartValid);
  185.     int iEnd = BufferIndex(m_pbStartValid + lAdvance);
  186.     m_lValid -= lAdvance;
  187.     m_pbStartValid += lAdvance;
  188.     /*  If we're at the end and the last buffer wasn't full move on
  189.         to the next
  190.     */
  191.     if (m_lValid == 0 &&
  192.         (m_pbStartValid - m_pBuffer) % m_lSize != 0) {
  193.         iEnd++;
  194.         m_pbStartValid = m_pBuffer + m_lSize * iEnd;
  195.     }
  196.     while (iStart != iEnd) {
  197.         m_parSamples[iStart]->Release();
  198.         iStart++;
  199.     }
  200. /*
  201.     ASSERT(m_lValid <= (m_lCount * m_lSize) / 2);
  202. */
  203.     /*
  204.         If we're already into the last buffer and about to wrap
  205.         NOTE m_Valid CAN be >  m_lSize - hit it with a huge
  206.         PROGRAM_STREAM_DIRECTORY packet (can be almost 64K)
  207.     */
  208.     if (m_pbStartValid + m_lValid == m_pBuffer + m_lSize * m_lCount) {
  209.         return Wrap();
  210.     } else {
  211.         return S_OK;
  212.     }
  213. }
  214. /*  Get the valid part */
  215. PBYTE CSequentialAllocator::GetValid(LONG *plValid)
  216. {
  217.     *plValid = m_lValid;
  218.     return m_pbStartValid;
  219. }
  220. /*  Wrap end to go back to start */
  221. HRESULT CSequentialAllocator::Wrap(void)
  222. {
  223.     if (m_lValid != 0) {
  224.         /*  Make sure the copy will work */
  225.         ASSERT(m_lValid <= (m_lSize * m_lCount) / 2);
  226.         IMediaSample *pSample;
  227.         /*  These samples will be AddRef'd already */
  228.         int nBuffers = (m_lValid + m_lSize - 1) / m_lSize;
  229.         ASSERT(nBuffers <= m_lCount / 2);
  230.         for (int i = 0; i < nBuffers; i++) {
  231.             HRESULT hr = GetBuffer(&pSample, NULL, NULL, 0);
  232.             if (FAILED(hr)) {
  233.                 return hr;
  234.             }
  235.             ASSERT(pSample == m_parSamples[i]);
  236.         }
  237.         /*  Now copy the data back to the start */
  238.         CopyMemory((PVOID)(m_pBuffer + m_lSize * nBuffers - m_lValid),
  239.                    (PVOID)m_pbStartValid,
  240.                    m_lValid);
  241.         m_pbStartValid = m_pBuffer + m_lSize * nBuffers - m_lValid;
  242.         /*  Release the last buffers since we've effectively
  243.             transferred the ref count to the first one
  244.         */
  245.         for ( ; nBuffers > 0; nBuffers--) {
  246.             m_parSamples[m_lCount - nBuffers]->Release();
  247.         }
  248.     } else {
  249.         m_pbStartValid = m_pBuffer;
  250.     }
  251.     return S_OK;
  252. }
  253. /*  Flush the allocator - just discard all the data in it */
  254. void CSequentialAllocator::Flush()
  255. {
  256.     Advance(m_lValid);
  257. }