Using Cutlists

This article summarizes the steps necessary to create and play a cutlist. It also lists the limitations of the current cutlist implementation and provides sample code for using cutlists in an application. For an introduction to cutlists, see What Are Cutlists?.

This article contains the following sections.

To use cutlists, you must first explicitly include the Cutlist.h header file in your project. Then you can create cutlist objects and use the interfaces they expose. The following list summarizes the steps for creating and playing back cutlists in your application. Creating a Video Cutlist presents the example code from this section as one unit rather than many separate fragments.

  1. Create a standard cutlist object (CLSID_SimpleCutList) for each cutlist. Each cutlist can contain only one media type, so if you want both audio and video you must create one standard cutlist for all of your video clips, and one standard cutlist for all of your audio clips.
    CoCreateInstance((REFCLSID)CLSID_SimpleCutList, NULL, CLSCTX_INPROC,
                      (REFIID)IID_IStandardCutList,(void**)&pVCutList);
    
  2. Create a video file clip object (CLSID_VideoFileClip) or an audio file clip object (CLSID_AudioFileClip), as appropriate, for each stream in each AVI or WAV file you will use as the source for clips. If you want to play back both video and audio from the same file, you must still create separate video and audio file clip objects because the file clip objects are based upon one stream (either a video stream or an audio stream) within a file.
    CoCreateInstance((REFCLSID)CLSID_VideoFileClip, NULL, CLSCTX_INPROC,
                      (REFIID)IID_IFileClip, (void**)&pVFileClip);
    
  3. Tell the file clip object what file and stream in that file to use by calling the IFileClip::SetFileAndStream method as follows. The first video and audio streams (stream 0) are the only streams that Microsoft® DirectShow® supports.
    hr = pVFileClip->SetFileAndStream(L"jupiter.avi", 0);
    
  4. Create one or more cutlist elements (individual clips) from each file clip by calling the IFileClip::CreateCut method. Each file clip represents a stream of data, and you can create more than one clip from each data stream. For instance, the example in What Are Cutlists? specifies two elements from Venus.avi, and one element from Mars.avi.
  5. Add each cutlist element to the cutlist by calling the IStandardCutList::AddElement method.

    The following example creates two cutlist elements from the file clip and adds them to the cutlist. The file clip is the first video stream (stream zero) of Jupiter.avi, as specified previously in IFileClip::SetFileAndStream. The first element plays seconds 5 through 10 of Jupiter.avi and the second element plays second 0 through 5 of the same file.

    hr = pVFileClip->CreateCut(&pVElement1,5*SCALE,10*SCALE,0,5*SCALE,0);
    hr = pVCutList->AddElement(pVElement1,CL_DEFAULT_TIME,CL_DEFAULT_TIME);
    hr = pVFileClip->CreateCut(&pVElement2,0,5*SCALE,0,5*SCALE,0);
    hr = pVCutList->AddElement(pVElement2,CL_DEFAULT_TIME,CL_DEFAULT_TIME);
    

    The first three parameters of IFileClip::CreateCut are the important ones. The first, ppElement, specifies the element, and is filled in for you. The second (mtTrimIn) and third (mtTrimOut) specify, respectively, the start and stop times for the clip relative to the original file (Jupiter.avi in this case). The last three parameters must always be zero, mtTrimOut minus mtTrimIn, and zero, respectively. A scale value of 10,000,000 scales the start and stop times to seconds.

    The first parameter in the IStandardCutList::AddElement call, pElement, is the element obtained from the call to IFileClip::CreateCut. The last two parameters must be CL_DEFAULT_TIME to indicate that the element should be added to the end of the current cutlist, and its duration is the same as its duration in the original file.

  6. Create a cutlist graph builder object (CLSID_CutListGraphBuilder) and use it to build a filter graph that will play your cutlists. Give it a standard cutlist object by using the ICutListGraphBuilder::AddCutList method, and then call the ICutListGraphBuilder::Render method to build a filter graph that can play the cutlist. The following code fragment illustrates these calls.
    CoCreateInstance((REFCLSID)CLSID_CutListGraphBuilder,NULL,CLSCTX_INPROC,
    
                      (REFIID)IID_ICutListGraphBuilder,(void**)&pGraphBuilder);
    
    .
    .
    .
    // Give the cutlist to the graph builder.
    hr = pGraphBuilder->AddCutList(pVCutList, NULL);
    
    // Tell the cutlist graph builder to build the graph.
    hr = pGraphBuilder->Render();
    
  7. Play the cutlist filter graph and clean up resources as in the following example. Be sure to stop the graph before you remove the cutlist from the graph using ICutListGraphBuilder::RemoveCutList.
    // Get the filter graph the builder just made.
    hr = pGraphBuilder->GetFilterGraph(&pGraph);
    
    // Now get some useful graph interfaces.
    pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl);
    pGraph->QueryInterface(IID_IMediaEvent, (void**)&pEvent);
    pGraph->Release();
    
    // Run the graph.
    pControl->Run();
    
    // Arbitrarily assumes 10000 millisecond timeout
    pEvent->WaitForCompletion(10000, &lEventCode);
    pControl->Stop();
    pEvent->Release();
    pControl->Release();
    
    // Cleanup
    hr = pGraphBuilder->RemoveCutList(pVCutList);
    pVElement1->Release();
    pVElement2->Release();
    pVCutList->Release();
    pVFileClip->Release();
    pGraphBuilder->Release();
    

