Microsoft DirectX 8.0

Loading and Previewing a Project

This article describes how to load and preview a project file with Microsoft® DirectShow® Editing Services (DES). It presents a sample application that loads an XML project file into an empty timeline and renders the timeline for preview. You can modify the sample application to work with any example XML project file that ships with this SDK.

This article contains the following topics.

Loading a Project File

To load a project file, you need two components: the XML parser and an empty timeline. The XML parser reads an XML project file and creates each object defined in the file. Then it inserts the objects into the timeline and sets any timeline attributes, such as the default frame rate. The following code example loads a file.

HRESULT         hr;
IAMTimeline     *pTL = NULL;
IXml2Dex        *pXML = NULL; 

hr = CoCreateInstance(CLSID_AMTimeline, NULL, CLSCTX_INPROC_SERVER, 
            IID_IAMTimeline, (void**)&pTL);

hr = CoCreateInstance(CLSID_Xml2Dex, NULL, CLSCTX_INPROC_SERVER, 
            IID_IXml2Dex, (void**)&pXML);

hr = pXML->ReadXMLFile(pTL, L"C:\\example.xtl"); 
pXML->Release();

The parser exposes the IXml2Dex interface, which contains methods for loading and saving project files. The timeline exposes the IAMTimeline interface, which contains methods for manipulating the timeline and creating new timeline objects. Call the CoCreateInstance function to create each component, as shown. Remember that by creating a new instance, you are incrementing the reference count on the interface. To avoid memory leaks, always release an interface when you are through with it. In this example, the pointer to IXml2Dex is not needed for anything more, so you can release the interface. The pointer to IAMTimeline is still needed for previewing the timeline.

The IXml2Dex::ReadXMLFile method reads the specified file and populates the timeline with the objects defined in the file. The file name is specified using a BSTR value. To shorten the example, the file name in the example is given as a literal string. Normally, you obtain it from an Open File dialog or something similar.

If the ReadXML method is successful, it returns a success code. Otherwise, it returns an error code such as VFW_E_INVALID_FILE_FORMAT. Always check the return value, in order to handle error conditions gracefully. Again for brevity, the example code does not check for errors.

Previewing the Project

To preview the project, you need a component called a render engine, which builds a DirectShow filter graph from a timeline. The filter graph is what actually renders the project. You can use the render engine to preview a project or to write the final output file.

This article does not go into detail about the render engine. For preview, you only need a few method calls. You can find a more thorough discussion, including how to write output files, in Rendering a Project. The following code example shows how to construct a preview graph.

IRenderEngine *pRender = NULL; 
hr = CoCreateInstance(CLSID_RenderEngine, NULL, CLSCTX_INPROC_SERVER,
            IID_IRenderEngine, (void**) &pRender);

hr = pRender->SetTimelineObject(pTL);
hr = pRender->ConnectFrontEnd( );
hr = pRender->RenderOutputPins( );

Create the render engine using the CoCreateInstance function. Then call the following methods on the render engine's IRenderEngine interface:

Once the graph is built, you can preview the project by running the graph, as you would with any DirectShow filter graph. First, obtain a pointer to the filter graph by calling the IRenderEngine::GetFilterGraph method.

IGraphBuilder   *pGraph = NULL;
hr = pRender->GetFilterGraph(&pGraph);

Query the filter graph for the IMediaControl and IMediaEvent interfaces. Use these two interfaces to run the graph and wait for playback to complete. For an explanation of how to use these interfaces, see How to Play a File and Responding to Events. The following code shows one way to use these interfaces.

IMediaControl   *pControl = NULL;
IMediaEvent     *pEvent = NULL;
long evCode;

pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
hr = pControl->Run();
hr = pEvent->WaitForCompletion(INFINITE, &evCode);
pControl->Stop();

The code in this example blocks program execution until playback completes, because of the INFINITE parameter in the IMediaEvent::WaitForCompletion method call. If something goes wrong during playback, however, it could cause the program to stop responding. In a real application, use a message loop to wait for playback to complete. It's also recommended that you provide the user with a way to interrupt playback.

Cleaning Up

When you finish using the render engine, always call the IRenderEngine::ScrapIt method. This method deletes the filter graph and releases any resources held by the render engine.

pRender->ScrapIt();

Sample Code

The following is the complete code for the sample application described in this article.

#include <dshow.h>
#include <qedit.h>

// Preview a timeline.
void PreviewTL(IAMTimeline *pTL, IRenderEngine *pRender) 
{
    HRESULT hr;
    IGraphBuilder   *pGraph = NULL;
    IMediaControl   *pControl = NULL;
    IMediaEvent     *pEvent = NULL;

    // Build the graph.
    hr = pRender->SetTimelineObject(pTL);
    hr = pRender->ConnectFrontEnd( );
    hr = pRender->RenderOutputPins( );

    // Run the graph.
    hr = pRender->GetFilterGraph(&pGraph);
    pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
    pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
    hr = pControl->Run();

    long evCode;
    hr = pEvent->WaitForCompletion(INFINITE, &evCode);
    pControl->Stop();

    // Clean up.
    pEvent->Release();
    pControl->Release();
    pGraph->Release();
}

void main( void )
{
    HRESULT         hr;
    IAMTimeline     *pTL = NULL;
    IRenderEngine   *pRender = NULL; 
    IXml2Dex        *pXML = NULL; 

    CoInitialize(NULL);
    hr = CoCreateInstance(CLSID_AMTimeline, NULL, CLSCTX_INPROC_SERVER, 
                IID_IAMTimeline, (void**)&pTL);
    hr = CoCreateInstance(CLSID_Xml2Dex, NULL, CLSCTX_INPROC_SERVER, 
                IID_IXml2Dex, (void**)&pXML);
    hr = CoCreateInstance(CLSID_RenderEngine, NULL, CLSCTX_INPROC_SERVER,
                IID_IRenderEngine, (void**)&pRender);

    // Load a project file.
    hr = pXML->ReadXMLFile(pTL, L"C:\\example.xtl"); 
    pXML->Release();

    PreviewTL(pTL, pRender);

    // Clean up.    
    pRender->ScrapIt();
    pTL->Release();
    pRender->Release();
    CoUninitialize();
}