|
|
// Copyright (c) 1997 - 1999 Microsoft Corporation. All Rights Reserved.
// bytestrm.cpp : Implementation of CByteStream
#include "stdafx.h"
#include "project.h"
/////////////////////////////////////////////////////////////////////////////
// CByteStream
CByteStream::CByteStream() : m_cbData(0), m_lBytesPerSecond(0), m_bEOSPending(false) { }
STDMETHODIMP CByteStream::GetBuffer( IMediaSample **ppBuffer, REFERENCE_TIME * pStartTime, REFERENCE_TIME * pEndTime, DWORD dwFlags ) { HRESULT hr; *ppBuffer = NULL; if (m_bStopIfNoSamples && m_cAllocated == 0) { return E_FAIL; } if (m_Direction == PINDIR_INPUT) { AtlTrace(_T("Should never get here!\n")); _ASSERTE(FALSE); hr = E_UNEXPECTED; } else { CSample *pSample; hr = AllocSampleFromPool(pStartTime, &pSample); if (hr == NOERROR) { pSample->m_pMediaSample->m_dwFlags = dwFlags; pSample->m_bReceived = false; pSample->m_bModified = true; *ppBuffer = (IMediaSample *)(pSample->m_pMediaSample); (*ppBuffer)->AddRef(); } } return hr; }
STDMETHODIMP CByteStream::BeginFlush() { AUTO_CRIT_LOCK; m_bEOSPending = false; m_arSamples.RemoveAll(); m_cbData = 0; m_TimeStamp.Reset(); return CStream::BeginFlush(); }
STDMETHODIMP CByteStream::EndOfStream() { HRESULT hr = S_OK; Lock(); if (m_bFlushing || m_bEndOfStream || m_bEOSPending) { hr = E_FAIL; } else { m_bEOSPending = TRUE; CheckEndOfStream(); } Unlock(); return hr; }
STDMETHODIMP CByteStream::GetAllocator(IMemAllocator ** ppAllocator) { HRESULT hr; AUTO_CRIT_LOCK; if (m_Direction == PINDIR_OUTPUT) { hr = CStream::GetAllocator(ppAllocator); } else { if (m_pAllocator == NULL) { hr = CoCreateInstance(CLSID_MemoryAllocator, 0, CLSCTX_INPROC_SERVER, IID_IMemAllocator, (void **)&m_pAllocator); if (FAILED(hr)) { goto Exit; } } m_pAllocator->AddRef(); *ppAllocator = m_pAllocator; hr = NOERROR; } Exit: return hr; }
STDMETHODIMP CByteStream::Receive(IMediaSample *pSample) { AUTO_CRIT_LOCK;
if (m_bFlushing || m_bStopIfNoSamples && m_cAllocated == 0) { EndOfStream(); return S_FALSE; }
if(m_FilterState == State_Stopped) { return VFW_E_WRONG_STATE; }
/* Put it on the queue */ if (!m_arSamples.Add(pSample)) { EndOfStream(); return E_OUTOFMEMORY; }
/* Eat as much as we can, then return */ FillSamples(); return S_OK; }
STDMETHODIMP CByteStream::SetState( /* [in] */ FILTER_STATE State ) { HRESULT hr = CStream::SetState(State); // Must be called with the critical seciton unowned!
Lock(); if (State == State_Stopped) { m_bEOSPending = false; m_arSamples.RemoveAll();
m_cbData = 0; m_TimeStamp.Reset(); } Unlock();
if (State == State_Stopped) { _ASSERTE(m_arSamples.Size() == 0); }
return hr; }
// Fill any samples lying around
void CByteStream::FillSamples() { while (m_arSamples.Size() != 0 && m_pFirstFree != NULL) { if (m_cbData == 0) { IMediaSample * const pSample = m_arSamples.Element(0);
/* At the start so initialize some stuff */ pSample->GetPointer(&m_pbData); m_cbData = m_arSamples.Element(0)->GetActualDataLength();
/* See if there are any time stamps */ REFERENCE_TIME rtStart, rtStop; if (SUCCEEDED(pSample->GetTime(&rtStart, &rtStop))) { #if 0
AtlTrace("TimeStamp current %d, new %d, length %d length(ms) %d, bytelen %d\n", (long)(m_TimeStamp.TimeStamp(0, m_lBytesPerSecond) / 10000), (long)(rtStart / 10000), (long)((rtStop - rtStart) / 10000), MulDiv(m_cbData, 1000, m_lBytesPerSecond), m_cbData); #endif
m_TimeStamp.SetTime(rtStart); } } /* Copy some data across */ CByteStreamSample* const pStreamSample = (CByteStreamSample *)m_pFirstFree;
/* Do timestamps */ if (pStreamSample->m_cbData == 0) { pStreamSample->m_pMediaSample->m_rtEndTime = pStreamSample->m_pMediaSample->m_rtStartTime = m_TimeStamp.TimeStamp(0, m_lBytesPerSecond); } /* See how much we can copy */ _ASSERTE(pStreamSample->m_cbData <= pStreamSample->m_cbSize);
DWORD cbBytesToCopy = min(m_cbData, pStreamSample->m_cbSize - pStreamSample->m_cbData); CopyMemory(pStreamSample->m_pbData + pStreamSample->m_cbData, m_pbData, cbBytesToCopy); m_cbData -= cbBytesToCopy; m_TimeStamp.AccumulateBytes(cbBytesToCopy);
/* Is this a bit expensive? - who cares about the stop time */ pStreamSample->m_pMediaSample->m_rtEndTime = m_TimeStamp.TimeStamp(0, m_lBytesPerSecond); if (m_cbData == 0) { // This performs the Release()
m_arSamples.Remove(0); } m_pbData += cbBytesToCopy; pStreamSample->m_cbData += cbBytesToCopy;
// Update the actual data object
pStreamSample->m_pMemData->SetActual(pStreamSample->m_cbData); if (pStreamSample->m_cbData == pStreamSample->m_cbSize) { // this is a lot of overhead since we know
// it's free but it's not a bug
#if 0
AtlTrace("Sample start %dms, length %dms bytelen %dms\n", (long)(pStreamSample->m_pMediaSample->m_rtEndTime / 10000), (long)((pStreamSample->m_pMediaSample->m_rtEndTime - pStreamSample->m_pMediaSample->m_rtStartTime) / 10000), MulDiv(pStreamSample->m_cbData, 1000, m_lBytesPerSecond)); #endif
StealSampleFromFreePool(m_pFirstFree, true); pStreamSample->SetCompletionStatus(S_OK); } } CheckEndOfStream(); }
void CByteStream::CheckEndOfStream() { AUTO_CRIT_LOCK; if (m_bEOSPending && m_arSamples.Size() == 0) { m_bEOSPending = false;
// If the first sample contains data set the status on the
// next one
if (m_pFirstFree != NULL) { CByteStreamSample* const pStreamSample = (CByteStreamSample *)m_pFirstFree; if (pStreamSample->m_cbData != 0) { StealSampleFromFreePool(m_pFirstFree, true); pStreamSample->SetCompletionStatus(S_OK); } }
CStream::EndOfStream(); } }
#if 0
HRESULT CByteStream::InternalAllocateSample( IByteStreamSample **ppBSSample ) { CByteStreamSample *pBSSample = new CComObject<CByteStreamSample>; if (pBSSample == NULL) { *ppBSSample = NULL; return E_OUTOFMEMORY; } else { return pBSSample->GetControllingUnknown()->QueryInterface( IID_IByteStreamSample, (void **)ppBSSample ); } } #endif
//
// CByteStreamSample
//
CByteStreamSample::CByteStreamSample() : m_pbData(NULL), m_cbSize(0), m_cbData(0) { }
HRESULT CByteStreamSample::InternalUpdate( DWORD dwFlags, HANDLE hEvent, PAPCFUNC pfnAPC, DWORD_PTR dwAPCData ) { if (m_pMemData == NULL) { return MS_E_NOTINIT; } HRESULT hr = m_pMemData->GetInfo( &m_cbSize, &m_pbData, &m_cbData ); if (FAILED(hr)) { return hr; }
// InternalUpdate will check everything and add us to queues etc
hr = CSample::InternalUpdate(dwFlags, hEvent, pfnAPC, dwAPCData); if (SUCCEEDED(hr) && m_pStream->m_Direction == PINDIR_INPUT) { m_cbData = 0; m_pMemData->SetActual(0); CByteStream *pStream = (CByteStream *)m_pStream; pStream->FillSamples(); } return hr; }
STDMETHODIMP::CByteStreamSample::GetInformation( /* [out] */ DWORD *pdwLength, /* [out] */ PBYTE *ppbData, /* [out] */ DWORD *pcbActualData ) { if (m_pbData == NULL) { return MS_E_NOTINIT; } if (pdwLength) { *pdwLength = m_cbSize; } if (ppbData) { *ppbData = m_pbData; } if (pcbActualData) { *pcbActualData = m_cbData; } return S_OK; }
HRESULT CByteStreamSample::Init( IMemoryData *pMemData ) { if (m_pMemData) { _ASSERTE(_T("Initialization called twice!")); return E_UNEXPECTED; } m_pMemData = pMemData; return S_OK; }
|