[ZZ]《directshow 开发指南》SimplePlayer例子之SimplePlayerDlg

 

            CDXGraph类是不用多说的,都很容易理解,这里贴的,是SimplePlayerDlg.cpp的代码:
首先来看析构:
CSimplePlayerDlg::~CSimplePlayerDlg()
{
    DestroyGraph();
}
调用了 DestroyGraph()函数,这个函数的主要作用是delete mFilterGraph。

打开文件按钮:
void CSimplePlayerDlg::OnButtonOpen()
{
    // TODO: Add your control notification handler code here
    CString    strFilter = "AVI File (*.avi)|*.avi|";
    strFilter += "MPEG File (*.mpg;*.mpeg)|*.mpg;*.mpeg|";
    strFilter += "Mp3 File (*.mp3)|*.mp3|";
    strFilter += "Wave File (*.wav)|*.wav|";
    strFilter += "All Files (*.*)|*.*|";
    CFileDialog dlgOpen(TRUE, NULL, NULL, OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
        strFilter, this);
    if (IDOK == dlgOpen.DoModal())
    {
        mSourceFile = dlgOpen.GetPathName();
        // Rebuild the file playback filter graph
        CreateGraph();
    }
}

这里,注意的是,调用了CreateGraph(),而CreateGraph()的作用,我们来看看:

void CSimplePlayerDlg::CreateGraph(void)//---------------------------创建Filter Graph Manager(打开文件的时候调用)_By_Laura
{
    DestroyGraph();//------------------------------------------------先析构掉上次的mFilterGraph

    mFilterGraph = new CDXGraph();
    if (mFilterGraph->Create())//------------------------------------(第一步)创建Filter Graph Manager
    {
        // Render the source clip
        mFilterGraph->RenderFile(mSourceFile);//---------------------(第二步)创建一条完整的Filter链路(过程需要字符编码转换)_By_Laura
        // Set video window and notification window
        mFilterGraph->SetDisplayWindow(mVideoWindow.GetSafeHwnd());//显示视频窗口_By_Laura
        mFilterGraph->SetNotifyWindow(this->GetSafeHwnd());//--------事件通知_By_Laura
        // Show the first frame
        mFilterGraph->Pause();//-------------------------------------(第三步)调用Filter Graph Manager的接口进行控制_By_Laura
    }
}

然后是播放按钮:
void CSimplePlayerDlg::OnButtonPlay()
{
    if (mFilterGraph)
    {
        mFilterGraph->Run();
        // Start a timer
        if (mSliderTimer == 0)                 //第一个参数是定时器ID,第二个是时间间隔(以毫秒为单位) _By_Laura
        {                                                            //第三个是响应这个时钟到来时的回调函数,如果为NULL  _By_Laura
            mSliderTimer = SetTimer(SLIDER_TIMER, 100, NULL);//则采用默认的回调函数OnTimer()  _By_Laura
        }                                        
    }
}

这里要注意的是SetTimer()函数,关于它:
/*---------------------------------About SetTimer()----------------------------------------*/

             详见:http://www.directshow.cn/site/?action-viewthread-tid-1419      By_Laura
                     :http://www.bloghome.cn/posts/20052_By_Laura                    By_Laura
     MSDN见:http://msdn2.microsoft.com/en-us/library/49313fdf(VS.71).aspx  By_Laura

/*-----------------------------------------------------------------------------------------*/
继续:
void CSimplePlayerDlg::OnButtonStop()
{
    if (mFilterGraph)
    {
        mFilterGraph->SetCurrentPosition(0);
        mFilterGraph->Stop();
        // Stop the timer
        if (mSliderTimer)
        {
            KillTimer(mSliderTimer);//-------------------------------销毁定时器_By_Laura
            mSliderTimer = 0;
        }
    }
}

void CSimplePlayerDlg::OnButtonGrab()//------------------------------抓图_By_Laura
{
    if (mFilterGraph)
    {
        // Firstly grab a bitmap to a temp file
        char  szTemp[] = "C://mysnapshot.bmp";
        if (mFilterGraph->SnapshotBitmap(szTemp))
        {
            // User can browser for a new file here
            CString   strFilter = "BMP File (*.bmp)|*.bmp|";
            CFileDialog dlgOpen(FALSE, ".bmp", NULL, OFN_HIDEREADONLY, strFilter, NULL);
            if (IDOK == dlgOpen.DoModal())
            {
                ::CopyFile(szTemp, dlgOpen.GetPathName(), FALSE);
                ::DeleteFile(szTemp);
            }
        }
       
    }
}

void CSimplePlayerDlg::OnButtonFullscreen()//------------------------全屏_By_Laura
{
    if (mFilterGraph)
    {
        mFilterGraph->SetFullScreen(TRUE);
    }
}

BOOL CSimplePlayerDlg::OnEraseBkgnd(CDC* pDC)//----------------------WM_ERASEBKGND 的消息响应_By_Laura
{
    // Intercept background erasing for the movie window, since the
    // video renderer will keep the screen painted.  Without this code,
    // your video window might get painted over with gray (the default
    // background brush) when it is obscured by another window and redrawn.
    CRect rc;
    // Get the bounding rectangle for the movie screen
    mVideoWindow.GetWindowRect(&rc);
    ScreenToClient(&rc);//-------------------------------------------屏幕坐标转为用户坐标_By_Laura
    // Exclude the clipping region occupied by our movie screen
    pDC->ExcludeClipRect(&rc);

    // Erase the remainder of the dialog as usual
    return CDialog::OnEraseBkgnd(pDC);
}

// We use "Return" key and "Esc" key to restore from fullscreen mode
BOOL CSimplePlayerDlg::PreTranslateMessage(MSG* pMsg) //-------------响应键盘的Enter与ESC操作(退出全屏模式)_By_Laura
{
    if (pMsg->message == WM_KEYDOWN)
    {
        if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
        {
            // Restore form fullscreen mode
            RestoreFromFullScreen();
            return 1;
        }
    }

    return CDialog::PreTranslateMessage(pMsg);
}

void CSimplePlayerDlg::RestoreFromFullScreen(void)//-----------------撤销全屏模式_By_Laura
{
    if (mFilterGraph)
    {
        if (mFilterGraph->GetFullScreen())
        {
            mFilterGraph->SetFullScreen(FALSE);
        }
    }
}

void CSimplePlayerDlg::OnTimer(UINT nIDEvent) //---------------------刷新进度条_By_Laura
{
    if (nIDEvent == mSliderTimer && mFilterGraph)
    {
        double pos = 0, duration = 1.;
        mFilterGraph->GetCurrentPosition(&pos);
        mFilterGraph->GetDuration(&duration);
        // Get the new position, and update the slider
        int newPos = int(pos * 1000 / duration);
        if (mSliderGraph.GetPos() != newPos)
        {
            mSliderGraph.SetPos(newPos);
        }
    }

    CDialog::OnTimer(nIDEvent);
}

BOOL CSimplePlayerDlg::DestroyWindow() //----------------------------(重载函数)关闭窗口时销毁计时器_By_Laura
{
    if (mSliderTimer)
    {
        KillTimer(mSliderTimer);
        mSliderTimer = 0;
    }
   
    return CDialog::DestroyWindow();
}

void CSimplePlayerDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) //当拖动滑杆时_By_Laura
{
    if (pScrollBar->GetSafeHwnd() == mSliderGraph.GetSafeHwnd())
    {
        if (mFilterGraph)
        {
            // Calculate the current seeking position
            double duration = 1.;
            mFilterGraph->GetDuration(&duration);
            double pos = duration * mSliderGraph.GetPos() / 1000.;
            mFilterGraph->SetCurrentPosition(pos);
        }       
    }
    else
    {
        CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
    }
}