To add an element to an existing cutlist after the graph has been rendered, you must call ICutListGraphBuilder::RemoveCutList to remove the cutlist from the filter graph, then call IStandardCutList::AddElement to add the new cutlist element, then call ICutListGraphBuilder::AddCutList to add the cutlist to the filter graph, and then call ICutListGraphBuilder::Render to create the final cutlist filter graph.

See the cutlist examples later in this article for more complete sample code illustrating these steps.

Cutlist Limitations

The following list discusses limitations that you should be aware of when using the current DirectShow cutlist implementation.

Creating a Video Cutlist

The following code creates and plays a cutlist consisting of two video clips from one AVI file. It plays seconds 5 through 10 of the file followed by seconds 0 through 5. The code fragment contains no error checking for the sake of brevity. For an example that performs error checking, see Cutlist Sample Code (Simplecl).

HRESULT              hr;
ICutListGraphBuilder *pGraphBuilder;
IMediaControl        *pControl;
IMediaEvent          *pEvent;
IGraphBuilder        *pGraph;
IStandardCutList     *pVCutList;
IFileClip            *pVFileClip;
IAMCutListElement      *pVElement1, *pVElement2;
LONG                 lEventCode=0L;

CoInitialize(NULL);
// We need these 3 objects.
CoCreateInstance((REFCLSID)CLSID_CutListGraphBuilder,NULL,CLSCTX_INPROC,
                  (REFIID)IID_ICutListGraphBuilder,(void**)&pGraphBuilder);
CoCreateInstance((REFCLSID)CLSID_VideoFileClip, NULL, CLSCTX_INPROC,
                  (REFIID)IID_IFileClip, (void**)&pVFileClip);
CoCreateInstance((REFCLSID)CLSID_SimpleCutList, NULL, CLSCTX_INPROC,
                  (REFIID)IID_IStandardCutList,(void**)&pVCutList);

// Tell the clip what file to use as a source file.
hr = pVFileClip->SetFileAndStream(L"jupiter.avi", 0);

// Create some cutlist elements and add them to the standard cutlist
// from 5 to 10 seconds, then from 0 to 5 seconds.
hr = pVFileClip->CreateCut(&pVElement1,5*SCALE,10*SCALE,0,5*SCALE,0);
hr = pVCutList->AddElement(pVElement1,CL_DEFAULT_TIME,CL_DEFAULT_TIME);
hr = pVFileClip->CreateCut(&pVElement2,0,5*SCALE,0,5*SCALE,0);
hr = pVCutList->AddElement(pVElement2,CL_DEFAULT_TIME,CL_DEFAULT_TIME);

// Give the cutlist to the graph builder.
hr = pGraphBuilder->AddCutList(pVCutList, NULL);

// Tell the cutlist graph builder to build the graph.
hr = pGraphBuilder->Render();

// Get the filter graph the builder just made.
hr = pGraphBuilder->GetFilterGraph(&pGraph);

// Now get some useful graph interfaces.
pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl);
pGraph->QueryInterface(IID_IMediaEvent, (void**)&pEvent);
pGraph->Release();

// Run the graph.
pControl->Run();

// Arbitrarily assumes 10000 millisecond timeout
pEvent->WaitForCompletion(10000, &lEventCode);
pControl->Stop();
pEvent->Release();
pControl->Release();

// Cleanup
hr = pGraphBuilder->RemoveCutList(pVCutList);
pVElement1->Release();
pVElement2->Release();
pVCutList->Release();
pVFileClip->Release();
pGraphBuilder->Release();

CoUninitialize();

// Exit
PostMessage(WM_QUIT, 0, 0);

The preceding example uses video only. The example in the next section uses both audio and video.

Creating Both Video and Audio Cutlists

The following code takes a file name from the command line and plays five different pieces of that AVI file back to back, with both sound and video synchronized. The code fragment contains no error checking for the sake of brevity. See Cutlist Sample Code (Simplecl) for an example that performs error checking.

HRESULT              hr;
ICutListGraphBuilder *pGraphBuilder;
IMediaControl        *pControl;
IMediaEvent          *pEvent;
IGraphBuilder        *pGraph;
IStandardCutList     *pVCutList, *pACutList;
IFileClip            *pAFileClip1;
IFileClip            *pVFileClip1;
IAMCutListElement      *pVElement1;
IAMCutListElement      *pVElement2;
IAMCutListElement      *pVElement3;
IAMCutListElement      *pVElement4;
IAMCutListElement      *pVElement5;
IAMCutListElement      *pAElement1;
IAMCutListElement      *pAElement2;
IAMCutListElement      *pAElement3;
IAMCutListElement      *pAElement4;
IAMCutListElement      *pAElement5;
LONG                 lEventCode=0L;
WCHAR                lpwstr[256];

CoInitialize(NULL);

CoCreateInstance((REFCLSID)CLSID_CutListGraphBuilder,NULL,CLSCTX_INPROC,
                  (REFIID)IID_ICutListGraphBuilder,(void**)&pGraphBuilder);

CoCreateInstance((REFCLSID)CLSID_AudioFileClip, NULL, CLSCTX_INPROC,
                  (REFIID)IID_IFileClip, (void**)&pAFileClip1);

CoCreateInstance((REFCLSID)CLSID_VideoFileClip, NULL, CLSCTX_INPROC,
                  (REFIID)IID_IFileClip, (void**)&pVFileClip1);

CoCreateInstance((REFCLSID)CLSID_SimpleCutList, NULL, CLSCTX_INPROC,
                  (REFIID)IID_IStandardCutList,(void**)&pVCutList);
CoCreateInstance((REFCLSID)CLSID_SimpleCutList, NULL, CLSCTX_INPROC,
                  (REFIID)IID_IStandardCutList,(void**)&pACutList);

// Get the Unicode file name to use from the command line.
MultiByteToWideChar(CP_ACP, 0, m_lpCmdLine, strlen(m_lpCmdLine)+1,
                     lpwstr, sizeof(lpwstr)/sizeof(*lpwstr));

// Tell the clips what file they are reading from.
hr = pVFileClip1->SetFileAndStream(lpwstr, 0);
hr = pAFileClip1->SetFileAndStream(lpwstr, 0);

// Create some cuts and add them the cutlist.

// From 2 to 6 seconds
hr = pVFileClip1->CreateCut(&pVElement1,2*SCALE,6*SCALE,0,4*SCALE,0);
hr = pVCutList->AddElement(pVElement1,CL_DEFAULT_TIME,CL_DEFAULT_TIME);
hr = pAFileClip1->CreateCut(&pAElement1,2*SCALE,6*SCALE,0,4*SCALE,0);
hr = pACutList->AddElement(pAElement1,CL_DEFAULT_TIME,CL_DEFAULT_TIME);

// From 20 to 24 seconds
hr = pVFileClip1->CreateCut(&pVElement2,20*SCALE,24*SCALE,0,4*SCALE,0);
hr = pVCutList->AddElement(pVElement2,CL_DEFAULT_TIME,CL_DEFAULT_TIME);
hr = pAFileClip1->CreateCut(&pAElement2,20*SCALE,24*SCALE,0,4*SCALE,0);
hr = pACutList->AddElement(pAElement2,CL_DEFAULT_TIME,CL_DEFAULT_TIME);

// From 65 to 69 seconds
hr = pVFileClip1->CreateCut(&pVElement3,65*SCALE,69*SCALE,0,4*SCALE,0);
hr = pVCutList->AddElement(pVElement3,CL_DEFAULT_TIME,CL_DEFAULT_TIME);
hr = pAFileClip1->CreateCut(&pAElement3,65*SCALE,69*SCALE,0,4*SCALE,0);
hr = pACutList->AddElement(pAElement3,CL_DEFAULT_TIME,CL_DEFAULT_TIME);

// From 35 to 39 seconds
hr = pVFileClip1->CreateCut(&pVElement4,35*SCALE,39*SCALE,0,4*SCALE,0);
hr = pVCutList->AddElement(pVElement4,CL_DEFAULT_TIME,CL_DEFAULT_TIME);
hr = pAFileClip1->CreateCut(&pAElement4,35*SCALE,39*SCALE,0,4*SCALE,0);
hr = pACutList->AddElement(pAElement4,CL_DEFAULT_TIME,CL_DEFAULT_TIME);

// From 12 to 16 seconds
hr = pVFileClip1->CreateCut(&pVElement5,12*SCALE,16*SCALE,0,4*SCALE,0);
hr = pVCutList->AddElement(pVElement5,CL_DEFAULT_TIME,CL_DEFAULT_TIME);
hr = pAFileClip1->CreateCut(&pAElement5,12*SCALE,16*SCALE,0,4*SCALE,0);
hr = pACutList->AddElement(pAElement5,CL_DEFAULT_TIME,CL_DEFAULT_TIME);

// Add the cutlists to the graph.
hr = pGraphBuilder->AddCutList(pVCutList, NULL);
hr = pGraphBuilder->AddCutList(pACutList, NULL);

// Tell the cutlist graph builder to build the graph.
hr = pGraphBuilder->Render();

// Get the filter graph the builder just made.
hr = pGraphBuilder->GetFilterGraph(&pGraph);

// Now get some useful graph interfaces.
pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl);
pGraph->QueryInterface(IID_IMediaEvent, (void**)&pEvent);
pGraph->Release();

// Run the graph.
pControl->Run();

// Arbitrarily assumes 10000 millisecond timeout
pEvent->WaitForCompletion(10000, &lEventCode);

pControl->Stop();

pEvent->Release();
pControl->Release();

// Cleanup

// Remove the cutlist from the graph.
hr = pGraphBuilder->RemoveCutList(pVCutList);
hr = pGraphBuilder->RemoveCutList(pACutList);

pVElement1->Release();
pVElement2->Release();
pVElement3->Release();
pVElement4->Release();
pVElement5->Release();
pAElement1->Release();
pAElement2->Release();
pAElement3->Release();
pAElement4->Release();
pAElement5->Release();

pACutList->Release();
pVCutList->Release();


pAFileClip1->Release();
pVFileClip1->Release();

pGraphBuilder->Release();

CoUninitialize();

// Exit
PostMessage(WM_QUIT, 0, 0);

