⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 blenderdlg.cpp

📁 最近在学习directshow, Directshow实务精选的源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    while (pEnum->Next(1, &pPin, NULL) == S_OK)
    {
        PIN_DIRECTION ThisPinDir;

        pPin->QueryDirection(&ThisPinDir);
        if (ThisPinDir == PinDir)
        {
            IPin *pTmp = 0;

            hr = pPin->ConnectedTo(&pTmp);
            if (SUCCEEDED(hr))  // Already connected, not the pin we want.
            {
                pTmp->Release();
            }
            else  // Unconnected, this is the pin we want.
            {
                pEnum->Release();
                *ppPin = pPin;
                return S_OK;
            }
        }
        pPin->Release();
    }

    // Release the enumerator
    pEnum->Release();

    // Did not find a matching pin
    return E_FAIL;
}


BOOL CBlenderDlg::IsWindowsMediaFile(WCHAR *lpszFile)
{
    USES_CONVERSION;
    TCHAR szFilename[MAX_PATH];

    // Copy the file name to a local string and convert to lowercase
    _tcsncpy(szFilename, W2T(lpszFile), NUMELMS(szFilename));
    szFilename[MAX_PATH-1] = 0;
    _tcslwr(szFilename);

    if (_tcsstr(szFilename, TEXT(".asf")) ||
        _tcsstr(szFilename, TEXT(".wma")) ||
        _tcsstr(szFilename, TEXT(".wmv")))
        return TRUE;
    else
        return FALSE;
}


HRESULT CBlenderDlg::RenderFileToVMR9(WCHAR *wFileName, IBaseFilter *pRenderer, BOOL bRenderAudio=TRUE)
{
    HRESULT hr=S_OK;
    CComPtr <IPin> pOutputPin;
    CComPtr <IBaseFilter> pSource;
    CComPtr <IBaseFilter> pAudioRenderer;
    CComPtr <IFilterGraph2> pFG;

    // Add a file source filter for this media file
    if (!IsWindowsMediaFile(wFileName))
    {
        // Add the source filter to the graph
        JIF(pGB->AddSourceFilter(wFileName, L"SOURCE", &pSource));

        // Get the interface for the output pin
        JIF(GetUnconnectedPin(pSource, PINDIR_OUTPUT, &pOutputPin));
    }
    else
    {
        Msg(TEXT("Windows Media files (ASF,WMA,WMV) are not supported by this application.\r\n\r\n")
            TEXT("For a full example of Windows Media support using the\r\n")
            TEXT("DirectShow WM ASF Reader filter and implementing a key provider\r\n")
            TEXT("for Windows Media content, refer to the following SDK samples:\r\n\r\n")
            TEXT("       - AudioBox   - Jukebox   - PlayWndASF\r\n\r\n")
            TEXT("Each of the listed samples provides the necessary extra code\r\n")
            TEXT("and links with the required Windows Media libraries.\0"),
            TEXT("Windows Media files are not supported"), MB_OK);
        return E_FAIL;
    }

    // Render audio if requested (defaults to TRUE)
    if (bRenderAudio)
    {
        // Because we will be rendering with the RENDERTOEXISTINGRENDERERS flag,
        // we need to create an audio renderer and add it to the graph.  
        // Create an instance of the DirectSound renderer (for each media file).
        JIF(CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER, 
                             IID_IBaseFilter, (void **)&pAudioRenderer));

        JIF(pGB->AddFilter(pAudioRenderer, L"Audio Renderer"));
    }

    // Get an IFilterGraph2 interface to assist in building the
    // multifile graph with the non-default VMR9 renderer
    JIF(pGB->QueryInterface(IID_IFilterGraph2, (void **)&pFG));

    // Render the output pin, using the VMR9 as the specified renderer.  This is 
    // necessary in case the GraphBuilder needs to insert a Color Space convertor,
    // or if multiple filters insist on using multiple allocators.
    // The audio renderer will also be used, if the media file contains audio.
    JIF(pFG->RenderEx(pOutputPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL));

    return hr;
}


HRESULT CBlenderDlg::ConfigureMultiFileVMR9(WCHAR *wFile1, WCHAR *wFile2)
{
    HRESULT hr=S_OK;
    CComPtr <IBaseFilter> pVmr;

    // Create the Video Mixing Renderer and add it to the graph
    JIF(InitializeWindowlessVMR(&pVmr));
            
    // Render the files programmatically to use the VMR9 as renderer
    if (SUCCEEDED(hr = RenderFileToVMR9(wFile1, pVmr, TRUE)))
        hr = RenderFileToVMR9(wFile2, pVmr, TRUE);

    return hr;
}

