总前言:我打算写一个能实现全能播放的播放器,功能比较简单,也算是抛砖引玉吧,因为内容较多,所以打算写三篇,这是开篇,欢迎大家吐槽

简易播放器的实现

本文的编写环境:visual studio 2008 ,基于MFC based DLG 的应用程序
前言:我写这个系列博客的目的,是想让大家知道,播放器的实现,其实没有想像的那么难,只是掌握了一点的方法,自己完全可以实现,当然出于容易讲解的目的,我会将代码写的尽量简洁,当然,在每个博客的最后都将贴出源代码地址,以供大家,研究学习。

前提:本文并不是假设你从零基础开始就能完全实现的,如果你根本没有了解过directShow,那还是请你从头开始吧,慢慢地了解个个函数的功能,然后再到这里来,因为我会从如何配置VS2005开始一步步的教到你完全写出这个播放器为止,但我并不会每句代码都会讲的很详细,如果有不理解的地方,你可以查看MSDN,directX SDK,找度娘,找谷歌,都是不错的选择。

注意:这篇博客与《DirectShow开发指南》第五章的例子,师从同路,高手可以不看

下面就开始播放器开发的旅程了,准备好了吧,那我们开始了

第一步:配置VS播放器,首先你得先安装directX 9.0开发包,安装好之后,记得编译dx9sdk\Samples\C++\DirectShow\BaseClasses这个目录下的baseclasses工程,然后就是将所需要的文件包含在VS2005配置中,为节省篇幅,这里就不再缀述,可以参看《DirectShow开发指南》P66-P67(开发环境的配置)

第二步:应用程序创建、界面及程序设置
创建一个MFC应用程序,based DLG,命名为Player

(一)配置
1、选择“项目”-》“player属性”打开属性页;
2、选择先在DEBUG模式下,选择“配置属性”-》“链接器”-》“输入”-》“附加依赖项”处添加:
strmbasd.lib uuid.lib winmm.lib Quartz.lib Strmiids.lib
如图:

3、然后将“配置”选项改为“Release”,重复上一操作,即添加相同的依赖项
4、在PlayDlg.cpp和PlayDlg.h的顶部加入directShow所需要的头文件#include<streams.h>

(二)界面设置
界面如下:

说明:
1、其中红框处,是添加的一个Picture Ctrl控件,ID号设置为:IDC_VIDEOWND,将其Type属性改为“Rectangle”

2、添加了一个Slider Ctrl,其ID设置为IDC_PROGRESS

3、添加三个按钮,“打开”按钮的ID号为:IDC_BTN_OPEN,“播放”按钮的ID号设置为IDC_BTN_PLAY,“暂停”按钮的ID号设置为“IDC_BTN_PAUSE”,“停止”按钮的ID号设置为:IDC_BTN_STOP

(三)关联变量

1、对Picture Ctrl控件关联CStatic型变量m_VideoWindowPlay;

2、对Slider Ctrl控件关联CSliderCtrl型变量m_Slider;

注意:由于MFC本身的CSliderCtrl会存在很多问题,比如定位不准确,等,所以我们一般不使用这个类,而改成我们自己的类,请到下面的地下下载CNiceSlider类

http://download.csdn.net/detail/harvic880925/4554013

然后将下载后的文件加载到工程中,并在PlayerDlg.h的文件中增加#include"NiceSlider.h"

然后将m_VideoWindow前的CStatic改为CNiceSliderCtrl,即

(四)初始化COM组件
因为DirectShow是COM组件,所以我们在使用前要先对其初始化,用完之后,也要手动解除

在CPlayerApp类中的InitInstance()函数中,添加初始化代码:

[cpp] view plain copy
  1. <span style="font-size:14px;">HRESULT hr=CoInitialize(NULL);
  2. if(FAILED(hr))
  3. {
  4. printf("ERROR-Could not initialize COM libray");
  5. return -1;
  6. }
  7. </span>

位置如图:

然后添加在CPlayerApp类中添加ExitInstance()函数,在其中添加::CoUninitialize();以解除使用


第三步:实战

(一)变量定义、初始化及实例化
1、变量定义:

[cpp] view plain copy
  1. <span style="font-size:14px;">  IGraphBuilder * m_Graph;   //GraphBuilder对象,实现整个Graph的构建及执行等
  2. IMediaControl * m_MediaControl; //主要用来媒体控制,Run()、Pause()、Stop()等
  3. IMediaEventEx * m_Event;     //主要用来关联消息接收及处理对象、实现消息处理,跟写WIN32 SDK程序差不多,需要自己捕捉消息,然后自定义处理函数
  4. IBasicVideo * m_BasicVideo;  //视频控制
  5. IBasicAudio * m_BasicAudio;  //音频控制
  6. IVideoWindow * m_VideoWindow;  //主要用来指定播放窗口,定义全屏,等
  7. IMediaSeeking * m_Seeking;   //主要用来媒体定位</span>

以上只是对各变量功能作了下简单的讲解,如果想具体了解,可以查看SDK或MSDN

2、初始化

CPlayerDlg::OnInitDialog()在添加初始化信息:

[cpp] view plain copy
  1. <span style="font-size:14px;">  m_Graph=NULL;
  2. m_MediaControl=NULL;
  3. m_Event=NULL;
  4. m_BasicVideo=NULL;
  5. m_BasicAudio=NULL;
  6. m_VideoWindow=NULL;
  7. m_Seeking=NULL;
  8. this->m_Slider.SetRange(0,1000);
  9. this->m_Slider.SetPos(0);</span>

3、实例化

在CPlayerDlg类中,添加一个函数Create();专门用来实例化各个变量

[csharp] view plain copy
  1. <span style="font-size:14px;">bool CPlayerDlg::Create()
  2. {
  3. if(!m_Graph)
  4. {
  5. HRESULT hr=S_OK;
  6. if(SUCCEEDED(::CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void * *)&m_Graph)))
  7. {
  8. hr |=this->m_Graph->QueryInterface(IID_IMediaControl,(void **)&this->m_MediaControl);
  9. hr |=this->m_Graph->QueryInterface(IID_IBasicAudio,(void **)&this->m_BasicAudio);
  10. hr |=this->m_Graph->QueryInterface(IID_IMediaEventEx,(void **)&this->m_Event);
  11. hr |=this->m_Graph->QueryInterface(IID_IBasicVideo,(void **)&this->m_BasicVideo);
  12. hr |=this->m_Graph->QueryInterface(IID_IVideoWindow,(void **)&this->m_VideoWindow);
  13. hr |=this->m_Graph->QueryInterface(IID_IMediaSeeking,(void **)&this->m_Seeking);
  14. if(this->m_Seeking)
  15. {
  16. m_Seeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);//将时间设置为以100ns为单位的格式
  17. }
  18. return SUCCEEDED(hr);
  19. }
  20. m_Graph=0;
  21. }
  22. return false;
  23. }</span>

(二)针对更接口函数的封装

1、针对IMediaControl类的函数封装,封装Run(),Stop,Pause()函数,及IsRun(),IsStop(),IsPause()函数的实现,代码简单,不再详述

[cpp] view plain copy
  1. <span style="font-size:14px;">bool CPlayerDlg::IsRunning()
  2. {
  3. if(m_Graph&&this->m_MediaControl)
  4. {
  5. OAFilterState FilterState=State_Stopped;
  6. HRESULT hr=this->m_MediaControl->GetState(10,&FilterState);
  7. if(SUCCEEDED(hr))
  8. {
  9. if(FilterState==State_Running)
  10. {return true;}
  11. }
  12. }
  13. return false;
  14. }
  15. bool CPlayerDlg::Run()
  16. {
  17. if(m_Graph&&this->m_MediaControl)
  18. {
  19. if(!IsRunning())
  20. {
  21. if(SUCCEEDED(this->m_MediaControl->Run()))
  22. {
  23. return true;
  24. }
  25. }else
  26. {
  27. return true;
  28. }
  29. }
  30. return false;
  31. }
  32. bool CPlayerDlg::IsStopped()
  33. {
  34. if(m_Graph&&this->m_MediaControl)
  35. {
  36. OAFilterState FilterState=State_Stopped;
  37. if(SUCCEEDED(this->m_MediaControl->GetState(10,&FilterState)))
  38. {
  39. if(FilterState==State_Stopped)
  40. {
  41. return true;
  42. }
  43. }
  44. }
  45. return false;
  46. }
  47. bool CPlayerDlg::Stop()
  48. {
  49. if(m_Graph&&this->m_MediaControl)
  50. {
  51. if(!this->IsStopped())
  52. {
  53. if(SUCCEEDED(this->m_MediaControl->Stop()))
  54. {
  55. return true;
  56. }
  57. }else
  58. {
  59. return true;
  60. }
  61. }
  62. return false;
  63. }
  64. bool CPlayerDlg::IsPaused()
  65. {
  66. if(m_Graph&&this->m_MediaControl)
  67. {
  68. OAFilterState FilterState=State_Stopped;
  69. if(SUCCEEDED(this->m_MediaControl->GetState(10,&FilterState)))
  70. {
  71. if(FilterState==State_Paused)
  72. {
  73. return true;
  74. }
  75. }
  76. }
  77. return false;
  78. }
  79. bool CPlayerDlg::Pause()
  80. {
  81. if(m_Graph&&this->m_MediaControl)
  82. {
  83. if(!this->IsPaused())
  84. {
  85. if(SUCCEEDED(this->m_MediaControl->Pause()))
  86. {
  87. return true;
  88. }
  89. }else
  90. {
  91. return true;
  92. }
  93. }
  94. return false;
  95. }</span>

2、针对IMediaSeeking类的函数封装,主要是针对GetDuration、GetCurrentPosition、SetPositions函数的封装,主要是用来计算当前S lider控件中托动点的位置用的,这里我只是封装了几个我们播放用的函数,其实IMediaSeeking还有其它的一些函数,也是很好的,大家可以查看下SDK,比如设置播放速率什么的,实现慢放、快放等,这些就靠大家去研究吧

[cpp] view plain copy
  1. <span style="font-size:14px;">bool CPlayerDlg::GetDuration(double * outDuration)
  2. {
  3. if (m_Seeking)
  4. {
  5. LONGLONG length = 0;
  6. if (SUCCEEDED(m_Seeking->GetDuration(&length)))
  7. {
  8. *outDuration = ((double)length) / 10000000.;
  9. return true;
  10. }
  11. }
  12. return false;
  13. }
  14. //这里要简单的做一个说明,因为我们在Create()函数中,已经设定了时间格式为TIME_FORMAT_MEDIA_TIME,即是以ns为播放单位的
  15. //也即IMediaSeeking::GetDuration()返回给我们的值是以ns的单位的,我们要化成以秒为单位,要除以的次方
  16. bool CPlayerDlg::GetCurrentPosition(double *outPosition)
  17. {
  18. if(m_Graph&&this->m_Seeking)
  19. {
  20. LONGLONG position=0;
  21. if(SUCCEEDED(this->m_Seeking->GetCurrentPosition(&position)))
  22. {
  23. *outPosition=((double)position) / 10000000.;
  24. return true;
  25. }
  26. }
  27. return false;
  28. }
  29. //原理与上一个函数类似,不再缀述
  30. bool  CPlayerDlg::SetCurrentPosition(double Position)
  31. {
  32. if(m_Graph&&this->m_Seeking)
  33. {
  34. LONGLONG pos=10000000*Position;//首先转换为正规时间格式
  35. HRESULT hr=this->m_Seeking->SetPositions(&pos,AM_SEEKING_AbsolutePositioning|AM_SEEKING_SeekToKeyFrame,0,AM_SEEKING_NoPositioning);
  36. if(SUCCEEDED(hr))
  37. {
  38. return true;
  39. }
  40. }
  41. return false;
  42. }
  43. //这里主要是将秒为单位的时间,转化为IMediaSeeking可以识别的ns为单位的时间,也就是上面两个函数的反操作</span>

3、针对IVideoWindow类的函数封装,这个就稍微有点难度了,不再是仅仅的对一个函数的封装了,这里是真正的自己实现,我们实现的函数有SetDisplayWindow(用于设置播放窗口),SetFullScreen(用于将视频设置为全屏)、GetFullScreen(获取当前全屏状态),具体实现代码如下:

[cpp] view plain copy
  1. <span style="font-size:14px;">bool CPlayerDlg::SetFullScreen(bool inEnabled)
  2. {
  3. if(m_Graph&&this->m_VideoWindow)
  4. {
  5. if(SUCCEEDED(this->m_VideoWindow->put_FullScreenMode(inEnabled ? OATRUE : OAFALSE)))
  6. {
  7. return true;
  8. }
  9. }
  10. return false;
  11. }
  12. //这里同样是一条函数的封装,我想三目运算符,大家应该还记得吧,这里就不讲了哦
  13. bool CPlayerDlg::GetFullScreen(void)
  14. {
  15. if (m_VideoWindow)
  16. {
  17. long  fullScreenMode = OAFALSE;
  18. m_VideoWindow->get_FullScreenMode(&fullScreenMode);
  19. return (fullScreenMode == OATRUE);
  20. }
  21. return false;
  22. }
  23. //这个函数难度不大,应该没什么可讲的吧
  24. bool CPlayerDlg::SetDisplayWindow(HWND HWindow)
  25. {
  26. if(this->m_VideoWindow)
  27. {
  28. this->m_VideoWindow->put_Visible(OAFALSE);//首先隐藏窗口
  29. if(HWindow)
  30. {
  31. this->m_VideoWindow->put_Owner(OAHWND(HWindow));
  32. CRect wndRect;
  33. ::GetClientRect(HWindow,&wndRect);//一定要注意要用WND坐标,而不能桌面坐标
  34. this->m_VideoWindow->put_Left(0);
  35. this->m_VideoWindow->put_Top(0);
  36. this->m_VideoWindow->put_Height((long)wndRect.Height());
  37. this->m_VideoWindow->put_Width((long)wndRect.Width());  //定义显示窗口位置
  38. this->m_VideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS);//WS_CLIPSIBLINGS表示重绘时,只重绘这一个窗口,其它窗口不发生重绘。
  39. //WS_CLIPCHILDREN表示此窗口不允许被其它窗口覆盖
  40. this->m_VideoWindow->put_MessageDrain((OAHWND)HWindow); //设置接收鼠标键盘的窗口
  41. this->m_VideoWindow->put_Visible(OATRUE);
  42. return true;
  43. }
  44. }
  45. return false;
  46. }
  47. //这个函数应该算是封装里面有点重量级的了,我们传进来所要设为显示窗口的句柄,首先用this->m_VideoWindow->put_Owner(OAHWND(HWindow));
  48. //将视频窗口隐藏,不然当反应速度变慢时,将会产生闪烁,下面就是获取当前GetClientRect()句柄的窗口大小信息,然后设定给m_VideoWindow
  49. //然后用put_MessageDrain()方法,让其接收鼠标键盘信息</span>

4、针对IMediaEventEx类的函数封装,实现对SetNotifyWindow的封装

[cpp] view plain copy
  1. <span style="font-size:14px;">bool CPlayerDlg::SetNotifyWindow(HWND HWindow)
  2. {
  3. if(this->m_Event&&HWindow)
  4. {
  5. HRESULT hr=this->m_Event->SetNotifyWindow((OAHWND)HWindow,WM_GRAPHNOTIFY,0);
  6. if(SUCCEEDED(hr))
  7. {
  8. return true;
  9. }
  10. }
  11. return false;
  12. }</span>

//定义消息接收的窗口,在其中定义的消息为WM_GRAPHNOTIFY,WM_GRAPHNOTIFY是我们自定义的消息,,

1、在PlayerDlg.h文件中,在顶部添加#define WM_GRAPHNOTIFY  (WM_USER+20)

2、在PlayerDlg.h文件中,并且在头文件中DECLARE_MESSAGE_MAP上面添加afx_msg LRESULT OnGraphNotify(WPARAM inWParam,LPARAM inLParam);位置如图:

3、在PlayerDlg.cpp中如图所示位置在//}}AFX_MSG_MAP下面,添加ON_MESSAGE(WM_GRAPHNOTIFY,OnGraphNotify)

4、最后在PlayerDlg.cpp中增加对响应函数的实现,这里可以先加一个框架,在文章的最后,会贴出具体实现,这里可以先写成

[cpp] view plain copy
  1. <span style="font-size:14px;">LRESULT CPlayerDlg::OnGraphNotify(WPARAM inWParam, LPARAM inLParam)
  2. {
  3. return true;
  4. }</span>

5,针对RenderFile()的封装

[cpp] view plain copy
  1. <span style="font-size:14px;">bool CPlayerDlg::RenderFile(const char * inFile)
  2. {
  3. if(m_Graph)
  4. {
  5. WCHAR szFilePath[MAX_PATH];
  6. MultiByteToWideChar(CP_ACP, 0, inFile, -1, szFilePath, MAX_PATH);//把ASCII编码转换成UNICODE编码
  7. if(SUCCEEDED(this->m_Graph->RenderFile(szFilePath,NULL)))
  8. {
  9. return true;
  10. }
  11. }
  12. return false;
  13. }</span>

(三)对添加对按钮的响应

一、添加对“打开”按钮的响应

在其响应函数中添加如下代码

[cpp] view plain copy
  1. void CPlayerDlg::OnBnClickedBtnOpen()
  2. {
  3. // TODO: 在此添加控件通知处理程序代码
  4. CString    strFilter = _T("AVI File (*.avi)|*.avi|");
  5. strFilter +=_T( "MPEG File (*.mpg;*.mpeg)|*.mpg;*.mpeg|");
  6. strFilter +=_T("Mp3 File (*.mp3)|*.mp3|");
  7. strFilter +=_T( "Wave File (*.wav)|*.wav|");
  8. strFilter +=_T( "All Files (*.*)|*.*|");
  9. CFileDialog dlgOpen(TRUE, NULL, NULL, OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
  10. strFilter, this);
  11. if (IDOK == dlgOpen.DoModal())
  12. {
  13. m_SourceFile = dlgOpen.GetPathName();
  14. this->CreateGraph();
  15. }
  16. }
  17. //主要是添加一个打开对话框,并在关闭之后,保存打开的文件的路径,然后就是构建Graph;

说明:1、m_SourceFile是定义的一个CStringA 对象,主要是用来保存打开文件的路径,大家自己添加定义和初始化一下吧。

2、CreateGraph()是新封装的一个函数,代码及讲解如下

[cpp] view plain copy
  1. bool CPlayerDlg::CreateGraph()
  2. {
  3. this->DestroyGraph();
  4. if(this->Create())
  5. {
  6. this->RenderFile(this->m_SourceFile);
  7. this->SetDisplayWindow(this->m_VideoWindowPlay.GetSafeHwnd());//设置显示窗口
  8. this->SetNotifyWindow(this->GetSafeHwnd());//将当前窗口作为接收消息窗口
  9. this->Pause();
  10. return true;
  11. }
  12. return false;
  13. }

//这里主要是先用this->Create()创建Graph中的各个变量及初始化操作,然后this->RenderFile(this->m_SourceFile);来渲染文件,也即采用智能链接模式,自动为我们构建播放链路,然后用SetDisplayWindow和SetNotifyWindow来设置播放窗口和消息接收窗口,最后this->Pause();先将视频暂停,等我们按下“播放”按钮时再播放视频。这里有个函数是我们新添加的,即this->DestroyGraph();,它主要实现的功能是释放变量,实现代码如下:

[cpp] view plain copy
  1. bool CPlayerDlg::DestroyGraph()
  2. {
  3. if(this->m_BasicAudio)
  4. {
  5. this->m_BasicAudio->Release();
  6. this->m_BasicAudio=NULL;
  7. }
  8. if(this->m_BasicVideo)
  9. {
  10. this->m_BasicVideo->Release();
  11. this->m_BasicVideo=NULL;
  12. }
  13. if(this->m_Event)
  14. {
  15. this->m_Event->Release();
  16. this->m_Event=NULL;
  17. }
  18. if(this->m_MediaControl)
  19. {
  20. this->m_MediaControl->Release();
  21. this->m_MediaControl=NULL;
  22. }
  23. if(this->m_Seeking)
  24. {
  25. this->m_Seeking->Release();
  26. this->m_Seeking=NULL;
  27. }
  28. if(this->m_VideoWindow)
  29. {
  30. this->m_VideoWindow->put_Visible(OAFALSE);// hide the video window
  31. this->m_VideoWindow->put_MessageDrain((OAHWND)NULL);//移除处理鼠标和键盘信息接收窗口
  32. this->m_VideoWindow->put_Owner((OAHWND)NULL);//移除视频窗口的拥有者
  33. this->m_VideoWindow->Release();
  34. this->m_VideoWindow=NULL;
  35. }
  36. if(this->m_Graph) //一定要最后释放m_Graph
  37. {
  38. this->m_Graph->Release();
  39. this->m_Graph=NULL;
  40. }
  41. return true;
  42. }

二、对“播放”按钮的响应

实现代码如下:

[cpp] view plain copy
  1. void CPlayerDlg::OnBnClickedBtnPlay()
  2. {
  3. // TODO: 在此添加控件通知处理程序代码
  4. if(this->m_Graph)
  5. {
  6. this->Run();
  7. }
  8. }

三、对“暂停”按钮的响应

[cpp] view plain copy
  1. void CPlayerDlg::OnBnClickedBtnPause()
  2. {
  3. // TODO: 在此添加控件通知处理程序代码
  4. if(this->m_Graph)
  5. {
  6. this->Pause();
  7. }
  8. }

四,对“停止”按钮的响应

[cpp] view plain copy
  1. void CPlayerDlg::OnBnClickedBtnStop()
  2. {
  3. // TODO: 在此添加控件通知处理程序代码
  4. if(this->m_Graph)
  5. {
  6. this->Stop();
  7. this->SetCurrentPosition(0);
  8. }
  9. }

(四)添加进度条推进与拖曳响应

1、首先要增加一个定时器,所以在OnBnClickedBtnOpen()、OnBnClickedBtnPause()、OnBnClickedBtnStop()函数中,添加如下代码:

[cpp] view plain copy
  1. if(this->m_SliderTimer==0)
  2. {
  3. m_SliderTimer=this->SetTimer(IDC_PROGRESS,100,NULL);
  4. }

//表示如果在点击这个按钮时,如果还没有创建定时器,就创建一个定时器,我们不指定接收消息函数,默认让OnTimer()来处理就可以了,这里有个新变量m_SliderTimer,是UINT 类型的变量,大家自己添加一下定义,记得初始化为0哦,用来保存创建Timer的ID号的。

2、对DLG添加WM_TIMER消息响应

[cpp] view plain copy
  1. void CPlayerDlg::OnTimer(UINT_PTR nIDEvent)
  2. {
  3. // TODO: 在此添加消息处理程序代码和/或调用默认值
  4. if(nIDEvent==this->m_SliderTimer&&this->m_Graph)
  5. {
  6. double pos=0,duration=1;
  7. this->GetCurrentPosition(&pos);
  8. this->GetDuration(&duration);
  9. int newPos = int(pos * 1000 / duration);
  10. if(this->m_Slider.GetPos()!=newPos)
  11. {
  12. this->m_Slider.SetPos(newPos);
  13. }
  14. }
  15. CDialog::OnTimer(nIDEvent);
  16. }
  17. //这里没什么函数难度,但主要是个思想,也就是根据当前视频的时间来设定滑动标记在Slider的位置

3、实现对鼠标拉动进度条时的消息响应

对DLG添加对WM_HSCROLL消息的响应OnHScroll()

代码如下:

[cpp] view plain copy
  1. void CPlayerDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  2. {
  3. // TODO: 在此添加消息处理程序代码和/或调用默认值
  4. if(pScrollBar->GetSafeHwnd()==this->m_Slider.GetSafeHwnd())
  5. {
  6. if(this->m_Slider)
  7. {
  8. double duration=1;
  9. double pos=0;
  10. pos=this->m_Slider.GetPos();
  11. this->GetDuration(&duration);
  12. double newPos=duration*pos/1000;
  13. this->SetCurrentPosition(newPos);
  14. }
  15. }else
  16. {
  17. CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
  18. }
  19. }
  20. //这段代码的主要思想,就是根据Slider的位置来设定视频的位置

最后贴出消息响应函数的实现代码:

[cpp] view plain copy
  1. LRESULT CPlayerDlg::OnGraphNotify(WPARAM inWParam, LPARAM inLParam)
  2. {
  3. if(this->m_Graph&&this->m_Event)
  4. {
  5. long eventCode=0,eventParam1=0,eventParam2=0;
  6. while(SUCCEEDED(this->m_Event->GetEvent(&eventCode,&eventParam1,&eventParam2,0)))
  7. {
  8. m_Event->FreeEventParams(eventCode,eventParam1,eventParam2);
  9. switch(eventCode)
  10. {
  11. case EC_COMPLETE:
  12. OnBnClickedBtnPause();
  13. this->SetCurrentPosition(0);
  14. break;
  15. case EC_USERABORT:
  16. case EC_ERRORABORT:
  17. OnBnClickedBtnStop();
  18. break;
  19. default:
  20. break;
  21. }
  22. }
  23. }
  24. return 0;
  25. }
  26. //这段代码理解起来应该难度不大,主要就是对消息类型的判断,然后根据不同的消息类型用不同的函数来处理

实现图如下:

写上面的内容实在是太累了,暂且写到这吧,下篇将会对播放器进行功能的稍微补充,解码器的安装配置与GraphEdit.exe的使用,而在最后一篇我打算讲解对于手动连接FILTER,以解决有些格式播放有晃动不清的问题,写的不好,还请大家批评指正谢谢大家的观摩。

最后,本文的源码地址是:
http://download.csdn.net/detail/harvic880925/4569951

不收分,仅供分享技术,转载请标明出处哦!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/harvic880925/article/details/7978566

基于directShow,打造全能播放器系列之一相关推荐

  1. 基于directShow,打造全能播放器系列之二

    前言:这一篇,分为三个部分,第一部分是添加对简易播放器的补充,第二部分是解码器的安装.配置. 简易播放器的补充 主要内容:添加对双击全屏的代码 注意:有些朋友可能会想,这个有这么麻烦吗,直接添加对ID ...

  2. 基于DirectShow的简单播放器

    一 个简单的基于DirectShow的打开本地视频文件的例子. 参考了各种资材,网上很多,也比较简单,但有个问题就是在调用" RenderFile "函数时只有在x86下都会返回S ...

  3. 打造全能播放器 totem-xine

    Fedora 默认安装的totem采用的gstreamer底端只能播放有版权信息的影音文件,然而国内的情况大家都知道,所以我们发现他什么都播放不了,留之无用,所以,第一步,理所当然是删除之: yum ...

  4. 基于单片机的音乐播放器设计

     word完整版可点击如下下载>>>>>>>> 基于单片机的音乐播放器设计-硬件开发文档类资源-CSDN下载内容包括详细设计文档word版,附带开题报告 ...

  5. 仿迅雷播放器教程 -- 基于VLC的MFC播放器 (6)

    代码下载: http://download.csdn.net/detail/qq316293804/6409417 昨天的教程里写着预计MFC播放器会隔得久一点,但是今晚仔细看了下VLC的常用代码,发 ...

  6. html5开发一个音乐播放器,HTML5开发学习(1):使用aduio标签打造音乐播放器

    关于html5的炒作已经有一段时间了,小弟亦是个跟风之人,对该新鲜事物也充满好奇和期待.本文为该系列(html5尝鲜)第一节,先以一个简单的demo开胃,希望能勾起各位同学对html5的兴趣和关注. ...

  7. linux 音频播放器源码,基于Linux的音频播放器的设计 源代码.doc

    嵌入式操作系统 课程设计 源代码 设计题目: 基于Linux的音频播放器的设计 院 系: ********* 班 级: ******** 组 别: 第1组 学 号: ****** 姓 名: 起止日期: ...

  8. 基于python的音频播放器_基于python实现音乐播放器代码实例

    基于python实现音乐播放器代码实例,一首,函数,按钮,布局,音乐 基于python实现音乐播放器代码实例 易采站长站,站长之家为您整理了基于python实现音乐播放器代码实例的相关内容. 核心播放 ...

  9. iOS播放器之基于VLCKit的自定义播放器

    VLC是一款了不起的播放器,很喜欢,功能很强大,目前据我所知能播放RMVB.MKV.mp4.FLV等等格式的视频,分享一个基于VLCKit的自定义播放器 源码地址:https://github.com ...

最新文章

  1. Java线程之线程池
  2. (chap6 Http首部) 其他首部字段
  3. 中报亮眼,阅文的增长“飞轮”是如何练成的?
  4. Yii资源包加载JS/CSS
  5. 合作开发过程产生的专利_被起诉专利侵权怎么办?专利律师给你出招!
  6. javascript expando
  7. 马云湖畔大学开学致辞:企业家要比谁都相信未来
  8. 《Essential C++》笔记之设定头文件
  9. Homebrew 更换阿里云镜像源
  10. ONVIFclient搜索设备获取rtsp地址开发笔记(精华篇)
  11. python窗口大小动态变化_python – 如何让tkinter画布动态调整窗口宽度?
  12. python怎么提取百度首页链接_python如何获取百度搜索结果的真实URL
  13. ST-LINK官方驱动下载方法
  14. Mysql基础(超详细)
  15. 低功耗高精度性能稳定 智芯传感ZXP0压阻式大气压力传感器适用多个领域
  16. 好佳居软装十大品牌 软装类型对应着主人
  17. 火车头如何把标题加html标签,火车采集器怎么编辑标签 火车采集器标签编辑教程...
  18. excel组合汇总_Excel汇总20150105
  19. springcloud+eureka简单的邮件监控
  20. html5 多点触控 缩放,WebBrowser禁用触摸缩放

热门文章

  1. 独家揭秘中国十大神秘豪宅
  2. 集客无线漫游之1——Hyper-V安装x86版集客AC
  3. 证明幂函数x^n的导数
  4. 计算机硬件拆解,拆解看硬件_台电一体电脑_主板评测-中关村在线
  5. T-SQL朝花夕拾(四) T-SQL函数及用法
  6. easybcd不认linux分区,kali linux双系统引导問題,easybcd不会设置。
  7. linux git 401,git push 提示 401 Unauthorized while accessing https 的原因及解决方法
  8. 6人游定增4000万 并完成部分认购,估值4亿元
  9. Android 颜色和颜色透明度列表
  10. 如何解决Profibus-DP总线在工业中通信距离短,布线难的问题?