⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cdecodedstream.cpp

📁 DIRECTSHOW 开发指南电子书
💻 CPP
字号:
//
// CDecodedStream.cpp
//

#include <streams.h>
#include <stdio.h>
#include "CFilterMpeg2VD.h"
#include "CDecodedStream.h"
#include "CMpegInputPin.h"

/////////////////////////////////////////////////////////////////////////////
CDecodedStream::CDecodedStream(TCHAR * inObjectName,
							   HRESULT * outResult, 
							   CFilterMpeg2VD * inFilter) :
CSourceStream(inObjectName, outResult, inFilter, L"Output")
{
	mDecodeFilter = inFilter;
	mPosition     = NULL;
	mFlushing     = FALSE;
	mMpegController = NULL;
	mSamplesSent    = 0;
}

CDecodedStream::~CDecodedStream()
{
	if (mPosition) 
	{
		mPosition->Release();
		mPosition = NULL;
	}
}

void CDecodedStream::SetController(CMpegController * inController)
{
	mMpegController = inController;
}

HRESULT CDecodedStream::FillBuffer(IMediaSample *pSample)
{
	return NOERROR;
}

HRESULT CDecodedStream::CompleteConnect(IPin *pReceivePin)
{
	HRESULT hr = mDecodeFilter->CompleteConnect(PINDIR_OUTPUT, pReceivePin);
    if (FAILED(hr)) 
	{
        return hr;
    }
    return CBaseOutputPin::CompleteConnect(pReceivePin);
}

//
// DecideBufferSize
//
// Tell the output pin's allocator what size buffers we
// require. Can only do this when the input is connected
//
HRESULT CDecodedStream::DecideBufferSize(IMemAllocator * pAllocator,
										 ALLOCATOR_PROPERTIES *pprop)
{
	// Is the input pin connected
	if (!mDecodeFilter->mMpegInputPin->IsConnected()) 
	{
		return E_UNEXPECTED;
	}

	ASSERT(pAllocator);
	ASSERT(pprop);
	HRESULT hr = NOERROR;

	pprop->cbBuffer  = mDecodeFilter->mOutputImageSize;
	pprop->cBuffers  = 1;
	pprop->cbAlign   = 1;

	ASSERT(pprop->cbBuffer);

	// Ask the allocator to reserve us some sample memory, NOTE the function
	// can succeed (that is return NOERROR) but still not have allocated the
	// memory that we requested, so we must check we got whatever we wanted

	ALLOCATOR_PROPERTIES Actual;
	hr = pAllocator->SetProperties(pprop, &Actual);
	if (FAILED(hr)) {
		return hr;
	}

	ASSERT( Actual.cBuffers == 1 );

	if (pprop->cBuffers > Actual.cBuffers ||
			pprop->cbBuffer > Actual.cbBuffer) {
				return E_FAIL;
	}
	return NOERROR;
}

HRESULT CDecodedStream::CheckMediaType(const CMediaType *mtOut)
{
	if (mDecodeFilter->mMpegInputPin->IsConnected())
	{
		if ((mtOut->subtype == MEDIASUBTYPE_YUY2 ||
			mtOut->subtype == MEDIASUBTYPE_RGB24) &&
			mtOut->formattype == FORMAT_VideoInfo)
		{
			VIDEOINFOHEADER * pFormat = (VIDEOINFOHEADER *) mtOut->pbFormat;
			if (pFormat->bmiHeader.biHeight == mDecodeFilter->mImageHeight &&
				pFormat->bmiHeader.biWidth == mDecodeFilter->mImageWidth)
			{
				return S_OK;
			}
		}
	}
	return E_FAIL;
}

// ---------------------------------------------------------
// Currently we only support YUY2 and RGB24 decoded out
// ---------------------------------------------------------
HRESULT CDecodedStream::GetMediaType(int iPosition, CMediaType *pMediaType)
{
    if (!mDecodeFilter->mMpegInputPin->IsConnected() || 
		iPosition < 0 || iPosition > 1)
	{
		return E_FAIL;
	}

	VIDEOINFOHEADER    format;
	ZeroMemory(&format, sizeof(VIDEOINFOHEADER));
	pMediaType->SetType(&MEDIATYPE_Video);
	switch (iPosition)
	{
	case 0:  // YUY2
		pMediaType->SetSubtype(&MEDIASUBTYPE_YUY2);
		format.bmiHeader.biBitCount    = 16;
		format.bmiHeader.biCompression = mmioFOURCC('Y','U','Y','2');
		break;

	case 1: // RGB24
		pMediaType->SetSubtype(&MEDIASUBTYPE_RGB24);
		format.bmiHeader.biBitCount    = 24;
		format.bmiHeader.biCompression = BI_RGB;
		break;
	}
	pMediaType->SetFormatType(&FORMAT_VideoInfo);
	format.bmiHeader.biSize   = sizeof(BITMAPINFOHEADER);
	format.bmiHeader.biPlanes = 1;
	format.AvgTimePerFrame    = mDecodeFilter->mSampleDuration;
	format.bmiHeader.biWidth  = mDecodeFilter->mImageWidth;
	format.bmiHeader.biHeight = mDecodeFilter->mImageHeight;
	format.bmiHeader.biSizeImage = mDecodeFilter->mImageWidth * mDecodeFilter->mImageHeight * format.bmiHeader.biBitCount / 8;
	pMediaType->SetFormat(PBYTE(&format), sizeof(VIDEOINFOHEADER));
    return S_OK;
} // GetMediaType

STDMETHODIMP CDecodedStream::QueryId(LPWSTR * Id)
{
	return CBaseOutputPin::QueryId(Id);
}

