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

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

分類: VC++ directShow 109人閱讀 評論(2) 收藏 舉報

目錄(?)[+]

前言:這一篇,分爲三個部分,第一部分是添加對簡易播放器的補充,第二部分是解碼器的安裝、配置。

簡易播放器的補充

主要內容:添加對雙擊全屏的代碼


注意:有些朋友可能會想,這個有這麼麻煩嗎,直接添加對IDC_VIDEOWNDSTN_CLICKED響應不就行了,你可以添加一下對該消息的響應,就會明白了,根本執行不進去!這是爲什麼呢,主要是因爲視頻信號已經覆蓋在圖片控件上面了,所以點擊的時候根本接收不到點擊消息,當然也就沒有辦法執行我們寫在雙擊響應裏面的代碼了。由此可知我們可以攔截雙擊動作,然後對攔截的消息添加處理代碼,要實現攔截就先添加CplayerDlg中的PreTranslateMessage()虛函數,此函數主要是爲了方便用戶對消息的處理

實現代碼如下:

  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”鍵來返回原來的狀態,代碼如下:

  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()主要是根據當前的顯示狀態來放大和縮小窗口的,代碼如下:

  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的成員變量

  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()函數更改爲以下代碼:

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

SetFullScreen2()是新實現的函數,實現代碼如下:

  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);函數保存當前框架的位置信息;

通過下面代碼實現全屏

  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);  

然後是保存原來各個控件的位置,以便縮小時還原,代碼如下:

  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);  

再下面是設置播放窗口的位置及視頻顯示窗口的大小

  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);//播放窗口最大化  

然後是設置各個控件在放大後的新位置

  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,代碼如下:

  1. ShowCaret();//顯示鼠標    
  2. m_bFullScreen=true;  

下面是IF語句部分的講解:

縮小時正好是放大的反過程,相比之下,比前面的步驟要簡單很多

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

然後是還原視頻顯示窗口的位置及大小,因爲我們已經保存了以前位置,所以直接用SetWindowPos就完全可以實現了。

  1. this->m_VideoWindowPlay.SetWindowPos(&wndTop,m_OldPlayWndRect.left,m_OldPlayWndRect.top,m_OldPlayWndRect.Width(),m_OldPlayWndRect.Height(),SWP_NOACTIVATE);  

設置視頻顯示大小

  1. this->SetDisplayWindow(m_VideoWindowPlay.GetSafeHwnd());  

還原其它控件位置

  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;  

放大時的效果圖:


縮小圖:

解碼器的安裝及配置

解碼器我使用的是K-Lite解碼器,它能夠實現全格式的解碼

一、安裝

到下面的位置去下載K-Lite解碼器,我上傳上去的,不要分,就是我現在使用的版本,下載,根據默認選項安裝即可。

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

二、配置

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

選中左邊欄中的“codecs,將左邊的“decoder”列,全部選擇上其中一個解碼器,部分截圖如下,其它類似:

配置好之後,即可播放任意格式的視頻了。

至此,我們就基本實現了全格式的播放器了

本文的源碼下載地址:

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

聲明:本文僅供交流,如需轉載,請標明出處哦!

 

第二篇就先寫到這吧,下篇將講解GraphEdit.exe的使用方法,最後一篇講解如何用代碼連接指定FILTER。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章