📄 blenderdlg.cpp
字号:
while (pEnum->Next(1, &pPin, NULL) == S_OK)
{
PIN_DIRECTION ThisPinDir;
pPin->QueryDirection(&ThisPinDir);
if (ThisPinDir == PinDir)
{
IPin *pTmp = 0;
hr = pPin->ConnectedTo(&pTmp);
if (SUCCEEDED(hr)) // Already connected, not the pin we want.
{
pTmp->Release();
}
else // Unconnected, this is the pin we want.
{
pEnum->Release();
*ppPin = pPin;
return S_OK;
}
}
pPin->Release();
}
// Release the enumerator
pEnum->Release();
// Did not find a matching pin
return E_FAIL;
}
BOOL CBlenderDlg::IsWindowsMediaFile(WCHAR *lpszFile)
{
USES_CONVERSION;
TCHAR szFilename[MAX_PATH];
// Copy the file name to a local string and convert to lowercase
_tcsncpy(szFilename, W2T(lpszFile), NUMELMS(szFilename));
szFilename[MAX_PATH-1] = 0;
_tcslwr(szFilename);
if (_tcsstr(szFilename, TEXT(".asf")) ||
_tcsstr(szFilename, TEXT(".wma")) ||
_tcsstr(szFilename, TEXT(".wmv")))
return TRUE;
else
return FALSE;
}
HRESULT CBlenderDlg::RenderFileToVMR9(WCHAR *wFileName, IBaseFilter *pRenderer, BOOL bRenderAudio=TRUE)
{
HRESULT hr=S_OK;
CComPtr <IPin> pOutputPin;
CComPtr <IBaseFilter> pSource;
CComPtr <IBaseFilter> pAudioRenderer;
CComPtr <IFilterGraph2> pFG;
// Add a file source filter for this media file
if (!IsWindowsMediaFile(wFileName))
{
// Add the source filter to the graph
JIF(pGB->AddSourceFilter(wFileName, L"SOURCE", &pSource));
// Get the interface for the output pin
JIF(GetUnconnectedPin(pSource, PINDIR_OUTPUT, &pOutputPin));
}
else
{
Msg(TEXT("Windows Media files (ASF,WMA,WMV) are not supported by this application.\r\n\r\n")
TEXT("For a full example of Windows Media support using the\r\n")
TEXT("DirectShow WM ASF Reader filter and implementing a key provider\r\n")
TEXT("for Windows Media content, refer to the following SDK samples:\r\n\r\n")
TEXT(" - AudioBox - Jukebox - PlayWndASF\r\n\r\n")
TEXT("Each of the listed samples provides the necessary extra code\r\n")
TEXT("and links with the required Windows Media libraries.\0"),
TEXT("Windows Media files are not supported"), MB_OK);
return E_FAIL;
}
// Render audio if requested (defaults to TRUE)
if (bRenderAudio)
{
// Because we will be rendering with the RENDERTOEXISTINGRENDERERS flag,
// we need to create an audio renderer and add it to the graph.
// Create an instance of the DirectSound renderer (for each media file).
JIF(CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void **)&pAudioRenderer));
JIF(pGB->AddFilter(pAudioRenderer, L"Audio Renderer"));
}
// Get an IFilterGraph2 interface to assist in building the
// multifile graph with the non-default VMR9 renderer
JIF(pGB->QueryInterface(IID_IFilterGraph2, (void **)&pFG));
// Render the output pin, using the VMR9 as the specified renderer. This is
// necessary in case the GraphBuilder needs to insert a Color Space convertor,
// or if multiple filters insist on using multiple allocators.
// The audio renderer will also be used, if the media file contains audio.
JIF(pFG->RenderEx(pOutputPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL));
return hr;
}
HRESULT CBlenderDlg::ConfigureMultiFileVMR9(WCHAR *wFile1, WCHAR *wFile2)
{
HRESULT hr=S_OK;
CComPtr <IBaseFilter> pVmr;
// Create the Video Mixing Renderer and add it to the graph
JIF(InitializeWindowlessVMR(&pVmr));
// Render the files programmatically to use the VMR9 as renderer
if (SUCCEEDED(hr = RenderFileToVMR9(wFile1, pVmr, TRUE)))
hr = RenderFileToVMR9(wFile2, pVmr, TRUE);
return hr;
}
HRESULT CBlenderDlg::InitializeVideo(void)
{
USES_CONVERSION;
WCHAR wFile1[MAX_PATH], wFile2[MAX_PATH];
HRESULT hr;
// Clear open dialog remnants before calling RenderFile()
UpdateWindow();
// Convert filenames to wide character strings for RenderFile()
wcsncpy(wFile1, T2W(m_szFile1), NUMELMS(wFile1)-1);
wcsncpy(wFile2, T2W(m_szFile2), NUMELMS(wFile2)-1);
wFile1[MAX_PATH-1] = wFile2[MAX_PATH-1] = 0;
// Create a DirectShow GraphBuilder object
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.
JIF(ConfigureMultiFileVMR9(wFile1, wFile2));
// Get DirectShow interfaces
JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC));
JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME));
JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS));
// Have the graph signal event via window callbacks
JIF(pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0));
#ifdef REGISTER_FILTERGRAPH
m_dwGraphRegister = 0;
hr = AddGraphToRot(pGB, &m_dwGraphRegister);
if (FAILED(hr))
Msg(TEXT("Failed to register filter graph with ROT! hr=0x%x"), hr);
#endif
// Run the graph to play the media files
OnPlay();
// Set initial movie position
MoveVideoWindow();
RepaintVideo();
}
return hr;
}
HRESULT CBlenderDlg::FreeDirectShow(void)
{
#ifdef REGISTER_FILTERGRAPH
RemoveGraphFromRot(m_dwGraphRegister);
#endif
HRESULT hr=S_OK;
// Stop the position timer
StopTimer();
// Stop playback
if (pMC)
hr = pMC->Stop();
// Disable event callbacks
if (pME)
hr = pME->SetNotifyWindow((OAHWND)NULL, 0, 0);
// Release all active interfaces
SAFE_RELEASE(pMC);
SAFE_RELEASE(pMS);
SAFE_RELEASE(pME);
SAFE_RELEASE(pGB);
SAFE_RELEASE(pWC); // IVMRWindowlessControl9
SAFE_RELEASE(pMix); // IVMRMixerControl9
return hr;
}
void CBlenderDlg::OnStop()
{
HRESULT hr;
// Update button state
m_ButtonPlay.EnableWindow(TRUE);
m_ButtonStop.EnableWindow(FALSE);
m_ButtonPause.EnableWindow(FALSE);
// Stop the position timer
StopTimer();
// Stop playback
if (pMC)
hr = pMC->Stop();
// Wait for the stop to propagate to all filters
WaitForState(State_Stopped);
// Reset to first frame of movie
if (pMS)
{
LONGLONG pos=0;
hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
NULL, AM_SEEKING_NoPositioning);
}
// Refresh the current position text display
UpdatePosition();
}
void CBlenderDlg::OnPause()
{
HRESULT hr;
// Update button state
m_ButtonPlay.EnableWindow(TRUE);
m_ButtonPause.EnableWindow(FALSE);
// Stop the position timer
StopTimer();
// Pause playback
if (pMC)
hr = pMC->Pause();
// Wait for the pause to propagate to all filters
WaitForState(State_Paused);
}
void CBlenderDlg::OnPlay()
{
HRESULT hr;
// Update button state
m_ButtonPlay.EnableWindow(FALSE);
m_ButtonStop.EnableWindow(TRUE);
m_ButtonPause.EnableWindow(TRUE);
// Start the filter graph
if (pMC)
hr = pMC->Run();
// Wait for the stop to propagate to all filters
WaitForState(State_Running);
// Start the position timer
StartTimer();
}
void CBlenderDlg::InitButtons(void)
{
// Set the default state of the media control buttons
m_ButtonPlay.EnableWindow(TRUE);
m_ButtonStop.EnableWindow(FALSE);
m_ButtonPause.EnableWindow(FALSE);
}
BOOL CBlenderDlg::VerifyVMR9(void)
{
HRESULT hres;
// Verify that the VMR exists on this system
IBaseFilter* pBF = NULL;
hres = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (LPVOID *)&pBF);
if(SUCCEEDED(hres))
{
// VMR successfully created, so release it
pBF->Release();
return TRUE;
}
else
{
MessageBox(
TEXT("This application requires the Video Mixing Renderer 9, which is present\r\n")
TEXT("only on DirectX 9 systems with hardware video acceleration enabled.\r\n\r\n")
TEXT("The Video Mixing Renderer (VMR) is not enabled when viewing a \r\n")
TEXT("remote Windows XP machine through a Remote Desktop session.\r\n")
TEXT("You can run VMR-enabled applications only on your local machine.\r\n\r\n")
TEXT("To verify that hardware acceleration is enabled on a Windows XP\r\n")
TEXT("system, follow these steps:\r\n")
TEXT("-----------------------------------------------------------------------\r\n")
TEXT(" - Open 'Display Properties' in the Control Panel\r\n")
TEXT(" - Click the 'Settings' tab\r\n")
TEXT(" - Click on the 'Advanced' button at the bottom of the page\r\n")
TEXT(" - Click on the 'Troubleshooting' tab in the window that appears\r\n")
TEXT(" - Verify that the 'Hardware Acceleration' slider is at the rightmost position\r\n")
TEXT("\r\nThis sample will now exit."),
TEXT("Video Mixing Renderer capabilities are required"), MB_OK);
return FALSE;
}
}
HRESULT CBlenderDlg::InitializeWindowlessVMR(IBaseFilter **ppVmr9)
{
IBaseFilter *pVmr=NULL;
if (!ppVmr9)
return E_POINTER;
*ppVmr9 = NULL;
// Create the VMR and add it to the filter graph.
HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL,
CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
if (SUCCEEDED(hr))
{
hr = pGB->AddFilter(pVmr, L"Video Mixing Renderer 9");
if (SUCCEEDED(hr))
{
// Set the rendering mode and number of streams
CComPtr <IVMRFilterConfig9> pConfig;
JIF(pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig));
JIF(pConfig->SetRenderingMode(VMR9Mode_Windowless));
// Set the bounding window and border for the video
JIF(pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pWC));
JIF(pWC->SetVideoClippingWindow(m_hwndScreen));
JIF(pWC->SetBorderColor(RGB(0,0,0))); // Black border
// Get the mixer control interface for later manipulation of video
// stream output rectangles and alpha values
JIF(pVmr->QueryInterface(IID_IVMRMixerControl9, (void**)&pMix));
}
// Don't release the pVmr interface because we are copying it into
// the caller's ppVmr9 pointer
*ppVmr9 = pVmr;
}
return hr;
}
void CBlenderDlg::OnClose()
{
// Release DirectShow interfaces
FreeDirectShow();
// Release COM
CoUninitialize();
CDialog::OnClose();
}
void CBlenderDlg::OnDestroy()
{
// Release DirectShow interfaces
FreeDirectShow();
CDialog::OnDestroy();
}
HRESULT CBlenderDlg::UpdatePinAlpha(int nStreamID)
{
HRESULT hr=S_OK;
// Get a pointer to the selected stream's information
STRM_PARAM* p = &strParam[nStreamID];
// Update the alpha value for the selected stream
if(pMix)
hr = pMix->SetAlpha(nStreamID, p->Alpha);
if (SUCCEEDED(hr))
DisplayAlpha(nStreamID);
return hr;
}
void CBlenderDlg::DisplayAlpha(int nStreamID)
{
USES_CONVERSION;
int nID[2] = {IDC_STATIC_ALPHA, IDC_STATIC_ALPHA2};
char szAnsiLabel[32];
TCHAR szLabel[32];
// The wsprintf method doesn't support floating point, so use the
// ANSI version and convert to UNICODE if necessary.
sprintf(szAnsiLabel, "(%02.2f)\0", strParam[nStreamID].Alpha);
_tcsncpy(szLabel, A2T(szAnsiLabel), NUMELMS(szLabel)-1);
CWnd *pWnd = GetDlgItem(nID[nStreamID]);
pWnd->SetWindowText(szLabel);
}
HRESULT CBlenderDlg::UpdatePinPos(int nStreamID)
{
HRESULT hr=S_OK;
// Get a pointer to the selected stream's information
STRM_PARAM* p = &strParam[nStreamID];
// Set the left, right, top, and bottom coordinates
VMR9NormalizedRect r = {p->xPos, p->yPos, p->xPos + p->xSize, p->yPos + p->ySize};
// If mirrored, swap the left/right coordinates in the destination rectangle
if (strParam[nStreamID].bMirrored)
{
float fLeft = strParam[nStreamID].xPos;
float fRight = strParam[nStreamID].xPos + strParam[nStreamID].xSize;
r.left = fRight;
r.right = fLeft;
}
// If flipped, swap the top/bottom coordinates in the destination rectangle
if (strParam[nStreamID].bFlipped)
{
float fTop = strParam[nStreamID].yPos;
float fBottom = strParam[nStreamID].yPos + strParam[nStreamID].ySize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -