程序代码
介绍
在正在播放的视频上显示一些图象似乎很难。在这里,我试图在一个视频上显示一个图片。并不是一个静止的图片,还要以动态的显示连续几张图片。
升级
我升级我的cVideo类用来动态显示几个图片。不仅这些,还要控制图片显示的透明度。看一下“深入DirectShow”一会就会明白怎么做。
背景:
在视频上动态显示图片需要DirectShow的相关技术和对图象的过滤技术。比如添加图形过滤VMR9(video mixing renderer)。VMR9是一把钥匙,允许我们在一个视频上显示图片。
建立环境:
所有想要使用DirectShow的程序必须包含 Dshow.h头文件,并使用Strmiids.lib库文件。
深入DirectShow:
在视频上显示图象技术是基于IVMRMixerBitmap9类,该类只有三个成员函数。
其它还有一个结构VMR9AlphaBitmap,用来在函数中传输数据。一些 VMR9AlphaBitmap的成员如下:
DWORD dwFlags;
HDC hdc;
RECT rSrc;
VMR9NormalizedRect rDest;
FLOAT fAlpha;
COLORREF clrSrcKey;
现在说一下如何使用这些。让我们看看怎样在开始的时候引入。首先,需要知道:
我们选定(SelectObject)图片的设备描述hDC,
其它重要的是图片的尺寸,
第三件事是在视频上显示图片的位置(一个rect),
透明的程度,指定图片在视频上的透明度,
隐藏图片背景原色的颜色值;将其设置为背景色;不只是隐藏背景,可以给出任何颜色值,然后该颜色可以作为透明色在视频上显示,最后,设置添入数据的标志。
现在一些都OK了,只是调用SetAlphaBitmap()就可以了。
想了解更多内容,请访问博客。
基本初始化:
首先,我们需要建立一个图象管理过滤的对象(过滤图象管理是用来控制过滤和数据更新)。通过调用CoCreateInstance()来实现。这样,我们建立了一个图象过滤管理对象并得到一个指向IGraphBuilder类的指针。该类用来建立一个用户过滤图象(过滤图形是DirectShow过滤显示图象文件的全部功能)。
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
After creating the filter graph manager, the other important issue is the addition of VMR9 in the filter graph. But before addition, we need to create it, and after creation, we will add that filter (VMR9) to our filter graph.
CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (void**)&pVmr);
pGraph->AddFilter(pVmr, L"Video");
现在需要定义VMR9。象在这里的情况,我们设置在提供的窗口中显示一个视频,设置视频的位置。
pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig);
pConfig->SetRenderingMode(VMR9Mode_Windowless);
pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pWC);
pWC->SetVideoPosition(NULL, pRect);
pWC->SetVideoClippingWindow(pParentWnd->m_hWnd);
以下IVMRMixerBitmap9是用来提供在视频上显示图片的工具。和位图信息结构包含了要显示图片的数据。这里第一次调用时都清0。
pWC->QueryInterface(IID_IVMRMixerBitmap9, (LPVOID *)&pBmp);
ZeroMemory(&bmpInfo, sizeof(bmpInfo) );
以下是在任何DirectShow程序中都很重要的类,因为它提供了通过IMediaControl控制数据更新的工具,并关注任何重要的事件。例如文件播放结束,提供该功能的类是IMediaEventEx。使用该类,需要设定接受事件的窗口。其它重要的类有IMediaSeeking提供查找媒体文件的功能。
pGraph->QueryInterface(IID_IMediaControl, (void **)&pMC);
pGraph->QueryInterface(IID_IMediaEventEx, (void **)&pME);
pME->SetNotifyWindow ( ( OAHWND ) pParentWnd->GetParent()->m_hWnd,
WM_GRAPHNOTIFY, 0 ) ;
pGraph->QueryInterface(IID_IMediaSeeking, (void **)&pMS);
Now create the custom filter graph. And then run it. After this, the video will start playing in our given window.
pGraph->RenderFile(mFileToPlay, NULL);
pMC->Run();
显示图片:
我们需要做的是选定图片设备句柄,图片尺寸,需要图片透明的背景颜色。现在开始。首先得到播放视频窗口的句柄。现在需要另一个设备,必须和视频窗口的句柄兼容,现在选择该设备中的图片。
CDC * pdc = GetDC();
CDC mCompatibleDC;
mCompatibleDC.CreateCompatibleDC(pdc);
mCompatibleDC.SelectObject(hBitmap);
CRect reSrc(0,0,mBitmapWidth,mBitmapHeight);
现在显示图片的实际工作开始了。引入位图信息结构并设定参数,例如,设定标签,设定设备句柄和资源,图片的大小等。
bmpInfo.dwFlags |= VMRBITMAP_HDC;
bmpInfo.hdc = pDC->m_hDC;
bmpInfo.rSrc = rectSize; // Size of the image图片大小
设定在屏幕上显示图片的矩形区域
//rDest指定目的合成区域的矩形(0.0f 到 1.0f)
bmpInfo.rDest.right = 1.0f;
bmpInfo.rDest.left = 1.0f - 0.3;
bmpInfo.rDest.top =1.0 - 0.3;
bmpInfo.rDest.bottom = 1.0f;
Set the transparency level. // 设定透明的程度(1.0不透明,0.0透明)
bmpInfo.fAlpha = 0.0;
设定颜色值和标记,这里设置成绿色,这意味着任何图片上的绿色将显示成透明。
//设置COLORREF,这样位图的外框是透明的
bmpInfo.dwFlags |= VMRBITMAP_SRCCOLORKEY;
bmpInfo.clrSrcKey = RGB(0, 255, 0);
pBmp->SetAlphaBitmap(&bmpInfo);
使用代码:
我试图尽可能简化。我建立了一个cVideo类。该类隐藏所有复杂的部分。你只需要调用类的方法,类中方法解决了所有问题。
该类有以下方法:
void InitInterfaces(BSTR mFileToPlay, CWnd* pParentWnd, CRect* pRect);
void Clean(void);
void Play(void);
void ShowImage(CDC* pDC, CRect rectSize);
void HideImage(void);
void SetTransparency( int tansparencyLevel )
void Animate();
InitInterfaces() 封装了所有DirectShow图象建立的方法。
play(), 播放一个视频
ShowImage() 只是提供了设备指针(CDC* pDC),该设备选择了要显示的图片。
HideImage() 隐藏或显示图片。
SetTransparency(int transparencyLevel) 控制图片在视频上的透明度。
Animate() 更新显示图片的矩形区域,显示动画效果
at last, Clean() 释放DirectShow类对象。