📄 fball.cpp
字号:
//------------------------------------------------------------------------------
// File: FBall.cpp
//
// Desc: DirectShow sample code - implementation of filter behaviors
// for the bouncing ball source filter. For more information,
// refer to Ball.cpp.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include <streams.h>
#include <olectl.h>
#include <initguid.h>
#include "ball.h"
#include "fball.h"
#include "CBallProp.h"
#pragma warning(disable:4710) // 'function': function not inlined (optimzation)
// Setup data
const AMOVIESETUP_MEDIATYPE sudOpPinTypes =
{
&MEDIATYPE_Video, // Major type
&MEDIASUBTYPE_NULL // Minor type
};
const AMOVIESETUP_PIN sudOpPin =
{
L"Output", // Pin string name
FALSE, // Is it rendered
TRUE, // Is it an output
FALSE, // Can we have none
FALSE, // Can we have many
&CLSID_NULL, // Connects to filter
NULL, // Connects to pin
1, // Number of types
&sudOpPinTypes }; // Pin details
const AMOVIESETUP_FILTER sudBallax =
{
&CLSID_BouncingBall, // Filter CLSID
L"Bouncing Ball plus", // String name
MERIT_DO_NOT_USE, // Filter merit
1, // Number pins
&sudOpPin // Pin details
};
// COM global table of objects in this dll
CFactoryTemplate g_Templates[] =
{
{
L"Bouncing Ball plus",
&CLSID_BouncingBall,
CBouncingBall::CreateInstance,
NULL,
&sudBallax
},
{
L"Ball Property Page",
&CLSID_BouncingBallProp,
CBallProp::CreateInstance
}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
////////////////////////////////////////////////////////////////////////
//
// Exported entry points for registration and unregistration
// (in this case they only call through to default implementations).
//
////////////////////////////////////////////////////////////////////////
//
// DllRegisterServer
//
// Exported entry points for registration and unregistration
//
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2(TRUE);
} // DllRegisterServer
//
// DllUnregisterServer
//
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2(FALSE);
} // DllUnregisterServer
//
// DllEntryPoint
//
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
LPVOID lpReserved)
{
return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}
//
// CreateInstance
//
// The only allowed way to create Bouncing balls!
//
CUnknown * WINAPI CBouncingBall::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
{
ASSERT(phr);
CUnknown *punk = new CBouncingBall(lpunk, phr);
if(punk == NULL)
{
if(phr)
*phr = E_OUTOFMEMORY;
}
return punk;
} // CreateInstance
//
// Constructor
//
// Initialise a CBallStream object so that we have a pin.
//
CBouncingBall::CBouncingBall(LPUNKNOWN lpunk, HRESULT *phr) :
CSource(NAME("Bouncing ball"), lpunk, CLSID_BouncingBall),
CPersistStream(lpunk, phr)
{
ASSERT(phr);
CAutoLock cAutoLock(&m_cStateLock);
m_paStreams = (CSourceStream **) new CBallStream*[1];
if(m_paStreams == NULL)
{
if(phr)
*phr = E_OUTOFMEMORY;
return;
}
m_paStreams[0] = new CBallStream(phr, this, L"Ball Out");
if(m_paStreams[0] == NULL)
{
if(phr)
*phr = E_OUTOFMEMORY;
return;
}
} // (Constructor)
// Added by HQ Tech
// Basic COM - used here to reveal our own interfaces
STDMETHODIMP CBouncingBall::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
{
CheckPointer(ppv, E_POINTER);
if (riid == IID_IBall)
{
return GetInterface((IBall *) this, ppv);
}
else if (riid == IID_ISpecifyPropertyPages)
{
return GetInterface((ISpecifyPropertyPages *) this, ppv);
}
else if (riid == IID_IPersistStream)
{
return GetInterface((IPersistStream *) this, ppv);
}
else
{
return CSource::NonDelegatingQueryInterface(riid, ppv);
}
}
// Added by HQ Tech
// --- ISpecifyPropertyPages methods ---
STDMETHODIMP CBouncingBall::GetPages(CAUUID *pPages)
{
pPages->cElems = 1;
pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
if (pPages->pElems == NULL)
{
return E_OUTOFMEMORY;
}
*(pPages->pElems) = CLSID_BouncingBallProp;
return NOERROR;
}
// --- IBall methods ---
STDMETHODIMP CBouncingBall::SetImageSize(int inWidth, int inHeight)
{
if (IsStopped() && m_paStreams[0]->IsConnected() == FALSE)
{
((CBallStream*)m_paStreams[0])->SetImageSize(inWidth, inHeight);
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP CBouncingBall::GetImageSize(int * outWidth, int * outHeight)
{
((CBallStream*)m_paStreams[0])->GetImageSize(outWidth, outHeight);
return NOERROR;
}
// CPersistStream overrides
HRESULT CBouncingBall::WriteToStream(IStream *pStream)
{
int width = 0, height = 0;
GetImageSize(&width, &height);
HRESULT hr = WriteInt(pStream, width);
hr = WriteInt(pStream, height);
return hr;
}
HRESULT CBouncingBall::ReadFromStream(IStream *pStream)
{
HRESULT hr = NOERROR;
int width = ReadInt(pStream, hr);
int height = ReadInt(pStream, hr);
SetImageSize(width, height);
return hr;
}
int CBouncingBall::SizeMax()
{
// When an int is expanded as characters it takes at most 12 characters
// including a trailing delimiter.
// Wide chars doubles this and we want two ints.
//
return (24 * 2);
}
STDMETHODIMP CBouncingBall::GetClassID(CLSID *pClsid)
{
return CBaseFilter::GetClassID(pClsid);
}
//
// Constructor
//
CBallStream::CBallStream(HRESULT *phr,
CBouncingBall *pParent,
LPCWSTR pPinName) :
CSourceStream(NAME("Bouncing Ball"),phr, pParent, pPinName),
m_iImageWidth(320),
m_iImageHeight(240),
m_iDefaultRepeatTime(20)
{
ASSERT(phr);
CAutoLock cAutoLock(&m_cSharedState);
m_Ball = new CBall(m_iImageWidth, m_iImageHeight);
if(m_Ball == NULL)
{
if(phr)
*phr = E_OUTOFMEMORY;
}
} // (Constructor)
//
// Destructor
//
CBallStream::~CBallStream()
{
CAutoLock cAutoLock(&m_cSharedState);
if(m_Ball)
delete m_Ball;
} // (Destructor)
// Added by HQ Tech
void CBallStream::SetImageSize(int inWidth, int inHeight)
{
m_iImageWidth = inWidth;
m_iImageHeight = inHeight;
if (m_Ball)
{
m_Ball->SetImageSize(m_iImageWidth, m_iImageHeight);
}
}
void CBallStream::GetImageSize(int * outWidth, int * outHeight)
{
if (outWidth && outHeight)
{
*outWidth = m_iImageWidth;
*outHeight = m_iImageHeight;
}
}
//
// FillBuffer
//
// Plots a ball into the supplied video buffer
//
HRESULT CBallStream::FillBuffer(IMediaSample *pms)
{
// Added by HQ Tech
// Please using Sleep when you meet the problem, High Usage of CPU!
// Sleep(40);
CheckPointer(pms,E_POINTER);
ASSERT(m_Ball);
BYTE *pData;
long lDataLen;
pms->GetPointer(&pData);
lDataLen = pms->GetSize();
ZeroMemory(pData, lDataLen);
{
CAutoLock cAutoLockShared(&m_cSharedState);
// If we haven't just cleared the buffer delete the old
// ball and move the ball on
m_Ball->MoveBall(m_rtSampleTime - (LONG) m_iRepeatTime);
m_Ball->PlotBall(pData, m_BallPixel, m_iPixelSize);
// The current time is the sample's start
CRefTime rtStart = m_rtSampleTime;
// Increment to find the finish time
m_rtSampleTime += (LONG)m_iRepeatTime;
pms->SetTime((REFERENCE_TIME *) &rtStart,(REFERENCE_TIME *) &m_rtSampleTime);
}
pms->SetSyncPoint(TRUE);
return NOERROR;
} // FillBuffer
//
// Notify
//
// Alter the repeat rate according to quality management messages sent from
// the downstream filter (often the renderer). Wind it up or down according
// to the flooding level - also skip forward if we are notified of Late-ness
//
STDMETHODIMP CBallStream::Notify(IBaseFilter * pSender, Quality q)
{
// Adjust the repeat rate.
if(q.Proportion<=0)
{
m_iRepeatTime = 1000; // We don't go slower than 1 per second
}
else
{
m_iRepeatTime = m_iRepeatTime*1000 / q.Proportion;
if(m_iRepeatTime>1000)
{
m_iRepeatTime = 1000; // We don't go slower than 1 per second
}
else if(m_iRepeatTime<10)
{
m_iRepeatTime = 10; // We don't go faster than 100/sec
}
}
// skip forwards
if(q.Late > 0)
m_rtSampleTime += q.Late;
return NOERROR;
} // Notify
//
// GetMediaType
//
// I _prefer_ 5 formats - 8, 16 (*2), 24 or 32 bits per pixel and
// I will suggest these with an image size of 320x240. However
// I can accept any image size which gives me some space to bounce.
//
// A bit of fun:
// 8 bit displays get red balls
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -