Building-a-Simple-Camera-DirectShow-Filter-graph-Application-in-WEC7

As you may know that Windows Embedded Compact 7 has new component for DirectShow video rendering(Video Mixing Render) which is more advanced than the old video render used in Windows Embedded CE 6.0.However the VMR has been available in PC side DirectX for a long time.

I am planning to explore few features of VMR on WEC7starting with bitmap mixing. Mixing the bitmap is not a cakewalk in Windows Embedded CE 6.0.We have to develop a transform filter to perform this, again the performance is not assured. But in WEC7 VMR facilitates the bitmap mixing easily by writing few lines of code.

This blog is the continuation of “Building a Simple Camera DirectShow Filter graph Application in WEC7” written by Prabu Kumar. He has already explained – How to include VMR on Filter graph with a simple application. I am exploring the VMR feature with the same sample application by including my source codeon it. So that it can be easy to follow. Also you can click here to download the Sample application code. This application is developed in VS2008 using the OMAP EVM SDK and tested in OMAP EVM.

 

Exploring Bitmap Mixing

VMR expose bitmap mixing through IVMRMixerBitmap interface and it is having few methods which help us to implement bitmap mixing in a simple and straight forward method. I have explained the bitmap mixing by alpha blending a bitmap and also create strobe effect on bitmap with the preview streaming from the camera.

Now I am explaining you on how to blend a bitmap image with the below given source code snippets. As I already told, I am continuing with sample application given by Prabu Kumar. So add the following code between step 3 and 4 of the above given blog.


    //Get the interface for configuring the VMR
    CHK(pVideoRenderer.QueryInterface(&pVMRConfig ));

    //Set VMR to Windowed Mode
    CHK(pVMRConfig->SetRenderingMode( VMRMode_Windowed));

    //Set the input stream for VMR as 2 to perform bitmap Mixing
    CHK(pVMRConfig->SetNumberOfStreams(2));

    //Retrieve the Bitmap mixer interface
    CHK(pVideoRenderer.QueryInterface(&pVMRMixerBitmap) );

We need two streams to perform bitmap mixing. One is the main video stream and another stream is bitmap. . Using IVMRFilterConfig ::SetNumberOfStreams() set the number of stream required as 2. Add the following code after step5.


    CHK(BlendBitMap( m_hwnd));

Also see the below given definition of the function BlendBitMap().I have explained below about the steps involved in loading and mixing the bitmap image with the live camera preview.

 

1) Load the bitmap and map with the windows compactible DC. This DC will be used as parameter for VMR bitmap mixer API as shown in the step 2.Following code snippet will perform this.


    HRESULT BlendBitMap(HWND hwndApp)
    {
    LONG cx=480, cy=480;
    HRESULT hr;
    RECT rc={0};
    // Load the multi-image bitmap to alpha blend from the resource file
    HBITMAP hbm = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1));
    BITMAP bm;
    HBITMAP hbmOld;
    HDC hdc = GetDC(hwndApp);
    HDC hdcBmp = CreateCompatibleDC(hdc);
    ReleaseDC(hwndApp, hdc);
    GetObject(hbm, sizeof(bm), &bm);
    hbmOld = (HBITMAP)SelectObject(hdcBmp, hbm);

 

2) Map the DC to VMR bitmap mixer, Configure the source and destination rectangle. Source reactance used to define the area where you are going to draw from bitmap image and destination rectangle used to define the area where you are going to draw on the live video stream.Following code snippet will do this.


    // Configure the VMR’s bitmap structure
    VMRALPHABITMAP bmpInfo;
    ZeroMemory(&bmpInfo, sizeof(bmpInfo) );
    bmpInfo.dwFlags = VMRBITMAP_HDC;
    bmpInfo.hdc = hdcBmp;
    // Display the bitmap in the bottom right corner. rSrc specifies the source rectangle in the GDI //device context.
    SetRect(&rc, 0, 0, bm.bmWidth, bm.bmHeight);
    bmpInfo.rSrc = rc;
    // rDest specifies the destination rectangle in composition space (0.0f to 1.0f)
    bmpInfo.rDest.left = (float)(cx – bm.bmWidth) / (float)cx – EDGE_BUFFER;
    bmpInfo.rDest.top = (float)(cy – bm.bmHeight) / (float)cy – EDGE_BUFFER;
    bmpInfo.rDest.right = 1.0f – EDGE_BUFFER;
    bmpInfo.rDest.bottom = 1.0f – EDGE_BUFFER;

 

