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; }