Example #1
0
static HRESULT STDCALL MemAllocator_GetBuffer(IMemAllocator * This,
					      /* [out] */ IMediaSample **ppBuffer,
					      /* [in] */ REFERENCE_TIME *pStartTime,
					      /* [in] */ REFERENCE_TIME *pEndTime,
					      /* [in] */ DWORD dwFlags)
{
    MemAllocator* me = (MemAllocator*)This;
    CMediaSample* sample;
    Debug printf("MemAllocator_ReleaseBuffer(%p) called   %d  %d\n", This,
		 avm_list_size(me->used_list), avm_list_size(me->free_list));

    if (!me->free_list)
    {
	Debug printf("No samples available\n");
	return E_FAIL;//should block here if no samples are available
    }

    sample = (CMediaSample*) me->free_list->member;
    me->free_list = avm_list_del_head(me->free_list);
    me->used_list = avm_list_add_tail(me->used_list, sample);

    *ppBuffer = (IMediaSample*) sample;
    sample->vt->AddRef((IUnknown*) sample);
    if (me->new_pointer)
    {
	if (me->modified_sample)
	    me->modified_sample->ResetPointer(me->modified_sample);
	sample->SetPointer(sample, me->new_pointer);
	me->modified_sample = sample;
	me->new_pointer = 0;
    }
    return 0;
}
STDMETHODIMP CSampleBuffer::GetSample(IMediaSample** pSample/*output*/, LONG size, bool bBlockIfNoBuffer)
{
	HRESULT hr = S_OK;
	while(true)
	{
		{ // lock block
			CAutoLock lock(&m_pointersCS);
			if (!m_busyIntervals.size()) // first time
			{
				Init();
				if (m_rbe-m_rbb < size)
				{
					return E_FAIL;
				}
					

				m_busyIntervals.insert(SB_INTERVAL_PAIR(m_rbb, SB_INTERVAL(m_rbb, m_rbb+size)));
				CMediaSample* newSample  = new CMediaSample(NAME("CMediaSample"),this,&hr,m_rbb,size);
				newSample->AddRef();
				*pSample = newSample;
				m_rbb+=size;
				break;
			}
			else
			{
				ASSERT(m_rbe >= m_rbb);
				if (m_rbe - m_rbb < size)// need wrap
				{
					if ((m_busyIntervals.begin()->first > m_pBuffer) && (m_rbe == m_pBuffer+m_lSize*m_lCount))
					{
						m_rbb = m_pBuffer;
						m_rbe = m_busyIntervals.begin()->first;
					}
				}

				ASSERT(m_rbe >= m_rbb);
				if (m_rbe - m_rbb >= size)
				{
					m_busyIntervals.insert(SB_INTERVAL_PAIR(m_rbb, SB_INTERVAL(m_rbb, m_rbb+size)));
					CMediaSample* newSample  = new CMediaSample(NAME("CMediaSample"),this,&hr,m_rbb,size);
					newSample->AddRef();
					*pSample = newSample; 
					m_rbb+=size;
					break;
				}
			}
			if (!bBlockIfNoBuffer)
				return S_FALSE;

		}
		// wait until it will
		
		WaitForSingleObject(m_changeBufEvent, INFINITE);
	}
	return hr;
}
//------------------------------------------------------------------------------
// IDecklinkPushSource2 interface
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// GetFrameBuffer
// Provide the caller with a free media sample.  If there are no free samples,
// all have been delivered downstream, block until one is returned to the free list.  
STDMETHODIMP CCustomAllocator::GetFrameBuffer(IMediaSample** ppSample)
{
	HRESULT hr = S_OK;

	if (ppSample)
	{
		CAutoLock lck(this);
		unsigned char* pBuffer = m_lBuffers.RemoveHead();	// retrieve a frame buffer
		if (pBuffer)
		{
			// attempt to retrieve a free media sample
			CMediaSample* pSample = NULL;
			for (;;)
			{
				{  // scope for lock
					CAutoLock cObjectLock(this);

					/* Check we are committed */
					if (!m_bCommitted)
					{
						return VFW_E_NOT_COMMITTED;
					}
					pSample = (CMediaSample*)m_lFree.RemoveHead();
					if (pSample == NULL)
					{
						SetWaitingFree();
					}
				}

				if (pSample)
				{
					// return the sample to the caller
					hr = pSample->SetPointer(pBuffer, m_lSize);
					*ppSample = pSample;
					break;
				}

				/* If we didn't get a sample then wait for the list to signal */
				ASSERT(m_hSemFree);
				WaitForSingleObject(m_hSemFree, INFINITE);
			}
		}
		else
		{
			hr = E_FAIL;
		}
	}
	else
	{
		hr = E_POINTER;
	}

	return hr;
}
//------------------------------------------------------------------------------
// Deliver
// Attach the supplied buffer to a free media sample.  Add media sample to delivery
// queue so that the streaming thread can deliver the sample downstream.  If there
// are no free samples, all have been delivered downstream, block until one is returned
// to the free list.  If the streaming thread is blocked, waiting for a sample to
// become available on the delivery queue, signal the thread when a new sample is added.
STDMETHODIMP CCustomAllocator::Deliver(unsigned char* pBuffer)
{
	HRESULT hr = S_OK;

	if (pBuffer)
	{
		CMediaSample* pSample = NULL;

	    for (;;)
		{
			{  // scope for lock
				CAutoLock cObjectLock(this);

	            /* Check we are committed */
		        if (!m_bCommitted)
			    {
				    return VFW_E_NOT_COMMITTED;
				}
				pSample = (CMediaSample*)m_lFree.RemoveHead();
				if (pSample == NULL)
				{
					SetWaitingFree();
	            }
		    }

		    if (pSample)
			{
				hr = pSample->SetPointer(pBuffer, m_lSize);
				if (SUCCEEDED(hr))
				{
					CAutoLock cObjectLock(this);
					m_lDeliver.AddTail(pSample);
					NotifySample();
					DbgLog((LOG_TRACE, DBG_MEM, TEXT("CCustomAllocator::Deliver(): m_lFree: %d  m_lDeliver: %d"), m_lFree.GetCount(), m_lDeliver.GetCount()));
				}
				break;
	        }

	        /* If we didn't get a sample then wait for the list to signal */
	        ASSERT(m_hSemFree);
		    WaitForSingleObject(m_hSemFree, INFINITE);
		}
	}
	else
	{
		hr = E_POINTER;
	}
	
	return hr;
}