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

📄 cfiltermpeg2vd.cpp

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

#include <streams.h>          // quartz, includes windows
// Eliminate two expected level 4 warnings from the Microsoft compiler.
// The class does not have an assignment or copy operator, and so cannot
// be passed by value.  This is normal.  This file compiles clean at the
// highest (most picky) warning level (-W4).
#pragma warning(disable: 4511 4512)

#include <measure.h>          // performance measurement (MSR_)
#include <initguid.h>

#if (1100 > _MSC_VER)
#include <olectlid.h>
#else
#include <olectl.h>
#endif

#include <dvdmedia.h>
#include <stdio.h>

#include "CFilterMpeg2VD.h"
#include "CMpegInputPin.h"
#include "CDecodedStream.h"
#include "CFilterMpeg2VDProp.h"

// {AFF8F523-DB02-495c-A1A1-605A505500A5}
DEFINE_GUID(CLSID_FilterMpeg2VD, 
0xaff8f523, 0xdb02, 0x495c, 0xa1, 0xa1, 0x60, 0x5a, 0x50, 0x55, 0x0, 0xa5);

// {8EDE98CF-17A3-471b-98AB-C944727E50BA}
DEFINE_GUID(CLSID_FilterMpeg2VDProp, 
0x8ede98cf, 0x17a3, 0x471b, 0x98, 0xab, 0xc9, 0x44, 0x72, 0x7e, 0x50, 0xba);




//
// setup data
//
const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
    &MEDIATYPE_Video,           // Major type
    &MEDIASUBTYPE_NULL          // Minor type
};

const AMOVIESETUP_PIN psudPins[] =
{
    {
        L"Input",           // String pin name
        FALSE,              // Is it rendered
        FALSE,              // Is it an output
        FALSE,              // Allowed none
        FALSE,              // Allowed many
        &CLSID_NULL,        // Connects to filter
        L"Output",          // Connects to pin
        1,                  // Number of types
        &sudPinTypes },     // The pin details
      { L"Output",          // String pin name
        FALSE,              // Is it rendered
        TRUE,               // Is it an output
        FALSE,              // Allowed none
        FALSE,              // Allowed many
        &CLSID_NULL,        // Connects to filter
        L"Input",           // Connects to pin
        1,                  // Number of types
        &sudPinTypes        // The pin details
    }
};


const AMOVIESETUP_FILTER sudFilter =
{
    &CLSID_FilterMpeg2VD,       // Filter CLSID
    L"HQ MPEG-2 Video Decoder",      // Filter name
    MERIT_PREFERRED,            // Its merit
    2,                       // Number of pins
    psudPins                 // Pin details
};


// List of class IDs and creator functions for the class factory. This
// provides the link between the OLE entry point in the DLL and an object
// being created. The class factory will call the static CreateInstance
CFactoryTemplate g_Templates[] = 
{
    { 
		L"HQ MPEG-2 Video Decoder",
		&CLSID_FilterMpeg2VD,
		CFilterMpeg2VD::CreateInstance,
		NULL,
		&sudFilter 
	}/*,
	{ 
		L"HQ Mpeg2 VD Property Page",
		&CLSID_FilterMpeg2VDProp,
		CFilterMpeg2VDProp::CreateInstance 
	}*/
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);


static int decoderInstances = 0;
// ----------------------------------------------------------------------------
//            Filter implementation
// ----------------------------------------------------------------------------
CFilterMpeg2VD::CFilterMpeg2VD(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr) :
CSource(tszName, punk, CLSID_FilterMpeg2VD)
{	
	decoderInstances++;

	mSampleDuration = 0;
	mImageWidth     = 0;
	mImageHeight    = 0;
	mOutputImageSize = 0;

	mIsFlushing    = FALSE;
	mEOSDelivered  = FALSE;
	mEOSReceived   = FALSE;

	*phr = NOERROR;
	mMpegInputPin = NULL;
	CDecodedStream * outStream = new CDecodedStream(NAME("Output"), phr, this);
	if (outStream == NULL)
	{
		*phr = E_OUTOFMEMORY;	
	}
	else
	{
		outStream->SetController(&mMpegController);
	}
}

CFilterMpeg2VD::~CFilterMpeg2VD()
{
	if (mMpegInputPin)
	{
		delete mMpegInputPin;
		mMpegInputPin = NULL;
	}
	decoderInstances--;
}

//
// CreateInstance
//
// Override CClassFactory method.
// Provide the way for COM to create a CNullInPlace object
//
CUnknown * WINAPI CFilterMpeg2VD::CreateInstance(LPUNKNOWN punk, HRESULT *phr) 
{
#if 0
	char    szCreatorPath[256], szCreatorName[256];
	::strcpy(szCreatorPath, "");
	::strcpy(szCreatorName, "");
	HMODULE hModule = ::GetModuleHandle(NULL);
	::GetModuleFileName(hModule, szCreatorPath, 256);
	char * backSlash = ::strrchr(szCreatorPath, '\\');
	if (backSlash)
	{
		strcpy(szCreatorName, backSlash);
	}
	::_strlwr(szCreatorName);
	// Please specify your app name with lowercase
	if (::strstr(szCreatorName, "graphedt") == NULL)
	{
		*phr = E_FAIL;
		return NULL;
	}
#endif 

	// Never use more than two instances of this decoder in the same application
	// Beccause of global variable problems!
	// 2002-12-26
	if (decoderInstances == 1)
	{
		*phr = E_FAIL;
		return NULL;
	}

    CFilterMpeg2VD *pNewObject = new CFilterMpeg2VD(NAME("Filter Mpeg2 VD"), punk, phr);
    if (pNewObject == NULL) 
	{
        *phr = E_OUTOFMEMORY;
    }
    return pNewObject;

} 

//
// Basic COM - used here to reveal our own interfaces
STDMETHODIMP CFilterMpeg2VD::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
{
	CheckPointer(ppv, E_POINTER);
	
//	if (riid == IID_ISpecifyPropertyPages) 
//	{
	//	return GetInterface((ISpecifyPropertyPages *) this, ppv);
//	}
//	else 
	{
        return CSource::NonDelegatingQueryInterface(riid, ppv);
    }
} // NonDelegatingQueryInterface

int CFilterMpeg2VD::GetPinCount()
{
	return 2;
}

CBasePin * CFilterMpeg2VD::GetPin(int n)
{
	if (mMpegInputPin == NULL)
	{
		HRESULT hr = NOERROR;
		mMpegInputPin = new CMpegInputPin(NAME("Input"), this, &hr);
		ASSERT(mMpegInputPin);
	}

	switch (n)
	{
	case 0:
		return mMpegInputPin;
	case 1:
		return m_paStreams[0];
	default:
		return NULL;
	}
}

STDMETHODIMP CFilterMpeg2VD::FindPin(LPCWSTR Id, IPin ** ppPin)
{
	return CBaseFilter::FindPin(Id, ppPin);
}

STDMETHODIMP CFilterMpeg2VD::Stop()
{
	CAutoLock lck1(&m_cStateLock);
	if (m_State == State_Stopped) 
	{
		return NOERROR;
	}

	// Succeed the Stop if we are not completely connected
	ASSERT(mMpegInputPin == NULL || m_paStreams[0] != NULL);
	if (mMpegInputPin == NULL || mMpegInputPin->IsConnected() == FALSE ||
		m_paStreams[0]->IsConnected() == FALSE) 
	{
		m_State = State_Stopped;
		mEOSDelivered = FALSE;
		return NOERROR;
	}

	// Important!!! Refuse to receive any more samples
	mMpegController.FlushAllPending();
	// decommit the input pin before locking or we can deadlock
	mMpegInputPin->Inactive();	

	// synchronize with Receive calls
	CAutoLock lck2(&m_csReceive);
	OutputPin()->BeginFlush();
	OutputPin()->Inactive();
	OutputPin()->EndFlush();

	// allow a class derived from CTransformFilter
	// to know about starting and stopping streaming
	HRESULT hr = StopStreaming();
	if (SUCCEEDED(hr)) 
	{
		// complete the state transition
		m_State = State_Stopped;
		mEOSDelivered = FALSE;
	}
	return hr;
}

STDMETHODIMP CFilterMpeg2VD::Pause()
{
	CAutoLock lck(&m_cStateLock);
	
	HRESULT hr = NOERROR;
	if (m_State == State_Paused) 
	{
		// (This space left deliberately blank)
	}
	
	// If we have no input pin or it isn't yet connected then when we are
	// asked to pause we deliver an end of stream to the downstream filter.
	// This makes sure that it doesn't sit there forever waiting for
	// samples which we cannot ever deliver without an input connection.
	else if (mMpegInputPin == NULL || mMpegInputPin->IsConnected() == FALSE) 
	{
		if(m_paStreams[0]->IsConnected() && mEOSDelivered == FALSE) 
		{
			m_paStreams[0]->DeliverEndOfStream();
			mEOSDelivered = TRUE;
		}
		m_State = State_Paused;
	}

	// We may have an input connection but no output connection
	// However, if we have an input pin we do have an output pin
	else if (m_paStreams[0]->IsConnected() == FALSE) 
	{
		m_State = State_Paused;
	}
	else 
	{
		if (m_State == State_Stopped) 
		{
			// allow a class derived from CTransformFilter
			// to know about starting and stopping streaming
			CAutoLock lck2(&m_csReceive);
			hr = StartStreaming();
		}
		if (SUCCEEDED(hr)) 
		{
			// Make sure the receive not blocking
			// Make sure the out-sending thread not working
			mMpegController.FlushAllPending();

			hr = CBaseFilter::Pause();
		}
	}
	return hr;
}

