windows-nt/Source/XPSP1/NT/multimedia/dshow/streams/ddstream/bytestrm.cpp
2020-09-26 16:20:57 +08:00

330 lines
8.8 KiB
C++

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