📄 ticker.cpp
字号:
//
// Not using this flag means that if GraphEdit remotely connects
// to this graph and then GraphEdit exits, this object registration
// will be deleted, causing future attempts by GraphEdit to fail until
// this application is restarted or until the graph is registered again.
hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph,
pMoniker, pdwRegister);
pMoniker->Release();
}
pROT->Release();
return hr;
}
void RemoveGraphFromRot(DWORD pdwRegister)
{
IRunningObjectTable *pROT;
if (SUCCEEDED(GetRunningObjectTable(0, &pROT)))
{
pROT->Revoke(pdwRegister);
pROT->Release();
}
}
#endif
void Msg(TCHAR *szFormat, ...)
{
TCHAR szBuffer[1024]; // Large buffer for long filenames or URLs
const size_t NUMCHARS = sizeof(szBuffer) / sizeof(szBuffer[0]);
const int LASTCHAR = NUMCHARS - 1;
// Format the input string
va_list pArgs;
va_start(pArgs, szFormat);
// Use a bounded buffer size to prevent buffer overruns. Limit count to
// character size minus one to allow for a NULL terminating character.
_vsntprintf(szBuffer, NUMCHARS - 1, szFormat, pArgs);
va_end(pArgs);
// Ensure that the formatted string is NULL-terminated
szBuffer[LASTCHAR] = TEXT('\0');
// Display a message box with the formatted string
MessageBox(NULL, szBuffer, TEXT("VMRTicker Sample"), MB_OK);
}
LRESULT CALLBACK AboutDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (wParam == IDOK)
{
EndDialog(hWnd, TRUE);
return TRUE;
}
break;
}
return FALSE;
}
LRESULT CALLBACK TextDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static TCHAR szSaveText[DYNAMIC_TEXT_SIZE]={0};
switch (message)
{
case WM_INITDIALOG:
// Save current dynamic text so that we can temporarily modify
// the dynamic text during font adjustment
_tcsncpy(szSaveText, g_szAppText, NUMELMS(szSaveText));
SendMessage(GetDlgItem(hWnd, IDC_EDIT_TEXT), EM_LIMITTEXT, DYNAMIC_TEXT_SIZE, 0L);
SetWindowText(GetDlgItem(hWnd, IDC_EDIT_TEXT), g_szAppText);
return TRUE;
case WM_COMMAND:
switch (wParam)
{
case IDOK:
{
TCHAR szText[DYNAMIC_TEXT_SIZE];
GetWindowText(GetDlgItem(hWnd, IDC_EDIT_TEXT), szText, DYNAMIC_TEXT_SIZE);
_tcsncpy(g_szAppText, szText, NUMELMS(g_szAppText)-1);
BlendApplicationText(ghApp, g_szAppText);
EndDialog(hWnd, TRUE);
return TRUE;
}
break;
case IDCANCEL:
// Restore the original text in case it was modified
// and previewed while adjusting the font
_tcsncpy(g_szAppText, szSaveText, NUMELMS(g_szAppText)-1);
BlendApplicationText(ghApp, g_szAppText);
EndDialog(hWnd, TRUE);
break;
case IDC_SET_FONT:
{
TCHAR szTempText[DYNAMIC_TEXT_SIZE]={0};
// Change the current font
g_hFont = UserSelectFont();
// Start displaying the text that is currently in the edit box
GetWindowText(GetDlgItem(hWnd, IDC_EDIT_TEXT), szTempText, DYNAMIC_TEXT_SIZE);
BlendApplicationText(ghApp, szTempText);
}
break;
}
break;
}
return FALSE;
}
LRESULT CALLBACK WndMainProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_PAINT:
OnPaint(hWnd);
break;
case WM_DISPLAYCHANGE:
if (pWC)
pWC->DisplayModeChanged();
break;
// Resize the video when the window changes
case WM_MOVE:
case WM_SIZE:
if (hWnd == ghApp)
MoveVideoWindow();
break;
// Enforce a minimum size
case WM_GETMINMAXINFO:
{
LPMINMAXINFO lpmm = (LPMINMAXINFO) lParam;
if (lpmm)
{
lpmm->ptMinTrackSize.x = MINIMUM_VIDEO_WIDTH;
lpmm->ptMinTrackSize.y = MINIMUM_VIDEO_HEIGHT;
}
}
break;
case WM_KEYDOWN:
switch(toupper((int) wParam))
{
case VK_ESCAPE:
case VK_F12:
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
CloseClip();
OpenClip(); // Open the new clip
break;
case ID_FILE_INITCLIP:
OpenClip(); // Open the new clip
break;
case ID_FILE_EXIT:
CloseClip();
PostQuitMessage(0);
break;
case ID_FILE_CLOSE:
CloseClip();
break;
case ID_DISABLE:
FlipFlag(MARK_DISABLE);
DisableTicker(g_dwTickerFlags);
break;
case ID_SLIDE:
FlipFlag(MARK_SLIDE);
SlideTicker(g_dwTickerFlags);
break;
case ID_TICKER_STATIC_IMAGE:
g_dwTickerFlags |= MARK_STATIC_IMAGE;
g_dwTickerFlags &= ~(MARK_DYNAMIC_TEXT);
BlendApplicationImage(ghApp);
CheckMenuItem(ghMenu, ID_TICKER_STATIC_IMAGE, MF_CHECKED);
CheckMenuItem(ghMenu, ID_TICKER_DYNAMIC_TEXT, MF_UNCHECKED);
break;
case ID_TICKER_DYNAMIC_TEXT:
g_dwTickerFlags |= MARK_DYNAMIC_TEXT;
g_dwTickerFlags &= ~(MARK_STATIC_IMAGE);
BlendApplicationText(ghApp, g_szAppText);
CheckMenuItem(ghMenu, ID_TICKER_STATIC_IMAGE, MF_UNCHECKED);
CheckMenuItem(ghMenu, ID_TICKER_DYNAMIC_TEXT, MF_CHECKED);
break;
case ID_SET_FONT:
g_hFont = UserSelectFont(); // Change the current font
PostMessage(ghApp, WM_COMMAND, ID_TICKER_DYNAMIC_TEXT, 0);
break;
case ID_SET_TEXT:
DialogBox(ghInst, MAKEINTRESOURCE(IDD_DIALOG_TEXT),
ghApp, (DLGPROC) TextDlgProc);
break;
case ID_HELP_ABOUT:
DialogBox(ghInst, MAKEINTRESOURCE(IDD_HELP_ABOUT),
ghApp, (DLGPROC) AboutDlgProc);
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
return DefWindowProc(hWnd, message, wParam, lParam);
}
int PASCAL WinMain(HINSTANCE hInstC, HINSTANCE hInstP, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg={0};
WNDCLASS wc;
USES_CONVERSION;
// Initialize COM
if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
Msg(TEXT("CoInitialize Failed!\r\n"));
return FALSE;
}
// Verify that the VMR is present on this system
if(!VerifyVMR9())
return FALSE;
// Was a filename specified on the command line?
if(lpCmdLine[0] != '\0')
{
USES_CONVERSION;
_tcsncpy(g_szFileName, A2T(lpCmdLine), NUMELMS(g_szFileName));
}
// Register the window class
ZeroMemory(&wc, sizeof wc);
ghInst = wc.hInstance = hInstC;
wc.lpfnWndProc = WndMainProc;
wc.lpszClassName = CLASSNAME;
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(hInstC, MAKEINTRESOURCE(IDI_TICKER));
if(!RegisterClass(&wc))
{
Msg(TEXT("RegisterClass Failed! Error=0x%x\r\n"), GetLastError());
CoUninitialize();
exit(1);
}
// Create the main window. The WS_CLIPCHILDREN style is required.
ghApp = CreateWindow(CLASSNAME, APPLICATIONNAME,
WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_CLIPCHILDREN | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
DEFAULT_PLAYER_WIDTH, DEFAULT_PLAYER_HEIGHT,
0, 0, ghInst, 0);
if(ghApp)
{
// Save menu handle for later use
ghMenu = GetMenu(ghApp);
EnableTickerMenu(FALSE);
// Set default dynamic text if user wants to display dynamic text
// instead of a static bitmap image
_tcsncpy(g_szAppText, BLEND_TEXT, NUMELMS(g_szAppText));
g_dwTickerFlags = DEFAULT_MARK;
// If a media file was specified on the command line, open it now.
// (If the first character in the string isn't NULL, post an open clip message.)
if (g_szFileName[0] != 0)
PostMessage(ghApp, WM_COMMAND, ID_FILE_INITCLIP, 0);
// Main message loop
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
Msg(TEXT("Failed to create the main window! Error=0x%x\r\n"), GetLastError());
}
// Finished with COM
CoUninitialize();
return (int) msg.wParam;
}
HRESULT 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));
hr = pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pWC);
if( SUCCEEDED(hr))
{
hr = pWC->SetVideoClippingWindow(ghApp);
hr = pWC->SetBorderColor(RGB(0,0,0));
}
#ifndef BILINEAR_FILTERING
// Request point filtering (instead of bilinear filtering)
// to improve the text quality. In general, if you are
// not scaling the app Image, you should use point filtering.
// This is very important if you are doing source color keying.
IVMRMixerControl9 *pMix;
hr = pVmr->QueryInterface(IID_IVMRMixerControl9, (void**)&pMix);
if( SUCCEEDED(hr))
{
DWORD dwPrefs=0;
hr = pMix->GetMixingPrefs(&dwPrefs);
if (SUCCEEDED(hr))
{
dwPrefs |= MixerPref_PointFiltering;
dwPrefs &= ~(MixerPref_BiLinearFiltering);
hr = pMix->SetMixingPrefs(dwPrefs);
}
pMix->Release();
}
#endif
// Get alpha-blended bitmap interface
hr = pVmr->QueryInterface(IID_IVMRMixerBitmap9, (void**)&pBMP);
}
else
Msg(TEXT("Failed to add VMR to graph! hr=0x%x\r\n"), hr);
// Don't release the pVmr interface because we are copying it into
// the caller's ppVmr9 pointer
*ppVmr9 = pVmr;
}
else
Msg(TEXT("Failed to create VMR! hr=0x%x\r\n"), hr);
return hr;
}
void OnPaint(HWND hwnd)
{
HRESULT hr;
PAINTSTRUCT ps;
HDC hdc;
RECT rcClient;
GetClientRect(hwnd, &rcClient);
hdc = BeginPaint(hwnd, &ps);
if(pWC)
{
// When using VMR Windowless mode, you must explicitly tell the
// renderer when to repaint the video in response to WM_PAINT
// messages. This is most important when the video is stopped
// or paused, since the VMR won't be automatically updating the
// window as the video plays.
if (pWC)
hr = pWC->RepaintVideo(hwnd, hdc);
}
else // No video image. Just paint the whole client area.
{
FillRect(hdc, &rcClient, (HBRUSH)(COLOR_BTNFACE + 1));
}
EndPaint(hwnd, &ps);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -