2015-05-08 4 views
0

Я хотел использовать 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, &param1, &param2, 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(&param, sizeof(param)); 
    param.event = event_handle; 
    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WindowThread, &param, 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)&param); 
    } 

    hr = pControl->Run(); 

    // allow child thread to run 
    getchar(); 

    pControl->Release(); 
    pEvent->Release(); 
    graph_builder->Release(); 

    CoUninitialize(); 
} 

ответ

1

Ваш основной поток спит в getchar();, когда предполагается осуществить сообщение насос и поставить окно сообщения, и как требование COM и для окна хелперов VMR создает в основном потоке.

Ваша фоновая нить здесь неактуальна, так как ваша контролирующая деятельность DirectShow имеет место в _tmain.

+0

Итак, я предполагаю, что метод SetNotifyWindow не имеет значения в оконном режиме, и вы должны получать сообщения вручную с помощью GetMessage и доставлять их в свое окно. Как я уже говорил, фоновый поток отлично работает в режиме без окон, когда основной поток спит. – igntec

+0

'SetNotifyWindow' в порядке. Неплохо, что вы создаете COM STA, тогда у вас есть окна, прикрепленные к этому потоку, и вы спите, не отправляя сообщения. –

+0

Хорошо, он работает в основной теме. Поэтому я предполагаю, что оконный режим не предназначен для нескольких потоков (потому что режим без окон работает отлично). – igntec

Смежные вопросы