3) Set the alpha value based on your requirement and set the VMR configuration structure using
IVMRMixerBitmap ::SetAlphaBitmap. In my case, I use the alpha value as 0.0 to hide the bitmap at the beginning.


    // Transparency value 1.0 is opaque, 0.0 is transparent. For initially setting the bitmap, we’ll make // it transparent
    bmpInfo.fAlpha = 0.0;
    // Set the COLORREF so that the bitmap outline will be transparent
    SetColorRef(bmpInfo);
    // Give the bitmap to the VMR. Since the alpha value is 0, nothing willbe displayed yet on the //screen, but the VMR will have the information that it needs to allow us to modify the bitmap.
    hr = pVMRMixerBitmap->SetAlphaBitmap(&bmpInfo);
    if (FAILED(hr))
    RETAILMSG(1,(TEXT(“SetAlphaBitmap FAILED! Bitmap operations will fail. hr=0x%x\r\n”), hr));
    // Clean up GDI resources
    DeleteObject(SelectObject(hdcBmp, hbmOld));
    DeleteObject(hbm);
    DeleteDC(hdcBmp);
    returnhr;
    }

 

Creating Strobe effect with bitmap mixer

I have explained the usage of IVMRMixerBitmap ::GetAlphaBitmapParameters and IVMRMixerBitmap::UpdateAlphaBitmapParameters functions by creating the strobe effect. Strobe effects can be created by changing the alpha value with the minimum delta value range between 0.0 to 1.0.

Following steps explain you to create the strobe effect

1) Create a function called StrobeEffect. Using GetAlphaBitmapParameters, we can get the current alpha value, apply the delta and update the new value using UpdateAlphaBitmapParameters. Following code snippet shows the usage.


    const float STROBE_VALUE = 0.125f;
    voidStrobeEffect(void)
    {
    HRESULT hr;
    VMRALPHABITMAP bmpInfo={0};
    staticint Increase=1;
    floatfAlpha=0.0f;
    hr = pVMRMixerBitmap->GetAlphaBitmapParameters(&bmpInfo);
    // Slowly increase the alpha value
    if(bmpInfo.fAlpha>=1.0f)
    Increase=0;
    else if(bmpInfo.fAlpha<=0.0f) Increase=1; if(Increase) fAlpha= bmpInfo.fAlpha + STROBE_VALUE; else fAlpha = bmpInfo.fAlpha – STROBE_VALUE; bmpInfo.fAlpha = fAlpha; // Set the COLORREF so that the bitmap outline will be transparent SetColorRef(bmpInfo);
    // If the bitmap is currently disabled, this call will fail hr = pVMRMixerBitmap->UpdateAlphaBitmapParameters(&bmpInfo);
    }

 

2) Create a TimerProc and and call the StrobeEffect function in a required period.


    VOID CALLBACK TimerProc(
    HWND hwnd, // handle to window
    UINT uMsg, // WM_TIMER message
    UINT_PTR idEvent, // timer identifier
    DWORD dwTime // current system time
    )
    {
    StrobeEffect();
    }

 

3) You can start and stop the Strobe effect by using SetTimer and KillTimer APIs. The functions StartTimer and StopTimer are invoked from the Menu item.


    voidStartTimer(void)
    {
    if (!gnTimer)
    gnTimer = (int) SetTimer(NULL, MAIN_TIMER, MAIN_TIMEOUT, TimerProc);
    }
    voidStopTimer(void)
    {
    if (gnTimer)
    {
    KillTimer(NULL, gnTimer);
    gnTimer = 0;
    }
    }

 

Hope this blog provides some pointers on VMR Bitmap Mixer on Windows Embedded Compact 7.