This article introduces cutlists, discusses interfaces that provide cutlist support and the limitations of the current cutlist implementation, and provides sample code for using cutlists in an application.
Contents of this article:
Introduction to Cutlists
A cutlist is a list of audio or video clips (cutlist elements) you want to play back sequentially. For each clip, the cutlist element contains the file name from which to create the clip, and details about the clip including start and stop time within that file. A cutlist is either video- or audio- specific, and that video or audio data must all be of the same media type. The beginning time for the clip, relative to the source file, is called the trimin position and the ending time for the clip is the trimout position.
You use cutlists to edit pieces of AVI and WAV files together. For instance a video cutlist could be made up of video clips with characteristics as follows:
Clip # | File Name | Start Time | Stop Time | Type | Stream # |
1 | venus.avi | 5 seconds | 10 seconds | video | 0 |
2 | mars.avi | 15 seconds | 20 seconds | video | 0 |
3 | venus.avi | 15 seconds | 30 seconds | video | 0 |
In the example above, the first and third clips are both taken from the same file. One clip is from seconds 5 through 10 of Venus.avi while another is from seconds 15 through 30 of the same file. Between those clips, the cutlist contains seconds 15 through 20 of Mars.avi. All clips are taken from the first video stream (stream 0) in their respective files. The clips play back sequentially (1, 2, and then 3).
Each of the three clips is referred to as a "cutlist element", and the whole thing is referred to as the "cutlist".
Cutlist Objects and Interfaces
DirectShow defines the following objects that implement the specified interfaces. Applications use these objects and interfaces to create, manipulate, and play cutlists.
Object | Supported Interfaces | Description |
CLSID_SimpleCutList | IStandardCutList | Cutlist object |
CLSID_VideoFileClip | IFileClip | Cutlist element (individual clip) object for video |
CLSID_AudioFileClip | IFileClip | Cutlist element (individual clip) object for audio |
CLSID_CutListGraphBuilder | ICutListGraphBuilder | Cutlist graph builder object |
These interfaces allow application writers to construct filter graphs without having to worry about the specifics of each cutlist object. They provide a simple way to create and manipulate cutlists, and to create a filter graph to play an edited movie in real time.
If you need more advanced cutlist functionality that is not provided by the above interfaces, see the following interfaces.
The following section discusses how to use cutlists.
Using Cutlists
Create cutlist objects and use the interfaces they expose in order to use cutlists. The following list summarizes the steps in using cutlists in your application. Cutlist Example 1 -- Video Only presents the example code from this section as one unit rather than many separate fragments.
CoCreateInstance((REFCLSID)CLSID_SimpleCutList, NULL, CLSCTX_INPROC, (REFIID)IID_IStandardCutList,(void**)&pVCutList);
CoCreateInstance((REFCLSID)CLSID_VideoFileClip, NULL, CLSCTX_INPROC, (REFIID)IID_IFileClip, (void**)&pVFileClip);
hr = pVFileClip->SetFileAndStream(L"jupiter.avi", 0);
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 five through ten of Jupiter.avi and the second element plays second zero through five 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 always have to 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.
CoCreateInstance((REFCLSID)CLSID_CutListGraphBuilder,NULL,CLSCTX_INPROC, (REFIID)IID_ICutListGraphBuilder,(void**)&pGraphBuilder); . . . // Give the cutlist to the graph builder hr = pGraphBuilder->AddCutList(pVCutList); // 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();
See the cutlist examples later in this article for more complete sample code illustrating these steps.
Cutlist Limitations
The following list discusses limitations of which you should be aware when using the current cutlist implementation.
For video cutlists, this means all the video clips must be of the same compression type, size, dimensions, bit depth, and so forth. In other words all video clips in the cutlist must be represented by the same BITMAPINFOHEADER structure. For audio cutlists, this means they must all use the same compression format, sampling rate, bit depth, and number of channels. In other words all audio clips in the cutlist must be represented by the same WAVEFORMATEX structure.
The first clip you add to a cutlist determines the media type of the cutlist, and the media type required for all other clips you add to the cutlist. IStandardCutList::AddElement returns an invalid media type error (VFW_E_INVALIDMEDIATYPE) if you attempt to add a clip of a different media type to an existing cutlist.
Cutlist Example 1 -- Video Only
The following code creates and plays a cutlist consisting of two video clips from one AVI file. It plays seconds five through ten of the file followed by seconds zero through five. The code fragment contains no error checking for the sake of brevity. See Simple Cutlist (Simplecl) SDK Sample for an example that performs error checking.
HRESULT hr; ICutListGraphBuilder *pGraphBuilder; IMediaControl *pControl; IMediaEvent *pEvent; IGraphBuilder *pGraph; IStandardCutList *pVCutList; IFileClip *pVFileClip; ICutListElement *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); // 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 example above uses video only. The example in the next section uses both audio and video.
Cutlist Example 2 -- Video and Audio
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 Simple Cutlist (Simplecl) SDK Sample for an example that performs error checking.
HRESULT hr; ICutListGraphBuilder *pGraphBuilder; IMediaControl *pControl; IMediaEvent *pEvent; IGraphBuilder *pGraph; IStandardCutList *pVCutList, *pACutList; IFileClip *pAFileClip1; IFileClip *pVFileClip1; ICutListElement *pVElement1; ICutListElement *pVElement2; ICutListElement *pVElement3; ICutListElement *pVElement4; ICutListElement *pVElement5; ICutListElement *pAElement1; ICutListElement *pAElement2; ICutListElement *pAElement3; ICutListElement *pAElement4; ICutListElement *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 filename 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); hr = pGraphBuilder->AddCutList(pACutList); // 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 example above 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 DirectShow SDK.
Simple Cutlist (Simplecl) SDK Sample
The simple cutlist (Simplecl) sample from the DirectShow SDK demonstrates using cutlists. By default, the DirectShow setup program installs Simplecl in the DXMedia\Samples\DS\cutlist\simplecl directory. Simplecl provides a File Open dialog 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 it 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 DirectShow SDK also includes a sample which reads a list of cuts from a text file and plays them, much like Simplecl does. That sample is called Cltext, and is installed in the DXMedia\Samples\DS\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(&gTheList, sizeof gTheList);
Simplecl keeps track of the name of the media file the user chooses as the source of a clip, tracks the number of files chosen, and displays a dialog box for the user to input 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;
Once the user has entered their file and clip choices, the SimpleCutList function does the cutlist work as follows.
void SimpleCutList () { // SimpleCutList // WCHAR wFile[MAX_PATH]; // file name // Initialize video and audio file clips and elements to NULL // so we 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 we 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 (FAILED(hr)) MessageBox(ghApp, "AddElement (video) failed!", APPLICATIONNAME, MB_OK); else ++nVidElems; } // Add the element to the cutlist else MessageBox(ghApp, "CreateCut (video) failed!", APPLICATIONNAME, MB_OK); } // Create video cut // Problems creating video stream else MessageBox(ghApp, "SetFileAndStream (video) failed!", APPLICATIONNAME, MB_OK); // Create an audio clip object and give it the file and stream // to read from. // SetFileAndStream will fail if we 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 MessageBox(ghApp, "AddElement (audio) failed!", APPLICATIONNAME, MB_OK); } // Add the element to the cutlist else MessageBox(ghApp, "CreateCut (audio) failed!", APPLICATIONNAME, MB_OK); } // Create audio cut // Problems creating audio stream else MessageBox(ghApp, "SetFileAndStream (audio) failed!", APPLICATIONNAME, MB_OK); } // Individual clips // Add the video cutlist to the filter graph hr = pCLGraphBuilder->AddCutList(pVideoCL); 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); 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 HELPER_RELEASE(pigb); // 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.
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(pCLGraphBuilder); HELPER_RELEASE(pVideoCL); HELPER_RELEASE(pAudioCL); HELPER_RELEASE(pigb); } // TearDownTheGraph //
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.