2017-08-01 31 views
0

編輯:更新代碼和調用該DLL的應用程序不再崩潰。在DirectShow中保持寬高比? (窗口)C++

當show_video()的第四個參數設置爲true時,我希望DirectShow播放的視頻保持其寬高比。這裏是我的DLL的源:

#include <windows.h> 
#include <dshow.h> 

#pragma comment (lib, "strmiids.lib") 
#define DLL extern "C" _declspec(dllexport) 

wchar_t *convertCharArrayToLPCWSTR(const char* charArray) { 
    wchar_t* wString = new wchar_t[4096]; 

    MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096); 

    return wString; 
} 

DLL void show_video(double window1, HWND window2, char *fname, double keep_aspect_ratio) { 
    CoInitialize(NULL); 

    HRESULT hr = S_OK; 

    IGraphBuilder *pGraph = NULL; 
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); 
    hr = pGraph->RenderFile(convertCharArrayToLPCWSTR(fname), NULL); 

    IBaseFilter *pVideoRenderer = NULL; 
    hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pVideoRenderer); 

    IVMRAspectRatioControl *pAspectRatio = NULL; 
    hr = pVideoRenderer->QueryInterface(IID_IVMRAspectRatioControl, (void**)&pAspectRatio); 

    if ((bool)keep_aspect_ratio == true) { 
     hr = pAspectRatio->SetAspectRatioMode(VMR_ARMODE_LETTER_BOX); 
    } 
    else { 
     hr = pAspectRatio->SetAspectRatioMode(VMR_ARMODE_NONE); 
    } 

    IVideoWindow *pVidWin = NULL; 
    hr = pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin); 

    RECT rect; 
    if ((HWND)(DWORD)window1 != NULL) { 
     SetWindowLong((HWND)(DWORD)window1, GWL_STYLE, GetWindowLong((HWND)(DWORD)window1, GWL_STYLE) | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); 
     hr = pVidWin->put_Owner((OAHWND)(HWND)(DWORD)window1); 
     GetClientRect((HWND)(DWORD)window1, &rect); 
    } 
    else { 
     SetWindowLong(window2, GWL_STYLE, GetWindowLong(window2, GWL_STYLE) | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); 
     hr = pVidWin->put_Owner((OAHWND)window2); 
     GetClientRect(window2, &rect); 
    } 

    hr = pVidWin->SetWindowPosition(0, 0, rect.right - rect.left, rect.bottom - rect.top); 
    hr = pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS); 
    hr = pVidWin->SetWindowForeground(OATRUE); 
    hr = pVidWin->HideCursor(OATRUE); 

    IMediaControl *pControl = NULL; 
    hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); 
    hr = pControl->Run(); 

    IMediaEvent *pEvent = NULL; 
    hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent); 
    long evCode; 

    hr = pEvent->WaitForCompletion(INFINITE, &evCode); 

    hr = pControl->Stop(); 
    hr = pVidWin->put_Visible(OAFALSE); 
    hr = pVidWin->put_Owner(NULL); 

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

    pAspectRatio->Release(); 
    pVideoRenderer->Release(); 
    pGraph->Release(); 

    CoUninitialize(); 
} 

因爲它的立場,從我的應用程序中調用DLL,我選擇了第三個參數視頻播放罰款,但視頻沒有保持其原始寬高比。有誰知道我做錯了什麼?

+0

你檢查了QueryInterface的hr結果嗎?也許pAspectRatio是NULL。你應該直接在渲染器上查詢接口。例如,對於EVR,您應該查詢它以獲取IMFVideoDisplayControl並使用SetAspectRatioMode。 – VuVirt

+0

@VuVirt我更新了代碼,以便它直接在渲染器上查詢它的接口(或者至少這是我認爲我所做的),並且它不再崩潰,但它仍然不能保持其縱橫比第四個參數設置爲true。 –

回答

1

找到解決方案。初始化pVideoRenderer後,我需要添加以下行:

pGraph->FindFilterByName(L"Video Renderer", &pVideoRenderer); 

所以生成的代碼如下所示:

#include <windows.h> 
#include <dshow.h> 

#pragma comment (lib, "strmiids.lib") 
#define DLL extern "C" _declspec(dllexport) 

wchar_t *convertCharArrayToLPCWSTR(const char* charArray) { 
    wchar_t* wString = new wchar_t[4096]; 

    MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096); 

    return wString; 
} 

DLL void show_video(double window1, HWND window2, char *fname, double keep_aspect_ratio) { 
    CoInitialize(NULL); 

    HRESULT hr = S_OK; 

    IGraphBuilder *pGraph = NULL; 
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); 
    hr = pGraph->RenderFile(convertCharArrayToLPCWSTR(fname), NULL); 

    IBaseFilter *pVideoRenderer = NULL; 
    hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pVideoRenderer); 
    pGraph->FindFilterByName(L"Video Renderer", &pVideoRenderer); 

    IVMRAspectRatioControl *pAspectRatio = NULL; 
    hr = pVideoRenderer->QueryInterface(IID_IVMRAspectRatioControl, (void**)&pAspectRatio); 

    if ((bool)keep_aspect_ratio == true) { 
     hr = pAspectRatio->SetAspectRatioMode(VMR_ARMODE_LETTER_BOX); 
    } 
    else { 
     hr = pAspectRatio->SetAspectRatioMode(VMR_ARMODE_NONE); 
    } 

    IVideoWindow *pVidWin = NULL; 
    hr = pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin); 

    RECT rect; 
    if ((HWND)(DWORD)window1 != NULL) { 
     SetWindowLong((HWND)(DWORD)window1, GWL_STYLE, GetWindowLong((HWND)(DWORD)window1, GWL_STYLE) | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); 
     hr = pVidWin->put_Owner((OAHWND)(HWND)(DWORD)window1); 
     GetClientRect((HWND)(DWORD)window1, &rect); 
    } 
    else { 
     SetWindowLong(window2, GWL_STYLE, GetWindowLong(window2, GWL_STYLE) | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); 
     hr = pVidWin->put_Owner((OAHWND)window2); 
     GetClientRect(window2, &rect); 
    } 

    hr = pVidWin->SetWindowPosition(0, 0, rect.right - rect.left, rect.bottom - rect.top); 
    hr = pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS); 
    hr = pVidWin->SetWindowForeground(OATRUE); 
    hr = pVidWin->HideCursor(OATRUE); 

    IMediaControl *pControl = NULL; 
    hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); 
    hr = pControl->Run(); 

    IMediaEvent *pEvent = NULL; 
    hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent); 
    long evCode; 

    hr = pEvent->WaitForCompletion(INFINITE, &evCode); 

    hr = pControl->Stop(); 
    hr = pVidWin->put_Visible(OAFALSE); 
    hr = pVidWin->put_Owner(NULL); 

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

    pAspectRatio->Release(); 
    pVideoRenderer->Release(); 
    pGraph->Release(); 

    CoUninitialize(); 
} 

問題解決了! :D

0

...調用DLL的進程現在崩潰了。

進程崩潰假定可以提供像碰撞點,異常細節等

可能的原因是在前面的QueryInterface呼叫和不存在IVMRAspectRatioControl指針的E_NOINTERFACE失敗附加細節。

Filter Graph Manager不應該執行IVMRAspectRatioControl。如果您在過濾器圖表中有一個視頻混合呈現器過濾器,則直接從其中獲取QueryInterface

UPD。另一個答案中的解決方案就是不應該如何做的事例。如果您對VR執行CoCreateInstance,則應將其添加到圖形並將其包括到渲染過程中。否則,根本不需要CoCreateInstance,而且您不應該通過名稱來定位過濾器 - 而應該枚舉過濾器,並通過查找實現接口的過濾器來識別您的VR。

+0

我在Windows XP及更高版本(VMR7)上使用DirectShow的默認視頻混合渲染器。任何機會,你可以提供一個代碼片段? –

+0

我更新了代碼,並設法解決了崩潰問題。但是,視頻仍然不能保持其原始高寬比。 –