HRESULT CBlenderDlg::InitializeVideo(void)
{
    USES_CONVERSION;
    WCHAR wFile1[MAX_PATH], wFile2[MAX_PATH];
    HRESULT hr;

    // Clear open dialog remnants before calling RenderFile()
    UpdateWindow();

    // Convert filenames to wide character strings for RenderFile()
    wcsncpy(wFile1, T2W(m_szFile1), NUMELMS(wFile1)-1);
    wcsncpy(wFile2, T2W(m_szFile2), NUMELMS(wFile2)-1);
    wFile1[MAX_PATH-1] = wFile2[MAX_PATH-1] = 0;

    // Create a DirectShow GraphBuilder object
    JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
                         IID_IGraphBuilder, (void **)&pGB));

    if(SUCCEEDED(hr))
    {
        // Unlike the VMR7 in Windows XP, the VMR9 is not the default renderer
        // (to preserve backward compatibility).  In some multifile graphs,
        // the filter graph manager could decide to load the default Video Renderer
        // filter during RenderFile(), even though the VMR9 is already present
        // in the graph.  Since the default Video Renderer has a higher merit 
        // than the VMR9, it would be connected instead of the VMR9, leading to
        // the video streams being displayed in multiple separate windows.
        // This could be the case with AVI files created with legacy VfW codecs
        // or when two Color Space convertors must be used (each requiring its
        // own allocator).
        // Therefore, we render the files programmatically instead of using
        // the standard IGraphBuilder::RenderFile() method.
        JIF(ConfigureMultiFileVMR9(wFile1, wFile2));

        // Get DirectShow interfaces
        JIF(pGB->QueryInterface(IID_IMediaControl, (void **)&pMC));
        JIF(pGB->QueryInterface(IID_IMediaEventEx, (void **)&pME));
        JIF(pGB->QueryInterface(IID_IMediaSeeking, (void **)&pMS));

        // Have the graph signal event via window callbacks
        JIF(pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0));

#ifdef REGISTER_FILTERGRAPH
        m_dwGraphRegister = 0;
        hr = AddGraphToRot(pGB, &m_dwGraphRegister);
        if (FAILED(hr))
            Msg(TEXT("Failed to register filter graph with ROT!  hr=0x%x"), hr);
#endif

        // Run the graph to play the media files
        OnPlay();

        // Set initial movie position
        MoveVideoWindow();
        RepaintVideo();
    }

    return hr;
}

HRESULT CBlenderDlg::FreeDirectShow(void)
{
#ifdef REGISTER_FILTERGRAPH
        RemoveGraphFromRot(m_dwGraphRegister);
#endif

    HRESULT hr=S_OK;

    // Stop the position timer
    StopTimer();

    // Stop playback
    if (pMC)
        hr = pMC->Stop();

    // Disable event callbacks
    if (pME)
        hr = pME->SetNotifyWindow((OAHWND)NULL, 0, 0);

    // Release all active interfaces
    SAFE_RELEASE(pMC);
    SAFE_RELEASE(pMS);
    SAFE_RELEASE(pME);
    SAFE_RELEASE(pGB);
    SAFE_RELEASE(pWC);      // IVMRWindowlessControl9
    SAFE_RELEASE(pMix);     // IVMRMixerControl9

    return hr;
}

void CBlenderDlg::OnStop() 
{
    HRESULT hr;

    // Update button state
    m_ButtonPlay.EnableWindow(TRUE);
    m_ButtonStop.EnableWindow(FALSE);
    m_ButtonPause.EnableWindow(FALSE);

    // Stop the position timer
    StopTimer();

    // Stop playback
    if (pMC)
        hr = pMC->Stop();

    // Wait for the stop to propagate to all filters
    WaitForState(State_Stopped);

    // Reset to first frame of movie
    if (pMS)
    {
        LONGLONG pos=0;
        hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
                               NULL, AM_SEEKING_NoPositioning);
    }

    // Refresh the current position text display
    UpdatePosition();
}

void CBlenderDlg::OnPause() 
{
    HRESULT hr;

    // Update button state
    m_ButtonPlay.EnableWindow(TRUE);
    m_ButtonPause.EnableWindow(FALSE);

    // Stop the position timer
    StopTimer();

    // Pause playback
    if (pMC)
        hr = pMC->Pause();

    // Wait for the pause to propagate to all filters
    WaitForState(State_Paused);
}

void CBlenderDlg::OnPlay() 
{
    HRESULT hr;

    // Update button state
    m_ButtonPlay.EnableWindow(FALSE);
    m_ButtonStop.EnableWindow(TRUE);
    m_ButtonPause.EnableWindow(TRUE);

    // Start the filter graph
    if (pMC)
        hr = pMC->Run();

    // Wait for the stop to propagate to all filters
    WaitForState(State_Running);

    // Start the position timer
    StartTimer();
}

void CBlenderDlg::InitButtons(void)
{
    // Set the default state of the media control buttons
    m_ButtonPlay.EnableWindow(TRUE);
    m_ButtonStop.EnableWindow(FALSE);
    m_ButtonPause.EnableWindow(FALSE);
}


