视频窗口没有响应,窗口模式,DirectShow

时间:2015-05-08 16:46:35

标签: c++ windows com directshow

我想使用Vmr 9而不是默认的Vmr 7,所以我使用CoCreateInstance创建它并使用AddFilter方法添加到图形中。接下来,我使用RenderFile方法构建图形。现在渲染器已连接,因此我查询IVideoWindow接口并使用在子线程中创建的窗口句柄调用put_Owner方法。调用Run方法时,视频会显示在窗口中,但窗口不会处理消息,因此您无法移动或调整大小。无窗口模式工作正常。为什么窗口会这样?

#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 个答案:

答案 0 :(得分:1)

当主要线程应该实现消息泵并传递窗口消息时,你的主线程将在getchar();中休眠,无论是COM要求还是VMR在主线程中创建的帮助窗口。

您的后台主题与此无关,因为您的控制DirectShow活动发生在_tmain