分类: C/C++
2007-06-08 19:44:33
#include "stdafx.h" #include "VR.h" #pragma comment(lib,"strmbase.lib") #pragma comment(lib,"winmm.lib") // Setup data const AMOVIESETUP_MEDIATYPE sudIpPinTypes = { &MEDIATYPE_Video, // MajorType &MEDIASUBTYPE_NULL // MinorType }; const AMOVIESETUP_PIN sudIpPin = { L"Input", // The Pins name FALSE, // Is rendered FALSE, // Is an output pin FALSE, // Allowed none FALSE, // Allowed many &CLSID_NULL, // Connects to filter NULL, // Connects to pin 1, // Number of types &sudIpPinTypes // Pin details }; const AMOVIESETUP_FILTER sudVRAx = { &CLSID_lwVideoRenderer, // Filter CLSID /**/ L"lwVideoRenderer", // String name /**/ MERIT_NORMAL, // Filter merit 1, // Number of pins &sudIpPin // 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 // function when it is asked to create a CLSID_VideoRenderer object CFactoryTemplate g_Templates[] = { { L"lwVideoRenderer" /**/ , &CLSID_lwVideoRenderer /**/ , CVideoRenderer::CreateInstance , NULL , &sudVRAx }, }; int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); // DllRegisterServer // Used to register and unregister the filter STDAPI DllRegisterServer() { return AMovieDllRegisterServer2( TRUE ); } // DllRegisterServer // DllUnregisterServer STDAPI DllUnregisterServer() { return AMovieDllRegisterServer2( FALSE ); } // DllUnregisterServer extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); // DllMain BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved); }// DllMain |
#include // 回调类定义 class FunCLS {public: virtual void procFun(BITMAPINFO* pBmpInfo, BYTE* pb){return;}; }; // 回调函数指针定义 typedef void (CALLBACK* pProcFun)(BITMAPINFO* pBmpInfo,BYTE* pb); // {F81331DB-2E46-43e7-8709-BE57205D8914} Filter的全局标识符 static const GUID CLSID_lwVideoRenderer = { 0xf81331db, 0x2e46, 0x43e7, { 0x87, 0x9, 0xbe, 0x57, 0x20, 0x5d, 0x89, 0x14 } }; // Filter 类定义 class CVideoRenderer : public CBaseVideoRenderer { public: // 创建进程。 static CUnknown * WINAPI CreateInstance(LPUNKNOWN, HRESULT *); // 构造、释构函数 CVideoRenderer(LPUNKNOWN pUnk,HRESULT* phr); ~CVideoRenderer(); public: // 检查是否有可以接受格式的数据 HRESULT CheckMediaType(const CMediaType* pmt); // 设置具体的数据格式,如视频图像的宽、高等 HRESULT SetMediaType(const CMediaType* pmt); // 递交数据,即显示、呈现数据 HRESULT DoRenderSample(IMediaSample* pMediaSample); private: BITMAPINFO m_bmpInfo; // 图片信息 BYTE* m_pCopyBuffer; // 复制缓冲区 UINT m_pixelNum; // 像素点的数目 FunCLS* m_pFunCLS; // 回调类指针 pProcFun m_pPF; // 回调函数指针 }; |
//=========================================================== // 创建进程。 CUnknown* WINAPI CVideoRenderer::CreateInstance(LPUNKNOWN pUnk,HRESULT* phr) { return new CVideoRenderer(pUnk,phr); } //=========================================================== // 构造函数 CVideoRenderer::CVideoRenderer(LPUNKNOWN pUnk,HRESULT *phr) : CBaseVideoRenderer(CLSID_lwVideoRenderer,"lw Video Renderer",pUnk,phr) { m_pCopyBuffer = NULL; m_pFunCLS = NULL; m_pPF = NULL; m_pixelNum = 0; } //=========================================================== // 释构函数 CVideoRenderer::~CVideoRenderer() { if(this->m_pCopyBuffer){ delete [] m_pCopyBuffer; } } //=========================================================== // 检查媒体类型 HRESULT CVideoRenderer::CheckMediaType(const CMediaType* pmt) { VIDEOINFO *pvi; // 只接受视频 if( *pmt->FormatType() != FORMAT_VideoInfo ) { return E_INVALIDARG; } // 只接受 RGB24 格式,即 R、G、B各 1 Byte pvi = (VIDEOINFO *)pmt->Format(); if(IsEqualGUID( *pmt->Type(),MEDIATYPE_Video) && IsEqualGUID( *pmt->Subtype(),MEDIASUBTYPE_RGB24)){ return S_OK; } return E_INVALIDARG; } //=========================================================== // 设置媒体类型,获取图像的各种信息(宽、高等具体信息),处理图像要用到 HRESULT CVideoRenderer::SetMediaType(const CMediaType* pmt) { VIDEOINFO *pviBmp; // Bitmap info header pviBmp = (VIDEOINFO *)pmt->Format(); memset(&m_bmpInfo,0,sizeof(BITMAPINFO)); // 清零 m_bmpInfo.bmiHeader = pviBmp->bmiHeader; // 改为 32bit,因为我会把它处理成 32bit 的 m_bmpInfo.bmiHeader.biBitCount = 32; // 当然,缓冲区大小也变了 m_bmpInfo.bmiHeader.biSizeImage = m_bmpInfo.bmiHeader.biSizeImage * 4 / 3; // 开辟新 32bit 图片的缓冲区 if(m_pCopyBuffer){ delete [] m_pCopyBuffer;} m_pCopyBuffer = new BYTE[m_bmpInfo.bmiHeader.biSizeImage]; m_pixelNum = m_bmpInfo.bmiHeader.biWidth * m_bmpInfo.bmiHeader.biHeight; return S_OK; } //=========================================================== // 处理媒体采样 HRESULT CVideoRenderer::DoRenderSample(IMediaSample* pMediaSample) { // 获取采样的数据区指针,即 24bit 图片的数据区指针 BYTE* pb = NULL; pMediaSample->GetPointer(&pb); if(!pb){ return E_FAIL; } // 加锁!锁住我要操作的数据区,以防处理到一半的时候被打断而造成错误 // 其实就是多线程编程中经常使用的临界区的类形式, // 利用构造函数和释构函数来进入和退出临界区 // m_RendererLock 是 CBaseVideoRenderer 的成员,继承得来。 CAutoLock cAutoLock(&this->m_RendererLock); // 把 24bit 图片处理成 32bit BYTE* pb32 = m_pCopyBuffer; // 指向 32bit 缓冲区的指针 for(UINT i = 0; i < m_pixelNum; i ++){ pb32[0] = pb[0]; pb32[1] = pb[1]; pb32[2] = pb[2]; pb32[3] = 0xff; // 0xff 即 255 pb += 3; pb32 += 4; } // 如果有回调类,进行回调处理 if(m_pFunCLS){ m_pFunCLS->procFun(&m_bmpInfo,m_pCopyBuffer); } // 如果有回调函数,进行处理 if(m_pPF){ m_pPF(&m_bmpInfo,m_pCopyBuffer); } return S_OK; } |
// {244DF760-7E93-4cf0-92F4-DCB79F646B7E} 接口的 GUID static const GUID IID_IVRControl = {0x244df760, 0x7e93, 0x4cf0, {0x92, 0xf4, 0xdc, 0xb7, 0x9f, 0x64, 0x6b, 0x7e}}; // 接口定义 DECLARE_INTERFACE_(IVRControl, IUnknown) { STDMETHOD(GetBmpInfo) (THIS_ // 方法一:获取图片信息 BITMAPINFO** ppBmpInfo ) PURE; STDMETHOD(GetPointer) (THIS_ // 方法二:获取缓冲区指针 BYTE** ppb // 缓冲区指针的指针 ) PURE; STDMETHOD(SetFunCLS) (THIS_ // 方法三:设置回调类 FunCLS* pFunCLS // 回调类指针 ) PURE; STDMETHOD(SetFun) (THIS_ // 方法四:设置回调函数 pProcFun pPF ) PURE; }; |
class CVideoRenderer : public CBaseVideoRenderer, public IVRControl |
// 询问接口,一般可以不要的,但这里需要使用接口,也重载了 STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); // 接口函数 DECLARE_IUNKNOWN; STDMETHODIMP GetBmpInfo(BITMAPINFO** ppBmpInfo); STDMETHODIMP GetPointer(BYTE** ppb); STDMETHODIMP SetFunCLS(FunCLS* pFunCLS); STDMETHODIMP SetFun(pProcFun pPF); |
//=========================================================== // 询问接口 STDMETHODIMP CVideoRenderer::NonDelegatingQueryInterface(REFIID riid,void** ppv) { CheckPointer(ppv,E_POINTER); if(riid == IID_IVRControl){ // 返回接口。这里有个细节:返回接口时,Filter 的引用计数会增一,所以外部程序用完接口后也要对它进行释放 return GetInterface((IVRControl*) this,ppv); }else{ return CBaseVideoRenderer::NonDelegatingQueryInterface(riid,ppv); } } //=========================================================== // 以下为接口函数的具体实现,只是简单的赋值 STDMETHODIMP CVideoRenderer::GetBmpInfo(BITMAPINFO** ppBmpInfo) { *ppBmpInfo = &this->m_bmpInfo; return S_OK; } STDMETHODIMP CVideoRenderer::GetPointer(BYTE** ppb) { *ppb = m_pCopyBuffer; return S_OK; } STDMETHODIMP CVideoRenderer::SetFunCLS(FunCLS* pFunCLS) { m_pFunCLS = pFunCLS; return S_OK; } STDMETHODIMP CVideoRenderer::SetFun(pProcFun pPF) { m_pPF = pPF; return S_OK; } |