2015-05-08 77 views
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, &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

你的主線程睡眠。

由於您的控制DirectShow活動發生在_tmain,因此您的後臺線程無關緊要。

+0

因此,我認爲SetNotifyWindow方法在窗口模式下是無關緊要的,您應該使用GetMessage手動獲取消息並將它們傳遞到窗口。正如我所說的背景線程在主線程睡眠時無窗口模式下工作正常。 – igntec

+0

'SetNotifyWindow'很好。不好的是你創建COM STA,那麼你有附加到這個線程的窗口,你睡覺不派遣消息。 –

+0

好吧,它在主線程中工作。所以,我假設窗口模式不是爲多線程設計的(因爲無窗口模式工作正常)。 – igntec