CLTEXT.CPP


//=========================================================================
//
// 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 //