The preceding example obtains video and audio clips from the same file. The next example adds a user interface and error checking, and it is available in the Microsoft® DirectX® Media SDK.

Adding a Cutlist Element to an Existing Cutlist

To add an element to an existing cutlist after the graph has been rendered, you must call ICutListGraphBuilder::RemoveCutList to remove the cutlist from the filter graph, then call IStandardCutList::AddElement to add the new cutlist element, then call ICutListGraphBuilder::AddCutList to add the cutlist to the filter graph. Then call ICutListGraphBuilder::Render to create the final cutlist filter graph.

Cutlist Sample Code (Simplecl)

The Simplecl Sample (Cutlist Application) (Simplecl) from the DirectX Media SDK demonstrates how to create and play back cutlists. By default, the DirectShow setup program installs Simplecl in the DXMedia\Samples\Multimedia\DShow\Src\Cutlist\Simplecl directory. Simplecl provides a File Open dialog box from which the user can chose a file to add to a cutlist. For each file, the user specifies a starting (trimin) position for the clip and an ending (trimout) position for the clip. For every AVI file specified, the sample tries to add the first video stream and the first audio stream to its respective cutlist. The user must add at least two files, and then can run the filter graph and see the clips played sequentially.

The DirectX Media SDK also includes a sample that reads a list of cuts from a text file and plays them, much like Simplecl does. That sample, Cltext, is installed in the DXMedia\Samples\Multimedia\DShow\Src\Cutlist\Cltext directory by default.

The following code excerpts are from the Simplecl.h and Simplecl.cpp sample files. The sample includes error checking.

Simplecl.h declares a few global variables, including a ClipDetails structure to manage the user's file and clip start and stop time choices, and a ClipCollection structure to group the clip details. It also defines a SCALE constant to scale all user-specified times in one-second increments. The HELPER_RELEASE macro releases objects only if they exist, and then sets the object pointer to NULL to guard against releasing the same object multiple times. The following example contains fragments from Simplecl.h.

#define MAX_CLIPS 150
#define SCALE 10000000   // scale for 1 second of reference time

// Clip (element) details
struct ClipDetails  
  {   
    TCHAR szFilename[MAX_PATH];   // name of file containing clip
    REFERENCE_TIME start;         // start (Trim In) position of clip within file
    REFERENCE_TIME stop;          // stop (Trim Out) position of clip within file
  }; 

// Cutlist is a collection of clips (elements).
struct ClipCollection
  { 
    int nNumClips;
    ClipDetails List[MAX_CLIPS];
  }; 

#define HELPER_RELEASE(x) { if (x) x->Release(); x = NULL; }

ClipCollection  gTheSet;            // cutlist 

The application initializes the user input structure as follows:

// ... in WinMain ...
ZeroMemory(&gTheSet, sizeof gTheSet);

Simplecl keeps track of the name of the media file that the user chooses as the source of a clip, tracks the number of files chosen, and displays a dialog box for the user to enter the start and stop times for each clip. The following code fragments relate to tracking the user input for clips:

// ... in WndMainProc ...

case IDM_ADDFILE:

  if (GetClipFileName(gTheSet.List[gTheSet.nNumClips].szFilename))

    { // Add file.

      TCHAR szTitleBar[200];

      DialogBox(ghInst, MAKEINTRESOURCE(wDlgRes = IDD_MEDIATIMES), 
                                        ghApp, (DLGPROC)DialogProc);
      gTheSet.nNumClips = gTheSet.nNumClips + 1;
      wsprintf(szTitleBar, "SimpleCutList - %d clips(s) added.", 
               gTheSet.nNumClips);
      SetWindowText(ghApp, szTitleBar);

    } // Add file.

.
.
.
// ... in DialogProc ...
case IDOKTIMES:

  gTheList.List[gTheSet.nNumClips].start = GetDlgItemInt(h, 
                                           IDC_TRIMIN2, NULL, FALSE);
  gTheList.List[gTheSet.nNumClips].stop = GetDlgItemInt(h, 
                                          IDC_TRIMOUT2, NULL, FALSE);

  EndDialog(h,1);
  break;

The real work of the Simplecl sample is in the SimpleCutList function. If the user has chosen more than one clip, and then chooses Run from the Cutlist menu, then Simplecl builds and plays the cutlist. The following code checks the number of clips chosen, and calls SimpleCutList if more than one clip was chosen.

case IDM_RUN:
  if (gTheSet.nNumClips > 1)
    SimpleCutList();
  else
    DialogBox(ghInst, MAKEINTRESOURCE(wDlgRes = IDD_LESSTHAN2), 
              ghApp, (DLGPROC)DialogProc);
  break;

After the user has entered the file and clip choices, the SimpleCutList function creates and plays the cutlist as follows:

  void SimpleCutList ()

    { // SimpleCutList //

      WCHAR wFile[MAX_PATH];  // file name

      // Initialize video and audio file clips and elements to NULL
      // so you can easily free objects later.
      for (int x = 0; x < MAX_CLIPS; ++x)

        { 
          pVidFileClip[x] = NULL; 
          pAudFileClip[x] = NULL; 
            pVidCLElem[x] = NULL; 
            pAudCLElem[x] = NULL; 
        };

      // Create cutlist graph builder object.
      hr = CoCreateInstance(CLSID_CutListGraphBuilder, NULL, 
                            CLSCTX_INPROC, IID_ICutListGraphBuilder, 
                            (void**)&pCLGraphBuilder);

      if (FAILED(hr))
        { // CoCreateInstance of CutListGraphBuiler failed.
          MessageBox(ghApp, 
                     "CoCreateInstance of CutListGraphBuiler failed",
                     APPLICATIONNAME, MB_OK);
          TearDownTheGraph();
          return;
        } // CoCreateInstance of CutListGraphBuiler failed.

      // Create simple (standard) cutlist object for video.
      hr = CoCreateInstance(CLSID_SimpleCutList, NULL, 
                            CLSCTX_INPROC, IID_IStandardCutList, 
                            (void**)&pVideoCL);

      if (FAILED(hr))
        { // CoCreateInstance of video SimpleCutList failed.
          MessageBox(ghApp, 
                     "CoCreateInstance of video SimpleCutList failed",
                     APPLICATIONNAME, MB_OK);
          TearDownTheGraph();
          return;
        } // CoCreateInstance of video SimpleCutList failed.

      // Create simple (standard) cutlist object for audio.
      hr = CoCreateInstance(CLSID_SimpleCutList, NULL, 
                            CLSCTX_INPROC, IID_IStandardCutList, 
                            (void**)&pAudioCL);

      if (FAILED(hr))
        { // CoCreateInstance of audio SimpleCutList failed.
          MessageBox(ghApp, 
                     "CoCreateInstance of audio SimpleCutList failed",
                     APPLICATIONNAME, MB_OK);
          TearDownTheGraph();
          return;
        } // CoCreateInstance of audio SimpleCutList failed.

      // Create the individual clips and add them to the cutlist.
      nVidElems = nAudElems = 0;
      for (x = 0; x < gTheSet.nNumClips; ++x)

        { // Individual clips

          MultiByteToWideChar(CP_ACP, 0, 
                              gTheSet.List[x].szFilename, 
                              -1, wFile, MAX_PATH );

          // Create a video clip object and give it the file and stream 
          // to read from.
          // SetFileAndStream will fail if you call it from a video clip 
          // object and the clip is not a video clip.
          hr = CoCreateInstance(CLSID_VideoFileClip, NULL, 
                                CLSCTX_INPROC, IID_IFileClip, 
                                (void**)&pVidFileClip[nVidElems]);

          hr = pVidFileClip[nVidElems]->SetFileAndStream(wFile, 0);

          if (SUCCEEDED(hr))

            { // Create video cut and add the clip (element) to the cutlist.

              hr = pVidFileClip[nVidElems]->CreateCut(&pVidCLElem[nVidElems], 
                      gTheSet.List[x].start*SCALE, 
                      gTheSet.List[x].stop*SCALE, 
                      0, 
                      (gTheSet.List[x].stop-gTheSet.List[x].start)*SCALE, 
                      0);

              if (SUCCEEDED(hr))

                { // Add the element to the cutlist.

                  hr = pVideoCL->AddElement(pVidCLElem[nVidElems], CL_DEFAULT_TIME, 
                      CL_DEFAULT_TIME);


                  if (SUCCEEDED(hr))
                    ++nVidElems;

                  else

                    { // AddElement failed so release associated objects.

                      HELPER_RELEASE(pVidCLElem[nVidElems]);
                      HELPER_RELEASE(pVidFileClip[nVidElems]);
                      MessageBox(ghApp, "AddElement (video) failed!", APPLICATIONNAME, MB_OK);

                    } // AddElement failed so release associated objects.
                } // Add the element to the cutlist.

              else MessageBox(ghApp, "CreateCut (video) failed!", APPLICATIONNAME, MB_OK);

            } // Create video cut.

          else 

            { // Problems creating video stream

              HELPER_RELEASE(pVidFileClip[nVidElems]);
              MessageBox(ghApp, "SetFileAndStream (video) failed!", APPLICATIONNAME, MB_OK);

            } // Problems creating video stream

          // Create an audio clip object and give it the file and stream 
          // to read from.
          // SetFileAndStream will fail if you call it from an audio clip 
          // object and the clip is not an audio clip.
          hr = CoCreateInstance(CLSID_AudioFileClip, NULL, 
                                CLSCTX_INPROC, IID_IFileClip, 
                                (void**)&pAudFileClip[nAudElems]);

          hr = pAudFileClip[nAudElems]->SetFileAndStream(wFile, 0);

          if (SUCCEEDED(hr))

            { // Create audio cut and add the clip (element) to the cutlist.

              hr = pAudFileClip[nAudElems]->CreateCut(&pAudCLElem[nAudElems], 
                      gTheSet.List[x].start*SCALE, 
                      gTheSet.List[x].stop*SCALE, 
                      0, 
                      (gTheSet.List[x].stop-gTheSet.List[x].start)*SCALE, 
                      0);

              if (SUCCEEDED(hr))

                { // Add the element to the cutlist.

                  hr = pAudioCL->AddElement(pAudCLElem[nAudElems],
                                            CL_DEFAULT_TIME, 
                                            CL_DEFAULT_TIME);

                  if (SUCCEEDED(hr))
                    ++nAudElems;

                  else 

                   { // AddElement failed so release associated objects.

                      HELPER_RELEASE(pAudCLElem[nAudElems]);
                      HELPER_RELEASE(pAudFileClip[nAudElems]);
                      MessageBox(ghApp, "AddElement (audio) failed!", APPLICATIONNAME, MB_OK);

                    } // AddElement failed so release associated objects.

                } // Add the element to the cutlist.

              else MessageBox(ghApp, "CreateCut (audio) failed!", APPLICATIONNAME, MB_OK);

            } // Create audio cut.

          // Problems creating audio stream
          else 

            { // Problems creating audio stream

              HELPER_RELEASE(pAudFileClip[nAudElems]);
              MessageBox(ghApp, "SetFileAndStream (audio) failed!", APPLICATIONNAME, MB_OK);

            } // Problems creating audio stream

        } // Individual clips

      // Add the video cutlist to the filter graph.
      hr = pCLGraphBuilder->AddCutList(pVideoCL, NULL);

      if (FAILED(hr)) // AddCutList (video) failed
          MessageBox(ghApp, "AddCutList (video) failed", APPLICATIONNAME, MB_OK);

      // Add the audio cutlist to the filter graph.
      hr = pCLGraphBuilder->AddCutList(pAudioCL, NULL);

      if (FAILED(hr)) // AddCutList (audio) failed
          MessageBox(ghApp, "AddCutList (audio) failed", APPLICATIONNAME, MB_OK);

      if ((!pVideoCL) && (!pAudioCL))

        { // Clean up

          TearDownTheGraph();
          return;

        } // Clean up

      // Let the filter graph manager construct the appropriate graph 
      // automatically.
      hr = pCLGraphBuilder->Render();

      if (FAILED(hr))
        { // Problems rendering the graph
          if (!AMGetErrorText(hr, gszScratch, 2048))
            MessageBox(ghApp, "Problems rendering the graph!", APPLICATIONNAME, MB_OK);
          else 
            MessageBox(ghApp, gszScratch, APPLICATIONNAME, MB_OK);
          TearDownTheGraph();
          return;
        } // Problems rendering the graph

      // Retrieve the filter graph and useful interfaces.
      hr = pCLGraphBuilder->GetFilterGraph(&pigb);

      if (FAILED(hr))
        { // Problems retrieving the graph pointer
          if (!AMGetErrorText(hr, gszScratch, 2048))
            MessageBox(ghApp, "Problems retrieving the graph pointer!", APPLICATIONNAME, MB_OK);
          else 
            MessageBox(ghApp, gszScratch, APPLICATIONNAME, MB_OK);
          TearDownTheGraph();
          return;
        } // Problems retrieving the graph pointer

      // QueryInterface for some basic interfaces
      pigb->QueryInterface(IID_IMediaControl, (void **)&pimc);
      pigb->QueryInterface(IID_IMediaEventEx, (void **)&pimex);
      pigb->QueryInterface(IID_IVideoWindow, (void **)&pivw);

      // Decrement the ref count on the filter graph.
      pigb->Release();

      // Prepare to play in the main application window's client area.

      RECT rc;
      GetClientRect(ghApp, &rc);
      hr = pivw->put_Owner((OAHWND)ghApp);
      hr = pivw->put_WindowStyle(WS_CHILD|WS_CLIPSIBLINGS);
      hr = pivw->SetWindowPosition(rc.left, rc.top, rc.right, rc.bottom);

      // Have the graph signal event via window callbacks for performance.
      pimex->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0);

      // Run the graph if RenderFile succeeded.
      pimc->Run();

    } // SimpleCutList //

