September 2, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Using a Camera with Windows Mobile 5

  • July 21, 2006
  • By Amit Ranjan
  • Send Email »
  • More Articles »

You have added the source and the transform filter in the filter graph, so the last thing remaining is adding a sink filter in the graph. For this, you call the SetOutputFileName method of ICaptureGraphBuilder2. The first parameter is a media subtype; the second parameter is the name of the file in which you want to save the video; the third parameter is the address of a pointer that receives the multiplexer's interface; and the fourth parameter receives the file writers' interface.

With that, your filter graph is ready. All you need to do is connect the source filter, encoder, and multiplexer. You can achieve this by using the RenderStream method of the graph builder, as follows:

hResult = pCaptureGraphBuilder->RenderStream( &PIN_CATEGORY_CAPTURE,
                                              &MEDIATYPE_Video,
                                              m_pVideoCaptureFilter,
                                              pVideoEncoder,
                                              pASFMultiplexer );

The first parameter is the pin category, which can be NULL to match any category.

The second parameter specifies the media type. The third, fourth, and fifth parameters specify a starting filter, an intermediate filter, and a sink filter, respectively. The method connects the source filter to the transform filter and then the transform filter to the sink filter.

Now your graph is ready, and you can start capturing the video.

Controlling the Graph

Before capturing video, you need two more things: the ImediaEventEx and IMediaControl pointers. IMediaEventEx derives from IMediaEvent, which supports event notification from the filter graph and individual filters to the application. ImediaEventEx provides a method to the register window that receives a message when any event occurs.

IMediaControl is an interface exposed by the filter graph that allows an application to control the streaming media through the graph. The application can use this to start, stop, or pause the running graph.

The following code sample first queries the filter graph for its IMediaEventEx interface. Once it gets the pointer to the IMediaEventEx interface, it then calls its method SetNotifyWindow, passing it the handle to the window that handles the message. The second parameter is the message that will be passed as notification to the Windows message handler. The third parameter is the instance data (this can be 0):

IMediaEventEx *pMediaEvent;
IMediaControl *pMediaControl;
#define WM_GRAPHNOTIFY WM_APP+1
hResult =pFilterGraph->QueryInterface( IID_IMediaEventEx, (void**)
                                       &pMediaEvent );
hResult =pMediaEvent->SetNotifyWindow((OAHWND)hWnd,
                                      WM_GRAPHNOTIFY,0);
hResult=pFilterGraph->QueryInterface(&pMediaControl);
hResult =pMediaControl->Run();

When an event occurs, DirectShow will send WM_GRAPHNOTIFY to the specified windows.

Note: WM_GRAPHNOTIFY is used here as an example. This can be any application-defined message.

Next, you get the pointer to the IMediaControl interface. You'll use this interface to control the graph. Call its Run method to put the entire graph into a running state. The following code shows how to start and stop capture by throwing the ControlStream method of CaptureGraphBuilder:

LONGLONG dwStart  = 0, dwEnd      = 0;
WORD wStartCookie = 1, wEndCookie = 2;
dwEnd=MAXLONGLONG
//start capturing
hResult=pCaptureGraphBuilder->ControlStream(
   &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
   pVideoCaptureFilter, &dwStart, &dwEnd,
   wStartCookie, wEndCookie );
//Stop capturing
dwStart=0;
hResult=pFilterGraph->QueryInterface(&pMediaSeeking );
hResult=pMediaSeeking->GetCurrentPosition( &dwEnd );
hResult= pCaptureGraphBuilder->ControlStream(
   &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pVideoCaptureFilter,
   &dwStart, &dwEnd, wStartCookie, wEndCookie );

The code uses the search criteria supplied in the method call to locate an output pin on the capture filter. ControlStream enables an application to control streams without it needing to enumerate filters and pins in the graph.

Start and End specify the start and stop times (MAX_LONGLONG is the largest possible reference time value). When you start, the End is set to MAXLONLONG. When you want to stop, you first get the current position of the stream by using the GetCurrentPosition method of the IMediaSeeking interface. You then call the ControlStream method with Start set at 0 and End set at the current position.

You now have the graph ready and running. You can start using it to capture and save in an .asf file.

Handling the Graph Events

Because an application will control the graph, you need to write the code to facilitate that. You already have registered the window and message with the filter graph, so the only thing remaining is to handle the message in the window's message handler as follows:

BOOL CALLBACK VidCapDlgProc(HWND hDlg,UINT Msg,WPARAM wParam,
                            LPARAM lParam)
{
   ... ... ... ...
   case WM_GRAPHNOTIFY:
      {
         ProcessGraphMessage();
      }
   ... ... ... ...
}
ProcessGraphMessage()
{
   HRESULT hResult=S_OK;
   long leventCode, param1, param2;
   while(hResult=pEvent->GetEvent(&leventCode, &param1, &param2, 0),
   SUCCEEDED(hResult))
   {
      hResult = pEvent->FreeEventParams(leventCode, param1, param2);
      if (EC_STREAM_CONTROL_STOPPED == leventCode)
      {
         pMediaControl->Stop();
         break;
      }
      else if(EC_CAP_FILE_COMPLETED== leventCode)
      {
         //Handle the file capture completed event
      }
      else if(EC_CAP_FILE_WRITE_ERROR== leventCode)
      {
         //Handle the file write error event
      }
   }
}

You handle the WM_GRAPHNOTIFY message in the windows handler. DirectShow sends this message to the application when any event arises. The application calls a user-defined method to process the events. The GetEvent method of the IMediaEvent interface retrieves the event code and two event parameters from the queue.

Because the message loop and event notification are asynchronous, the queue might hold more then one event. Hence, the GetEvent code is called in a loop until it returns a failure code. Also, whenever you call GetEvent, it's important to call FreeEvent to free the resource associated with the event parameter. And, being the good programmer that you are, you won't forget to release the resources afterwards, will you? Call Release on every object that you have created, as follows:

PVideoCaptureFilter->Release ();
pVideoEncoder->Release ();
pMediaEvent ->Release();
pMediaSeeking ->Release();
pASFMultiplexer->Release();
pFileSinkFilter->Release();
pWrapperFilter ->Release();
pFilterGraph->Release();
pCaptureGraphBuilder->Release();

What Have You Learned?

You now understand how to create, run, and control a filter graph manually. By using the DirectShow framework to capture from a camera, you gain good control with ease.

About the Author

Amit Ranjan, a Windows Embedded MVP who speaks at various Microsoft conferences and user group sessions, has six years of professional experience. He currently works with Sasken Communication Tech Ltd. in Bangalore, India.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel