|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThis article shows the steps involved in creating and configuring DirectShow’s Video Mixing Renderer Filter 9 (VMR9). The two video streams, one on top of the other, are rendered on a single surface. This surface, in our case, is a How VMR9 is differentThe following diagrams show the difference between rendering two videos with VMR9 and without VMR9. Without VMR9
We notice that simply rendering two videos will result in two separate Video Renderers, which means that the videos are being played on two separate surfaces. With VMR9
In this case, the VMR9 filter directs both video streams into its own input pins. This means there is only one renderer, and thus a single rendering surface for both video streams. The WorkingTo enhance reusability and readability factors, the functionality of the VMR9 filter has been encapsulated inside a class named The myVMR9 classThis class has the following private data members:
The constructorThe constructor receives a public: myVMR9(System::Drawing::Rectangle rect, HWND hwnd) { // initialize video coordinates with normal values r = new VMR9NormalizedRect; r->left = 0; r->top = 0; r->right = 1; r->bottom = 1; pWC = NULL; pMix = NULL; pGB = NULL; pVmr = NULL; pConfig = NULL; pMC = NULL; pMS = NULL; // create an instance of the Filter Graph Manager CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB); // create an instance of the VMR9 filter CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr); // add the VMR9 filter to the Graph Manager pGB->AddFilter(pVmr, L"Video"); // get a pointer to the IVMRFilterConfig9 interface pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig); // make sure VMR9 is in windowless mode pConfig->SetRenderingMode(VMR9Mode_Windowless); // get a pointer to the IVMRWindowlessControl9 interface pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pWC); // explicitly convert System::Drawing::Rectangle type to RECT type RECT rcDest = {0}; rcDest.bottom = rect.Bottom; rcDest.left = rect.Left; rcDest.right = rect.Right; rcDest.top = rect.Top; // set destination rectangle for the video pWC->SetVideoPosition(NULL, &rcDest); // specify the container window that the video should be clipped to pWC->SetVideoClippingWindow(hwnd); // IVMRMixerControl manipulates video streams pVmr->QueryInterface(IID_IVMRMixerControl9, (void**)&pMix); // IMediaSeeking seeks to a position in the video stream pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS); // IMediaControl controls flow of data through the graph pGB->QueryInterface(IID_IMediaControl, (void **)&pMC); } The methodsHRESULT play()
{
pMC->Run(); return
S_OK;
}
HRESULT pause()
{
pMC->Pause();
return S_OK;
}
HRESULT stop()
{
LONGLONG pos = 0;
pMC->Stop();
pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning,
NULL,AM_SEEKING_NoPositioning);
pMC->Pause();
return S_OK;
}
HRESULT close()
{
// make sure resources are freed
SAFE_RELEASE(pWC);
SAFE_RELEASE(pMix);
SAFE_RELEASE(pGB);
SAFE_RELEASE(pVmr);
SAFE_RELEASE(pConfig);
SAFE_RELEASE(pMC);
SAFE_RELEASE(pMS);
return S_OK;
}
HRESULT setAlpha(DWORD stream, float alpha)
{
// set alpha of specified video stream
pMix->SetAlpha(stream, alpha);
return S_OK;
}
HRESULT setX(DWORD stream, float x)
{
// video displacement along x-axis
r->right = x + (r->right - r->left);
r->left = x;
pMix->SetOutputRect(stream, r);
return S_OK;
}
HRESULT setY(DWORD stream, float y)
{
// video displacement along y-axis
r->bottom = y + (r->bottom - r->top);
r->top = y;
pMix->SetOutputRect(stream, r);
return S_OK;
}
HRESULT setW(DWORD stream, float w)
{
// video stretching/shrinking along x-axis
r->right = r->left + w;
pMix->SetOutputRect(stream, r);
return S_OK;
}
HRESULT setH(DWORD stream, float h)
{
// video stretching/shrinking along y-axis
r->bottom = r->top + h;
pMix->SetOutputRect(stream, r);
return S_OK;
}
HRESULT renderFiles(String* file1, String* file2)
{
// convert String type to LPCSTR type and render the videos
LPCTSTR lFile;
lFile =
static_cast<LPCTSTR>(const_cast<void*>(static_cast<const void*>
(System::Runtime::InteropServices::Marshal::StringToHGlobalAuto(file1))));
pGB->RenderFile((LPCWSTR)lFile, NULL);
lFile =
static_cast<LPCTSTR>(const_cast<void*>(static_cast<const void*>
(System::Runtime::InteropServices::Marshal::StringToHGlobalAuto(file2))));
pGB->RenderFile((LPCWSTR)lFile, NULL);
System::Runtime::InteropServices::Marshal::FreeHGlobal
(static_cast<IntPtr>(const_cast<void*>
(static_cast<const void*>(lFile))));
pMC->StopWhenReady();
return S_OK;
}
Now that the VMR9's functionality has been separated from the GUI, Button and TrackBar handlers can simply create a pointer to a
Additional Information
|
||||||||||||||||||||||