//========================================================================= // // 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 - 1998 Microsoft Corporation. All Rights Reserved. // //========================================================================= #include #include #include #include #include #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 //