Building a Filter Graph for ASF Output (Windows Embedded CE 6.0)
1/6/2010
You can use the Windows Media encoder DMO to write your captured data to an Advanced Systems Format (ASF) file.
Step 1
The first step in the process is to do some general setup by declaring variables, instantiating objects, and obtaining interface pointers.
// Declare pointers to DirectShow interfaces
CComPtr<ICaptureGraphBuilder2> pCaptureGraphBuilder;
CComPtr<IBaseFilter> pVideoCap, pAsfWriter,
pVideoEncoder, pAudioEncoder;
CComPtr<IBaseFilter> pAudioCaptureFilter;
CComPtr<IDMOWrapperFilter> pVideoWrapperFilter, pAudioWrapperFilter;
CComPtr<IPersistPropertyBag> pPropertyBag;
CComPtr<IGraphBuilder> pGraph;
CComPtr<IMediaControl> pMediaControl;
CComPtr<IMediaEvent> pMediaEvent;
CComPtr<IMediaSeeking> pMediaSeeking;
CComPtr<IFileSinkFilter> pFileSink;
// Create the graph builder and the filtergraph
pCaptureGraphBuilder.CoCreateInstance( CLSID_CaptureGraphBuilder );
pGraph.CoCreateInstance( CLSID_FilterGraph );
pCaptureGraphBuilder->SetFiltergraph( pGraph );
// Query all the interfaces needed later
pGraph.QueryInterface( &pMediaControl );
pGraph.QueryInterface( &pMediaEvent );
pGraph.QueryInterface( &pMediaSeeking );
Step 2
To initialize the video capture filter, you must determine the name of the capture device and then pass that device name to the capture filter. In the code below, the name of the capture device is hard coded with a specific device name. This approach works in certain tightly controlled scenarios, but a better general approach would be to determine the capture device's name by enumerating all the capture devices using FindFirstDevice and FindNextDevice. For more information, see Capture Device Selection.
In the following code, PropBag is an object that implements an IPropertyBag interface that is used to pass information to the capture filter.
// Initialize the video capture filter
pVideoCap.CoCreateInstance( CLSID_VideoCapture ));
pVideoCap.QueryInterface( &pPropertyBag ));
varCamName = L"CAM1:";
if(( varCamName.vt == VT_BSTR ) == NULL ) {
return E_OUTOFMEMORY;
}
PropBag.Write( L"VCapName", &varCamName );
pPropertyBag->Load( &PropBag, NULL );
pPropertyBag.Release();
pGraph->AddFilter( pVideoCap, L"Video capture source" );
Step 3
Once the capture filter knows what capture device to use, you can begin to initialize the audio and video filters. In the following code, video is encoded with the Windows Media Video 9 DMO by using the DMO Wrapper Filter.
// Initialize the audio capture filter
pAudioCaptureFilter.CoCreateInstance( CLSID_AudioCapture );
pAudioCaptureFilter.QueryInterface( &pPropertyBag );
pPropertyBag->Load( NULL, NULL );
pGraph->AddFilter( pAudioCaptureFilter, L"Audio Capture Filter" );
// Initialize the Video DMO Wrapper
pVideoEncoder.CoCreateInstance( CLSID_DMOWrapperFilter );
pVideoEncoder.QueryInterface( &pVideoWrapperFilter );
// Load the WMV9 encoder in the DMO Wrapper.
// To encode in MPEG, replace CLSID_CWMV9EncMediaObject with the
// CLSID of your DMO
pVideoWrapperFilter->Init( CLSID_CWMV9EncMediaObject,
DMOCATEGORY_VIDEO_ENCODER );
pGraph->AddFilter( pVideoEncoder, L"WMV9 DMO Encoder" );
// Load ASF multiplexer.
// To create a MPEG file, change the CLSID_ASFWriter into the GUID
// of your multiplexer
pAsfWriter.CoCreateInstance( CLSID_ASFWriter );
pAsfWriter->QueryInterface( IID_IFileSinkFilter, (void**) &pFileSink );
pFileSink->SetFileName( L"\\My Documents\\test0.asf", NULL );
Step 4
Once the individual filters are initialized, you can connect their pins together, using the ICaptureGraphBuilder2 interface, pCaptureGraphBuilder.
// Connect the preview pin to the video renderer
pCaptureGraphBuilder->RenderStream( &PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video, pVideoCap,
NULL, NULL );
// Connect the video capture pin to the multiplexer through the
// video renderer.
pCaptureGraphBuilder->RenderStream( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, pVideoCap,
pVideoEncoder, pAsfWriter );
// Connect the audio capture pin to the multiplexer through the
// audio renderer.
pCaptureGraphBuilder->RenderStream( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Audio, pAudioCaptureFilter,
pAudioEncoder, pAsfWriter );
Step 5
With all the filters initialized and all of their pins connected together into a capture graph, you can now being to capture data. The code below first blocks the capture graph and then lets it run for a short period of time prior to actually capturing any data. This give the filter graph time to make sure that all of its buffers are allocated and all processes are synchronized.
// Block the capture.
pCaptureGraphBuilder->ControlStream( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, pVideoCap,
0, 0 ,0,0 );
pCaptureGraphBuilder->ControlStream( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Audio, pAudioCaptureFilter,
0, 0, 0, 0 );
// Let's run the graph and wait one second before capturing.
pMediaControl->Run();
Sleep( 1000 );
// Let's capture 5 seconds of data in a file
dwEnd=MAXLONGLONG;
OutputDebugString( L"Starting to capture the first file" );
pCaptureGraphBuilder->ControlStream( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, pVideoCap,
&dwStart, &dwEnd, 0, 0 );
pCaptureGraphBuilder->ControlStream( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Audio, pAudioCaptureFilter,
&dwStart, &dwEnd, 0, 0 ));
// Wait 5 seconds.
Sleep( 5000 );
OutputDebugString( L"Stopping the capture" );
pMediaSeeking->GetCurrentPosition( &dwEnd );
pCaptureGraphBuilder->ControlStream( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Video, pVideoCap,
&dwStart, &dwEnd, 1, 2 );
pCaptureGraphBuilder->ControlStream( &PIN_CATEGORY_CAPTURE,
&MEDIATYPE_Audio, pAudioCaptureFilter,
&dwStart, &dwEnd, 1, 2 );
// Wait for the ControlStream event.
OutputDebugString( L"Wating for the control stream events" );
do
{
pMediaEvent->GetEvent( &lEventCode, &lParam1, &lParam2, INFINITE );
pMediaEvent->FreeEventParams( lEventCode, lParam1, lParam2 );
if( lEventCode == EC_STREAM_CONTROL_STOPPED ) {
OutputDebugString( L"Received a control stream stop event" );
count++;
}
} while( count < 2);
OutputDebugString( L"The file has been captured" );
See Also
Concepts
Creating ASF Files in DirectShow
Windows Media Applications
DirectX Media Objects