基於directShow,打造全能播放器系列之二
前言:這一篇,分爲三個部分,第一部分是添加對簡易播放器的補充,第二部分是解碼器的安裝、配置。
簡易播放器的補充
主要內容:添加對雙擊全屏的代碼
注意:有些朋友可能會想,這個有這麼麻煩嗎,直接添加對IDC_VIDEOWND的STN_CLICKED響應不就行了,你可以添加一下對該消息的響應,就會明白了,根本執行不進去!這是爲什麼呢,主要是因爲視頻信號已經覆蓋在圖片控件上面了,所以點擊的時候根本接收不到點擊消息,當然也就沒有辦法執行我們寫在雙擊響應裏面的代碼了。由此可知我們可以攔截雙擊動作,然後對攔截的消息添加處理代碼,要實現攔截就先添加CplayerDlg中的PreTranslateMessage()虛函數,此函數主要是爲了方便用戶對消息的處理
實現代碼如下:
- BOOL CPlayerDlg::PreTranslateMessage(MSG* pMsg)
- {
- // TODO: 在此添加專用代碼和/或調用基類
- if (pMsg->message == WM_KEYDOWN)
- {
- if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
- {
- RestoreFromFullScreen();
- return 1;
- }
- }
- if(pMsg->message==WM_LBUTTONDBLCLK) //響應雙擊鼠標信息
- {
- CPoint pt;
- pt.x=LOWORD(pMsg->lParam); //X座標
- pt.y=HIWORD(pMsg->lParam); //Y座標
- CRect rect;
- GetDlgItem(IDC_VIDEOWND)->GetWindowRect(&rect);
- this->ScreenToClient(&rect);
- CRgn rgn;
- rgn.CreateEllipticRgnIndirect(&rect);//創建一個rgn對象,主要用於判斷當前點擊的點是否在視頻顯示區域內
- //注意,如果已經全屏,就直接縮小,不應該這樣判斷,此方法主要用於將視頻全屏
- if(this->GetFullScreen())//如果全屏則直接縮小
- {
- this->m_VideoWindow->put_FullScreenMode(OAFALSE);
- return true;
- }
- if(rgn.PtInRegion(pt)) //判斷是否是在指定區域內
- {
- RestoreFromFullScreen();
- return true;
- }
- }
- return CDialog::PreTranslateMessage(pMsg);
- }
上面我們先添加了對按鍵的響應,主要是爲了方便用戶在全屏狀態時,通過按“ESC”鍵來返回原來的狀態,代碼如下:
- if (pMsg->message == WM_KEYDOWN)
- {
- if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
- {
- RestoreFromFullScreen();
- return 1;
- }
- }
然後是添加對左鍵雙擊信息的響應,消息爲WM_LBUTTONDBLCLK
首先是獲取雙擊點的座標,用pt.x=LOWORD(pMsg->lParam);獲取X座標, pt.y=HIWORD(pMsg->lParam);來獲取Y座標,然後根據顯示窗口的大小(IDC_VIDEOWND)創建一個Rgn對象,然後判斷當前的點是否在這個RGN區域內,如果在,就根據當前的狀態來放大和縮小
其中有個函數RestoreFromFullScreen()主要是根據當前的顯示狀態來放大和縮小窗口的,代碼如下:
- bool CPlayerDlg::RestoreFromFullScreen()
- {
- if (this->m_Graph)
- {
- if (this->GetFullScreen())
- {
- this->SetFullScreen(FALSE);
- return true;
- }else
- {
- this->SetFullScreen(TRUE);
- return true;
- }
- }
- return false;
- }
以上就實現了雙擊全屏和雙擊退出全屏,但你可能會發現這裏還是存在了點問題,主要是,全屏後,鼠標不見了,下面我們採用另一種方法來實現全屏。
1、先申請幾個CPlayerDlg的成員變量
- public:
- WINDOWPLACEMENT m_OldWndPlacement;//保存原始位置
- CRect m_OldPlayWndRect; //保存原始的播放窗口的位置
- CRect m_OldProgressRect;//保存進度條原始位置
- CRect m_OldOpenBtnRect;//保存打開按鈕原始位置
- CRect m_OldPlayBtnRect;//保存播放按鈕原始位置
- CRect m_OldPauseBtnRect;//保存暫停按鈕原始位置
- CRect m_OldStopBtnRect;//保存停止按鈕原始位置
- BOOL m_bFullScreen;//屏顯示標誌
初始化時,將m_bFullScreen=false;其它變量無需初始化。
2、先貼實現代碼,等下講解
先將RestoreFromFullScreen()函數更改爲以下代碼:
- bool CPlayerDlg::RestoreFromFullScreen()
- {
- if (this->m_Graph)
- {
- this->SetFullScreen2();
- return true;
- }
- return false;
- }
SetFullScreen2()是新實現的函數,實現代碼如下:
- bool CPlayerDlg::SetFullScreen2()
- {
- if(m_bFullScreen)
- {
- ModifyStyle(WS_POPUP,WS_CAPTION);
- //首先還原框架的大小及位置
- SetWindowPlacement(&m_OldWndPlacement);
- //將播放窗口還原到原來的位置
- this->m_VideoWindowPlay.SetWindowPos(&wndTop,m_OldPlayWndRect.left,m_OldPlayWndRect.top,m_OldPlayWndRect.Width(),m_OldPlayWndRect.Height(),SWP_NOACTIVATE);
- //還原視頻顯示大小
- this->SetDisplayWindow(m_VideoWindowPlay.GetSafeHwnd());
- //還原其它控件的位置
- this->GetDlgItem(IDC_PROGRESS)->MoveWindow(m_OldProgressRect.left,m_OldProgressRect.top,m_OldProgressRect.Width(),m_OldProgressRect.Height(),true);
- this->GetDlgItem(IDC_BTN_OPEN)->MoveWindow(m_OldOpenBtnRect.left,m_OldOpenBtnRect.top,m_OldOpenBtnRect.Width(),m_OldOpenBtnRect.Height(),true);
- this->GetDlgItem(IDC_BTN_PLAY)->MoveWindow(m_OldPlayBtnRect.left,m_OldPlayBtnRect.top,m_OldPlayBtnRect.Width(),m_OldPlayBtnRect.Height(),true);
- this->GetDlgItem(IDC_BTN_PAUSE)->MoveWindow(m_OldPauseBtnRect.left,m_OldPauseBtnRect.top,m_OldPauseBtnRect.Width(),m_OldPauseBtnRect.Height(),true);
- this->GetDlgItem(IDC_BTN_STOP)->MoveWindow(m_OldStopBtnRect.left,m_OldStopBtnRect.top,m_OldStopBtnRect.Width(),m_OldStopBtnRect.Height(),true);
- m_bFullScreen=false;
- return true;
- }else
- {
- //先放大總框架
- GetWindowPlacement(&m_OldWndPlacement);
- CRect m_RectOfCurrentWindow,m_RectOfClient;
- GetWindowRect(&m_RectOfCurrentWindow);
- RepositionBars(0,0xffff,AFX_IDW_PANE_FIRST,reposQuery,&m_RectOfClient);
- ClientToScreen(&m_RectOfClient);
- int nFullWidth = GetSystemMetrics(SM_CXSCREEN);
- int nFullHeight = GetSystemMetrics(SM_CYSCREEN);
- CRect m_FSRect;
- m_FSRect.left = m_RectOfCurrentWindow.left-m_RectOfClient.left;
- m_FSRect.top = m_RectOfCurrentWindow.top - m_RectOfClient.top;
- m_FSRect.right = m_RectOfCurrentWindow.right - m_RectOfClient.right+nFullWidth;
- m_FSRect.bottom = m_RectOfCurrentWindow.bottom - m_RectOfClient.bottom + nFullHeight;
- MoveWindow(&m_FSRect,TRUE);
- CRect rect;
- ::GetWindowRect(::GetDesktopWindow(),rect);
- //先保存播放窗口及各控件原來的位置,以便還原
- this->m_VideoWindowPlay.GetWindowRect(this->m_OldPlayWndRect);
- this->GetDlgItem(IDC_PROGRESS)->GetWindowRect(m_OldProgressRect);
- this->GetDlgItem(IDC_BTN_OPEN)->GetWindowRect(m_OldOpenBtnRect);
- this->GetDlgItem(IDC_BTN_PLAY)->GetWindowRect(m_OldPlayBtnRect);
- this->GetDlgItem(IDC_BTN_PAUSE)->GetWindowRect(m_OldPauseBtnRect);
- this->GetDlgItem(IDC_BTN_STOP)->GetWindowRect(m_OldStopBtnRect);
- //設置作爲播放窗口的圖片控件的位置
- this->m_VideoWindowPlay.SetWindowPos(&wndTop,rect.left,rect.top,rect.Width(),rect.Height()-100,SWP_NOACTIVATE);
- //設置視頻圖像顯示輸出的大小
- this->m_VideoWindow->put_Left(rect.left);
- this->m_VideoWindow->put_Top(rect.top);
- this->m_VideoWindow->put_Width(rect.right - rect.left);
- this->m_VideoWindow->put_Height( rect.bottom - rect.top);//播放窗口最大化
- //設置其它控件新的位置
- this->GetDlgItem(IDC_PROGRESS)->MoveWindow(rect.left,rect.bottom-90,rect.Width(),20,true);
- CRect rectTemp;
- this->GetDlgItem(IDC_BTN_OPEN)->GetWindowRect(rectTemp);
- this->GetDlgItem(IDC_BTN_OPEN)->MoveWindow(rect.left+rect.Width()/2-300,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);
- this->GetDlgItem(IDC_BTN_PLAY)->MoveWindow(rect.left+rect.Width()/2-100,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);
- this->GetDlgItem(IDC_BTN_PAUSE)->MoveWindow(rect.left+rect.Width()/2+100,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);
- this->GetDlgItem(IDC_BTN_STOP)->MoveWindow(rect.left+rect.Width()/2+300,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);
- ShowCaret();//顯示鼠標
- m_bFullScreen=true;
- return true;
- }
- return false;
- }
代碼講解:
這裏只講解SetFullScreen2()的實現過程:
首先根據m_bFullScreen的值來判斷當前窗口是全屏(值爲TRUE)還是縮小狀態(值爲FALSE),如果全屏則縮小,如果縮小狀態則全屏
先講ELSE的全屏部分
先用GetWindowPlacement(&m_OldWndPlacement);函數保存當前框架的位置信息;
通過下面代碼實現全屏
- CRect m_RectOfCurrentWindow,m_RectOfClient;
- GetWindowRect(&m_RectOfCurrentWindow);
- RepositionBars(0,0xffff,AFX_IDW_PANE_FIRST,reposQuery,&m_RectOfClient);
- ClientToScreen(&m_RectOfClient);
- int nFullWidth = GetSystemMetrics(SM_CXSCREEN);
- int nFullHeight = GetSystemMetrics(SM_CYSCREEN);
- CRect m_FSRect;
- m_FSRect.left = m_RectOfCurrentWindow.left-m_RectOfClient.left;
- m_FSRect.top = m_RectOfCurrentWindow.top - m_RectOfClient.top;
- m_FSRect.right = m_RectOfCurrentWindow.right - m_RectOfClient.right+nFullWidth;
- m_FSRect.bottom = m_RectOfCurrentWindow.bottom - m_RectOfClient.bottom + nFullHeight;
- MoveWindow(&m_FSRect,TRUE);
然後是保存原來各個控件的位置,以便縮小時還原,代碼如下:
- //先保存播放窗口及各控件原來的位置,以便還原
- this->m_VideoWindowPlay.GetWindowRect(this->m_OldPlayWndRect);
- this->GetDlgItem(IDC_PROGRESS)->GetWindowRect(m_OldProgressRect);
- this->GetDlgItem(IDC_BTN_OPEN)->GetWindowRect(m_OldOpenBtnRect);
- this->GetDlgItem(IDC_BTN_PLAY)->GetWindowRect(m_OldPlayBtnRect);
- this->GetDlgItem(IDC_BTN_PAUSE)->GetWindowRect(m_OldPauseBtnRect);
- this->GetDlgItem(IDC_BTN_STOP)->GetWindowRect(m_OldStopBtnRect);
再下面是設置播放窗口的位置及視頻顯示窗口的大小
- CRect rect;
- ::GetWindowRect(::GetDesktopWindow(),rect);
- //設置作爲播放窗口的圖片控件的位置
- this->m_VideoWindowPlay.SetWindowPos(&wndTop,rect.left,rect.top,rect.Width(),rect.Height()-100,SWP_NOACTIVATE);
- //設置視頻圖像顯示輸出的大小
- this->m_VideoWindow->put_Left(rect.left);
- this->m_VideoWindow->put_Top(rect.top);
- this->m_VideoWindow->put_Width(rect.right - rect.left);
- this->m_VideoWindow->put_Height( rect.bottom - rect.top);//播放窗口最大化
然後是設置各個控件在放大後的新位置
- //設置其它控件新的位置
- this->GetDlgItem(IDC_PROGRESS)->MoveWindow(rect.left,rect.bottom-90,rect.Width(),20,true);
- CRect rectTemp;
- this->GetDlgItem(IDC_BTN_OPEN)->GetWindowRect(rectTemp);
- this->GetDlgItem(IDC_BTN_OPEN)->MoveWindow(rect.left+rect.Width()/2-300,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);
- this->GetDlgItem(IDC_BTN_PLAY)->MoveWindow(rect.left+rect.Width()/2-100,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);
- this->GetDlgItem(IDC_BTN_PAUSE)->MoveWindow(rect.left+rect.Width()/2+100,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);
- this->GetDlgItem(IDC_BTN_STOP)->MoveWindow(rect.left+rect.Width()/2+300,rect.bottom-50,rectTemp.Width(),rectTemp.Height(),true);
最後是顯示鼠標語句,及設置m_bFullScreen,代碼如下:
- ShowCaret();//顯示鼠標
- m_bFullScreen=true;
下面是IF語句部分的講解:
縮小時正好是放大的反過程,相比之下,比前面的步驟要簡單很多
首先用SetWindowPlacement(&m_OldWndPlacement);還原框架的大小及位置
然後是還原視頻顯示窗口的位置及大小,因爲我們已經保存了以前位置,所以直接用SetWindowPos就完全可以實現了。
- this->m_VideoWindowPlay.SetWindowPos(&wndTop,m_OldPlayWndRect.left,m_OldPlayWndRect.top,m_OldPlayWndRect.Width(),m_OldPlayWndRect.Height(),SWP_NOACTIVATE);
設置視頻顯示大小
- this->SetDisplayWindow(m_VideoWindowPlay.GetSafeHwnd());
還原其它控件位置
- this->GetDlgItem(IDC_PROGRESS)->MoveWindow(m_OldProgressRect.left,m_OldProgressRect.top,m_OldProgressRect.Width(),m_OldProgressRect.Height(),true);
- this->GetDlgItem(IDC_BTN_OPEN)->MoveWindow(m_OldOpenBtnRect.left,m_OldOpenBtnRect.top,m_OldOpenBtnRect.Width(),m_OldOpenBtnRect.Height(),true);
- this->GetDlgItem(IDC_BTN_PLAY)->MoveWindow(m_OldPlayBtnRect.left,m_OldPlayBtnRect.top,m_OldPlayBtnRect.Width(),m_OldPlayBtnRect.Height(),true);
- this->GetDlgItem(IDC_BTN_PAUSE)->MoveWindow(m_OldPauseBtnRect.left,m_OldPauseBtnRect.top,m_OldPauseBtnRect.Width(),m_OldPauseBtnRect.Height(),true);
- this->GetDlgItem(IDC_BTN_STOP)->MoveWindow(m_OldStopBtnRect.left,m_OldStopBtnRect.top,m_OldStopBtnRect.Width(),m_OldStopBtnRect.Height(),true);
- 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。