// overriden to expose IMediaPosition and IMediaSeeking control interfaces
STDMETHODIMP CDecodedStream::NonDelegatingQueryInterface(REFIID riid, void **ppv) 
{
    CheckPointer(ppv,E_POINTER);
    ValidateReadWritePtr(ppv,sizeof(PVOID));
    *ppv = NULL;

	if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking) 
	{
		// we should have an input pin by now
		ASSERT(mDecodeFilter->mMpegInputPin != NULL);
		if (mPosition == NULL) 
		{
			HRESULT hr = CreatePosPassThru(GetOwner(),
				FALSE,
				(IPin *)mDecodeFilter->mMpegInputPin,
				&mPosition);
			if (FAILED(hr)) 
			{
				return hr;
			}
		}
		return mPosition->QueryInterface(riid, ppv);
	}
    else 
	{
        return CSourceStream::NonDelegatingQueryInterface(riid, ppv);
    }
}

// Override this if you can do something constructive to act on the
// quality message.  Consider passing it upstream as well
// Pass the quality mesage on upstream.
STDMETHODIMP CDecodedStream::Notify(IBaseFilter * pSender, Quality q) 
{
    UNREFERENCED_PARAMETER(pSender);
    ValidateReadPtr(pSender, sizeof(IBaseFilter));
    return mDecodeFilter->mMpegInputPin->PassNotify(q);
} // Notify

STDMETHODIMP CDecodedStream::BeginFlush(void)
{
	mFlushing = TRUE;
	mMpegController->BeginFlush();
	{
		CAutoLock   lck(&mDataAccess);
		mSamplesSent   = 0;
	}
	return NOERROR;
}

STDMETHODIMP CDecodedStream::EndFlush(void)
{
	mMpegController->EndFlush();
	mFlushing = FALSE;
	return NOERROR;
}

HRESULT CDecodedStream::EndOfStream(void)
{
	return NOERROR;
}

HRESULT CDecodedStream::DoBufferProcessingLoop(void)
{
	Command com;
    OnThreadStartPlay();

	BOOL   EOS_Flag = FALSE;
    do 
	{
        while (!CheckRequest(&com)) 
		{
			// If no data, never enter blocking reading
			if (mFlushing || mMpegController->IsCacheEmpty() || EOS_Flag) 
			{
				if (mDecodeFilter->mEOSReceived)
				{
					EOS_Flag = TRUE;
					mMpegController->EndEndOfStream();
					if (!mDecodeFilter->mEOSDelivered)
					{
						mDecodeFilter->mEOSDelivered = TRUE;
						DeliverEndOfStream();	
					}
				}
				
				Sleep(1);
				continue;
			}

			mMpegController->SequenceHeaderChecking();
			BOOL pass = mMpegController->LocatePictureHeader();
			if (pass)
			{
				pass = mMpegController->DecodeOnePicture();
			}
			if (pass)
			{
				IMediaSample *pSample;
				HRESULT hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0);
				if (FAILED(hr)) 
				{
					Sleep(1);
					continue;   // go round again. Perhaps the error will go away
					// or the allocator is decommited & we will be asked to
					// exit soon.
				}
				hr = DeliverCurrentPicture(pSample);
				if (FAILED(hr) && mDecodeFilter->mEOSReceived)
				{
					EOS_Flag = TRUE;
					mMpegController->EndEndOfStream();
					if (!mDecodeFilter->mEOSDelivered)
					{
						mDecodeFilter->mEOSDelivered = TRUE;
						DeliverEndOfStream();	
					}
				}
			}
        }

		// For all commands sent to us there must be a Reply call!
		if (com == CMD_RUN || com == CMD_PAUSE) 
		{
			Reply(NOERROR);
		}
		else if (com != CMD_STOP) 
		{
			Reply((DWORD) E_UNEXPECTED);
			DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!")));
		}
    } while (com != CMD_STOP);

	// If EOS not delivered at the moment, just do it here!
//	mMpegController->EndEndOfStream();
//	if (!mDecodeFilter->mEOSDelivered)
//	{
//		mDecodeFilter->mEOSDelivered = TRUE;
//		DeliverEndOfStream();	
//	}
    return S_FALSE;
}

HRESULT CDecodedStream::OnThreadStartPlay(void)
{
	mSamplesSent = 0;
	return NOERROR;
}

HRESULT CDecodedStream::OnThreadDestroy(void)
{	
	return NOERROR;
}

HRESULT CDecodedStream::DeliverCurrentPicture(IMediaSample * pSample)
{
	PBYTE   pOut;
	pSample->GetPointer(&pOut);
	mMpegController->GetDecoded(pOut);
	pSample->SetActualDataLength(mDecodeFilter->mOutputImageSize);
	ULONG    alreadySent = 0;
	{
		CAutoLock   lck(&mDataAccess);
		alreadySent  = mSamplesSent;
		mSamplesSent++;
	}
	LONGLONG   llStart = alreadySent;
	LONGLONG   llEnd   = alreadySent + 1;
	pSample->SetMediaTime(&llStart, &llEnd);
	REFERENCE_TIME	rtStart = alreadySent * mDecodeFilter->mSampleDuration;
	REFERENCE_TIME	rtEnd   = (alreadySent + 1) * mDecodeFilter->mSampleDuration;
	pSample->SetTime(&rtStart, &rtEnd);
	pSample->SetDiscontinuity(FALSE);
	pSample->SetPreroll(FALSE);
	pSample->SetSyncPoint(TRUE);
	HRESULT hr = Deliver(pSample);
	pSample->Release();
	return hr;
}

HRESULT CDecodedStream::StopThreadSafely(void)
{
	if (ThreadExists()) 
	{
		Stop();
	}
	return NOERROR;
}

HRESULT CDecodedStream::RunThreadSafely(void)
{
	if (ThreadExists()) 
	{
		Run();
	}
	return NOERROR;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -