Визуализация Directshow на панель с использованием C ++ Builder - PullRequest
0 голосов
/ 02 июня 2019

Я пытаюсь заставить проигрыватель DirectShow отображать на панели, отличной от главного окна в C ++ Builder.Я взял пример кода проигрывателя Microsoft и превратил его в приложение c ++, которое создавало форму и воспроизводило видео в окне.

Теперь я хочу добавить приложение vcl и показать видео наконкретная панель.Каждый раз, когда я пытаюсь запустить график в VCL, он будет создаваться и запускаться, только если я передам дескриптор в качестве дескриптора приложения, а не дескриптора панели.Я знаю, что график работает, потому что я слышу звук, но я не могу получить видео для рендеринга на панель.Если я передаю hwnd как дескриптор любого окна VCL, назначение обратного вызова завершается неудачно для filtergraph (SetNotifyWindow), оно работает, если я передаю Application-> Handle.

    hr = m_pEvent->SetNotifyWindow((OAHWND)m_hwnd, WM_GRAPH_EVENT, NULL);
    if (FAILED(hr))
    {
        goto done;
    }

Функция видео рендеринга связывается, чтобы найти наиболее подходящий рендерерследующим образом

HRESULT DShowPlayer::CreateVideoRenderer()
{
    HRESULT hr = E_FAIL;

    enum { Try_EVR, Try_VMR9, Try_VMR7 };

    for (DWORD i = Try_EVR; i <= Try_VMR7; i++)
    {
        switch (i)
        {
        case Try_EVR:
            m_pVideo = new (std::nothrow) CEVR();
            break;

        case Try_VMR9:
            m_pVideo = new (std::nothrow) CVMR9();
            break;

        case Try_VMR7:
            m_pVideo = new (std::nothrow) CVMR7();
            break;
        }

        if (m_pVideo == NULL)
        {
            hr = E_OUTOFMEMORY;
            break;
        }

        hr = m_pVideo->AddToGraph(m_pGraph, m_hwnd);
        if (SUCCEEDED(hr))
        {
            break;
        }

        delete m_pVideo;
        m_pVideo = NULL;
    }
    return hr;
}

Каждый из них инициализируется в режиме без окон, например VMR9

HRESULT InitWindowlessVMR9( 
    IBaseFilter *pVMR,              // Pointer to the VMR
    HWND hwnd,                      // Clipping window
    IVMRWindowlessControl9** ppWC   // Receives a pointer to the VMR.
    ) 
{ 

    IVMRFilterConfig9 * pConfig = NULL; 
    IVMRWindowlessControl9 *pWC = NULL;

    // Set the rendering mode.  
    HRESULT hr = pVMR->QueryInterface(IID_PPV_ARGS(&pConfig)); 
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pConfig->SetRenderingMode(VMR9Mode_Windowless); 
    if (FAILED(hr))
    {
        goto done;
    }

    // Query for the windowless control interface.
    hr = pVMR->QueryInterface(IID_PPV_ARGS(&pWC));
    if (FAILED(hr))
    {
        goto done;
    }

    // Set the clipping window.
    hr = pWC->SetVideoClippingWindow(hwnd);
    if (FAILED(hr))
    {
        goto done;
    }

    // Preserve aspect ratio by letter-boxing
    hr = pWC->SetAspectRatioMode(VMR9ARMode_LetterBox);
    if (FAILED(hr))
    {
        goto done;
    }

    // Return the IVMRWindowlessControl pointer to the caller.
    *ppWC = pWC;
    (*ppWC)->AddRef();

done:
    SafeRelease(&pConfig);
    SafeRelease(&pWC);
    return hr; 
} 

И добавляет фильтр рендеринга к графику следующим образом:

HRESULT CVMR9::AddToGraph(IGraphBuilder *pGraph, HWND hwnd)
{
    IBaseFilter *pVMR = NULL;

    HRESULT hr = AddFilterByCLSID(pGraph, CLSID_VideoMixingRenderer9, &pVMR, L"VMR-9");
    if (SUCCEEDED(hr))
    {
        // Set windowless mode on the VMR. This must be done before the VMR 
        // is connected.
        hr = InitWindowlessVMR9(pVMR, hwnd, &m_pWindowless);
    }
    SafeRelease(&pVMR);
    return hr;
}

Как мне заставить плеер отображаться на панели?

Ответы [ 2 ]

1 голос
/ 03 июня 2019

Обратите внимание, что IMediaEventEx::SetNotifyWindow, указанный вами во фрагменте кода, не определяет, где отображается видео. Этот вызов предназначен для того, чтобы сообщить менеджеру графов фильтров, где вы хотите получать уведомления.

Вы не указываете, какой режим рендеринга видео вы используете, поэтому я предполагаю, что это самый простой (хотя и упоминается как "устаревший") - оконный режим . IVideoWindow::put_Owner и IVideoWindow::SetWindowPosition - это то, как вы определяете, где видео отображается в оконном режиме, put_Owner, в частности, использует дескриптор родительского окна.

2019-06-04 Обновление

Итак, вы пытаетесь изменить Пример и руководство по DShowPlayer , и код использует безоконный режим.

В Windows Vista в примере будет использоваться путь к коду EVR, поэтому я не уверен, почему вы предпочитаете ссылаться на VMR-9. Тем не менее, у них обоих есть методы "инициализации без окон" с HWND в качестве аргумента. Это дескриптор окна, в который встроено видео. Предполагается, что вы используете видимый дескриптор окна ( ссылка для EVR), а также укажите допустимый прямоугольник отсечения ( ссылка ). Пример уже делает это, и вы можете изменить его и аналогичным образом использовать другое окно, например панель.

0 голосов
/ 05 июня 2019

Я нашел проблему. Если вы установите максимальное значение окна для основной формы.

    WindowState = wsMaximized;

Дескриптор форм классифицируется как недопустимый при попытке добавить средство визуализации на график.

        hr = m_pVideo->AddToGraph(m_pGraph, m_hwnd);
        if (SUCCEEDED(hr))
        {
            break;
        }

У меня была эта строка в конструкторе для MainForm, и это вызвало проблему, перемещение строки в FormActivate устранило проблему.

...