//=========================================================================
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1996 - 1997 Microsoft Corporation. All Rights Reserved.
//
//=========================================================================
#include <windows.h>
#include <streams.h>
#include <strmif.h>
#include <cutlist.h>
#include <stdio.h>
#include "cltext.h"
ICutListGraphBuilder *pCLGraphBuilder = NULL;
IStandardCutList *pVideoCL = NULL;
IStandardCutList *pAudioCL = NULL;
IGraphBuilder *pigb = NULL;
IMediaControl *pimc = NULL;
IMediaEventEx *pimex = NULL;
IVideoWindow *pivw = NULL;
IMediaSeeking *pims = NULL;
IFileClip *pVidFileClip[MAX_CLIPS];
IFileClip *pAudFileClip[MAX_CLIPS];
IAMCutListElement *pVidCLElem[MAX_CLIPS];
IAMCutListElement *pAudCLElem[MAX_CLIPS];
HRESULT hr;
int nVidElems, nAudElems;
void CutlistFromTextfile ()
{ // CutlistFromTextfile //
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
MBOX("CoCreateInstance of CutListGraphBuiler failed");
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 CutlistFromTextfile failed
MBOX("CoCreateInstance of video CLSID_SimpleCutList failed");
TearDownTheGraph();
return;
} // CoCreateInstance of video CLSID_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 CutlistFromTextfile failed
MBOX("CoCreateInstance of audio CLSID_SimpleCutList failed");
TearDownTheGraph();
return;
} // CoCreateInstance of audio CutlistFromTextfile 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 (SUCCEEDED(hr))
++nVidElems;
else
{ // AddElement failed so release associated objects
HELPER_RELEASE(pVidCLElem[nVidElems]);
HELPER_RELEASE(pVidFileClip[nVidElems]);
MBOX("AddElement (video) failed!");
} // AddElement failed so release associated objects
} // Add the element to the cutlist
else MBOX("CreateCut (video) failed!");
} // Create video cut
else
{ // Problems creating video stream
HELPER_RELEASE(pVidFileClip[nVidElems]);
MBOX("SetFileAndStream (video) failed!");
} // Problems creating video stream
// 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
{ // AddElement failed so release associated objects
HELPER_RELEASE(pAudCLElem[nAudElems]);
HELPER_RELEASE(pAudFileClip[nAudElems]);
MBOX("AddElement (audio) failed!");
} // AddElement failed so release associated objects
} // Add the element to the cutlist
else MBOX("CreateCut (audio) failed!");
} // Create audio cut
else
{ // Problems creating audio stream
HELPER_RELEASE(pAudFileClip[nAudElems]);
MBOX("SetFileAndStream (audio) failed!");
} // 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
MBOX("AddCutList (video) failed");
// Add the audio cutlist to the filter graph
hr = pCLGraphBuilder->AddCutList(pAudioCL, NULL);
if (FAILED(hr)) // AddCutList (audio) failed
MBOX("AddCutList (audio) failed");
if ((!gTheSet.nNumClips) || (!pVideoCL) && (!pAudioCL))
{ // Clean up
TearDownTheGraph();
return;
} // Clean up
// Let the filter graph manager construct the the appropriate graph
// automatically
hr = pCLGraphBuilder->Render();
if (FAILED(hr))
{ // Problems rendering the graph
if (!AMGetErrorText(hr, gszScratch, 2048))
MBOX("Problems rendering the graph!");
else
MBOX(gszScratch);
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))
MBOX("Problems retrieving the graph pointer!");
else
MBOX(gszScratch);
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);
pigb->QueryInterface(IID_IMediaSeeking, (void **)&pims);
// 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);
hr = pims->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
hr = pims->GetDuration(&glTotalLength);
SetScrollRange(ghApp, SB_HORZ, 0, 100, TRUE);
//Ready to rumble...
pimc->Run();
} // CutlistFromTextfile //
void TearDownTheGraph (void)
{ // TearDownTheGraph //
if (gTimerNum)
timeKillEvent(gTimerNum);
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);
HELPER_RELEASE(pims);
// 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);
gTheSet.nNumClips = 0;
} // TearDownTheGraph //
BOOL GetCliplistTxtFilename (LPSTR szName)
{ // GetCliplistTxtFilename //
OPENFILENAME ofn;
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = ghApp;
ofn.lpstrFilter = NULL;
ofn.lpstrFilter = "Text Files (clip list) (*.txt)\0*.txt\0\0\0";
ofn.lpstrCustomFilter = NULL;
ofn.nFilterIndex = 1;
*szName = 0;
ofn.lpstrFile = szName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = NULL;
ofn.lpstrFileTitle = NULL;
ofn.lpstrDefExt = "TXT";
ofn.Flags = OFN_FILEMUSTEXIST | OFN_READONLY | OFN_PATHMUSTEXIST;
return GetOpenFileName((LPOPENFILENAME)&ofn);
} // GetCliplistTxtFilename //
LRESULT CALLBACK WndMainProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ // WndMainProc //
LONGLONG l;
switch(message)
{ // Window msgs handling
case WM_COMMAND:
switch(wParam)
{ // Program menu option
case ID_FILE_EXIT:
if (gTheSet.nNumClips)
TearDownTheGraph();
PostQuitMessage(0);
break;
case ID_CUTLIST_PLAY:
l = 0;
hr = pimc->Stop();
hr = pims->SetPositions(&l, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
hr = pimc->Run();
break;
} // Program menu option
break;
case WM_HSCROLL:
if (SB_THUMBPOSITION == LOWORD(wParam))
{ // Seeking via horiz. scroll
l = (glTotalLength * (LONGLONG)HIWORD(wParam))/100;
pimc->Stop();
hr = pims->SetPositions(&l, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
pimc->Run();
} // Seeking via horiz. scroll
break;
case WM_EXITSIZEMOVE:
RECT rc;
GetClientRect(ghApp, &rc);
if (pivw)
pivw->SetWindowPosition(rc.left, rc.top, rc.right, rc.bottom);
break;
case WM_SIZE:
if ((SIZE_RESTORED == wParam) || (SIZE_MAXIMIZED == wParam))
PostMessage(ghApp, WM_EXITSIZEMOVE, 0, 0);
break;
case WM_DESTROY:
if (gTheSet.nNumClips)
TearDownTheGraph();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
} // Window msgs handling
return FALSE;
} // WndMainProc //
void ReadTextFile (LPCSTR cFilename)
{ // ReadTextFile //
FILE *fp;
TCHAR cString[MAX_PATH];
if (!(fp = fopen(cFilename, "rt")))
return; // File not found!
while (!feof(fp) && (gTheSet.nNumClips < MAX_CLIPS))
{ // Parse individual lines
ZeroMemory(cString, MAX_PATH);
fgets(cString, MAX_PATH, fp);
if (lstrlen(cString) && (cString[0] != TCHAR(';')))
{ // Decipher filename, start, stop times
int i = lstrlen(cString);
while (i && (cString[i] != TCHAR(','))) --i;
gTheSet.List[gTheSet.nNumClips].stop = atol(&cString[i+1]); --i;
while (i && (cString[i] != TCHAR(','))) --i;
gTheSet.List[gTheSet.nNumClips].start = atol(&cString[i+1]);
cString[i] = TCHAR('\0');
lstrcpy(gTheSet.List[gTheSet.nNumClips].szFilename, cString);
gTheSet.nNumClips += 1;
} // Deciphering
} // Parse individual lines
fclose(fp);
} // ReadTextFile //
void CALLBACK TimerProc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{ // TimerProc //
LONGLONG lPos;
if (pims)
pims->GetCurrentPosition(&lPos);
lPos = (lPos * 100)/glTotalLength;
SetScrollPos(ghApp, SB_HORZ, (int)lPos, TRUE);
} // TimerProc //
int PASCAL WinMain(HINSTANCE hInstC, HINSTANCE hInstP, LPSTR lpCmdLine, int nCmdShow)
{ // WinMain //
MSG msg;
WNDCLASS wc;
// OLE subsystem requires applications to initialize things first!
CoInitialize(NULL);
ZeroMemory(&wc, sizeof wc);
wc.lpfnWndProc = WndMainProc;
ghInst = wc.hInstance = hInstC;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = CLASSNAME;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(hInstC, MAKEINTRESOURCE(IDI_CUTLIST));
RegisterClass(&wc);
RECT rc;
GetWindowRect(GetDesktopWindow(), &rc);
rc.right >>= 1;
rc.bottom >>= 1;
ghApp = CreateWindow(CLASSNAME,
APPLICATIONNAME,
WS_OVERLAPPEDWINDOW|WS_HSCROLL,
rc.right-200,
rc.bottom-200,
400,
400,
0,
0,
ghInst,
0);
SetMenu(ghApp, ghMenu = LoadMenu(hInstC, MAKEINTRESOURCE(IDR_MENU1)));
ShowWindow(ghApp, SW_NORMAL);
UpdateWindow(ghApp);
ZeroMemory(&gTheSet, sizeof gTheSet);
// Text-file
TCHAR szFilename[MAX_PATH];
if (lstrlen(lpCmdLine))
ReadTextFile(lpCmdLine);
else
if (GetCliplistTxtFilename(szFilename))
ReadTextFile(szFilename);
else
return FALSE;
if (gTheSet.nNumClips)
CutlistFromTextfile();
// Establish a callback-based tracking timer
gTimerNum = 0;
if (nVidElems || nAudElems)
gTimerNum = timeSetEvent(125, 0, TimerProc, 0, TIME_PERIODIC);
while (GetMessage(&msg,NULL,0,0))
{ // Message loop
TranslateMessage(&msg);
DispatchMessage(&msg);
} // Message loop
DestroyMenu(ghMenu);
// Finished with OLE subsystem
CoUninitialize();
return msg.wParam;
} // WinMain //