Я хотел использовать Vmr 9 вместо Vmr 7 по умолчанию, поэтому я создал его с CoCreateInstance и добавил к графику с помощью метода AddFilter. Затем я построю график с помощью метода RenderFile. Теперь визуализатор подключен, поэтому я запрашиваю интерфейс IVideoWindow и вызываю метод put_Owner с дескриптором окна, созданным в дочернем потоке. Когда вызывается метод Run, в окне отображается видео, но окно не обрабатывает сообщения, поэтому вы не можете его перемещать или изменять размер. Режим без окон работает нормально. Почему окно ведет себя так?Video Window не отвечает, оконный режим, 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