/* 构建滤波器链表,添加各个滤波器,链接并运行链表*/ HRESULT CVMR_Capture::Init(int iDeviceID,HWND hWnd, int iWidth, int iHeight) { HRESULT hr; //再次调用函数,释放已经建立的链表 CloseInterfaces(); // 创建IGraphBuilder hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB); if (SUCCEEDED(hr)) { // 创建VMR并添加到Graph中 InitializeWindowlessVMR(hWnd); // 把指定的设备捆绑到一个滤波器 if(!BindFilter(iDeviceID, &m_pDF)) return S_FALSE; // 添加采集设备滤波器到Graph中 hr = m_pGB->AddFilter(m_pDF, L"Video Capture"); if (FAILED(hr)) return hr; // 获取捕获滤波器的引脚 IEnumPins *pEnum; m_pDF->EnumPins(&pEnum); hr |= pEnum->Reset(); hr |= pEnum->Next(1, &m_pCamOutPin, NULL); // 获取媒体控制和事件接口 hr |= m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC); hr |= m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pME); // 设置窗口通知消息处理 //hr = pME->SetNotifyWindow((OAHWND)hWnd, WM_GRAPHNOTIFY, 0); // 匹配视频分辨率,对视频显示窗口设置 hr |= InitVideoWindow(hWnd,iWidth, iHeight); // 为捕获图像帧申请内存 m_nFramelen=iWidth*iHeight*3; m_pFrame=(BYTE*) new BYTE[m_nFramelen]; // 运行Graph,捕获视频 m_psCurrent = STOPPED; hr |= m_pGB->Render(m_pCamOutPin); hr |= m_pMC->Run(); if (FAILED(hr)) return hr; m_psCurrent = RUNNING; } return hr; }
HRESULT CVMR_Capture::Init(int iDeviceID,HWND hWnd, int iWidth, int iHeight) { HRESULT hr; // Get the interface for DirectShow's GraphBuilder hr=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGB); if(SUCCEEDED(hr)) { // Create the Video Mixing Renderer and add it to the graph InitializeWindowlessVMR(hWnd); // Bind Device Filter. We know the device because the id was passed in if(!BindFilter(iDeviceID, &m_pDF)) return S_FALSE; hr=m_pGB->AddFilter(m_pDF, L"Video Capture"); if (FAILED(hr)) return hr; CComPtr<IEnumPins> pEnum; m_pDF->EnumPins(&pEnum); hr = pEnum->Reset(); hr = pEnum->Next(1, &m_pCamOutPin, NULL); // QueryInterface for DirectShow interfaces hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC); hr = m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pME); // Have the graph signal event via window callbacks for performance //hr = pME->SetNotifyWindow((OAHWND)hWnd, WM_GRAPHNOTIFY, 0); hr = InitVideoWindow(hWnd,iWidth, iHeight); m_nFramelen=iWidth*iHeight*3; m_pFrame=(BYTE*) new BYTE[m_nFramelen]; // Run the graph to play the media file m_psCurrent=Stopped; hr = m_pGB->Render(m_pCamOutPin); hr = m_pMC->Run(); m_psCurrent=Running; } return hr; }
HRESULT BlendVideo(LPTSTR szFile1, LPTSTR szFile2) { USES_CONVERSION; WCHAR wFile1[MAX_PATH], wFile2[MAX_PATH]; HRESULT hr; // Check input string if ((szFile1 == NULL) || (szFile2 == NULL)) return E_POINTER; // Clear open dialog remnants before calling RenderFile() UpdateWindow(ghApp); // Convert filenames to wide character strings wcsncpy(wFile1, T2W(szFile1), NUMELMS(wFile1)-1); wcsncpy(wFile2, T2W(szFile2), NUMELMS(wFile2)-1); wFile1[MAX_PATH-1] = wFile2[MAX_PATH-1] = 0; // Get the interface for DirectShow's GraphBuilder JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB)); if(SUCCEEDED(hr)) { // Unlike the VMR7 in Windows XP, the VMR9 is not the default renderer // (to preserve backward compatibility). In some multifile graphs, // the filter graph manager could decide to load the default Video Renderer // filter during RenderFile(), even though the VMR9 is already present // in the graph. Since the default Video Renderer has a higher merit // than the VMR9, it would be connected instead of the VMR9, leading to // the video streams being displayed in multiple separate windows. // This could be the case with AVI files created with legacy VfW codecs // or when two Color Space convertors must be used (each requiring its // own allocator). // Therefore, we render the files programmatically instead of using // the standard IGraphBuilder::RenderFile() method. if (FAILED(ConfigureMultiFileVMR9(wFile1, wFile2))) return hr; // QueryInterface for DirectShow interfaces JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC)); JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME)); JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS)); // Is this an audio-only file (no video component)? if (CheckVideoVisibility()) { JIF(InitVideoWindow(1, 1)); } else { // This sample requires video clips to be loaded Msg(TEXT("This sample requires media with a video component. ") TEXT("Please select another file.")); return E_FAIL; } // Have the graph signal event via window callbacks JIF(pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0)); // Complete the window setup ShowWindow(ghApp, SW_SHOWNORMAL); UpdateWindow(ghApp); SetForegroundWindow(ghApp); SetFocus(ghApp); #ifdef REGISTER_FILTERGRAPH if (FAILED(AddGraphToRot(pGB, &g_dwGraphRegister))) { Msg(TEXT("Failed to register filter graph with ROT!")); g_dwGraphRegister = 0; } #endif // Run the graph to play the media files MoveVideoWindow(); JIF(pMC->Run()); EnableMenus(TRUE); } return hr; }
HRESULT PlayMovieInWindow(LPTSTR szFile) { USES_CONVERSION; WCHAR wFile[MAX_PATH]; HRESULT hr; // Check input string if (szFile == NULL) return E_POINTER; // Clear open dialog remnants before calling RenderFile() UpdateWindow(ghApp); // Convert filename to wide character string wcsncpy(wFile, T2W(szFile), NUMELMS(wFile)-1); wFile[MAX_PATH-1] = 0; // Get the interface for DirectShow's GraphBuilder JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB)); if(SUCCEEDED(hr)) { // Create the Video Mixing Renderer and add it to the graph JIF(InitializeWindowlessVMR()); // Have the graph builder construct its the appropriate graph automatically JIF(pGB->RenderFile(wFile, NULL)); // QueryInterface for DirectShow interfaces JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC)); JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME)); JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS)); // Is this an audio-only file (no video component)? if (CheckVideoVisibility()) { JIF(InitVideoWindow(1, 1)); } else { // This sample requires a video clip to be loaded Msg(TEXT("This sample requires media with a video component. ") TEXT("Please select another file.")); return E_FAIL; } // Have the graph signal event via window callbacks for performance JIF(pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0)); // Add the bitmap (static image or dynamic text) to the VMR's input if (g_dwTickerFlags & MARK_STATIC_IMAGE) { hr = BlendApplicationImage(ghApp); if (FAILED(hr)) PostMessage(ghApp, WM_CLOSE, 0, 0); CheckMenuItem(ghMenu, ID_TICKER_STATIC_IMAGE, MF_CHECKED); CheckMenuItem(ghMenu, ID_TICKER_DYNAMIC_TEXT, MF_UNCHECKED); } else // MARK_DYNAMIC_TEXT { if (!g_hFont) g_hFont = SetTextFont(FALSE); // Don't display the Windows Font Select dialog // If the initial blend fails, post a close message to exit the app hr = BlendApplicationText(ghApp, g_szAppText); if (FAILED(hr)) PostMessage(ghApp, WM_CLOSE, 0, 0); CheckMenuItem(ghMenu, ID_TICKER_STATIC_IMAGE, MF_UNCHECKED); CheckMenuItem(ghMenu, ID_TICKER_DYNAMIC_TEXT, MF_CHECKED); } // Complete the window setup ShowWindow(ghApp, SW_SHOWNORMAL); UpdateWindow(ghApp); SetForegroundWindow(ghApp); SetFocus(ghApp); #ifdef REGISTER_FILTERGRAPH if (FAILED(AddGraphToRot(pGB, &g_dwGraphRegister))) { Msg(TEXT("Failed to register filter graph with ROT!")); g_dwGraphRegister = 0; } #endif // Run the graph to play the media file JIF(pMC->Run()); // Start animation by default PostMessage(ghApp, WM_COMMAND, ID_SLIDE, 0); } return hr; }
HRESULT PlayMovieInWindow(LPTSTR szFile, BOOL bReOpenAfterLicenseAcquired) { USES_CONVERSION; WCHAR wFile[MAX_PATH]; HRESULT hr; // Check input string if (!szFile) return E_POINTER; // Clear open dialog remnants before calling RenderFile() UpdateWindow(ghApp); // Convert filename to wide character string wcsncpy(wFile, T2W(szFile), NUMELMS(wFile)-1); wFile[MAX_PATH-1] = 0; // First pass of rendering the media file. If a DRM license must // be acquired before the file can be loaded, then the reopen flag // will be set. if( !bReOpenAfterLicenseAcquired ) { // Get the interface for DirectShow's GraphBuilder JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB)); JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME)); if(SUCCEEDED(hr)) { // Have the graph signal event via window callbacks // // Start this before we insert the reader filter, since we may need // to monitor DRM license acquistion messages on reader creation // JIF(pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0)); // Use special handling for Windows Media files if (IsWindowsMediaFile(szFile)) { // Load the improved ASF reader filter by CLSID hr = CreateFilter(CLSID_WMAsfReader, &g_pReader); if(FAILED(hr)) { Msg(TEXT("Failed to create WMAsfWriter filter! hr=0x%x\0"), hr); return hr; } // Add the ASF reader filter to the graph. For ASF/WMV/WMA content, // this filter is NOT the default and must be added explicitly. hr = pGB->AddFilter(g_pReader, L"ASF Reader"); if(FAILED(hr)) { Msg(TEXT("Failed to add ASF reader filter to graph! hr=0x%x\0"), hr); return hr; } // Create the key provider that will be used to unlock the WM SDK JIF(AddKeyProvider(pGB)); // Create the DRM license event g_hLicenseEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if( !g_hLicenseEvent ) { return E_OUTOFMEMORY; } // Set its source filename JIF(g_pReader->QueryInterface(IID_IFileSourceFilter, (void **) &g_pFileSource)); // Attempt to load this file hr = g_pFileSource->Load(wFile, NULL); // Handle Digital Rights Management (DRM) errors if(NS_E_LICENSE_REQUIRED == hr) { Msg(TEXT("This media file is protected by DRM and needs a license.\r\n\r\n") TEXT("Attempting to acquire a license...\0")); g_bWaitingForLicense = TRUE; return hr; } else if(NS_E_PROTECTED_CONTENT == hr) { Msg(TEXT("This media file is protected by DRM and needs a license.\r\n\r\n") TEXT("In order to play DRM-encoded content, you must acquire a DRM stub library\r\n") TEXT("from Microsoft and link it with this application. The default version of\r\n") TEXT("the WMStub.lib library does not support Digital Rights Management (DRM).")); return hr; } else if (FAILED(hr)) { Msg(TEXT("Failed to load file in source filter (g_pFileSource->Load())! hr=0x%x\0"), hr); return hr; } // Render the output pins of the ASF reader to build the // remainder of the graph automatically JIF(RenderOutputPins(pGB, g_pReader)); // Since the graph is built and the filters are added to the graph, // the WM ASF reader interface can be released. g_pReader->Release(); g_pReader = NULL; } // Not a Windows Media file, so just render the standard way else { // Have the graph builder construct the appropriate graph automatically JIF(pGB->RenderFile(wFile, NULL)); } } } else { hr = g_pFileSource->Load(wFile, NULL); if( SUCCEEDED( hr ) ) { Msg(TEXT("Successfully loaded file after DRM license acquisition!")); // Render the output pins of the ASF reader to build the // remainder of the graph automatically JIF(RenderOutputPins(pGB, g_pReader)); // Since the graph is built and the filters are added to the graph, // the WM ASF reader interface can be released. g_pReader->Release(); // not really necessary g_pReader = NULL; } else { Msg(TEXT("Failed to Load file after acquiring license! hr=0x%x\0"), hr); } } if( SUCCEEDED( hr ) ) { // QueryInterface for DirectShow interfaces JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC)); JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS)); // Query for video interfaces, which may not be relevant for audio files JIF(pGB->QueryInterface(IID_IVideoWindow, (void **)&pVW)); JIF(pGB->QueryInterface(IID_IBasicVideo, (void **)&pBV)); // Query for audio interfaces, which may not be relevant for video-only files JIF(pGB->QueryInterface(IID_IBasicAudio, (void **)&pBA)); // Is this an audio-only file (no video component)? CheckVisibility(); if (!g_bAudioOnly) { // Setup the video window JIF(pVW->put_Owner((OAHWND)ghApp)); JIF(pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN)); JIF(InitVideoWindow(1, 1)); GetFrameStepInterface(); } else { // Initialize the default player size and enable playback menu items JIF(InitPlayerWindow()); EnablePlaybackMenu(TRUE, AUDIO); } // Complete window initialization CheckSizeMenu(ID_FILE_SIZE_NORMAL); ShowWindow(ghApp, SW_SHOWNORMAL); UpdateWindow(ghApp); SetForegroundWindow(ghApp); g_bFullscreen = FALSE; UpdateMainTitle(); #ifdef REGISTER_FILTERGRAPH hr = AddGraphToRot(pGB, &g_dwGraphRegister); if (FAILED(hr)) { Msg(TEXT("Failed to register filter graph with ROT! hr=0x%x"), hr); g_dwGraphRegister = 0; } #endif // Run the graph to play the media file JIF(pMC->Run()); g_psCurrent=Running; SetFocus(ghApp); } return hr; }
LRESULT CALLBACK WndMainProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { // Resize the video when the window changes case WM_MOVE: case WM_SIZE: if ((hWnd == ghApp) && (!g_bAudioOnly)) MoveVideoWindow(); break; // Enforce a minimum size case WM_GETMINMAXINFO: { LPMINMAXINFO lpmm = (LPMINMAXINFO) lParam; lpmm->ptMinTrackSize.x = MINIMUM_VIDEO_WIDTH; lpmm->ptMinTrackSize.y = MINIMUM_VIDEO_HEIGHT; } break; case WM_KEYDOWN: switch(toupper((int) wParam)) { // Frame stepping case VK_SPACE: case '1': StepOneFrame(); break; // Frame stepping (multiple frames) case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': StepFrames((int) wParam - '0'); break; case 'P': PauseClip(); break; case 'S': StopClip(); break; case 'M': ToggleMute(); break; case 'F': case VK_RETURN: ToggleFullScreen(); break; case 'H': InitVideoWindow(1,2); CheckSizeMenu(wParam); break; case 'N': InitVideoWindow(1,1); CheckSizeMenu(wParam); break; case 'D': InitVideoWindow(2,1); CheckSizeMenu(wParam); break; case 'T': InitVideoWindow(3,4); CheckSizeMenu(wParam); break; case VK_ESCAPE: if (g_bFullscreen) ToggleFullScreen(); else CloseClip(); break; case VK_F12: case 'Q': case 'X': CloseClip(); break; } break; case WM_COMMAND: switch(wParam) { // Menus case ID_FILE_OPENCLIP: // If we have ANY file open, close it and shut down DirectShow if (g_psCurrent != Init) CloseClip(); // Open the new clip OpenClip(); break; case ID_FILE_EXIT: CloseClip(); PostQuitMessage(0); break; case ID_FILE_PAUSE: PauseClip(); break; case ID_FILE_STOP: StopClip(); break; case ID_FILE_CLOSE: CloseClip(); break; case ID_FILE_MUTE: ToggleMute(); break; case ID_FILE_FULLSCREEN: ToggleFullScreen(); break; case ID_HELP_ABOUT: DialogBox(ghInst, MAKEINTRESOURCE(IDD_ABOUTBOX), ghApp, (DLGPROC) AboutDlgProc); break; case ID_FILE_SIZE_HALF: InitVideoWindow(1,2); CheckSizeMenu(wParam); break; case ID_FILE_SIZE_NORMAL: InitVideoWindow(1,1); CheckSizeMenu(wParam); break; case ID_FILE_SIZE_DOUBLE: InitVideoWindow(2,1); CheckSizeMenu(wParam); break; case ID_FILE_SIZE_THREEQUARTER: InitVideoWindow(3,4); CheckSizeMenu(wParam); break; case ID_SINGLE_STEP: StepOneFrame(); break; } // Menus break; case WM_GRAPHNOTIFY: HandleGraphEvent(); break; case WM_CLOSE: SendMessage(ghApp, WM_COMMAND, ID_FILE_EXIT, 0); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } // Window msgs handling // Pass this message to the video window for notification of system changes if (pVW) pVW->NotifyOwnerMessage((LONG_PTR) hWnd, message, wParam, lParam); return DefWindowProc(hWnd, message, wParam, lParam); }
HRESULT PlayMovieInWindow(LPTSTR szFile) { USES_CONVERSION; WCHAR wFile[MAX_PATH]; HRESULT hr; // Clear open dialog remnants before calling RenderFile() UpdateWindow(ghApp); // Convert filename to wide character string wcscpy(wFile, T2W(szFile)); // Get the interface for DirectShow's GraphBuilder JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB)); if(SUCCEEDED(hr)) { // Have the graph builder construct its the appropriate graph automatically JIF(pGB->RenderFile(wFile, NULL)); // QueryInterface for DirectShow interfaces JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC)); JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME)); JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS)); JIF(pGB->QueryInterface(IID_IMediaPosition, (void **)&pMP)); // Query for video interfaces, which may not be relevant for audio files JIF(pGB->QueryInterface(IID_IVideoWindow, (void **)&pVW)); JIF(pGB->QueryInterface(IID_IBasicVideo, (void **)&pBV)); // Query for audio interfaces, which may not be relevant for video-only files JIF(pGB->QueryInterface(IID_IBasicAudio, (void **)&pBA)); // Is this an audio-only file (no video component)? CheckVisibility(); // Have the graph signal event via window callbacks for performance JIF(pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0)); if (!g_bAudioOnly) { JIF(pVW->put_Owner((OAHWND)ghApp)); JIF(pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN)); JIF(InitVideoWindow(1, 1)); GetFrameStepInterface(); } else { JIF(InitPlayerWindow()); } // Let's get ready to rumble! CheckSizeMenu(ID_FILE_SIZE_NORMAL); ShowWindow(ghApp, SW_SHOWNORMAL); UpdateWindow(ghApp); SetForegroundWindow(ghApp); SetFocus(ghApp); g_bFullscreen = FALSE; g_PlaybackRate = 1.0; UpdateMainTitle(); #ifdef REGISTER_FILTERGRAPH hr = AddGraphToRot(pGB, &g_dwGraphRegister); if (FAILED(hr)) { Msg(TEXT("Failed to register filter graph with ROT! hr=0x%x"), hr); g_dwGraphRegister = 0; } #endif // Run the graph to play the media file JIF(pMC->Run()); g_psCurrent=Running; SetFocus(ghApp); } return hr; }
HRESULT PlayMovieInWindow(LPTSTR szFile) { HRESULT hr; // Check input string if (szFile == NULL) return E_POINTER; // Clear open dialog remnants before calling RenderFile() UpdateWindow(ghApp); // Get the interface for DirectShow's GraphBuilder JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB)); if(SUCCEEDED(hr)) { SmartPtr <IBaseFilter> pVmr; // Create the Video Mixing Renderer and add it to the graph JIF(InitializeWindowlessVMR(&pVmr)); // Render the file programmatically to use the VMR9 as renderer. // Pass TRUE to create an audio renderer also. if (FAILED(hr = RenderFileToVideoRenderer(pGB, szFile, TRUE))) return hr; // QueryInterface for DirectShow interfaces JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC)); JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME)); JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS)); JIF(pGB->QueryInterface(IID_IBasicAudio, (void **)&pBA)); // Is this an audio-only file (no video component)? if (CheckVideoVisibility()) { JIF(InitVideoWindow(1, 1)); } else { // This sample requires a video clip to be loaded Msg(TEXT("This sample requires media with a video component. ") TEXT("Please select another file.")); return E_FAIL; } // Add the bitmap to the VMR's input BlendApplicationImage(ghApp); // Have the graph signal event via window callbacks for performance JIF(pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY, 0)); // Complete the window setup ShowWindow(ghApp, SW_SHOWNORMAL); UpdateWindow(ghApp); SetForegroundWindow(ghApp); SetFocus(ghApp); UpdateMainTitle(); #ifdef REGISTER_FILTERGRAPH hr = AddGraphToRot(pGB, &g_dwGraphRegister); if (FAILED(hr)) { Msg(TEXT("Failed to register filter graph with ROT! hr=0x%x"), hr); g_dwGraphRegister = 0; } #endif // Run the graph to play the media file JIF(pMC->Run()); g_psCurrent=Running; } return hr; }