Microsoft DirectX 9.0

Capturing Video to an AVI File

The following illustration shows the simplest possible graph for capturing video to an AVI file.

AVI Video Capture Graph

The AVI Mux filter takes the video stream from the capture pin and packages it into an AVI stream. An audio stream could also be connected to the AVI Mux filter, in which case the mux would interleave the two streams. The File Writer filter writes the AVI stream to disk.

To build the graph, start by calling the ICaptureGraphBuilder2::SetOutputFileName method, as follows:

IBaseFilter *pMux;
hr = pBuild->SetOutputFileName(
    &MEDIASUBTYPE_Avi,  // Specifies AVI for the target file.
    L"C:\\Example.avi", // File name.
    &pMux,              // Receives a pointer to the mux.
    NULL);              // (Optional) Receives a pointer to the file sink.

The first parameter specifies the file type — in this case, AVI. The second parameter gives the file name. For AVI, the SetOutputFileName method cocreates the AVI Mux filter and the File Writer filter and adds them to the graph. It also sets the file name on the File Writer filter, by calling the IFileSinkFilter::SetFileName method, and connects the two filters. The method returns a pointer to the AVI Mux in the third parameter. Optionally, it returns a pointer to the IFileSinkFilter interface in the fourth parameter. If you don't need this interface, you can set this parameter to NULL, as shown in the previous example.

Next, call the ICaptureGraphBuilder2::RenderStream method to connect the capture filter to the AVI Mux, as follows:

hr = pBuild->RenderStream(
    &PIN_CATEGORY_CAPTURE, // Pin category.
    &MEDIATYPE_Video,      // Media type.
    pCap,                  // Capture filter.
    NULL,                  // Intermediate filter (optional).
    pMux);                 // Mux or file sink filter.

// Release the mux filter.
pMux->Release();

The first parameter gives the pin category, which is PIN_CATEGORY_CAPTURE for capture. The second parameter gives the media type. The third parameter is a pointer to the capture filter's IBaseFilter interface. The fourth parameter is optional; it lets you route the video stream through an intermediate filter, such as an encoder, before passing it to the mux filter. Otherwise, set this parameter to NULL, as shown in the previous example. The fifth parameter is the pointer to the mux filter. This pointer is obtained by calling the SetOutputFileName method.

To capture audio, call RenderStream with the media type MEDIATYPE_Audio. If you are capturing audio and video from two separate devices, it is a good idea to make the audio stream the master stream. This helps to prevent drift between the two streams, because the AVI Mux filter adjust the playback rate on the video stream to match the audio stream. To set the master stream, call the IConfigAviMux::SetMasterStream method on the AVI Mux filter:

IConfigAviMux *pConfigMux = NULL;
hr = pMux->QueryInterface(IID_IConfigAviMux, (void**)&pConfigMux);
if (SUCCEEDED(hr))
{
    pConfigMux->SetMasterStream(1);
    pConfigMux->Release();
}

The parameter to SetMasterStream is the stream number, which is determined by the order in which you call RenderStream. For example, if you call RenderStream first for video and then for audio, the video is stream 0 and the audio is stream 1.

You may also want to set how the AVI Mux filter interleaves the audio and video streams, by calling the IConfigInterleaving::put_Mode method.

IConfigInterleaving *pInterleave = NULL;
hr = pMux->QueryInterface(IID_IConfigInterleaving, (void**)&pInterleave);
if (SUCCEEDED(hr))
{
    pInterleave->put_Mode(INTERLEAVE_CAPTURE);
    pInterleave->Release();
}

With the INTERLEAVE_CAPTURE flag, the AVI Mux performs interleaving at a rate that is suitable for video capture. You can also use INTERLEAVE_NONE, which means no interleaving — the AVI Mux will simply write the data in the order that it arrives. The INTERLEAVE_FULL flag means the AVI Mux performs full interleaving; however, this mode is less suitable for video capture because it requires the most overheard.

Encoding the Video Stream

You can encode the video stream by inserting an encoder filter between the capture filter and the AVI Mux filter. Use the System Device Enumerator or the Filter Mapper to select an encoder filter. (For more information, see Enumerating Devices and Filters.)

Specify the encoder filter as the fourth parameter to RenderStream, shown in bold in the following example:

IBaseFilter *pEncoder;
/* Create the encoder filter (not shown). */
// Add it to the filter graph.
pGraph->AddFilter(pEncoder, L"Encoder);

/* Call SetOutputFileName as shown previously. */

// Render the stream.
hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, 
    pCap, pEncoder, pMux);
pEncoder->Release();

The encoder filter might support IAMVideoCompression or other interfaces for setting the encoding parameters. For a list of possible interfaces, see File Encoding and Decoding Interfaces.