BOOL CBlenderDlg::VerifyVMR9(void)
{
    HRESULT hres;

    // Verify that the VMR exists on this system
    IBaseFilter* pBF = NULL;
    hres = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC,
        IID_IBaseFilter, (LPVOID *)&pBF);

    if(SUCCEEDED(hres))
    {
        // VMR successfully created, so release it
        pBF->Release();
        return TRUE;
    }
    else
    {
        MessageBox(
            TEXT("This application requires the Video Mixing Renderer 9, which is present\r\n")
            TEXT("only on DirectX 9 systems with hardware video acceleration enabled.\r\n\r\n")

            TEXT("The Video Mixing Renderer (VMR) is not enabled when viewing a \r\n")
            TEXT("remote Windows XP machine through a Remote Desktop session.\r\n")
            TEXT("You can run VMR-enabled applications only on your local machine.\r\n\r\n")

            TEXT("To verify that hardware acceleration is enabled on a Windows XP\r\n")
            TEXT("system, follow these steps:\r\n")
            TEXT("-----------------------------------------------------------------------\r\n")
            TEXT(" - Open 'Display Properties' in the Control Panel\r\n")
            TEXT(" - Click the 'Settings' tab\r\n")
            TEXT(" - Click on the 'Advanced' button at the bottom of the page\r\n")
            TEXT(" - Click on the 'Troubleshooting' tab in the window that appears\r\n")
            TEXT(" - Verify that the 'Hardware Acceleration' slider is at the rightmost position\r\n")

            TEXT("\r\nThis sample will now exit."),

            TEXT("Video Mixing Renderer capabilities are required"), MB_OK);
        
        return FALSE;
    }
}


HRESULT CBlenderDlg::InitializeWindowlessVMR(IBaseFilter **ppVmr9)
{
    IBaseFilter *pVmr=NULL;

    if (!ppVmr9)
        return E_POINTER;
    *ppVmr9 = NULL;

    // Create the VMR and add it to the filter graph.
    HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL,
                     CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);

    if (SUCCEEDED(hr)) 
    {
        hr = pGB->AddFilter(pVmr, L"Video Mixing Renderer 9");
        if (SUCCEEDED(hr)) 
        {
            // Set the rendering mode and number of streams
            CComPtr <IVMRFilterConfig9> pConfig;

            JIF(pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig));
            JIF(pConfig->SetRenderingMode(VMR9Mode_Windowless));

            // Set the bounding window and border for the video
            JIF(pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pWC));
            JIF(pWC->SetVideoClippingWindow(m_hwndScreen));
            JIF(pWC->SetBorderColor(RGB(0,0,0)));    // Black border

            // Get the mixer control interface for later manipulation of video 
            // stream output rectangles and alpha values
            JIF(pVmr->QueryInterface(IID_IVMRMixerControl9, (void**)&pMix));
        }

        // Don't release the pVmr interface because we are copying it into
        // the caller's ppVmr9 pointer
        *ppVmr9 = pVmr;
    }

    return hr;
}


void CBlenderDlg::OnClose() 
{
    // Release DirectShow interfaces
    FreeDirectShow();

    // Release COM
    CoUninitialize();

    CDialog::OnClose();
}

void CBlenderDlg::OnDestroy() 
{
    // Release DirectShow interfaces
    FreeDirectShow();   

    CDialog::OnDestroy();
}

HRESULT CBlenderDlg::UpdatePinAlpha(int nStreamID)
{
    HRESULT hr=S_OK;

    // Get a pointer to the selected stream's information
    STRM_PARAM* p = &strParam[nStreamID];

    // Update the alpha value for the selected stream
    if(pMix)
        hr = pMix->SetAlpha(nStreamID, p->Alpha);

    if (SUCCEEDED(hr))
        DisplayAlpha(nStreamID);

    return hr;
}

void CBlenderDlg::DisplayAlpha(int nStreamID)
{
    USES_CONVERSION;
    int nID[2] = {IDC_STATIC_ALPHA, IDC_STATIC_ALPHA2};
    char szAnsiLabel[32];
    TCHAR szLabel[32];

    // The wsprintf method doesn't support floating point, so use the
    // ANSI version and convert to UNICODE if necessary.
    sprintf(szAnsiLabel, "(%02.2f)\0", strParam[nStreamID].Alpha);
    _tcsncpy(szLabel, A2T(szAnsiLabel), NUMELMS(szLabel)-1);

    CWnd *pWnd = GetDlgItem(nID[nStreamID]);
    pWnd->SetWindowText(szLabel);
}

HRESULT CBlenderDlg::UpdatePinPos(int nStreamID)
{
    HRESULT hr=S_OK;

    // Get a pointer to the selected stream's information
    STRM_PARAM* p = &strParam[nStreamID];

    // Set the left, right, top, and bottom coordinates
    VMR9NormalizedRect r = {p->xPos, p->yPos, p->xPos + p->xSize, p->yPos + p->ySize};

    // If mirrored, swap the left/right coordinates in the destination rectangle
    if (strParam[nStreamID].bMirrored)
    {
        float fLeft = strParam[nStreamID].xPos;
        float fRight = strParam[nStreamID].xPos + strParam[nStreamID].xSize;
        r.left = fRight;
        r.right = fLeft;
    }

    // If flipped, swap the top/bottom coordinates in the destination rectangle
    if (strParam[nStreamID].bFlipped)
    {
        float fTop = strParam[nStreamID].yPos;
        float fBottom = strParam[nStreamID].yPos + strParam[nStreamID].ySize;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -