📄 cfiltermpeg2vd.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 + -