Simplecl's TearDownTheGraph function releases all objects and cleans up as follows.

 void TearDownTheGraph (void)

    { // TearDownTheGraph //

      if (pimc)
        pimc->Stop();

      if (pivw)

        { // Hide the playback window first thing.

          pivw->put_Visible(OAFALSE);
          pivw->put_Owner(NULL);

        } //

      HELPER_RELEASE(pimex);
      HELPER_RELEASE(pimc);
      HELPER_RELEASE(pivw);

      // Remove the video cutlist from the filter graph to free resources.
      if (pCLGraphBuilder && pVideoCL)
        pCLGraphBuilder->RemoveCutList(pVideoCL);

      // Remove the audio cutlist from the filter graph to free resources.
      if (pCLGraphBuilder && pAudioCL)
        pCLGraphBuilder->RemoveCutList(pAudioCL);

      for (int x = 0; x < nAudElems; ++x)

        { // Release audio objects.

          HELPER_RELEASE(pAudCLElem[x]);
          HELPER_RELEASE(pAudFileClip[x]);

        } // Release audio objects.

      for (x = 0; x < nVidElems; ++x)

        { // Release video objects.

          HELPER_RELEASE(pVidCLElem[x]);
          HELPER_RELEASE(pVidFileClip[x]);

        } // Release video objects.

      HELPER_RELEASE(pVideoCL);
      HELPER_RELEASE(pAudioCL);      
      HELPER_RELEASE(pCLGraphBuilder);

    } // TearDownTheGraph //

Top of Page Top of Page
© 2000 Microsoft and/or its suppliers. All rights reserved. Terms of Use.