HRESULT CFilterMpeg2VD::StartStreaming()
{
	mIsFlushing  = FALSE;
	mEOSReceived = FALSE;
	return NOERROR;
}

HRESULT CFilterMpeg2VD::StopStreaming()
{
	mIsFlushing  = FALSE;
	mEOSReceived = FALSE;
	return NOERROR;
}

HRESULT CFilterMpeg2VD::Receive(IMediaSample *pSample)
{
	// Check for other streams and pass them on
	AM_SAMPLE2_PROPERTIES * const pProps = mMpegInputPin->SampleProps();
	if (pProps->dwStreamId != AM_STREAM_MEDIA) 
	{
		return m_paStreams[0]->Deliver(pSample);
	}

	// Receive mpeg2 data to buffer
	ASSERT(pSample);
	long lSourceSize = pSample->GetActualDataLength();
	BYTE * pSourceBuffer;
	pSample->GetPointer(&pSourceBuffer);
	mMpegController.ReceiveMpeg(pSourceBuffer, lSourceSize);
	return NOERROR;
}

HRESULT CFilterMpeg2VD::EndOfStream(void)
{
	// Ignoring the more than twice EOS
	if (!mEOSReceived)
	{
		mEOSReceived  = TRUE;
		mMpegController.BeginEndOfStream();
		// Wait for all caching data having been fetched out
	//	while (!mMpegController.IsCacheOutputWaiting() && 
	//		!mMpegController.IsCacheEmpty())
	//	{
	//		Sleep(10);
	//	}
	//	mMpegController.EndEndOfStream();

	//	mEOSDelivered = TRUE;
	//	return m_paStreams[0]->DeliverEndOfStream();
	}
	return NOERROR;
}

HRESULT CFilterMpeg2VD::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
{
	return m_paStreams[0]->DeliverNewSegment(tStart, tStop, dRate);
}

HRESULT CFilterMpeg2VD::BeginFlush(void)
{
	HRESULT hr  = m_paStreams[0]->DeliverBeginFlush(); // Call downstreamly
	mIsFlushing = TRUE;
	OutputPin()->BeginFlush();
	return hr;
}

HRESULT CFilterMpeg2VD::EndFlush(void)
{
	mEOSReceived = FALSE;
	OutputPin()->EndFlush();
	mIsFlushing = FALSE;
	return m_paStreams[0]->DeliverEndFlush();
}

HRESULT CFilterMpeg2VD::CompleteConnect(PIN_DIRECTION inDirection, IPin * inReceivePin)
{
	if (inDirection == PINDIR_INPUT)
	{
		CMediaType  mtIn = mMpegInputPin->CurrentMediaType();
		if (mtIn.formattype == FORMAT_MPEG2Video)
		{
			MPEG2VIDEOINFO * pFormat = (MPEG2VIDEOINFO *) mtIn.pbFormat;
			mSampleDuration = pFormat->hdr.AvgTimePerFrame;
			mImageWidth     = pFormat->hdr.bmiHeader.biWidth;
			mImageHeight    = pFormat->hdr.bmiHeader.biHeight;
			// Init the mpeg decoder system
			mMpegController.Uninitialize();
			mMpegController.Initialize();
			return S_OK;
		}
	}
	else
	{
		CMediaType  mtOut = OutputPin()->CurrentMediaType();
		int bitcount = 2;
		if (mtOut.subtype == MEDIASUBTYPE_YUY2)
		{
			bitcount = 2;
			mMpegController.SetOutputType(2);
		}
		else if (mtOut.subtype == MEDIASUBTYPE_RGB24)
		{
			bitcount = 3;
			mMpegController.SetOutputType(1);
		}
		mOutputImageSize = mImageWidth * mImageHeight * bitcount;
		mMpegController.SetOutputImageSize(mOutputImageSize);
		return S_OK;
	}
	return E_FAIL;
}



/*
//
STDMETHODIMP CFilterMpeg2VD::GetPages(CAUUID *pPages)
{
	pPages->cElems = 1;
    pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
    if (pPages->pElems == NULL) 
	{
        return E_OUTOFMEMORY;
    }
    *(pPages->pElems) = CLSID_FilterMpeg2VDProp;
    return NOERROR;
}
*/












/******************************Public Routine******************************\
* exported entry points for registration and
* unregistration (in this case they only call
* through to default implmentations).
*
*
*
* History:
*
\**************************************************************************/
STDAPI DllRegisterServer()
{
	return AMovieDllRegisterServer2( TRUE );
}

STDAPI DllUnregisterServer()
{
	return AMovieDllRegisterServer2( FALSE );
}

// Microsoft C Compiler will give hundreds of warnings about
// unused inline functions in header files.  Try to disable them.
#pragma warning( disable:4514)

⌨️ 快捷键说明

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