//--------------------------------------------------------------------------------------- // // Simple Windows DirectShow Example Code // // Jim Shaw 12/3/2004 // //--------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------- // Always include windows.h for windows programs //--------------------------------------------------------------------------------------- #define _WIN32_DCOM #include #ifdef __WATCOMC__ #define _WINGDI_ #define _IAMFilterGraphCallback_ #endif #include #include #include #include #include //--------------------------------------------------------------------------------------- // Screen dimensions //--------------------------------------------------------------------------------------- #define SCREEN_X 640 #define SCREEN_Y 480 #define IN_OWN_WINDOW 1 //--------------------------------------------------------------------------------------- // Variable to hold the address of the Windows window //--------------------------------------------------------------------------------------- HWND game_window; //--------------------------------------------------------------------------------------- // Name of our window class. every class has a name. every window is one of a class. // this can be pretty much anything //--------------------------------------------------------------------------------------- char game_class[]="DSCPPWindow"; static int quit = 0; //--------------------------------------------------------------------------------------- // Function prototypes //--------------------------------------------------------------------------------------- void draw(void); void flip(void); int init_dshow(wchar_t *, int); void shutdown_dshow(void); int handle_dshow_event(void); //--------------------------------------------------------------------------------------- // DirectShow Variables //--------------------------------------------------------------------------------------- IGraphBuilder *pGB=NULL; IMediaControl *pMC=NULL; IMediaEventEx *pME=NULL; IMediaSeeking *pMS=NULL; IVMRWindowlessControl *pWC=NULL; #define WM_GRAPHNOTIFY0 (WM_USER+13) //--------------------------------------------------------------------------------------- // Every window has a WindowProc which handles messages Windows sends to them. These // are things like key presses, mouse clicks, and thousands of other things you might // be interested in. //--------------------------------------------------------------------------------------- LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { //this message gets sent to the window when you click the close box on it case WM_DESTROY: //tell Windows to close the app PostQuitMessage(0); quit = 1; break; //this message gets sent when you press a key case WM_KEYDOWN: switch (wParam) { //pressed Escape key? case VK_ESCAPE: //tell Windows to close the app PostQuitMessage(0); quit = 1; break; } break; case WM_GRAPHNOTIFY0: if (handle_dshow_event()) { PostQuitMessage(0); quit = 1; } break; //any message you don't process gets passed to this function inside Windows. default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } //any message you do process, return 0 (unless the message documentation says otherwise) return 0; } //--------------------------------------------------------------------------------------- // Convert char string to wchar_t string //--------------------------------------------------------------------------------------- static wchar_t c[_MAX_PATH]; static wchar_t *ctowc(char *p) { #ifdef __WATCOMC__ swprintf(c, _MAX_PATH, L"%hs", p); #else swprintf(c, L"%S", p); #endif return c; } //--------------------------------------------------------------------------------------- // WinMain //--------------------------------------------------------------------------------------- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX clas; MSG msg; int style; RECT rect; //need COM for DirectShow CoInitializeEx(NULL, COINIT_MULTITHREADED); //Here we create the Class we named above clas.cbSize = sizeof(WNDCLASSEX); clas.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; clas.lpfnWndProc = WindowProc;//<- tell it where the WindowProc is clas.cbClsExtra = 0; clas.cbWndExtra = 0; clas.hInstance = hInstance; clas.hIcon = NULL; clas.hCursor = NULL; clas.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);//<- background colour of window clas.lpszMenuName = NULL; clas.lpszClassName = game_class;//<- the class name clas.hIconSm = 0; //do it! RegisterClassEx(&clas); //style of the window - what boxes do we need (close minimised etc) style = WS_CAPTION|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX; //create the window game_window = CreateWindowEx(0, game_class, "DirectShow", style, CW_USEDEFAULT, CW_USEDEFAULT, 1,1, NULL, NULL, hInstance, 0); //adjust the window size so that a SCREEN_X x SCREEN_Y window will fit inside its frame rect.left = rect.top = 0; rect.right = SCREEN_X; rect.bottom = SCREEN_Y; AdjustWindowRectEx(&rect, style , FALSE, 0); SetWindowPos(game_window, NULL, 0,0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE|SWP_NOZORDER); //show the window on the desktop ShowWindow(game_window, nCmdShow); char filename[_MAX_PATH]; OPENFILENAME ofn; BOOL res; filename[0] = '\0'; ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = NULL; ofn.hInstance = NULL; ofn.lpstrFilter = "AVI Files\0*.avi\0"; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = filename; ofn.nMaxFile = _MAX_PATH; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = "Select Video File"; ofn.Flags = OFN_FILEMUSTEXIST|OFN_EXPLORER; ofn.nFileOffset=0; ofn.nFileExtension=0; ofn.lpstrDefExt="bin"; ofn.lCustData=0; ofn.lpfnHook=NULL; ofn.lpTemplateName=""; res = GetOpenFileName(&ofn); if (res == 0) return 0; if (init_dshow(ctowc(filename), IN_OWN_WINDOW)==0) { MessageBox(NULL, "A problem occurred creating the DirectShow FilterGraph.\nCheck your video CODECs and " "DirectX version.\nThis demo requires DirectX9.0 or better.", "DirectX Initialisation Error", MB_ICONWARNING|MB_OK); shutdown_dshow(); return 0; } //message processing loop //all Windows programs have one of these. It receives the messages Windows sends to the program and //passes them to the WindowProc in the Class we registered for the window. quit = 0; do { //Are there any messages waiting? while (PeekMessage(&msg, game_window, 0, 0, PM_NOREMOVE)) { //yes! read it. if (GetMessage(&msg, game_window, 0,0) < 0) break; //pass the message to WindowProc TranslateMessage(&msg); DispatchMessage(&msg); } } while (!quit); shutdown_dshow(); CoUninitialize(); return 0; } //--------------------------------------------------------------------------------------- // Initialise all the DirectShow structures we need //--------------------------------------------------------------------------------------- int init_dshow(wchar_t *FileName, int render_in_own_window) { HRESULT err; FILTER_STATE state = State_Stopped; // Create a new graph err = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB); if (err != S_OK) return 0; // Get access to the video controls err = pGB->QueryInterface(IID_IMediaControl, (void **)&pMC); if (err != S_OK) return 0; err = pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS); if (err != S_OK) return 0; err = pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME); if (err != S_OK) return 0; if (render_in_own_window) { IBaseFilter *pVMR; IVMRFilterConfig *pFC; long lWidth, lHeight; RECT rcSrc, rcDest; err = CoCreateInstance(CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVMR); if (err != S_OK) return 0; // Add the VMR to the filter graph. err = pGB->AddFilter(pVMR, L"VMR"); if (err != S_OK) return 0; // Set the rendering mode. err = pVMR->QueryInterface(IID_IVMRFilterConfig, (void**)&pFC); if (err != S_OK) return 0; err = pFC->SetRenderingMode(VMRMode_Windowless); if (err != S_OK) return 0; pFC->Release(); // Set the window. err = pVMR->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWC); if (err != S_OK) return 0; err = pWC->SetVideoClippingWindow(game_window); if (err != S_OK) return 0; pVMR->Release(); // Find the native video size. err = pWC->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL); // Set the source rectangle. SetRect(&rcSrc, 0, 0, lWidth/2, lHeight/2); // Get the window client area. GetClientRect(game_window, &rcDest); // Set the destination rectangle. SetRect(&rcDest, 0, 0, rcDest.right, rcDest.bottom); // Set the video position. err = pWC->SetVideoPosition(&rcSrc, &rcDest); } // Add the source file err = pGB->RenderFile(FileName, NULL); if (err != S_OK) return 0; // Have the graph signal event via window callbacks for performance err = pME->SetNotifyWindow((OAHWND)game_window, WM_GRAPHNOTIFY0, 0); if (err != S_OK) return 0; err = pMS->SetTimeFormat(&TIME_FORMAT_FRAME); if(err != S_OK) { err = pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME); } err = pMC->Run(); do { err = pMC->GetState(0, (long *)&state); } while (state != State_Running); return 1; } //--------------------------------------------------------------------------------------- // Shutdown DirectShow //--------------------------------------------------------------------------------------- void shutdown_dshow(void) { if (pWC) pWC->Release(); if (pMS) pMS->Release(); if (pME) pME->Release(); if (pMC) pMC->Release(); if (pGB) pGB->Release(); } //--------------------------------------------------------------------------------------- // Handle DirectShow Event //--------------------------------------------------------------------------------------- int handle_dshow_event(void) { LONG evCode, evParam1, evParam2; int stopping = 0; // Make sure that we don't access the MediaEventEx interface after it has already been released. if (!pME) return S_OK; // Process all queued events while (pME->GetEvent(&evCode, &evParam1, &evParam2, 0) == S_OK) { switch (evCode) { case EC_COMPLETE: stopping = 1; break; default: break; } // Free memory associated with callback, since we're not using it pME->FreeEventParams(evCode, evParam1, evParam2); } return stopping; }