// Deal with the graph events
LRESULT CSimplePlayerDlg::OnGraphNotify(WPARAM inWParam, LPARAM inLParam)//获取Filter Graph通知并处理_By_Laura
{
    IMediaEventEx * pEvent = NULL;
    if (mFilterGraph && (pEvent = mFilterGraph->GetEventHandle()))
    {
        LONG   eventCode = 0, eventParam1 = 0, eventParam2 = 0;
        while (SUCCEEDED(pEvent->GetEvent(&eventCode, &eventParam1, &eventParam2, 0)))
        {
            // Spin through the events
            pEvent->FreeEventParams(eventCode, eventParam1, eventParam2);
            switch (eventCode)
            {
            case EC_COMPLETE://--------------------------------------播放完毕此流后,暂停,转到流的开始处_By_Laura
                OnButtonPause();
                mFilterGraph->SetCurrentPosition(0);
                break;
           
            case EC_USERABORT:
            case EC_ERRORABORT://------------------------------------Filter Graph运行时的错误处理_By_Laura
                OnButtonStop();
                break;

            default:
                break;
            }
        }
    }
    return 0;
}
=============================================
注意,以上都是必须的代码,而以下的,则用于测试:
HRESULT CSimplePlayerDlg::FindFilterByInterface(REFIID riid, IBaseFilter** ppFilter)
{
    *ppFilter = NULL;
    if (!mFilterGraph)
    {
        return E_FAIL;
    }

    IEnumFilters* pEnum;
    HRESULT hr = mFilterGraph->GetGraph()->EnumFilters(&pEnum);
    if (FAILED(hr))
    {
        return hr;
    }

    IBaseFilter* pFilter = NULL;
    while (pEnum->Next(1, &pFilter, NULL) == S_OK)
    {
        // Check for required interface
        IUnknown* pUnk;
        HRESULT hrQuery = pFilter->QueryInterface(riid, (void**)&pUnk);
        if (SUCCEEDED(hrQuery))
        {
            pUnk->Release();
            pEnum->Release();
            *ppFilter = pFilter;
            return S_OK;
        }
        pFilter->Release();
    }
    pEnum->Release();

    return E_FAIL;
}

void CSimplePlayerDlg::ShowVRPropertyPage(void)
{
    IBaseFilter *pFilter = NULL;
    if (FAILED(FindFilterByInterface(IID_IVideoWindow, &pFilter)))
    {
        return;
    }
    pFilter->Release();

    ISpecifyPropertyPages *pProp = NULL;
    HRESULT hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
    if (SUCCEEDED(hr))
    {
        // Get the filter's name and IUnknown pointer.
        FILTER_INFO FilterInfo;
        hr = pFilter->QueryFilterInfo(&FilterInfo);
        IUnknown *pFilterUnk;
        pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);

        // Show the page.
        CAUUID caGUID;
        pProp->GetPages(&caGUID);
        pProp->Release();
        OleCreatePropertyFrame(
            this->GetSafeHwnd(),                   // Parent window
            0, 0,                   // Reserved
            FilterInfo.achName,     // Caption for the dialog box
            1,                      // Number of objects (just the filter)
            &pFilterUnk,            // Array of object pointers.
            caGUID.cElems,          // Number of property pages
            caGUID.pElems,          // Array of property page CLSIDs
            0,                      // Locale identifier
            0, NULL                 // Reserved
        );

        // Clean up.
        pFilterUnk->Release();
        FilterInfo.pGraph->Release();
        CoTaskMemFree(caGUID.pElems);
    }
}

void CSimplePlayerDlg::OnButtonTest()
{
    ShowVRPropertyPage();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android 系统中的 SimplePlayer.cpp 文件是一个简单的媒体播放器示例程序,它并不负责将文件编码成 MP4 格式。如果需要将一个视频文件编码成 MP4 格式,可以使用 Android 系统中提供的 MediaCodec 和 MediaMuxer 类来完成。具体的步骤如下: 1. 创建一个 MediaCodec 对象,并将其配置为编码器。可以使用 MediaCodec.createEncoderByType() 方法来创建编码器对象,然后使用 MediaCodec.configure() 方法进行配置,设置输出格式、编码器参数等参数。 2. 创建一个 MediaMuxer 对象,并调用其 addTrack() 方法添加一个音频或视频轨道。可以使用 MediaMuxer 构造函数创建一个对象,然后使用 addTrack() 方法添加轨道。 3. 开始编码和封装视频数据。使用 MediaCodec.start() 方法启动编码器,并调用 MediaCodec.getInputBuffer() 和 MediaCodec.getOutputBuffer() 方法获取输入和输出缓冲区。将视频数据写入输入缓冲区,然后将输出缓冲区中的数据写入 MediaMuxer 中。 4. 结束编码和封装过程,释放资源。在完成编码和封装过程后,需要调用 MediaCodec.stop() 和 MediaCodec.release() 方法释放编码器资源,调用 MediaMuxer.stop() 和 MediaMuxer.release() 方法释放 Muxer 资源,最后关闭文件输出流。 需要注意的是,编码和封装视频数据是一项相对复杂的任务,需要熟练掌握 Android 媒体编码、封装、解码等技术,以及相关的音视频编码标准和格式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值