0
我想使用Vmr 9而不是默認Vmr 7,所以我使用CoCreateInstance創建了它,並使用AddFilter方法將其添加到圖形中。接下來,我使用RenderFile方法構建圖形。現在渲染器已連接,因此我查詢IVideoWindow接口並使用在子線程中創建的窗口句柄調用put_Owner方法。當調用Run方法時,視頻顯示在窗口中,但窗口不處理消息,因此無法移動或調整大小。無窗口模式正常工作。爲什麼窗戶以這種方式行事?當它應該實現消息泵和傳遞窗口消息,無論是作爲COM要求和助手窗口VMR會在主線程中getchar();
視頻窗口不響應,窗口模式,DirectShow
#include <dshow.h>
#include <D3D9.h>
#include <Vmr9.h>
#pragma comment(lib, "Strmiids.lib")
#pragma comment(lib, "D3d9.lib")
#define WM_GRAPHNOTIFY WM_APP + 1
DWORD HandleGraphEvent(IMediaEventEx* media_event)
{
long EvCode;
LONG_PTR param1, param2;
while (media_event->GetEvent(&EvCode, ¶m1, ¶m2, 0) == S_OK)
{
media_event->FreeEventParams(EvCode, param1, param2);
switch (EvCode)
{
case EC_COMPLETE:
printf("All data is rendered\n");
return 0;
case EC_USERABORT:
printf("User has closed the window\n");
return 0;
case EC_ERRORABORT:
printf("Error occured\n");
return 0;
}
}
return 1;
}
struct WindowThreadParam
{
HANDLE event;
HWND window;
IMediaEventEx* media_event;
};
LRESULT WINAPI WindowProcedure(HWND window, unsigned int msg, WPARAM wp, LPARAM lp)
{
WindowThreadParam* param = (WindowThreadParam*)lp;
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_GRAPHNOTIFY:
HandleGraphEvent(param->media_event);
default:
return DefWindowProc(window, msg, wp, lp);
}
}
DWORD WINAPI WindowThread(WindowThreadParam* param)
{
LPCWSTR myclass = TEXT("myclass");
WNDCLASSEX wndclass =
{ sizeof(WNDCLASSEX), CS_DBLCLKS, WindowProcedure,
0, 0, GetModuleHandle(0), LoadIcon(0, IDI_APPLICATION),
LoadCursor(0, IDC_ARROW), HBRUSH(COLOR_WINDOW + 1),
0, myclass, LoadIcon(0, IDI_APPLICATION) };
HWND window = NULL;
if (RegisterClassEx(&wndclass))
{
window = CreateWindowEx(0, myclass, TEXT("title"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0);
if (window)
{
ShowWindow(window, SW_SHOWDEFAULT);
param->window = window;
SetEvent(param->event);
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg);
}
else SetEvent(param->event);
UnregisterClass(myclass, GetModuleHandle(0));
}
else SetEvent(param->event);
return 0;
}
void _tmain(int argc, _TCHAR* argv[])
{
HANDLE event_handle;
event_handle = CreateEvent(NULL, 0, 0, NULL); // auto, unsignaled
WindowThreadParam param;
ZeroMemory(¶m, sizeof(param));
param.event = event_handle;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WindowThread, ¶m, 0, NULL);
IMediaControl *pControl = NULL;
IMediaEventEx *pEvent = NULL;
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return;
}
IGraphBuilder* graph_builder;
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&graph_builder);
IBaseFilter* Vrm;
hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&Vrm);
hr = graph_builder->AddFilter(Vrm, L"Video Mixing Renderer");
hr = graph_builder->RenderFile(L"anim.avi", NULL);
hr = graph_builder->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = graph_builder->QueryInterface(IID_IMediaEventEx, (void **)&pEvent);
IVideoWindow* VideoWindow;
RECT window_client_area;
WaitForSingleObject(param.event, INFINITE);
if (param.window)
{
// set window
hr = graph_builder->QueryInterface(IID_IVideoWindow, (void**)&VideoWindow);
hr = VideoWindow->put_Owner((OAHWND)param.window);
hr = VideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
// set video position
GetClientRect(param.window, &window_client_area);
hr = VideoWindow->SetWindowPosition(0, 0, window_client_area.right, window_client_area.bottom);
param.media_event = pEvent;
hr = pEvent->SetNotifyWindow((OAHWND)param.window, WM_GRAPHNOTIFY, (LONG_PTR)¶m);
}
hr = pControl->Run();
// allow child thread to run
getchar();
pControl->Release();
pEvent->Release();
graph_builder->Release();
CoUninitialize();
}
因此,我認爲SetNotifyWindow方法在窗口模式下是無關緊要的,您應該使用GetMessage手動獲取消息並將它們傳遞到窗口。正如我所說的背景線程在主線程睡眠時無窗口模式下工作正常。 – igntec
'SetNotifyWindow'很好。不好的是你創建COM STA,那麼你有附加到這個線程的窗口,你睡覺不派遣消息。 –
好吧,它在主線程中工作。所以,我假設窗口模式不是爲多線程設計的(因爲無窗口模式工作正常)。 – igntec