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

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

分类: VC++ directShow 109人阅读 评论(2) 收藏 举报

目录(?)[+]

前言:这一篇,分为三个部分,第一部分是添加对简易播放器的补充,第二部分是解码器的安装、配置。

简易播放器的补充

主要内容:添加对双击全屏的代码

基于directShow,打造全能播放器系列之二_第1张图片
注意:有些朋友可能会想,这个有这么麻烦吗,直接添加对IDC_VIDEOWNDSTN_CLICKED响应不就行了,你可以添加一下对该消息的响应,就会明白了,根本执行不进去!这是为什么呢,主要是因为视频信号已经覆盖在图片控件上面了,所以点击的时候根本接收不到点击消息,当然也就没有办法执行我们写在双击响应里面的代码了。由此可知我们可以拦截双击动作,然后对拦截的消息添加处理代码,要实现拦截就先添加CplayerDlg中的PreTranslateMessage()虚函数,此函数主要是为了方便用户对消息的处理

实现代码如下:

[cpp] view plain copy
  1. BOOL CPlayerDlg::PreTranslateMessage(MSG* pMsg)  
  2. {  
  3.     // TODO: 在此添加专用代码和/或调用基类  
  4.     if (pMsg->message == WM_KEYDOWN)  
  5.     {  
  6.         if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)  
  7.         {  
  8.             RestoreFromFullScreen();  
  9.             return 1;  
  10.         }  
  11.     }  
  12.     if(pMsg->message==WM_LBUTTONDBLCLK)  //响应双击鼠标信息  
  13.         {  
  14.             CPoint pt;  
  15.             pt.x=LOWORD(pMsg->lParam); //X坐标  
  16.             pt.y=HIWORD(pMsg->lParam);  //Y坐标  
  17.   
  18.             CRect rect;  
  19.             GetDlgItem(IDC_VIDEOWND)->GetWindowRect(&rect);  
  20.             this->ScreenToClient(&rect);  
  21.   
  22.             CRgn rgn;  
  23.             rgn.CreateEllipticRgnIndirect(&rect);//创建一个rgn对象,主要用于判断当前点击的点是否在视频显示区域内  
  24.                                                  //注意,如果已经全屏,就直接缩小,不应该这样判断,此方法主要用于将视频全屏  
  25.             if(this->GetFullScreen())//如果全屏则直接缩小  
  26.             {  
  27.                 this->m_VideoWindow->put_FullScreenMode(OAFALSE);  
  28.                 return true;  
  29.             }  
  30.   
  31.             if(rgn.PtInRegion(pt))  //判断是否是在指定区域内  
  32.             {  
  33.                 RestoreFromFullScreen();  
  34.                 return true;  
  35.             }  
  36.         }  
  37.   
  38.     return CDialog::PreTranslateMessage(pMsg);  
  39. }  

上面我们先添加了对按键的响应,主要是为了方便用户在全屏状态时,通过按“ESC”键来返回原来的状态,代码如下:

[cpp] view plain copy
  1. if (pMsg->message == WM_KEYDOWN)  
  2.     {  
  3.         if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)  
  4.         {  
  5.             RestoreFromFullScreen();  
  6.             return 1;  
  7.         }  
  8.     }  

然后是添加对左键双击信息的响应,消息为WM_LBUTTONDBLCLK

首先是获取双击点的坐标,用pt.x=LOWORD(pMsg->lParam);获取X坐标, pt.y=HIWORD(pMsg->lParam);来获取Y坐标,然后根据显示窗口的大小(IDC_VIDEOWND)创建一个Rgn对象,然后判断当前的点是否在这个RGN区域内,如果在,就根据当前的状态来放大和缩小

其中有个函数RestoreFromFullScreen()主要是根据当前的显示状态来放大和缩小窗口的,代码如下:

[cpp] view plain copy
  1. bool CPlayerDlg::RestoreFromFullScreen()  
  2. {  
  3.     if (this->m_Graph)  
  4.     {  
  5.         if (this->GetFullScreen())  
  6.         {  
  7.             this->SetFullScreen(FALSE);  
  8.             return true;  
  9.         }else  
  10.         {  
  11.             this->SetFullScreen(TRUE);  
  12.             return true;  
  13.         }  
  14.     }  
  15.     return false;  
  16. }  

以上就实现了双击全屏和双击退出全屏,但你可能会发现这里还是存在了点问题,主要是,全屏后,鼠标不见了,下面我们采用另一种方法来实现全屏。

1、先申请几个CPlayerDlg的成员变量

[cpp] view plain copy
  1. public:  
  2.     WINDOWPLACEMENT m_OldWndPlacement;//保存原始位置  
  3.     CRect m_OldPlayWndRect; //保存原始的播放窗口的位置  
  4.     CRect m_OldProgressRect;//保存进度条原始位置  
  5.     CRect m_OldOpenBtnRect;//保存打开按钮原始位置  
  6.     CRect m_OldPlayBtnRect;//保存播放按钮原始位置  
  7.     CRect m_OldPauseBtnRect;//保存暂停按钮原始位置  
  8.     CRect m_OldStopBtnRect;//保存停止按钮原始位置  
  9.     BOOL m_bFullScreen;//屏显示标志  

初始化时,将m_bFullScreen=false;其它变量无需初始化。

2、先贴实现代码,等下讲解

先将RestoreFromFullScreen()函数更改为以下代码:

[cpp] view plain copy
  1. bool CPlayerDlg::RestoreFromFullScreen()  
  2. {  
  3.     if (this->m_Graph)  
  4.     {  
  5.         this->SetFullScreen2();  
  6.         return true;  
  7.     }  
  8.     return false;  
  9. }  

SetFullScreen2()是新实现的函数,实现代码如下:

[cpp] view plain copy
  1. bool CPlayerDlg::SetFullScreen2()  
  2. {  
  3.     if(m_bFullScreen)  
  4.     {  
  5.         ModifyStyle(WS_POPUP,WS_CAPTION);  
  6.         //首先还原框架的大小及位置  
  7.         SetWindowPlacement(&m_OldWndPlacement);  
  8.   
  9.         //将播放窗口还原到原来的位置  
  10.         this->m_VideoWindowPlay.SetWindowPos(&wndTop,m_OldPlayWndRect.left,m_OldPlayWndRect.top,m_OldPlayWndRect.Width(),m_OldPlayWndRect.Height(),SWP_NOACTIVATE);  
  11.         //还原视频显示大小  
  12.         this->SetDisplayWindow(m_VideoWindowPlay.GetSafeHwnd());  
  13.         //还原其它控件的位置  
  14.         this->GetDlgItem(IDC_PROGRESS)->MoveWindow(m_OldProgressRect.left,m_OldProgressRect.top,m_OldProgressRect.Width(),m_OldProgressRect.Height(),true);  
  15.         this->GetDlgItem(IDC_BTN_OPEN)->MoveWindow(m_OldOpenBtnRect.left,m_OldOpenBtnRect.top,m_OldOpenBtnRect.Width(),m_OldOpenBtnRect.Height(),true);  
  16.         this->GetDlgItem(IDC_BTN_PLAY)->MoveWindow(m_OldPlayBtnRect.left,m_OldPlayBtnRect.top,m_OldPlayBtnRect.Width(),m_OldPlayBtnRect.Height(),true);  
  17.         this->GetDlgItem(IDC_BTN_PAUSE)->MoveWindow(m_OldPauseBtnRect.left,m_OldPauseBtnRect.top,m_OldPauseBtnRect.Width(),m_OldPauseBtnRect.Height(),true);  
  18.         this->GetDlgItem(IDC_BTN_STOP)->MoveWindow(m_OldStopBtnRect.left,m_OldStopBtnRect.top,m_OldStopBtnRect.Width(),m_OldStopBtnRect.Height(),true);  
  19.   
  20.         m_bFullScreen=false;  
  21.         return true;  
  22.       
  23.     }else  
  24.     {  
  25.         //先放大总框架  
  26.         GetWindowPlacement(&m_OldWndPlacement);  
  27.         CRect m_RectOfCurrentWindow,m_RectOfClient;  
  28.         GetWindowRect(&m_RectOfCurrentWindow);  
  29.         RepositionBars(0,0xffff,AFX_IDW_PANE_FIRST,reposQuery,&m_RectOfClient);  
  30.         ClientToScreen(&m_RectOfClient);  
  31.         int nFullWidth = GetSystemMetrics(SM_CXSCREEN);  
  32.         int nFullHeight = GetSystemMetrics(SM_CYSCREEN);  
  33.         CRect m_FSRect;  
  34.         m_FSRect.left = m_RectOfCurrentWindow.left-m_RectOfClient.left;  
  35.         m_FSRect.top = m_RectOfCurrentWindow.top - m_RectOfClient.top;  
  36.         m_FSRect.right = m_RectOfCurrentWindow.right - m_RectOfClient.right+nFullWidth;  
  37.         m_FSRect.bottom = m_RectOfCurrentWindow.bottom - m_RectOfClient.bottom + nFullHeight;  
  38.         MoveWindow(&m_FSRect,TRUE);  
  39.   
  40.         CRect rect;  
  41.         ::GetWindowRect(::GetDesktopWindow(),rect);  
  42.   
  43.         //先保存播放窗口及各控件原来的位置,以便还原  
  44.         this->m_VideoWindowPlay.GetWindowRect(this->m_OldPlayWndRect);  
  45.         this->GetDlgItem(IDC_PROGRESS)->GetWindowRect(m_OldProgressRect);  
  46.         this->GetDlgItem(IDC_BTN_OPEN)->GetWindowRect(m_OldOpenBtnRect);  
  47.         this->GetDlgItem(IDC_BTN_PLAY)->GetWindowRect(m_OldPlayBtnRect);  
  48.         this->GetDlgItem(IDC_BTN_PAUSE)->GetWindowRect(m_OldPauseBtnRect);  
  49.         this->GetDlgItem(IDC_BTN_STOP)->GetWindowRect(m_OldStopBtnRect);  
  50.   
  51.         //设置作为播放窗口的图片控件的位置  
  52.         this->m_VideoWindowPlay.SetWindowPos(&wndTop,rect.left,rect.top,rect.Width(),rect.Height()-100,SWP_NOACTIVATE);  
  53.         //设置视频图像显示输出的大小  
  54.         this->m_VideoWindow->put_Left(rect.left);  
  55.         this->m_VideoWindow->put_Top(rect.top);  
  56.         this->m_VideoWindow->put_Width(rect.right   -   rect.left);  
  57.         this->m_VideoWindow->put_Height( rect.bottom   -   rect.top);//播放窗口最大化  
  58.   
  59.         //设置其它控件新的位置  
  60.         this->GetDlgItem(IDC_PROGRESS)->MoveWindow(rect.left,rect.bottom-90,rect.Width(),20,true);  
  61.         CRect rectTemp;  
  62.         this->GetDlgItem(IDC_BTN_OPEN)->GetWindowRect(rectTemp);  
  63.         this->GetDlgItem(IDC_BTN_OPEN)->MoveWindow(rect.left+rect.Width()/2-300,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);  
  64.         this->GetDlgItem(IDC_BTN_PLAY)->MoveWindow(rect.left+rect.Width()/2-100,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);  
  65.         this->GetDlgItem(IDC_BTN_PAUSE)->MoveWindow(rect.left+rect.Width()/2+100,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);  
  66.         this->GetDlgItem(IDC_BTN_STOP)->MoveWindow(rect.left+rect.Width()/2+300,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);  
  67.   
  68.         ShowCaret();//显示鼠标    
  69.   
  70.         m_bFullScreen=true;  
  71.         return true;          
  72.     }  
  73.     return false;  
  74. }  

代码讲解:

这里只讲解SetFullScreen2()的实现过程:

首先根据m_bFullScreen的值来判断当前窗口是全屏(值为TRUE)还是缩小状态(值为FALSE),如果全屏则缩小,如果缩小状态则全屏

先讲ELSE的全屏部分

先用GetWindowPlacement(&m_OldWndPlacement);函数保存当前框架的位置信息;

通过下面代码实现全屏

[cpp] view plain copy
  1. CRect m_RectOfCurrentWindow,m_RectOfClient;  
  2. GetWindowRect(&m_RectOfCurrentWindow);  
  3. RepositionBars(0,0xffff,AFX_IDW_PANE_FIRST,reposQuery,&m_RectOfClient);  
  4. ClientToScreen(&m_RectOfClient);  
  5. int nFullWidth = GetSystemMetrics(SM_CXSCREEN);  
  6. int nFullHeight = GetSystemMetrics(SM_CYSCREEN);  
  7. CRect m_FSRect;  
  8. m_FSRect.left = m_RectOfCurrentWindow.left-m_RectOfClient.left;  
  9. m_FSRect.top = m_RectOfCurrentWindow.top - m_RectOfClient.top;  
  10. m_FSRect.right = m_RectOfCurrentWindow.right - m_RectOfClient.right+nFullWidth;  
  11. m_FSRect.bottom = m_RectOfCurrentWindow.bottom - m_RectOfClient.bottom + nFullHeight;  
  12. MoveWindow(&m_FSRect,TRUE);  

然后是保存原来各个控件的位置,以便缩小时还原,代码如下:

[cpp] view plain copy
  1. //先保存播放窗口及各控件原来的位置,以便还原  
  2.         this->m_VideoWindowPlay.GetWindowRect(this->m_OldPlayWndRect);  
  3.         this->GetDlgItem(IDC_PROGRESS)->GetWindowRect(m_OldProgressRect);  
  4.         this->GetDlgItem(IDC_BTN_OPEN)->GetWindowRect(m_OldOpenBtnRect);  
  5.         this->GetDlgItem(IDC_BTN_PLAY)->GetWindowRect(m_OldPlayBtnRect);  
  6.         this->GetDlgItem(IDC_BTN_PAUSE)->GetWindowRect(m_OldPauseBtnRect);  
  7.         this->GetDlgItem(IDC_BTN_STOP)->GetWindowRect(m_OldStopBtnRect);  

再下面是设置播放窗口的位置及视频显示窗口的大小

[cpp] view plain copy
  1. CRect rect;  
  2.         ::GetWindowRect(::GetDesktopWindow(),rect);  
  3.         //设置作为播放窗口的图片控件的位置  
  4.     this->m_VideoWindowPlay.SetWindowPos(&wndTop,rect.left,rect.top,rect.Width(),rect.Height()-100,SWP_NOACTIVATE);  
  5.         //设置视频图像显示输出的大小  
  6.         this->m_VideoWindow->put_Left(rect.left);  
  7.         this->m_VideoWindow->put_Top(rect.top);  
  8.         this->m_VideoWindow->put_Width(rect.right   -   rect.left);  
  9.         this->m_VideoWindow->put_Height( rect.bottom   -   rect.top);//播放窗口最大化  

然后是设置各个控件在放大后的新位置

[cpp] view plain copy
  1. //设置其它控件新的位置  
  2.         this->GetDlgItem(IDC_PROGRESS)->MoveWindow(rect.left,rect.bottom-90,rect.Width(),20,true);  
  3.         CRect rectTemp;  
  4.         this->GetDlgItem(IDC_BTN_OPEN)->GetWindowRect(rectTemp);  
  5.         this->GetDlgItem(IDC_BTN_OPEN)->MoveWindow(rect.left+rect.Width()/2-300,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);  
  6.         this->GetDlgItem(IDC_BTN_PLAY)->MoveWindow(rect.left+rect.Width()/2-100,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);  
  7.         this->GetDlgItem(IDC_BTN_PAUSE)->MoveWindow(rect.left+rect.Width()/2+100,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);  
  8.         this->GetDlgItem(IDC_BTN_STOP)->MoveWindow(rect.left+rect.Width()/2+300,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);  

最后是显示鼠标语句,及设置m_bFullScreen,代码如下:

[cpp] view plain copy
  1. ShowCaret();//显示鼠标    
  2. m_bFullScreen=true;  

下面是IF语句部分的讲解:

缩小时正好是放大的反过程,相比之下,比前面的步骤要简单很多

首先用SetWindowPlacement(&m_OldWndPlacement);还原框架的大小及位置

然后是还原视频显示窗口的位置及大小,因为我们已经保存了以前位置,所以直接用SetWindowPos就完全可以实现了。

[cpp] view plain copy
  1. this->m_VideoWindowPlay.SetWindowPos(&wndTop,m_OldPlayWndRect.left,m_OldPlayWndRect.top,m_OldPlayWndRect.Width(),m_OldPlayWndRect.Height(),SWP_NOACTIVATE);  

设置视频显示大小

[cpp] view plain copy
  1. this->SetDisplayWindow(m_VideoWindowPlay.GetSafeHwnd());  

还原其它控件位置

[cpp] view plain copy
  1. this->GetDlgItem(IDC_PROGRESS)->MoveWindow(m_OldProgressRect.left,m_OldProgressRect.top,m_OldProgressRect.Width(),m_OldProgressRect.Height(),true);  
  2. this->GetDlgItem(IDC_BTN_OPEN)->MoveWindow(m_OldOpenBtnRect.left,m_OldOpenBtnRect.top,m_OldOpenBtnRect.Width(),m_OldOpenBtnRect.Height(),true);  
  3. this->GetDlgItem(IDC_BTN_PLAY)->MoveWindow(m_OldPlayBtnRect.left,m_OldPlayBtnRect.top,m_OldPlayBtnRect.Width(),m_OldPlayBtnRect.Height(),true);  
  4. this->GetDlgItem(IDC_BTN_PAUSE)->MoveWindow(m_OldPauseBtnRect.left,m_OldPauseBtnRect.top,m_OldPauseBtnRect.Width(),m_OldPauseBtnRect.Height(),true);  
  5. this->GetDlgItem(IDC_BTN_STOP)->MoveWindow(m_OldStopBtnRect.left,m_OldStopBtnRect.top,m_OldStopBtnRect.Width(),m_OldStopBtnRect.Height(),true);  
  6.   
  7. m_bFullScreen=false;  

放大时的效果图:

基于directShow,打造全能播放器系列之二_第2张图片

缩小图:

基于directShow,打造全能播放器系列之二_第3张图片

解码器的安装及配置

解码器我使用的是K-Lite解码器,它能够实现全格式的解码

一、安装

到下面的位置去下载K-Lite解码器,我上传上去的,不要分,就是我现在使用的版本,下载,根据默认选项安装即可。

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

二、配置

在“开始”-》“所有程序”-》“K-Lite codec pack-》“configuration-》“ffdshow video decoder

选中左边栏中的“codecs,将左边的“decoder”列,全部选择上其中一个解码器,部分截图如下,其它类似:

基于directShow,打造全能播放器系列之二_第4张图片

配置好之后,即可播放任意格式的视频了。

至此,我们就基本实现了全格式的播放器了

本文的源码下载地址:

http://download.csdn.net/detail/harvic880925/4575507 不收分,有需要的朋友可以去下载

声明:本文仅供交流,如需转载,请标明出处哦!

 

第二篇就先写到这吧,下篇将讲解GraphEdit.exe的使用方法,最后一篇讲解如何用代码连接指定FILTER。


你可能感兴趣的:(框架,filter,video,Graph,vc++,Codec,directshow)