今天是:   | 登录中心 | | 网络导航
logo 来海南旅游咨询 海南旅游 预订海南酒店 自驾租车 海南高尔夫 问路订房就请拔打海南旅游百事通  全天24小时为您守候 设为首页
加入收藏
联系站长
导航页为首页
内容页为首页
当前位置:南国风 >> IT.信息技术 >> vc.net >> 浏览文章

Visual C++.NET DirectShow编程2

作者:佚名 日期:2009年07月08日 来源:不详 人气:
  6.定义媒体控制成员变量

  修改PlayWndDlg.h如下:
protected:

 HICON m_hIcon;

 // 生成的消息映射函数

 virtual BOOL OnInitDialog();
  afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  afx_msg void OnPaint();
  afx_msg HCURSOR OnQueryDragIcon();
 DECLARE_MESSAGE_MAP()

 //和媒体控制相关的成员变量

private:

 IGraphBuilder *m_pGraph; //IGraphBuilder 接口提供了生成Filter Graph相//关的方法
  IMediaControl *m_pMediaControl;
  //IMediaControl 接口提供了控制流经Filter //Graph数据流的相关方法

 IMediaEventEx *m_pEvent;
  //IMediaEventEx 继承自IMediaEvent,提供了从
  //Filter Graph 管理器获取事件消息的方法

 IMediaSeeking *m_pMediaSeeking; //IMediaSeeking 提供了控制流的播放位置和播放//速度的方法
  CString m_strMediaFile; //当前播放的媒体文件的名称
  BOOL m_isPlaying; //当前的播放状态

};

  在CPlayWndDlg的构造函数中添加初始化代码。

CPlayWndDlg::CPlayWndDlg(CWnd* pParent /*=NULL*/)
: CDialog(CPlayWndDlg::IDD, pParent)

{
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

  m_pGraph = NULL;
  m_pMediaControl = NULL;
  m_pEvent = NULL;
  m_pMediaSeeking = NULL;
  m_strMediaFile = "";
  m_isPlaying = FALSE;

}

  由于一些和窗体控制有关的初始化代码不能放在构造函数中进行,我们将其放在CPlayWndDlg::OnInitDialog()中,我们必须在此必须对CPlayWndDlg添加WS_CLIPCHILDREN 的Style,因为在我们的应用中把视频窗体作为CPlayWndDlg的一个子窗体来使用的,这是非常重要的,许多开发人员在刚开始使用DirectShow时,父窗体的Style没有设置正确,造成视频不能正确显示,代码如下:

// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作

SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标

// TODO: 在此添加额外的初始化代码

ModifyStyle(0, WS_CLIPCHILDREN);
((CEdit*)GetDlgItem(IDC_MEDIAFILE_EDIT))->SetReadOnly(TRUE);

return TRUE; // 除非设置了控件的焦点,否则返回 TRUE

}
   添加相应的清除代码,重载CPlayWndDlg的DestoryWindow方法,如下:

BOOL CPlayWndDlg::DestroyWindow()
{
 // TODO: 在此添加专用代码和/或调用基类
 
 if(m_pGraph)
   m_pGraph->Release();
  if(m_pMediaControl)
   m_pMediaControl->Release();
  if(m_pEvent)
   m_pEvent->Release();
  if(m_pMediaSeeking)
   m_pMediaSeeking->Release();

 m_pGraph = NULL;
  m_pMediaControl = NULL;
  m_pEvent = NULL;
  m_pMediaSeeking = NULL;
  return CDialog::DestroyWindow();

}

  7.修改CPlayWndDlg::OnPaint(),由于现在视频显示区域必须由我们自己进行重画:

void CPlayWndDlg::OnPaint()
{
 if (IsIconic())
  {
  CPaintDC dc(this); // 用于绘制的设备上下文
   SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

  // 使图标在工作矩形中居中
  
  int cxIcon = GetSystemMetrics(SM_CXICON);
   int cyIcon = GetSystemMetrics(SM_CYICON);
   CRect rect;
  GetClientRect(&rect);
  int x = (rect.Width() - cxIcon + 1) / 2;
   int y = (rect.Height() - cyIcon + 1) / 2;

  // 绘制图标

  dc.DrawIcon(x, y, m_hIcon);

 }
 else
  {
  if(m_isPlaying == FALSE)
   {
    CClientDC dc(GetDlgItem(IDC_VW_FRAME));
    dc.SetBkColor(RGB(0,0,0));
    CRect rc;
    GetDlgItem(IDC_VW_FRAME)->GetClientRect(rc);
 
    //ClientToScreen(rc);

    dc.FillRect(rc, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
    GetDlgItem(IDC_VW_FRAME)->Invalidate();
   }
   CDialog::OnPaint();
 }
}

  添加浏览、播放、暂停、关闭四按钮的相应事件响应函数,同时在CPlayWndDlg中添加如下四个私有方法:

void MoveVideoWindow(void);
void CleanUp(void);
BOOL Stop(void);
BOOL Play(void);
   上述方法的实现如下:

// IDC_VW_FRAME控件Picture Control主要作用是控制Vedio Window的显示位置
void CPlayWndDlg::MoveVideoWindow(void)
{
  IVideoWindow* pVideoWinow = NULL;
  if(m_pGraph)
  {
   m_pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVideoWinow);
   CRect rc;
   GetDlgItem(IDC_VW_FRAME)->GetWindowRect(rc);
   ScreenToClient(rc);
   pVideoWinow->SetWindowPosition(rc.left, rc.top, rc.Width(), rc.Height());
   pVideoWinow->Release();
   pVideoWinow = NULL;
  }
}

void CPlayWndDlg::CleanUp(void)
{
  long levCode;
  IVideoWindow *pVidWin = NULL;

  if(!m_pGraph)
   return;

  m_pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
  m_pEvent->WaitForCompletion(INFINITE, &levCode);

  pVidWin->put_Visible(OAFALSE);
  pVidWin->Release();
  m_pMediaSeeking->Release();
  m_pMediaControl->Release();
  m_pEvent->Release();
  m_pGraph->Release();
  m_pMediaSeeking = NULL;
  m_pMediaControl = NULL;
  m_pEvent = NULL;
  m_pGraph = NULL;

  UpdateData(FALSE);
  CClientDC dc(GetDlgItem(IDC_VW_FRAME));
  dc.SetBkColor(RGB(0,0,0));

  CRect rc;

  GetDlgItem(IDC_VW_FRAME)->GetClientRect(rc);
  ClientToScreen(rc);
  dc.FillRect(rc, CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
  Invalidate();
}

BOOL CPlayWndDlg::Stop(void)
{
  IVideoWindow *pVidWin = NULL;
  HRESULT hr;

  if(m_pMediaControl)
  {
   LONGLONG pos = 0;
   hr = m_pMediaControl->Stop();
   hr = m_pMediaSeeking->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,&pos, AM_SEEKING_NoPositioning);

   m_pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
   pVidWin->put_Visible(OAFALSE);

   m_isPlaying = FALSE;
   GetDlgItem(IDC_PLAY_BUTTON)->EnableWindow(TRUE);
   GetDlgItem(IDC_PAUSE_BUTTON)->EnableWindow(FALSE);
   pVidWin->Release();
   long levCode;
   m_pEvent->WaitForCompletion(INFINITE, &levCode);
   m_pMediaControl->Release();

   return TRUE;
  }
  return FALSE;
}

BOOL CPlayWndDlg::Play(void)
{
  // 运行

  IVideoWindow *pVidWin = NULL;

  if(m_pGraph)
  {
   m_pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
   pVidWin->put_Visible(OATRUE);
   m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pMediaControl);
   m_pMediaControl->Run();
   m_isPlaying = TRUE;
   GetDlgItem(IDC_PLAY_BUTTON)->EnableWindow(FALSE);
   GetDlgItem(IDC_PAUSE_BUTTON)->EnableWindow(TRUE);

   return TRUE;
  }
  return FALSE;
}

  浏览、播放、暂停、关闭四按钮的相应事件响应函数如下:

void CPlayWndDlg::OnBnClickedBrowseButton()
{
  CFileDialog dlgFile(TRUE, NULL, NULL,
  OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
  "Movie Files (*.avi;*.mpg;*.mpeg) |\
  *.avi;*.mpg;*.mpeg |\
  Audio Files (*.wav;*mp3;*.mpa;*.mpu;*.au) |\
  *.wav;*.mp3;*.mpa;*.mpu;*.au |\
  Midi Files (*.mid;*.midi;*.rmi) |\
  *.mid;*.midi;*.rmi| | ", this);

  if(dlgFile.DoModal() == IDOK)
  {
   m_strMediaFile = dlgFile.GetPathName();
   GetDlgItem(IDC_MEDIAFILE_EDIT)->SetWindowText(m_strMediaFile);
  }
  else
   return;

  CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGraph);

  HRESULT hr = m_pGraph->RenderFile(CA2W(m_strMediaFile), NULL);
 
  if(FAILED(hr))
  {
   char szMsg[200];
   AMGetText(hr, szMsg, sizeof(szMsg));
   AfxMessageBox(szMsg);
  }

  //指定父窗体

  IVideoWindow* pVidWin = NULL;
  m_pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
  pVidWin->put_Owner((OAHWND)m_hWnd);
  pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);

  CRect rc;
 
  GetDlgItem(IDC_VW_FRAME)->GetWindowRect(rc);
  ScreenToClient(rc);
  pVidWin->SetWindowPosition(rc.left, rc.top, rc.Width(), rc.Height());

  // 注意此处Filter Graph Manager的事件以WM_GRAPHNOTIFY发出(用户定义的消息).
 
  m_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&m_pEvent);
  m_pEvent->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0);

  // 设置Seeking
 
  m_pGraph->QueryInterface(IID_IMediaSeeking, (void **)&m_pMediaSeeking);

}

void CPlayWndDlg::OnBnClickedPlayButton()
{
 Play();
}

void CPlayWndDlg::OnBnClickedPauseButton()
{
 m_pMediaControl->Pause();
 m_isPlaying = TRUE;

 GetDlgItem(IDC_PLAY_BUTTON)->EnableWindow(TRUE);
 GetDlgItem(IDC_PAUSE_BUTTON)->EnableWindow(FALSE);
}

void CPlayWndDlg::OnBnClickedCancel()
{
 // TODO: 在此添加控件通知处理程序代码

 CleanUp();
 OnCancel();
}

  8.添加对WM_GRAPHNOTIFY消息,及其响应函数

  在PlayWndDlg添加消息ID定义:

#define WM_GRAPHNOTIFY WM_USER + 101
   在PlayWndDlg.h中,代码如下:

// 实现

protected:

 HICON m_hIcon;

 // 生成的消息映射函数

 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  afx_msg void OnPaint();
  afx_msg HCURSOR OnQueryDragIcon();

 DECLARE_MESSAGE_MAP()

 afx_msg HRESULT OnGraphNotify(WPARAM wParam,LPARAM lParam);

private:
 
 IGraphBuilder *m_pGraph;
 IMediaControl *m_pMediaControl;
 IMediaEventEx *m_pEvent;

  PlayWndDlg.cpp,如下:

 ON_BN_CLICKED(IDC_BROWSE_BUTTON, OnBnClickedBrowseButton)
  ON_BN_CLICKED(IDC_PLAY_BUTTON, OnBnClickedPlayButton)
  ON_BN_CLICKED(IDC_PAUSE_BUTTON, OnBnClickedPauseButton)
  ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel)
  ON_MESSAGE(WM_GRAPHNOTIFY, OnGraphNotify)

END_MESSAGE_MAP()
   实现如下:

HRESULT CPlayWndDlg::OnGraphNotify(WPARAM wParam,LPARAM lParam)
{
 long levCode, lparam1, lparam2;
  HRESULT hr;

 while (hr = m_pEvent->GetEvent(&levCode, &lparam1, &lparam2, 0), SUCCEEDED(hr))
  {
  hr = m_pEvent->FreeEventParams(levCode, lparam1, lparam2);
  if ((EC_COMPLETE == levCode) || (EC_USERABORT == levCode))
   {
   TRACE("End of the media file!!.\n");
   Stop();

   //CleanUp();

   break;
  }
 }
 return hr;
}



email:lifat@yeah.net| QQ:_3000_99**61 T先生
  服务指南 | 著作权与商标声明 | 法律声明 | 服务条款 | 隐私声明 |


南国风网站的版权信息:保留所有权力

不良信息举报中心!
琼ICP备15001822号