Media Player Classic - HC 源代码分析

来源:互联网 发布:网上淘宝试衣间特点 编辑:程序博客网 时间:2024/05/12 17:29


VC2010 编译 Media Player Classic - Home Cinema (mpc-hc)

Media Player Classic - Home Cinema (mpc-hc)播放器一个经典的影音播放器,免费软件,可播放CD、VCD、DVD、及MP3、MP4、AVI、AAC等多种影音格式。与此同时,它还是开源的。今天尝试着编译了一下它的源代码(还是第一次接触这么大的MFC工程)

第一步::准备

  1. 安装 Visual C++ 2010(不能是Express版本)
  2. 安装Visual Studio 2010 Service Pack 1 -> http://www.microsoft.com/downloads/en/details.aspx?FamilyID=75568aa6-8107-475d-948a-ef22627e57a5&displaylang=en
  3. 安装DirectX SDK (June 2010) -> http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=3021d52b-514e-41d3-ad02-438a3ba730ba
第二步:准备GCC环境(这个主要是编译FFMPEG用的,FFMPEG只能用GCC编译)

1. 下载并解压 MSYS_MinGW-w64_GCC_481_x86-x64.7z 到 "C:\MSYS" 地址: http://xhmikosr.1f0.de/tools/MSYS_MinGW-w64_GCC_481_x86-x64.7z

(注意:就算自己电脑上有MSYS_MinGW,也建议下载这个)

2. 在 "C:\mpc-hc" 创建一个"build.user.bat",内容如下(有些参数根据自己系统确定):

复制代码
@ECHO OFF  SET "MPCHC_MSYS=C:\MSYS"  SET "MPCHC_MINGW32=%MPCHC_MSYS%\mingw"  SET "MPCHC_MINGW64=%MPCHC_MINGW32%"  REM Git is optional to set if you chose to add it in PATH when installing it(下面这条可以不要)  SET "MPCHC_GIT=C:\Program Files (x86)\Git"
复制代码

第三步:编译

1.使用Git 下载 MPC-HC's 到 "C:\mpc-hc" (其他地方也行)

Git命令(俩都行):

      git clone --recursive https://github.com/mpc-hc/mpc-hc.git

或:

      git clone https://github.com/mpc-hc/mpc-hc.git
      git submodule update --init --recursive

2. 打开sln文件 "C:\mpc-hc\mpc-hc.sln",编译之(注:如果Release编译不成功,可以试试编译Release-Lite)

3. 在"C:\mpc-hc\bin\mpc-hc_x86"下得到"mpc-hc.exe" 
4. 打开sln文件  "C:\mpc-hc\mpciconlib.sln",编译之
5. 得到"mpciconlib.dll" 
6. 打开sln文件  "C:\mpc-hc\mpcresources.sln",编译之
7. 得到 "mpcresources.XX.dll" 
注:直接运行"build.bat" 可以编译所有文件

1:整体结构

Media Player Classic - Home Cinema (mpc-hc)播放器一个经典的影音播放器,可播放CD、VCD、DVD、及MP3、MP4、AVI、AAC等多种影音格式。与此同时,它还是开源的。很多知名的视频播放器都是在它的基础上建立起来的,在这里就不例举了。本文将会对其源代码进行简要的分析。

之前一篇博客中曾经介绍了它的编译过程:VC2010 编译 Media Player Classic - Home Cinema (mpc-hc)

在这里就不再重复说明了,直入主题,看看它的工程是什么样子:

相信大部分人看到这个工程的第一反应就是:好大啊!确实,我看到这个工程的时候也是这个反应。mpc-hc总体上分为3个部分:Apps,Filters,Libraries。其中Apps是其主程序;Filters是其附带的一些directshow filter,比如说AVI分离器,FLV分离器等等;Libraries则是其依赖的一些库:像Zlib这类的。

来细看看mpc-hc都有什么directshow filter吧(截图都放不下了...)

Filters分为以下几种:

Muxer(封装),Parser(解封装,或称为分离器),Reader(读取),Renderer(显示),Source(源),Switcher(这个我不懂),Transform(处理)

在这里就不一一例举各种Filter了,因为数量实在太多,大部分Filter工程都可以通过名称来判断其功能。

再看看主程序Apps工程吧:

可见主程序包含了巨量的代码,截图也只能显示其中的一部分。因此在代码分析的时候,不可能做到面面俱到,只能选择其中的重点部分进行详细的分析。

mpc-hc的对话框数量也很惊人:

在这里就不再花篇幅形容mpc-hc工程的巨大了。赶紧说说如何来研究分析它的代码。本文主要分析它的主程序即在Apps目录下的工程。先介绍一下我总结出来的一些规则:

1.以PPage开头的.cpp或.h文件通常是一些属性选项卡的对话框对应的类。随后会详细介绍一个“视频信息”选项卡的代码(在这里用到了开源库MediaInfo)

2.主框架所在的位置是Mainfrm.cpp

目前只有这两条规则,以后会随着研究的不断深入,进一步完善这些规则。

2:核心类 (CMainFrame)(1)

mpc-hc最核心的类名字叫CMainFrame,它的定义位于MainFrm.h文件中

CMainFrame定义非常的长,包含了视频播放器的方方面面,一共900多行,在这里应该快放不下了。因此我删掉了很多代码,只保留了部分代码。关键的函数上面都写上了注释。

复制代码
class CMainFrame : public CFrameWnd, public CDropTarget  {      ...  // TODO: wrap these graph objects into a class to make it look cleaner//各种DirectShow接口//CComPtr被称为智能指针,是ATL提供的一个模版类,能够从语法上自动完成COM的AddRef和Release。    CComPtr<IGraphBuilder2> m_pGB;      CComQIPtr<IMediaControl> m_pMC;      CComQIPtr<IMediaEventEx> m_pME;      CComQIPtr<IVideoWindow> m_pVW;  //这里也可以获得//分辨率,比特率,帧率//经过测试,貌似这里取不到值 = =    CComQIPtr<IBasicVideo> m_pBV;  //音量,均衡器等信息    CComQIPtr<IBasicAudio> m_pBA;      CComQIPtr<IMediaSeeking> m_pMS;      CComQIPtr<IVideoFrameStep> m_pFS;  //接收端质量信息:抖动,抖动,视音频同步情况等。。。    CComQIPtr<IQualProp, &IID_IQualProp> m_pQP;  //缓存信息    CComQIPtr<IBufferInfo> m_pBI;      CComQIPtr<IAMOpenProgress> m_pAMOP;      CComPtr<IVMRMixerControl9> m_pVMRMC;      CComPtr<IMFVideoDisplayControl> m_pMFVDC;      CComPtr<IMFVideoProcessor> m_pMFVP;      CComPtr<IVMRWindowlessControl9> m_pVMRWC;      ...  void SetVolumeBoost(UINT nAudioBoost);  void SetBalance(int balance);  // subtitles    CCritSec m_csSubLock;      CList<SubtitleInput> m_pSubStreams;      POSITION m_posFirstExtSub;      ISubStream* m_pCurrentSubStream;      SubtitleInput* GetSubtitleInput(int& i, bool bIsOffset = false);  friend class CTextPassThruFilter;  // windowing    CRect m_lastWindowRect;      CPoint m_lastMouseMove;  void ShowControls(int nCS, bool fSave = false);  void SetUIPreset(int iCaptionMenuMode, UINT nCS);  void SetDefaultWindowRect(int iMonitor = 0);  void SetDefaultFullscreenState();  void RestoreDefaultWindowRect();  void ZoomVideoWindow(bool snap = true, double scale = ZOOM_DEFAULT_LEVEL);  double GetZoomAutoFitScale(bool bLargerOnly = false) const;  void SetAlwaysOnTop(int iOnTop);  // dynamic menus// 动态菜单void SetupOpenCDSubMenu();  void SetupFiltersSubMenu();  void SetupAudioSwitcherSubMenu();  void SetupSubtitlesSubMenu();      ...      CMenu m_popupmain, m_popup;      CMenu m_opencds;      CMenu m_filters, m_subtitles, m_audios;      CMenu m_language;      ...  // chapters (file mode)    CComPtr<IDSMChapterBag> m_pCB;  void SetupChapters();  // chapters (dvd mode)void SetupDVDChapters();  void SetupIViAudReg();  void AddTextPassThruFilter();  int m_nLoops;  UINT m_nLastSkipDirection;  bool m_fCustomGraph;      ...  public:  void StartWebServer(int nPort);  void StopWebServer();      CString GetStatusMessage() const;  int GetPlaybackMode() const { return m_iPlaybackMode; }  void SetPlaybackMode(int iNewStatus);  bool IsMuted() { return m_wndToolBar.GetVolume() == -10000; }  int GetVolume() { return m_wndToolBar.m_volctrl.GetPos(); }  public:      CMainFrame();      DECLARE_DYNAMIC(CMainFrame)  // Attributespublic:  bool m_fFullScreen;  bool m_fFirstFSAfterLaunchOnFS;  bool m_fStartInD3DFullscreen;  bool m_fHideCursor;      CMenu m_navaudio, m_navsubtitle;      CComPtr<IBaseFilter> m_pRefClock; // Adjustable reference clock. GothSync    CComPtr<ISyncClock> m_pSyncClock;      ...      CControlBar* m_pLastBar;  protected:      MPC_LOADSTATE m_iMediaLoadState;  bool m_bFirstPlay;  bool m_fAudioOnly;      dispmode m_dmBeforeFullscreen;      CString m_LastOpenFile, m_LastOpenBDPath;  HMONITOR m_LastWindow_HM;      DVD_DOMAIN m_iDVDDomain;  DWORD m_iDVDTitle;  double m_dSpeedRate;  double m_ZoomX, m_ZoomY, m_PosX, m_PosY;  int m_AngleX, m_AngleY, m_AngleZ;  //操作 Operations//打开一个媒体bool OpenMediaPrivate(CAutoPtr<OpenMediaData> pOMD);  //关闭媒体void CloseMediaPrivate();  void DoTunerScan(TunerScanData* pTSD);      CWnd* GetModalParent();  void OpenCreateGraphObject(OpenMediaData* pOMD);  //打开文件void OpenFile(OpenFileData* pOFD);  //打开DVDvoid OpenDVD(OpenDVDData* pODD);  //打开摄像头void OpenCapture(OpenDeviceData* pODD);  HRESULT OpenBDAGraph();  void OpenCustomizeGraph();  //设置视频窗口void OpenSetupVideo();  //设置音量void OpenSetupAudio();  void OpenSetupInfoBar();  void UpdateChapterInInfoBar();  //打开统计工具条void OpenSetupStatsBar();  //打开状态工具条void OpenSetupStatusBar();  // void OpenSetupToolBar();void OpenSetupCaptureBar();  //设置窗口标题void OpenSetupWindowTitle(CString fn = _T(""));  void AutoChangeMonitorMode();  bool GraphEventComplete();  friend class CGraphThread;      CGraphThread* m_pGraphThread;  bool m_bOpenedThruThread;      CAtlArray<REFERENCE_TIME> m_kfs;  bool m_fOpeningAborted;  bool m_bWasSnapped;  public:  void OpenCurPlaylistItem(REFERENCE_TIME rtStart = 0);  void OpenMedia(CAutoPtr<OpenMediaData> pOMD);  void PlayFavoriteFile(CString fav);  void PlayFavoriteDVD(CString fav);  bool ResetDevice();  bool DisplayChange();  void CloseMedia();  void StartTunerScan(CAutoPtr<TunerScanData> pTSD);  void StopTunerScan();  HRESULT SetChannel(int nChannel);  void AddCurDevToPlaylist();  bool m_fTrayIcon;  //设置系统托盘图标void ShowTrayIcon(bool fShow);  void SetTrayTip(CString str);      CSize GetVideoSize() const;  void ToggleFullscreen(bool fToNearest, bool fSwitchScreenResWhenHasTo);  void ToggleD3DFullscreen(bool fSwitchScreenResWhenHasTo);  void MoveVideoWindow(bool fShowStats = false);  void RepaintVideo();  void HideVideoWindow(bool fHide);      OAFilterState GetMediaState() const;      REFERENCE_TIME GetPos() const;      REFERENCE_TIME GetDur() const;  void SeekTo(REFERENCE_TIME rt, bool fSeekToKeyFrame = false);  //设置播放速率void SetPlayingRate(double rate);  DWORD SetupAudioStreams();  DWORD SetupSubtitleStreams();  //字幕bool LoadSubtitle(CString fn, ISubStream** actualStream = nullptr, bool bAutoLoad = false);  bool SetSubtitle(int i, bool bIsOffset = false, bool bDisplayMessage = false, bool bApplyDefStyle = false);  void SetSubtitle(ISubStream* pSubStream, bool bApplyDefStyle = false);  void ToggleSubtitleOnOff(bool bDisplayMessage = false);  void ReplaceSubtitle(const ISubStream* pSubStreamOld, ISubStream* pSubStreamNew);  void InvalidateSubtitle(DWORD_PTR nSubtitleId = -1, REFERENCE_TIME rtInvalidate = -1);  void ReloadSubtitle();  HRESULT InsertTextPassThruFilter(IBaseFilter* pBF, IPin* pPin, IPin* pPinto);  void SetAudioTrackIdx(int index);  void SetSubtitleTrackIdx(int index);  void AddFavorite(bool fDisplayMessage = false, bool fShowDialog = true);  // shaders    CAtlList<CString> m_shaderlabels;      CAtlList<CString> m_shaderlabelsScreenSpace;  void SetShaders();  void UpdateShaders(CString label);  // capturingbool m_fCapturing;  HRESULT BuildCapture(IPin* pPin, IBaseFilter* pBF[3], const GUID& majortype, AM_MEDIA_TYPE* pmt); // pBF: 0 buff, 1 enc, 2 mux, pmt is for 1 encbool BuildToCapturePreviewPin(IBaseFilter* pVidCap, IPin** pVidCapPin, IPin** pVidPrevPin,                                    IBaseFilter* pAudCap, IPin** pAudCapPin, IPin** pAudPrevPin);  bool BuildGraphVideoAudio(int fVPreview, bool fVCapture, int fAPreview, bool fACapture);  bool DoCapture(), StartCapture(), StopCapture();  bool DoAfterPlaybackEvent();  void ParseDirs(CAtlList<CString>& sl);  bool SearchInDir(bool bDirForward, bool bLoop = false);  virtual BOOL PreCreateWindow(CREATESTRUCT& cs);  virtual BOOL PreTranslateMessage(MSG* pMsg);  virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);  virtual void RecalcLayout(BOOL bNotify = TRUE);  // DVB capturevoid ShowCurrentChannelInfo(bool fShowOSD = true, bool fShowInfoBar = false);  // Implementationpublic:  virtual ~CMainFrame();  #ifdef _DEBUGvirtual void AssertValid() const;  virtual void Dump(CDumpContext& dc) const;  #endifprotected:    // control bar embedded members    CChildView m_wndView;  UINT m_nCS;      CPlayerSeekBar m_wndSeekBar;      CPlayerToolBar m_wndToolBar;      CPlayerInfoBar m_wndInfoBar;      CPlayerInfoBar m_wndStatsBar;      CPlayerStatusBar m_wndStatusBar;      CList<CControlBar*> m_bars;      CPlayerSubresyncBar m_wndSubresyncBar;      CPlayerPlaylistBar m_wndPlaylistBar;      CPlayerCaptureBar m_wndCaptureBar;      CPlayerNavigationBar m_wndNavigationBar;      CPlayerShaderEditorBar m_wndShaderEditorBar;      CEditListEditor m_wndEditListEditor;      CList<CSizingControlBar*> m_dockingbars;      ...  // Generated message map functions    DECLARE_MESSAGE_MAP()  public:  //打开的时候加载    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);  //关闭的时候加载    afx_msg void OnDestroy();      afx_msg LRESULT OnTaskBarRestart(WPARAM, LPARAM);      afx_msg LRESULT OnNotifyIcon(WPARAM, LPARAM);      afx_msg LRESULT OnTaskBarThumbnailsCreate(WPARAM, LPARAM);      afx_msg LRESULT OnSkypeAttach(WPARAM wParam, LPARAM lParam);      afx_msg void OnSetFocus(CWnd* pOldWnd);      afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);      afx_msg void OnMove(int x, int y);      afx_msg void OnMoving(UINT fwSide, LPRECT pRect);      afx_msg void OnSize(UINT nType, int cx, int cy);      afx_msg void OnSizing(UINT fwSide, LPRECT pRect);      afx_msg void OnDisplayChange();      afx_msg void OnSysCommand(UINT nID, LPARAM lParam);      afx_msg void OnActivateApp(BOOL bActive, DWORD dwThreadID);      afx_msg LRESULT OnAppCommand(WPARAM wParam, LPARAM lParam);      afx_msg void OnRawInput(UINT nInputcode, HRAWINPUT hRawInput);      afx_msg LRESULT OnHotKey(WPARAM wParam, LPARAM lParam);      afx_msg void OnTimer(UINT_PTR nIDEvent);      afx_msg LRESULT OnGraphNotify(WPARAM wParam, LPARAM lParam);      afx_msg LRESULT OnResetDevice(WPARAM wParam, LPARAM lParam);      afx_msg LRESULT OnRepaintRenderLess(WPARAM wParam, LPARAM lParam);      afx_msg LRESULT OnResumeFromState(WPARAM wParam, LPARAM lParam);      ...  // menu item handlers    afx_msg void OnFileOpenQuick();      afx_msg void OnFileOpenmedia();      afx_msg void OnUpdateFileOpen(CCmdUI* pCmdUI);      afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);      afx_msg void OnFileOpendvd();      afx_msg void OnFileOpendevice();      afx_msg void OnFileOpenCD(UINT nID);      afx_msg void OnFileReopen();      afx_msg void OnFileRecycle();      afx_msg void OnDropFiles(HDROP hDropInfo); // no menu item    ...      afx_msg void OnHelpHomepage();      afx_msg void OnHelpCheckForUpdate();      afx_msg void OnHelpToolbarImages();      afx_msg void OnHelpDonate();  //关闭的时候加载    afx_msg void OnClose();      afx_msg void OnLanguage(UINT nID);      afx_msg void OnUpdateLanguage(CCmdUI* pCmdUI);      CMPC_Lcd m_Lcd;  // ==== Added by CASIMIR666    CWnd*           m_pVideoWnd;            // Current Video (main display screen or 2nd)    SIZE            m_fullWndSize;      CFullscreenWnd* m_pFullscreenWnd;      CVMROSD     m_OSD;  bool        m_bRemainingTime;  int         m_nCurSubtitle;  long        m_lSubtitleShift;      REFERENCE_TIME m_rtCurSubPos;      CString     m_strTitle;  bool        m_bToggleShader;  bool        m_bToggleShaderScreenSpace;  bool        m_bInOptions;  bool        m_bStopTunerScan;  bool        m_bLockedZoomVideoWindow;  int         m_nLockedZoomVideoWindow;  bool        m_fSetChannelActive;  void        SetLoadState(MPC_LOADSTATE iState);  void        SetPlayState(MPC_PLAYSTATE iState);  bool        CreateFullScreenWindow();  void        SetupEVRColorControl();  void        SetupVMR9ColorControl();  void        SetColorControl(DWORD flags, int& brightness, int& contrast, int& hue, int& saturation);  void        SetClosedCaptions(bool enable);  LPCTSTR     GetDVDAudioFormatName(const DVD_AudioAttributes& ATR) const;  void        SetAudioDelay(REFERENCE_TIME rtShift);  void        SetSubtitleDelay(int delay_ms);  //void      AutoSelectTracks();bool        IsRealEngineCompatible(CString strFilename) const;  void        SetTimersPlay();  void        KillTimersStop();  // MPC API functionsvoid        ProcessAPICommand(COPYDATASTRUCT* pCDS);  void        SendAPICommand(MPCAPI_COMMAND nCommand, LPCWSTR fmt, ...);  void        SendNowPlayingToApi();  void        SendSubtitleTracksToApi();  void        SendAudioTracksToApi();  void        SendPlaylistToApi();      ...  protected:  // GDI+ULONG_PTR m_gdiplusToken;  virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);  void WTSRegisterSessionNotification();  void WTSUnRegisterSessionNotification();  DWORD m_nMenuHideTick;  UINT m_nSeekDirection;  public:      afx_msg UINT OnPowerBroadcast(UINT nPowerEvent, UINT nEventData);      afx_msg void OnSessionChange(UINT nSessionState, UINT nId);  void EnableShaders1(bool enable);  void EnableShaders2(bool enable);      CAtlList<CHdmvClipInfo::PlaylistItem> m_MPLSPlaylist;  bool m_bIsBDPlay;  bool OpenBD(CString Path);  };
复制代码

面对一个如此巨大的类,可能会让人感觉到无从下手。我开始研究的时候也不知道该从何学起(实际上找到CMainFrame这个类就花了我挺长时间的,开始的时候根本没找到哪个类才是mpc-hc的最核心的类)。经过一段时间的探索,我发现了打开一个媒体的函数OpenMedia(),这个函数应该是我们每次使用mpc-hc都一定会调用的函数。从这个函数开始学习源代码还是比较合适的。

在看OpenMedia()代码之前,先来看看有哪些函数调用它了。我们可以借助VC2010的“查看调用层次结构”功能来完成这个任务。发现有3个函数:

OnFileOpendevice()//打开一个设备(比如说摄像头)OnFileOpendvd()//打开一个DVDOpenCurPlaylistItem()//打开播放列表的一条记录(比如说一个文件)

这3个函数正好对应着mpc-hc的3个功能:打开设备(摄像头),打开DVD,打开文件。这3个函数在这里就不多讲了,以后有机会再进行分析。

下面我们来看看OpenMedia()函数:

复制代码
//打开媒体(非private)void CMainFrame::OpenMedia(CAutoPtr<OpenMediaData> pOMD)  {  // shortcutif (OpenDeviceData* p = dynamic_cast<OpenDeviceData*>(pOMD.m_p)) {  if (m_iMediaLoadState == MLS_LOADED && m_pAMTuner                  && m_VidDispName == p->DisplayName[0] && m_AudDispName == p->DisplayName[1]) {              m_wndCaptureBar.m_capdlg.SetVideoInput(p->vinput);              m_wndCaptureBar.m_capdlg.SetVideoChannel(p->vchannel);              m_wndCaptureBar.m_capdlg.SetAudioInput(p->ainput);              SendNowPlayingToSkype();  return;          }      }  if (m_iMediaLoadState != MLS_CLOSED) {          CloseMedia();      }  //m_iMediaLoadState = MLS_LOADING; // HACK: hides the logoconst CAppSettings& s = AfxGetAppSettings();  bool fUseThread = m_pGraphThread && s.fEnableWorkerThreadForOpening;  if (OpenFileData* p = dynamic_cast<OpenFileData*>(pOMD.m_p)) {  if (!p->fns.IsEmpty()) {              engine_t e = s.m_Formats.GetEngine(p->fns.GetHead());  if (e != DirectShow /*&& e != RealMedia && e != QuickTime*/) {                  fUseThread = false;              }          }      } else if (OpenDeviceData* p = dynamic_cast<OpenDeviceData*>(pOMD.m_p)) {          fUseThread = false;      }  // Create D3DFullscreen window if launched in fullscreenif (s.IsD3DFullscreen() && m_fStartInD3DFullscreen) {  if (s.AutoChangeFullscrRes.bEnabled) {              AutoChangeMonitorMode();          }          CreateFullScreenWindow();          m_pVideoWnd = m_pFullscreenWnd;          m_fStartInD3DFullscreen = false;      } else {          m_pVideoWnd = &m_wndView;      }  if (fUseThread) {          m_pGraphThread->PostThreadMessage(CGraphThread::TM_OPEN, 0, (LPARAM)pOMD.Detach());          m_bOpenedThruThread = true;      } else {  //打开媒体(private)        OpenMediaPrivate(pOMD);          m_bOpenedThruThread = false;      }  }
复制代码

这里需要注意,OpenMedia()调用了函数OpenMediaPrivate()。文件的打开功能实际上是在OpenMediaPrivate()中完成的。

下面我们来看看OpenMediaPrivate()的代码,发现比OpenMedia()要复杂很多。

复制代码
//打开一个媒体(private)bool CMainFrame::OpenMediaPrivate(CAutoPtr<OpenMediaData> pOMD)  {  //获得设置信息    CAppSettings& s = AfxGetAppSettings();  if (m_iMediaLoadState != MLS_CLOSED) {          ASSERT(0);  return false;      }  //OpenFileData//OpenDVDData//OpenDeviceData//里面包含了文件或者DVD信息(名称等)    OpenFileData* pFileData = dynamic_cast<OpenFileData*>(pOMD.m_p);      OpenDVDData* pDVDData = dynamic_cast<OpenDVDData*>(pOMD.m_p);      OpenDeviceData* pDeviceData = dynamic_cast<OpenDeviceData*>(pOMD.m_p);  if (!pFileData && !pDVDData  && !pDeviceData) {          ASSERT(0);  return false;      }  // Clear DXVA state ...    ClearDXVAState();  #ifdef _DEBUG// Debug trace code - Begin// Check for bad / buggy auto loading file codeif (pFileData) {          POSITION pos = pFileData->fns.GetHeadPosition();  UINT index = 0;  while (pos != nullptr) {              CString path = pFileData->fns.GetNext(pos);              TRACE(_T("--> CMainFrame::OpenMediaPrivate - pFileData->fns[%d]:\n"), index);              TRACE(_T("\t%ws\n"), path.GetString()); // %ws - wide character string always            index++;          }      }  // Debug trace code - End#endif    CString mi_fn = _T("");  if (pFileData) {  if (pFileData->fns.IsEmpty()) {  return false;          }          CString fn = pFileData->fns.GetHead();  int i = fn.Find(_T(":\\"));  if (i > 0) {              CString drive = fn.Left(i + 2);  UINT type = GetDriveType(drive);              CAtlList<CString> sl;  if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM && GetCDROMType(drive[0], sl) != CDROM_Audio) {  int ret = IDRETRY;  while (ret == IDRETRY) {                      WIN32_FIND_DATA findFileData;  HANDLE h = FindFirstFile(fn, &findFileData);  if (h != INVALID_HANDLE_VALUE) {                          FindClose(h);                          ret = IDOK;                      } else {                          CString msg;                          msg.Format(IDS_MAINFRM_114, fn);                          ret = AfxMessageBox(msg, MB_RETRYCANCEL);                      }                  }  if (ret != IDOK) {  return false;                  }              }              mi_fn = fn;          }      }      SetLoadState(MLS_LOADING);  // FIXME: Don't show "Closed" initially    PostMessage(WM_KICKIDLE);      CString err;      m_fUpdateInfoBar = false;      BeginWaitCursor();  try {          CComPtr<IVMRMixerBitmap9>    pVMB;          CComPtr<IMFVideoMixerBitmap> pMFVMB;          CComPtr<IMadVRTextOsd>       pMVTO;  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }          OpenCreateGraphObject(pOMD);  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }          SetupIViAudReg();  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //按类型的不同打开不同的文件if (pFileData) {  //文件            OpenFile(pFileData);          } else if (pDVDData) {  //DVD            OpenDVD(pDVDData);          } else if (pDeviceData) {  if (s.iDefaultCaptureDevice == 1) {  HRESULT hr = OpenBDAGraph();  if (FAILED(hr)) {  throw (UINT)IDS_CAPTURE_ERROR_DEVICE;                  }              } else {                  OpenCapture(pDeviceData);              }          } else {  throw (UINT)IDS_INVALID_PARAMS_ERROR;          }          m_pCAP2 = nullptr;          m_pCAP = nullptr;  //查找接口        m_pGB->FindInterface(__uuidof(ISubPicAllocatorPresenter), (void**)&m_pCAP, TRUE);          m_pGB->FindInterface(__uuidof(ISubPicAllocatorPresenter2), (void**)&m_pCAP2, TRUE);          m_pGB->FindInterface(__uuidof(IVMRWindowlessControl9), (void**)&m_pVMRWC, FALSE); // might have IVMRMixerBitmap9, but not IVMRWindowlessControl9        m_pGB->FindInterface(__uuidof(IVMRMixerControl9), (void**)&m_pVMRMC, TRUE);          m_pGB->FindInterface(__uuidof(IVMRMixerBitmap9), (void**)&pVMB, TRUE);          m_pGB->FindInterface(__uuidof(IMFVideoMixerBitmap), (void**)&pMFVMB, TRUE);          pMVTO = m_pCAP;  if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is usedif (pVMB) {                  m_OSD.Start(m_pVideoWnd, pVMB, IsD3DFullScreenMode());              } else if (pMFVMB) {                  m_OSD.Start(m_pVideoWnd, pMFVMB, IsD3DFullScreenMode());              } else if (pMVTO) {                  m_OSD.Start(m_pVideoWnd, pMVTO);              }          }  //VMR9        SetupVMR9ColorControl();  // === EVR !        m_pGB->FindInterface(__uuidof(IMFVideoDisplayControl), (void**)&m_pMFVDC,  TRUE);          m_pGB->FindInterface(__uuidof(IMFVideoProcessor), (void**)&m_pMFVP, TRUE);  if (m_pMFVDC) {              m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd);          }  //SetupEVRColorControl();//does not work at this location//need to choose the correct mode (IMFVideoProcessor::SetVideoProcessorMode)        BeginEnumFilters(m_pGB, pEF, pBF) {  if (m_pLN21 = pBF) {                  m_pLN21->SetServiceState(s.fClosedCaptions ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off);  break;              }          }          EndEnumFilters;  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //打开自定义的Graph        OpenCustomizeGraph();  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //设置视频窗口        OpenSetupVideo();  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //设置音量        OpenSetupAudio();  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  if (m_pCAP && (!m_fAudioOnly || m_fRealMediaGraph)) {  if (s.fDisableInternalSubtitles) {                  m_pSubStreams.RemoveAll(); // Needs to be replaced with code that checks for forced subtitles.            }              m_posFirstExtSub = nullptr;              POSITION pos = pOMD->subs.GetHeadPosition();  while (pos) {                  LoadSubtitle(pOMD->subs.GetNext(pos), nullptr, true);              }          }  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //设置视频窗口标题        OpenSetupWindowTitle(pOMD->title);  if (s.fEnableEDLEditor) {              m_wndEditListEditor.OpenFile(pOMD->title);          }  if (::GetCurrentThreadId() == AfxGetApp()->m_nThreadID) {              OnFilePostOpenmedia();          } else {              PostMessage(WM_COMMAND, ID_FILE_POST_OPENMEDIA);          }  while (m_iMediaLoadState != MLS_LOADED                  && m_iMediaLoadState != MLS_CLOSING // FIXME              ) {              Sleep(50);          }  //设置音频流DWORD audstm = SetupAudioStreams();  //设置字幕流DWORD substm = SetupSubtitleStreams();  if (audstm) {              OnPlayAudio(ID_AUDIO_SUBITEM_START + audstm);          }  if (substm) {              SetSubtitle(substm - 1);          }  // PostMessage instead of SendMessage because the user might call CloseMedia and then we would deadlock        PostMessage(WM_COMMAND, ID_PLAY_PAUSE);          m_bFirstPlay = true;  if (!(s.nCLSwitches & CLSW_OPEN) && (s.nLoops > 0)) {              PostMessage(WM_COMMAND, ID_PLAY_PLAY);          } else {  // If we don't start playing immediately, we need to initialize// the seekbar and the time counter.            OnTimer(TIMER_STREAMPOSPOLLER);              OnTimer(TIMER_STREAMPOSPOLLER2);          }          s.nCLSwitches &= ~CLSW_OPEN;  if (pFileData) {  if (pFileData->rtStart > 0) {                  PostMessage(WM_RESUMEFROMSTATE, (WPARAM)PM_FILE, (LPARAM)(pFileData->rtStart / 10000));  // REFERENCE_TIME doesn't fit in LPARAM under a 32bit env.            }          } else if (pDVDData) {  if (pDVDData->pDvdState) {                  PostMessage(WM_RESUMEFROMSTATE, (WPARAM)PM_DVD, (LPARAM)(CComPtr<IDvdState>(pDVDData->pDvdState).Detach()));    // must be released by the called message handler            }          } else if (pDeviceData) {              m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput);              m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel);              m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput);          }      } catch (LPCTSTR msg) {          err = msg;      } catch (CString& msg) {          err = msg;      } catch (UINT msg) {          err.LoadString(msg);      }      EndWaitCursor();  if (!err.IsEmpty()) {  //关闭        CloseMediaPrivate();          m_closingmsg = err;  if (err != ResStr(IDS_AG_ABORTED)) {  if (pFileData) {                  m_wndPlaylistBar.SetCurValid(false);  if (m_wndPlaylistBar.IsAtEnd()) {                      m_nLoops++;                  }  if (s.fLoopForever || m_nLoops < s.nLoops) {  bool hasValidFile = false;  if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) {                          hasValidFile = m_wndPlaylistBar.SetPrev();                      } else {                          hasValidFile = m_wndPlaylistBar.SetNext();                      }  if (hasValidFile) {                          OpenCurPlaylistItem();                      }                  } else if (m_wndPlaylistBar.GetCount() > 1) {                      DoAfterPlaybackEvent();                  }              } else {                  OnNavigateSkip(ID_NAVIGATE_SKIPFORWARD);              }          }      } else {          m_wndPlaylistBar.SetCurValid(true);  // Apply command line audio shiftif (s.rtShift != 0) {              SetAudioDelay(s.rtShift);              s.rtShift = 0;          }      }      m_nLastSkipDirection = 0;  if (s.AutoChangeFullscrRes.bEnabled && (m_fFullScreen || IsD3DFullScreenMode())) {          AutoChangeMonitorMode();      }  if (m_fFullScreen && s.fRememberZoomLevel) {          m_fFirstFSAfterLaunchOnFS = true;      }      m_LastOpenFile = pOMD->title;      PostMessage(WM_KICKIDLE); // calls main thread to update thingsif (!m_bIsBDPlay) {          m_MPLSPlaylist.RemoveAll();          m_LastOpenBDPath = _T("");      }      m_bIsBDPlay = false;  return err.IsEmpty();  }
复制代码

这里需要注意,根据打开方式的不同,OpenMediaPrivate()调用了不同的函数。

如果输入的类型为文件,则调用OpenFile()

如果输入的类型为DVD,则调用OpenDVD()

如果输入的类型为设备(例如摄像头),则调用OpenCapture()

在这里,我们假设输入的类型为文件(实际上这也是最普遍的情况)。

看看OpenFile()的源代码。

复制代码
//打开文件void CMainFrame::OpenFile(OpenFileData* pOFD)  {  if (pOFD->fns.IsEmpty()) {  throw (UINT)IDS_MAINFRM_81;      }  //获取设置    CAppSettings& s = AfxGetAppSettings();  bool bMainFile = true;      POSITION pos = pOFD->fns.GetHeadPosition();  while (pos) {          CString fn = pOFD->fns.GetNext(pos);          fn.Trim();  if (fn.IsEmpty() && !bMainFile) {  break;          }  //使用DirectShow播放文件HRESULT hr = m_pGB->RenderFile(CStringW(fn), nullptr);  if (bMainFile) {  // Don't try to save file position if source isn't seekable            REFERENCE_TIME rtDur = 0;              m_pMS->GetDuration(&rtDur);              m_bRememberFilePos = s.fKeepHistory && s.fRememberFilePos && rtDur > 0;  if (m_bRememberFilePos && !s.filePositions.AddEntry(fn)) {                  REFERENCE_TIME rtPos = s.filePositions.GetLatestEntry()->llPosition;  if (m_pMS) {                      m_pMS->SetPositions(&rtPos, AM_SEEKING_AbsolutePositioning, nullptr, AM_SEEKING_NoPositioning);                  }              }          }          QueryPerformanceCounter(&m_liLastSaveTime);  if (FAILED(hr)) {  if (bMainFile) {  if (s.fReportFailedPins) {                      CComQIPtr<IGraphBuilderDeadEnd> pGBDE = m_pGB;  if (pGBDE && pGBDE->GetCount()) {                          CMediaTypesDlg(pGBDE, GetModalParent()).DoModal();                      }                  }  UINT err;  switch (hr) {  case E_ABORT:  case RFS_E_ABORT:                          err = IDS_MAINFRM_82;  break;  case E_FAIL:  case E_POINTER:  default:                          err = IDS_MAINFRM_83;  break;  case E_INVALIDARG:                          err = IDS_MAINFRM_84;  break;  case E_OUTOFMEMORY:                          err = IDS_AG_OUT_OF_MEMORY;  break;  case VFW_E_CANNOT_CONNECT:                          err = IDS_MAINFRM_86;  break;  case VFW_E_CANNOT_LOAD_SOURCE_FILTER:                          err = IDS_MAINFRM_87;  break;  case VFW_E_CANNOT_RENDER:                          err = IDS_MAINFRM_88;  break;  case VFW_E_INVALID_FILE_FORMAT:                          err = IDS_MAINFRM_89;  break;  case VFW_E_NOT_FOUND:                          err = IDS_MAINFRM_90;  break;  case VFW_E_UNKNOWN_FILE_TYPE:                          err = IDS_MAINFRM_91;  break;  case VFW_E_UNSUPPORTED_STREAM:                          err = IDS_MAINFRM_92;  break;  case RFS_E_NO_FILES:                          err = IDS_RFS_NO_FILES;  break;  case RFS_E_COMPRESSED:                          err = IDS_RFS_COMPRESSED;  break;  case RFS_E_ENCRYPTED:                          err = IDS_RFS_ENCRYPTED;  break;  case RFS_E_MISSING_VOLS:                          err = IDS_RFS_MISSING_VOLS;  break;                  }  throw err;              }          }  // We don't keep track of the standard input since that hardly makes any senseif (s.fKeepHistory && fn != _T("pipe:0")) {              CRecentFileList* pMRU = bMainFile ? &s.MRU : &s.MRUDub;              pMRU->ReadList();              pMRU->Add(fn);              pMRU->WriteList();              SHAddToRecentDocs(SHARD_PATH, fn);          }  if (bMainFile) {              pOFD->title = fn;          }          bMainFile = false;  if (m_fCustomGraph) {  break;          }      }  if (s.fReportFailedPins) {          CComQIPtr<IGraphBuilderDeadEnd> pGBDE = m_pGB;  if (pGBDE && pGBDE->GetCount()) {              CMediaTypesDlg(pGBDE, GetModalParent()).DoModal();          }      }  if (!(m_pAMOP = m_pGB)) {          BeginEnumFilters(m_pGB, pEF, pBF);  if (m_pAMOP = pBF) {  break;          }          EndEnumFilters;      }  if (FindFilter(CLSID_MPCShoutcastSource, m_pGB)) {          m_fUpdateInfoBar = true;      }      SetupChapters();      CComQIPtr<IKeyFrameInfo> pKFI;      BeginEnumFilters(m_pGB, pEF, pBF);  if (pKFI = pBF) {  break;      }      EndEnumFilters;  UINT nKFs = 0;  if (pKFI && S_OK == pKFI->GetKeyFrameCount(nKFs) && nKFs > 0) {  UINT k = nKFs;  if (!m_kfs.SetCount(k) || S_OK != pKFI->GetKeyFrames(&TIME_FORMAT_MEDIA_TIME, m_kfs.GetData(), k) || k != nKFs) {              m_kfs.RemoveAll();          }      }  //设置播放模式    SetPlaybackMode(PM_FILE);  }
复制代码

从OpenFile()函数的源代码我们可以看出,mpc-hc调用了DirectShow的函数,打开相应的文件。比如说:

HRESULT hr = m_pGB->RenderFile(CStringW(fn), nullptr);

3:核心类 (CMainFrame)(2)

本文补充介绍CMainFrame类中的其他一些函数。

再回顾一下打开文件功能主要所在的函数OpenMediaPrivate():

复制代码
//打开一个媒体(private)bool CMainFrame::OpenMediaPrivate(CAutoPtr<OpenMediaData> pOMD)  {  //获得设置信息    CAppSettings& s = AfxGetAppSettings();  if (m_iMediaLoadState != MLS_CLOSED) {          ASSERT(0);  return false;      }  //OpenFileData//OpenDVDData//OpenDeviceData//里面包含了文件或者DVD信息(名称等)    OpenFileData* pFileData = dynamic_cast<OpenFileData*>(pOMD.m_p);      OpenDVDData* pDVDData = dynamic_cast<OpenDVDData*>(pOMD.m_p);      OpenDeviceData* pDeviceData = dynamic_cast<OpenDeviceData*>(pOMD.m_p);  if (!pFileData && !pDVDData  && !pDeviceData) {          ASSERT(0);  return false;      }  // Clear DXVA state ...    ClearDXVAState();  #ifdef _DEBUG// Debug trace code - Begin// Check for bad / buggy auto loading file codeif (pFileData) {          POSITION pos = pFileData->fns.GetHeadPosition();  UINT index = 0;  while (pos != nullptr) {              CString path = pFileData->fns.GetNext(pos);              TRACE(_T("--> CMainFrame::OpenMediaPrivate - pFileData->fns[%d]:\n"), index);              TRACE(_T("\t%ws\n"), path.GetString()); // %ws - wide character string always            index++;          }      }  // Debug trace code - End#endif    CString mi_fn = _T("");  if (pFileData) {  if (pFileData->fns.IsEmpty()) {  return false;          }          CString fn = pFileData->fns.GetHead();  int i = fn.Find(_T(":\\"));  if (i > 0) {              CString drive = fn.Left(i + 2);  UINT type = GetDriveType(drive);              CAtlList<CString> sl;  if (type == DRIVE_REMOVABLE || type == DRIVE_CDROM && GetCDROMType(drive[0], sl) != CDROM_Audio) {  int ret = IDRETRY;  while (ret == IDRETRY) {                      WIN32_FIND_DATA findFileData;  HANDLE h = FindFirstFile(fn, &findFileData);  if (h != INVALID_HANDLE_VALUE) {                          FindClose(h);                          ret = IDOK;                      } else {                          CString msg;                          msg.Format(IDS_MAINFRM_114, fn);                          ret = AfxMessageBox(msg, MB_RETRYCANCEL);                      }                  }  if (ret != IDOK) {  return false;                  }              }              mi_fn = fn;          }      }      SetLoadState(MLS_LOADING);  // FIXME: Don't show "Closed" initially    PostMessage(WM_KICKIDLE);      CString err;      m_fUpdateInfoBar = false;      BeginWaitCursor();  try {          CComPtr<IVMRMixerBitmap9>    pVMB;          CComPtr<IMFVideoMixerBitmap> pMFVMB;          CComPtr<IMadVRTextOsd>       pMVTO;  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }          OpenCreateGraphObject(pOMD);  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }          SetupIViAudReg();  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //按类型的不同打开不同的文件if (pFileData) {  //文件            OpenFile(pFileData);          } else if (pDVDData) {  //DVD            OpenDVD(pDVDData);          } else if (pDeviceData) {  if (s.iDefaultCaptureDevice == 1) {  HRESULT hr = OpenBDAGraph();  if (FAILED(hr)) {  throw (UINT)IDS_CAPTURE_ERROR_DEVICE;                  }              } else {                  OpenCapture(pDeviceData);              }          } else {  throw (UINT)IDS_INVALID_PARAMS_ERROR;          }          m_pCAP2 = nullptr;          m_pCAP = nullptr;  //查找接口        m_pGB->FindInterface(__uuidof(ISubPicAllocatorPresenter), (void**)&m_pCAP, TRUE);          m_pGB->FindInterface(__uuidof(ISubPicAllocatorPresenter2), (void**)&m_pCAP2, TRUE);          m_pGB->FindInterface(__uuidof(IVMRWindowlessControl9), (void**)&m_pVMRWC, FALSE); // might have IVMRMixerBitmap9, but not IVMRWindowlessControl9        m_pGB->FindInterface(__uuidof(IVMRMixerControl9), (void**)&m_pVMRMC, TRUE);          m_pGB->FindInterface(__uuidof(IVMRMixerBitmap9), (void**)&pVMB, TRUE);          m_pGB->FindInterface(__uuidof(IMFVideoMixerBitmap), (void**)&pMFVMB, TRUE);          pMVTO = m_pCAP;  if (s.fShowOSD || s.fShowDebugInfo) { // Force OSD on when the debug switch is usedif (pVMB) {                  m_OSD.Start(m_pVideoWnd, pVMB, IsD3DFullScreenMode());              } else if (pMFVMB) {                  m_OSD.Start(m_pVideoWnd, pMFVMB, IsD3DFullScreenMode());              } else if (pMVTO) {                  m_OSD.Start(m_pVideoWnd, pMVTO);              }          }  //VMR9        SetupVMR9ColorControl();  // === EVR !        m_pGB->FindInterface(__uuidof(IMFVideoDisplayControl), (void**)&m_pMFVDC,  TRUE);          m_pGB->FindInterface(__uuidof(IMFVideoProcessor), (void**)&m_pMFVP, TRUE);  if (m_pMFVDC) {              m_pMFVDC->SetVideoWindow(m_pVideoWnd->m_hWnd);          }  //SetupEVRColorControl();//does not work at this location//need to choose the correct mode (IMFVideoProcessor::SetVideoProcessorMode)        BeginEnumFilters(m_pGB, pEF, pBF) {  if (m_pLN21 = pBF) {                  m_pLN21->SetServiceState(s.fClosedCaptions ? AM_L21_CCSTATE_On : AM_L21_CCSTATE_Off);  break;              }          }          EndEnumFilters;  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //打开自定义的Graph        OpenCustomizeGraph();  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //设置视频窗口        OpenSetupVideo();  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //设置音量        OpenSetupAudio();  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  if (m_pCAP && (!m_fAudioOnly || m_fRealMediaGraph)) {  if (s.fDisableInternalSubtitles) {                  m_pSubStreams.RemoveAll(); // Needs to be replaced with code that checks for forced subtitles.            }              m_posFirstExtSub = nullptr;              POSITION pos = pOMD->subs.GetHeadPosition();  while (pos) {                  LoadSubtitle(pOMD->subs.GetNext(pos), nullptr, true);              }          }  if (m_fOpeningAborted) {  throw (UINT)IDS_AG_ABORTED;          }  //设置视频窗口标题        OpenSetupWindowTitle(pOMD->title);  if (s.fEnableEDLEditor) {              m_wndEditListEditor.OpenFile(pOMD->title);          }  if (::GetCurrentThreadId() == AfxGetApp()->m_nThreadID) {              OnFilePostOpenmedia();          } else {              PostMessage(WM_COMMAND, ID_FILE_POST_OPENMEDIA);          }  while (m_iMediaLoadState != MLS_LOADED                  && m_iMediaLoadState != MLS_CLOSING // FIXME              ) {              Sleep(50);          }  //设置音频流DWORD audstm = SetupAudioStreams();  //设置字幕流DWORD substm = SetupSubtitleStreams();  if (audstm) {              OnPlayAudio(ID_AUDIO_SUBITEM_START + audstm);          }  if (substm) {              SetSubtitle(substm - 1);          }  // PostMessage instead of SendMessage because the user might call CloseMedia and then we would deadlock        PostMessage(WM_COMMAND, ID_PLAY_PAUSE);          m_bFirstPlay = true;  if (!(s.nCLSwitches & CLSW_OPEN) && (s.nLoops > 0)) {              PostMessage(WM_COMMAND, ID_PLAY_PLAY);          } else {  // If we don't start playing immediately, we need to initialize// the seekbar and the time counter.            OnTimer(TIMER_STREAMPOSPOLLER);              OnTimer(TIMER_STREAMPOSPOLLER2);          }          s.nCLSwitches &= ~CLSW_OPEN;  if (pFileData) {  if (pFileData->rtStart > 0) {                  PostMessage(WM_RESUMEFROMSTATE, (WPARAM)PM_FILE, (LPARAM)(pFileData->rtStart / 10000));  // REFERENCE_TIME doesn't fit in LPARAM under a 32bit env.            }          } else if (pDVDData) {  if (pDVDData->pDvdState) {                  PostMessage(WM_RESUMEFROMSTATE, (WPARAM)PM_DVD, (LPARAM)(CComPtr<IDvdState>(pDVDData->pDvdState).Detach()));    // must be released by the called message handler            }          } else if (pDeviceData) {              m_wndCaptureBar.m_capdlg.SetVideoInput(pDeviceData->vinput);              m_wndCaptureBar.m_capdlg.SetVideoChannel(pDeviceData->vchannel);              m_wndCaptureBar.m_capdlg.SetAudioInput(pDeviceData->ainput);          }      } catch (LPCTSTR msg) {          err = msg;      } catch (CString& msg) {          err = msg;      } catch (UINT msg) {          err.LoadString(msg);      }      EndWaitCursor();  if (!err.IsEmpty()) {  //关闭        CloseMediaPrivate();          m_closingmsg = err;  if (err != ResStr(IDS_AG_ABORTED)) {  if (pFileData) {                  m_wndPlaylistBar.SetCurValid(false);  if (m_wndPlaylistBar.IsAtEnd()) {                      m_nLoops++;                  }  if (s.fLoopForever || m_nLoops < s.nLoops) {  bool hasValidFile = false;  if (m_nLastSkipDirection == ID_NAVIGATE_SKIPBACK) {                          hasValidFile = m_wndPlaylistBar.SetPrev();                      } else {                          hasValidFile = m_wndPlaylistBar.SetNext();                      }  if (hasValidFile) {                          OpenCurPlaylistItem();                      }                  } else if (m_wndPlaylistBar.GetCount() > 1) {                      DoAfterPlaybackEvent();                  }              } else {                  OnNavigateSkip(ID_NAVIGATE_SKIPFORWARD);              }          }      } else {          m_wndPlaylistBar.SetCurValid(true);  // Apply command line audio shiftif (s.rtShift != 0) {              SetAudioDelay(s.rtShift);              s.rtShift = 0;          }      }      m_nLastSkipDirection = 0;  if (s.AutoChangeFullscrRes.bEnabled && (m_fFullScreen || IsD3DFullScreenMode())) {          AutoChangeMonitorMode();      }  if (m_fFullScreen && s.fRememberZoomLevel) {          m_fFirstFSAfterLaunchOnFS = true;      }      m_LastOpenFile = pOMD->title;      PostMessage(WM_KICKIDLE); // calls main thread to update thingsif (!m_bIsBDPlay) {          m_MPLSPlaylist.RemoveAll();          m_LastOpenBDPath = _T("");      }      m_bIsBDPlay = false;  return err.IsEmpty();  }
复制代码

来看一看OpenMediaPrivate()函数的细节:

1.开始的时候有这么一句

CAppSettings& s = AfxGetAppSettings();

在这里涉及到一个类CAppSettings,存储的是mpc-hc用到的各种设置信息。源代码如下:

复制代码
//应用程序中的各种参数class CAppSettings  {  bool fInitialized;  class CRecentFileAndURLList : public CRecentFileList      {  public:          CRecentFileAndURLList(UINT nStart, LPCTSTR lpszSection,  LPCTSTR lpszEntryFormat, int nSize,  int nMaxDispLen = AFX_ABBREV_FILENAME_LEN);  virtual void Add(LPCTSTR lpszPathName); // we have to override CRecentFileList::Add because the original version can't handle URLs    };  public:  bool fShaderEditorWasOpened;  // cmdline paramsUINT nCLSwitches;      CAtlList<CString>   slFiles, slDubs, slSubs, slFilters;  // Initial position (used by command line flags)    REFERENCE_TIME      rtShift;      REFERENCE_TIME      rtStart;  ULONG               lDVDTitle;  ULONG               lDVDChapter;      DVD_HMSF_TIMECODE   DVDPosition;      CSize sizeFixedWindow;  bool HasFixedWindowSize() const { return sizeFixedWindow.cx > 0 || sizeFixedWindow.cy > 0; }  //int           iFixedWidth, iFixedHeight;int             iMonitor;      CString         ParseFileName(CString const& param);  void            ParseCommandLine(CAtlList<CString>& cmdln);  // Added a Debug display to the screen (/debug option)bool            fShowDebugInfo;  int             iAdminOption;  //播放器 Playerbool            fAllowMultipleInst;  bool            fTrayIcon;  bool            fShowOSD;  bool            fLimitWindowProportions;  bool            fSnapToDesktopEdges;  bool            fHideCDROMsSubMenu;  DWORD           dwPriority;  int             iTitleBarTextStyle;  bool            fTitleBarTextTitle;  bool            fKeepHistory;      CRecentFileAndURLList MRU;      CRecentFileAndURLList MRUDub;      CFilePositionList filePositions;      CDVDPositionList  dvdPositions;  bool            fRememberDVDPos;  bool            fRememberFilePos;  bool            bRememberPlaylistItems;  bool            fRememberWindowPos;      CRect           rcLastWindowPos;  bool            fRememberWindowSize;  bool            fSavePnSZoom;  double          dZoomX;  double          dZoomY;  // Formats    CMediaFormats   m_Formats;  bool            fAssociatedWithIcons;  // Keys    CList<wmcmd>    wmcmds;  HACCEL          hAccel;  bool            fWinLirc;      CString         strWinLircAddr;      CWinLircClient  WinLircClient;  bool            fUIce;      CString         strUIceAddr;      CUIceClient     UIceClient;  bool            fGlobalMedia;  //图标 LogoUINT            nLogoId;  bool            fLogoExternal;      CString         strLogoFileName;  //web界面? Web IntefaceBOOL            fEnableWebServer;  int             nWebServerPort;  int             nCmdlnWebServerPort;  bool            fWebServerUseCompression;  bool            fWebServerLocalhostOnly;  bool            fWebServerPrintDebugInfo;      CString         strWebRoot, strWebDefIndex;      CString         strWebServerCGI;  //播放时候 Playbackint             nVolume;  bool            fMute;  int             nBalance;  int             nLoops;  bool            fLoopForever;  bool            fRewind;  bool            fRememberZoomLevel;  int             nAutoFitFactor;  int             iZoomLevel;      CStringW        strAudiosLanguageOrder;      CStringW        strSubtitlesLanguageOrder;  bool            fEnableWorkerThreadForOpening;  bool            fReportFailedPins;  bool            fAutoloadAudio;  bool            fAutoloadSubtitles;  bool            fBlockVSFilter;  UINT            nVolumeStep;  UINT            nSpeedStep;  // DVD/OGMbool            fUseDVDPath;      CString         strDVDPath;  LCID            idMenuLang, idAudioLang, idSubtitlesLang;  bool            fAutoSpeakerConf;  bool            fClosedCaptions;  //输出 Output    CRenderersSettings m_RenderersSettings;  int             iDSVideoRendererType;  int             iRMVideoRendererType;  int             iQTVideoRendererType;      CStringW        strAudioRendererDisplayName;  bool            fD3DFullscreen;  //全屏 Fullscreenbool            fLaunchfullscreen;  bool            fShowBarsWhenFullScreen;  int             nShowBarsWhenFullScreenTimeOut;  bool            fExitFullScreenAtTheEnd;      CStringW        strFullScreenMonitor;      AChFR           AutoChangeFullscrRes;  bool            fRestoreResAfterExit;  // Sync Renderer Settings// Capture (BDA configuration)int             iDefaultCaptureDevice;      // Default capture device (analog=0, 1=digital)    CString         strAnalogVideo;      CString         strAnalogAudio;  int             iAnalogCountry;      CString         strBDANetworkProvider;      CString         strBDATuner;      CString         strBDAReceiver;  //CString           strBDAStandard;int             iBDAScanFreqStart;  int             iBDAScanFreqEnd;  int             iBDABandwidth;  bool            fBDAUseOffset;  int             iBDAOffset;  bool            fBDAIgnoreEncryptedChannels;  UINT            nDVBLastChannel;      CAtlList<CDVBChannel> m_DVBChannels;      DVB_RebuildFilterGraph nDVBRebuildFilterGraph;      DVB_StopFilterGraph nDVBStopFilterGraph;  // Internal Filtersbool            SrcFilters[SRC_LAST + !SRC_LAST];  bool            TraFilters[TRA_LAST + !TRA_LAST];  //音频 Audio Switcherbool            fEnableAudioSwitcher;  bool            fAudioNormalize;  UINT            nAudioMaxNormFactor;  bool            fAudioNormalizeRecover;  UINT            nAudioBoost;  bool            fDownSampleTo441;  bool            fAudioTimeShift;  int             iAudioTimeShift;  bool            fCustomChannelMapping;  int             nSpeakerChannels;  DWORD           pSpeakerToChannelMap[AS_MAX_CHANNELS][AS_MAX_CHANNELS];  // External Filters    CAutoPtrList<FilterOverride> m_filters;  //字幕 Subtitlesbool            fOverridePlacement;  int             nHorPos, nVerPos;  int             nSubDelayInterval;  // Default Style    STSStyle        subdefstyle;  // Miscbool            bPreferDefaultForcedSubtitles;  bool            fPrioritizeExternalSubtitles;  bool            fDisableInternalSubtitles;  bool            bAllowOverridingExternalSplitterChoice;      CString         strSubtitlePaths;      CString         strISDb;  // Tweaksint             nJumpDistS;  int             nJumpDistM;  int             nJumpDistL;  bool            fFastSeek;  bool            fShowChapters;  bool            bNotifySkype;  bool            fPreventMinimize;  bool            fUseWin7TaskBar;  bool            fLCDSupport;  bool            fUseSearchInFolder;  bool            fUseTimeTooltip;  int             nTimeTooltipPosition;      CString         strOSDFont;  int             nOSDSize;  //亮度色度饱和度 Miscellaneousint             iBrightness;  int             iContrast;  int             iHue;  int             iSaturation;  int             nUpdaterAutoCheck;  int             nUpdaterDelay;  // MENUS// Viewint             iCaptionMenuMode; // normal -> hidemenu -> frameonly -> borderlessbool            fHideNavigation;  UINT            nCS; // Control state for toolbars// LanguageLANGID          language;  // Subtitles menubool            fEnableSubtitles;  bool            fUseDefaultSubtitlesStyle;  // Video Frameint             iDefaultVideoSize;  bool            fKeepAspectRatio;      CSize           sizeAspectRatio;  bool            fCompMonDeskARDiff;  // Pan&Scan    CString         strPnSPreset;      CStringArray    m_pnspresets;  // On top menuint             iOnTop;  // After Playbackbool            fExitAfterPlayback;  bool            fNextInDirAfterPlayback;  // WINDOWS// Add Favoritebool            bFavRememberPos;  bool            bFavRelativeDrive;  // Save Image...    CString         strSnapShotPath, strSnapShotExt;  // Save Thumbnails...int             iThumbRows, iThumbCols, iThumbWidth;  // Shader Editorstruct Shader {          CString     label;          CString     target;          CString     srcdata;      };      CAtlList<Shader> m_shaders;  // Shader Combinerbool            fToggleShader;  bool            fToggleShaderScreenSpace;      CString         strShaderList;      CString         strShaderListScreenSpace;  // Playlist (contex menu)bool            bShufflePlaylistItems;  bool            bHidePlaylistFullScreen;  // OTHER STATES    CStringW        strLastOpenDir;  UINT            nLastWindowType;  UINT            nLastUsedPage;  bool            fRemainingTime;  bool            fLastFullScreen;  bool            fIntRealMedia;  //bool          fRealMediaRenderless;//float         dRealMediaQuickTimeFPS;//int           iVideoRendererType;//int           iQuickTimeRenderer;//bool          fMonitorAutoRefreshRate;bool            fEnableEDLEditor;  HWND            hMasterWnd;  bool            IsD3DFullscreen() const;      CString         SelectedAudioRenderer() const;  bool            IsISREnabled() const;  private:      CString         SrcFiltersKeys[SRC_LAST + !SRC_LAST];      CString         TraFiltersKeys[TRA_LAST + !TRA_LAST];  __int64         ConvertTimeToMSec(const CString& time) const;  void            ExtractDVDStartPos(CString& strParam);  void            CreateCommands();  void            SaveExternalFilters(CAutoPtrList<FilterOverride>& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS);  void            LoadExternalFilters(CAutoPtrList<FilterOverride>& filters, LPCTSTR baseKey = IDS_R_EXTERNAL_FILTERS);  void            ConvertOldExternalFiltersList();  void            UpdateRenderersData(bool fSave);  friend void     CRenderersSettings::UpdateData(bool bSave);  public:      CAppSettings();  virtual ~CAppSettings();  void            SaveSettings();  void            LoadSettings();  void            SaveExternalFilters() { if (fInitialized) { SaveExternalFilters(m_filters); } };  void            GetFav(favtype ft, CAtlList<CString>& sl) const;  void            SetFav(favtype ft, CAtlList<CString>& sl);  void            AddFav(favtype ft, CString s);      CDVBChannel*    FindChannelByPref(int nPrefNumber);  bool            GetAllowMultiInst() const;  static bool     IsVSFilterInstalled();  static bool     HasEVR();  };
复制代码

由代码可见,包含的参数信息很多。在mpc-hc中,任何需要获取设置信息的地方,都可以使用AfxGetAppSettings()获得CAppSettings的引用。

2.OpenSetupVideo()这个函数的作用是设置视频窗口,源代码如下:

复制代码
//设置视频窗口void CMainFrame::OpenSetupVideo()  {  //大部分都在确定:m_fAudioOnly是否为True    m_fAudioOnly = true;  //获得视频的宽和高,然后调整窗口大小if (m_pMFVDC) { // EVR        m_fAudioOnly = false;      } else if (m_pCAP) {          CSize vs = m_pCAP->GetVideoSize();          m_fAudioOnly = (vs.cx <= 0 || vs.cy <= 0);      } else {          {  long w = 0, h = 0;  if (CComQIPtr<IBasicVideo> pBV = m_pGB) {                  pBV->GetVideoSize(&w, &h);              }  if (w > 0 && h > 0) {                  m_fAudioOnly = false;              }          }  //如果 m_fAudioOnly=true;再检查if (m_fAudioOnly) {              BeginEnumFilters(m_pGB, pEF, pBF) {  long w = 0, h = 0;  if (CComQIPtr<IVideoWindow> pVW = pBF) {  long lVisible;  if (FAILED(pVW->get_Visible(&lVisible))) {  continue;                      }                      pVW->get_Width(&w);                      pVW->get_Height(&h);                  }  if (w > 0 && h > 0) {                      m_fAudioOnly = false;  break;                  }              }              EndEnumFilters;          }      }  if (m_fShockwaveGraph) {          m_fAudioOnly = false;      }  if (m_pCAP) {          SetShaders();      }  // else    {  // TESTME//设置所有者。。。        m_pVW->put_Owner((OAHWND)m_pVideoWnd->m_hWnd);          m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);          m_pVW->put_MessageDrain((OAHWND)m_hWnd);  for (CWnd* pWnd = m_wndView.GetWindow(GW_CHILD); pWnd; pWnd = pWnd->GetNextWindow()) {              pWnd->EnableWindow(FALSE);    // little trick to let WM_SETCURSOR thru        }      }  //如果只有音频,则消灭视频窗口!if (m_fAudioOnly && IsD3DFullScreenMode()) {          m_pFullscreenWnd->DestroyWindow();      }  }
复制代码

3.OpenSetupAudio()这个函数的作用是设置音频,源代码如下:

复制代码
//设置音量void CMainFrame::OpenSetupAudio()  {  //设置音量    m_pBA->put_Volume(m_wndToolBar.Volume);  // FIXMEint balance = AfxGetAppSettings().nBalance;  int sign = balance > 0 ? -1 : 1; // -1: invert sign for more right channelif (balance > -100 && balance < 100) {          balance = sign * (int)(100 * 20 * log10(1 - abs(balance) / 100.0f));      } else {          balance = sign * (-10000);  // -10000: only left, 10000: only right    }  //设置均衡    m_pBA->put_Balance(balance);  }
复制代码

4.如果出现问题,则会调用CloseMediaPrivate(),关闭打开的媒体。

复制代码
//关闭void CMainFrame::CloseMediaPrivate()  {      SetLoadState(MLS_CLOSING); // why it before OnPlayStop()? // TODO: remake or add detailed comments    OnPlayStop(); // SendMessage(WM_COMMAND, ID_PLAY_STOP);if (m_pMC) {          m_pMC->Stop(); // needed for StreamBufferSource, because m_iMediaLoadState is always MLS_CLOSED // TODO: fix the opening for such media    }      SetPlaybackMode(PM_NONE);      m_fLiveWM = false;      m_fEndOfStream = false;      m_rtDurationOverride = -1;      m_kfs.RemoveAll();      m_pCB.Release();      {          CAutoLock cAutoLock(&m_csSubLock);          m_pSubStreams.RemoveAll();      }      m_pSubClock.Release();  //if (m_pVW) m_pVW->put_Visible(OAFALSE);//if (m_pVW) m_pVW->put_MessageDrain((OAHWND)NULL), m_pVW->put_Owner((OAHWND)NULL);// IMPORTANT: IVMRSurfaceAllocatorNotify/IVMRSurfaceAllocatorNotify9 has to be released before the VMR/VMR9, otherwise it will crash in Release()//各种清空    m_OSD.Stop();      m_pCAP2.Release();      m_pCAP.Release();      m_pVMRWC.Release();      m_pVMRMC.Release();      m_pMFVP.Release();      m_pMFVDC.Release();      m_pLN21.Release();      m_pSyncClock.Release();      m_pAMXBar.Release();      m_pAMDF.Release();      m_pAMVCCap.Release();      m_pAMVCPrev.Release();      m_pAMVSCCap.Release();      m_pAMVSCPrev.Release();      m_pAMASC.Release();      m_pVidCap.Release();      m_pAudCap.Release();      m_pAMTuner.Release();      m_pCGB.Release();      m_pDVDC.Release();      m_pDVDI.Release();      m_pAMOP.Release();      m_pBI.Release();      m_pQP.Release();      m_pFS.Release();      m_pMS.Release();      m_pBA.Release();      m_pBV.Release();      m_pVW.Release();      m_pME.Release();      m_pMC.Release();  if (m_pGB) {          m_pGB->RemoveFromROT();          m_pGB.Release();      }      m_pProv.Release();      m_fRealMediaGraph = m_fShockwaveGraph = m_fQuicktimeGraph = false;      m_VidDispName.Empty();      m_AudDispName.Empty();      m_closingmsg.LoadString(IDS_CONTROLS_CLOSED);      AfxGetAppSettings().nCLSwitches &= CLSW_OPEN | CLSW_PLAY | CLSW_AFTERPLAYBACK_MASK | CLSW_NOFOCUS;  //设置状态    SetLoadState(MLS_CLOSED);  }
复制代码

4:核心类 (CMainFrame)(3)

此前的文章一直都是围绕着OpenMedia()以及其调用的函数进行分析的。研究的都是和文件打开有关系的功能。在这里再介绍一些其它函数。

在mpc-hc开始运行的时候,会调用OnCreate():

复制代码
//刚打开的时候加载int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)  {  if (__super::OnCreate(lpCreateStruct) == -1) {  return -1;      }  //加载菜单    m_popup.LoadMenu(IDR_POPUP);      m_popupmain.LoadMenu(IDR_POPUPMAIN);  // create a view to occupy the client area of the frame// 创建视频画面部分?if (!m_wndView.Create(nullptr, nullptr, AFX_WS_DEFAULT_VIEW,                            CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, nullptr)) {          TRACE(_T("Failed to create view window\n"));  return -1;      }  // Should never be RTLed    m_wndView.ModifyStyleEx(WS_EX_LAYOUTRTL, WS_EX_NOINHERITLAYOUT);  // static bars//各种状态栏BOOL bResult = m_wndStatusBar.Create(this);  if (bResult) {          bResult = m_wndStatsBar.Create(this);      }  if (bResult) {          bResult = m_wndInfoBar.Create(this);      }  if (bResult) {          bResult = m_wndToolBar.Create(this);      }  if (bResult) {          bResult = m_wndSeekBar.Create(this);      }  if (!bResult) {          TRACE(_T("Failed to create all control bars\n"));  return -1;      // fail to create    }  // 各种Bar    m_pFullscreenWnd = DEBUG_NEW CFullscreenWnd(this);      m_bars.AddTail(&m_wndSeekBar);      m_bars.AddTail(&m_wndToolBar);      m_bars.AddTail(&m_wndInfoBar);      m_bars.AddTail(&m_wndStatsBar);      m_bars.AddTail(&m_wndStatusBar);      m_wndSeekBar.Enable(false);  // dockable bars// 可停靠的    EnableDocking(CBRS_ALIGN_ANY);      m_dockingbars.RemoveAll();      m_wndSubresyncBar.Create(this, AFX_IDW_DOCKBAR_TOP, &m_csSubLock);      m_wndSubresyncBar.SetBarStyle(m_wndSubresyncBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);      m_wndSubresyncBar.EnableDocking(CBRS_ALIGN_ANY);      m_wndSubresyncBar.SetHeight(200);      m_dockingbars.AddTail(&m_wndSubresyncBar);      m_wndPlaylistBar.Create(this, AFX_IDW_DOCKBAR_BOTTOM);      m_wndPlaylistBar.SetBarStyle(m_wndPlaylistBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);      m_wndPlaylistBar.EnableDocking(CBRS_ALIGN_ANY);      m_wndPlaylistBar.SetHeight(100);      m_dockingbars.AddTail(&m_wndPlaylistBar);      m_wndPlaylistBar.LoadPlaylist(GetRecentFile());      m_wndEditListEditor.Create(this, AFX_IDW_DOCKBAR_RIGHT);      m_wndEditListEditor.SetBarStyle(m_wndEditListEditor.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);      m_wndEditListEditor.EnableDocking(CBRS_ALIGN_ANY);      m_dockingbars.AddTail(&m_wndEditListEditor);      m_wndEditListEditor.SetHeight(100);      m_wndCaptureBar.Create(this, AFX_IDW_DOCKBAR_LEFT);      m_wndCaptureBar.SetBarStyle(m_wndCaptureBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);      m_wndCaptureBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);      m_dockingbars.AddTail(&m_wndCaptureBar);      m_wndNavigationBar.Create(this, AFX_IDW_DOCKBAR_LEFT);      m_wndNavigationBar.SetBarStyle(m_wndNavigationBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);      m_wndNavigationBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);      m_dockingbars.AddTail(&m_wndNavigationBar);      m_wndShaderEditorBar.Create(this, AFX_IDW_DOCKBAR_TOP);      m_wndShaderEditorBar.SetBarStyle(m_wndShaderEditorBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);      m_wndShaderEditorBar.EnableDocking(CBRS_ALIGN_ANY);      m_dockingbars.AddTail(&m_wndShaderEditorBar);  // Hide all dockable bars by default    POSITION pos = m_dockingbars.GetHeadPosition();  while (pos) {          m_dockingbars.GetNext(pos)->ShowWindow(SW_HIDE);      }      m_fileDropTarget.Register(this);  const CAppSettings& s = AfxGetAppSettings();  // Load the controls    m_nCS = s.nCS;      ShowControls(m_nCS);  //是否在最前?    SetAlwaysOnTop(s.iOnTop);  //显示系统托盘图标    ShowTrayIcon(s.fTrayIcon);  //焦点    SetFocus();  //创建CGraphThread类的线程    m_pGraphThread = (CGraphThread*)AfxBeginThread(RUNTIME_CLASS(CGraphThread));  //设置。。if (m_pGraphThread) {          m_pGraphThread->SetMainFrame(this);      }  if (s.nCmdlnWebServerPort != 0) {  if (s.nCmdlnWebServerPort > 0) {              StartWebServer(s.nCmdlnWebServerPort);          } else if (s.fEnableWebServer) {              StartWebServer(s.nWebServerPort);          }      }  // Casimir666 : reload Shaders    {          CString strList = s.strShaderList;          CString strRes;  int curPos = 0;          strRes = strList.Tokenize(_T("|"), curPos);  while (!strRes.IsEmpty()) {              m_shaderlabels.AddTail(strRes);              strRes = strList.Tokenize(_T("|"), curPos);          }      }      {          CString strList = s.strShaderListScreenSpace;          CString strRes;  int curPos = 0;          strRes = strList.Tokenize(_T("|"), curPos);  while (!strRes.IsEmpty()) {              m_shaderlabelsScreenSpace.AddTail(strRes);              strRes = strList.Tokenize(_T("|"), curPos);          }      }      m_bToggleShader = s.fToggleShader;      m_bToggleShaderScreenSpace = s.fToggleShaderScreenSpace;  //标题    m_strTitle.LoadString(IDR_MAINFRAME);  #ifdef MPCHC_LITE    m_strTitle += _T(" Lite");  #endif//设置窗口标题    SetWindowText(m_strTitle);      m_Lcd.SetMediaTitle(LPCTSTR(m_strTitle));      WTSRegisterSessionNotification();  if (s.bNotifySkype) {          m_pSkypeMoodMsgHandler.Attach(DEBUG_NEW SkypeMoodMsgHandler());          m_pSkypeMoodMsgHandler->Connect(m_hWnd);      }  return 0;  }
复制代码

在mpc-hc关闭的时候,会调用OnDestroy():

复制代码
//关闭的时候加载void CMainFrame::OnDestroy()  {      WTSUnRegisterSessionNotification();  //关闭系统托盘图标    ShowTrayIcon(false);      m_fileDropTarget.Revoke();  //线程还在运行的话if (m_pGraphThread) {          CAMMsgEvent e;  //退出        m_pGraphThread->PostThreadMessage(CGraphThread::TM_EXIT, 0, (LPARAM)&e);  if (!e.Wait(5000)) {              TRACE(_T("ERROR: Must call TerminateThread() on CMainFrame::m_pGraphThread->m_hThread\n"));              TerminateThread(m_pGraphThread->m_hThread, (DWORD) - 1);          }      }  if (m_pFullscreenWnd) {  if (m_pFullscreenWnd->IsWindow()) {              m_pFullscreenWnd->DestroyWindow();          }  delete m_pFullscreenWnd;      }      __super::OnDestroy();  }
复制代码

在关闭一个媒体的时候,会调用OnClose():

复制代码
//关闭的时候加载void CMainFrame::OnClose()  {  //获取设置    CAppSettings& s = AfxGetAppSettings();  // Casimir666 : save shaders list    {          POSITION pos;          CString strList = "";          pos = m_shaderlabels.GetHeadPosition();  while (pos) {              strList += m_shaderlabels.GetAt(pos) + "|";              m_dockingbars.GetNext(pos);          }          s.strShaderList = strList;      }      {          POSITION pos;          CString  strList = "";          pos = m_shaderlabelsScreenSpace.GetHeadPosition();  while (pos) {              strList += m_shaderlabelsScreenSpace.GetAt(pos) + "|";              m_dockingbars.GetNext(pos);          }          s.strShaderListScreenSpace = strList;      }      s.fToggleShader = m_bToggleShader;      s.fToggleShaderScreenSpace = m_bToggleShaderScreenSpace;      s.dZoomX = m_ZoomX;      s.dZoomY = m_ZoomY;  //存储播放列表    m_wndPlaylistBar.SavePlaylist();  //存储控制条    SaveControlBars();      ShowWindow(SW_HIDE);  //关闭媒体(非private)    CloseMedia();      s.WinLircClient.DisConnect();      s.UIceClient.DisConnect();      SendAPICommand(CMD_DISCONNECT, L"\0");  // according to CMD_NOTIFYENDOFSTREAM (ctrl+f it here), you're not supposed to send NULL here//调用父类onclose    __super::OnClose();  }
复制代码

同时还有一个定时器函数OnTimer()。根据不同的nIDEvent做不同的处理操作。

复制代码
//定时刷新的操作void CMainFrame::OnTimer(UINT_PTR nIDEvent)  {  switch (nIDEvent) {  //当前播放到的位置case TIMER_STREAMPOSPOLLER:  if (m_iMediaLoadState == MLS_LOADED) {                  REFERENCE_TIME rtNow = 0, rtDur = 0;  //播放方式是文件的时候(还可以是DVD或者摄像头)if (GetPlaybackMode() == PM_FILE) {  //当前位置                    m_pMS->GetCurrentPosition(&rtNow);  //时常                    m_pMS->GetDuration(&rtDur);  // Casimir666 : autosave subtitle sync after playif ((m_nCurSubtitle >= 0) && (m_rtCurSubPos != rtNow)) {  if (m_lSubtitleShift != 0) {  if (m_wndSubresyncBar.SaveToDisk()) {                                  m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_AG_SUBTITLES_SAVED), 500);                              } else {                                  m_OSD.DisplayMessage(OSD_TOPLEFT, ResStr(IDS_MAINFRM_4));                              }                          }                          m_nCurSubtitle   = -1;                          m_lSubtitleShift = 0;                      }  if (!m_fEndOfStream) {                          CAppSettings& s = AfxGetAppSettings();  if (m_bRememberFilePos) {                              FILE_POSITION* filePosition = s.filePositions.GetLatestEntry();  if (filePosition) {                                  filePosition->llPosition = rtNow;                                  LARGE_INTEGER time;                                  QueryPerformanceCounter(&time);                                  LARGE_INTEGER freq;                                  QueryPerformanceFrequency(&freq);  if ((time.QuadPart - m_liLastSaveTime.QuadPart) >= 30 * freq.QuadPart) { // save every half of minute                                    m_liLastSaveTime = time;                                      s.filePositions.SaveLatestEntry();                                  }                              }                          }                      }  if (m_rtDurationOverride >= 0) {                          rtDur = m_rtDurationOverride;                      }  //设置滑动条控件的参数(位置等。。。)                    g_bNoDuration = rtDur <= 0;                      m_wndSeekBar.Enable(rtDur > 0);                      m_wndSeekBar.SetRange(0, rtDur);                      m_wndSeekBar.SetPos(rtNow);                      m_OSD.SetRange(0, rtDur);                      m_OSD.SetPos(rtNow);                      m_Lcd.SetMediaRange(0, rtDur);                      m_Lcd.SetMediaPos(rtNow);                  } else if (GetPlaybackMode() == PM_CAPTURE) {  //如果是摄像头的话,就没有时长信息了                    m_pMS->GetCurrentPosition(&rtNow);  if (m_fCapturing && m_wndCaptureBar.m_capdlg.m_pMux) {                          CComQIPtr<IMediaSeeking> pMuxMS = m_wndCaptureBar.m_capdlg.m_pMux;  if (!pMuxMS || FAILED(pMuxMS->GetCurrentPosition(&rtNow))) {                              rtNow = 0;                          }                      }  if (m_rtDurationOverride >= 0) {                          rtDur = m_rtDurationOverride;                      }                      g_bNoDuration = rtDur <= 0;                      m_wndSeekBar.Enable(false);                      m_wndSeekBar.SetRange(0, rtDur);                      m_wndSeekBar.SetPos(rtNow);                      m_OSD.SetRange(0, rtDur);                      m_OSD.SetPos(rtNow);                      m_Lcd.SetMediaRange(0, rtDur);                      m_Lcd.SetMediaPos(rtNow);                  }  if (m_pCAP && GetPlaybackMode() != PM_FILE) {                      g_bExternalSubtitleTime = true;  if (m_pDVDI) {                          DVD_PLAYBACK_LOCATION2 Location;  if (m_pDVDI->GetCurrentLocation(&Location) == S_OK) {  double fps = Location.TimeCodeFlags == DVD_TC_FLAG_25fps ? 25.0                                           : Location.TimeCodeFlags == DVD_TC_FLAG_30fps ? 30.0                                           : Location.TimeCodeFlags == DVD_TC_FLAG_DropFrame ? 29.97                                           : 25.0;                              REFERENCE_TIME rtTimeCode = HMSF2RT(Location.TimeCode, fps);                              m_pCAP->SetTime(rtTimeCode);                          } else {                              m_pCAP->SetTime(/*rtNow*/m_wndSeekBar.GetPos());                          }                      } else {  // Set rtNow to support DVB subtitle                        m_pCAP->SetTime(rtNow);                      }                  } else {                      g_bExternalSubtitleTime = false;                  }              }  break;  case TIMER_STREAMPOSPOLLER2:  if (m_iMediaLoadState == MLS_LOADED) {  __int64 start, stop, pos;                  m_wndSeekBar.GetRange(start, stop);                  pos = m_wndSeekBar.GetPosReal();                  GUID tf;                  m_pMS->GetTimeFormat(&tf);  if (GetPlaybackMode() == PM_CAPTURE && !m_fCapturing) {                      CString str = ResStr(IDS_CAPTURE_LIVE);  long lChannel = 0, lVivSub = 0, lAudSub = 0;  if (m_pAMTuner                              && m_wndCaptureBar.m_capdlg.IsTunerActive()                              && SUCCEEDED(m_pAMTuner->get_Channel(&lChannel, &lVivSub, &lAudSub))) {                          CString ch;                          ch.Format(_T(" (ch%d)"), lChannel);                          str += ch;                      }                      m_wndStatusBar.SetStatusTimer(str);                  } else {                      m_wndStatusBar.SetStatusTimer(pos, stop, !!m_wndSubresyncBar.IsWindowVisible(), &tf);  if (m_bRemainingTime) {                          m_OSD.DisplayMessage(OSD_TOPLEFT, m_wndStatusBar.GetStatusTimer());                      }                  }                  m_wndSubresyncBar.SetTime(pos);  if (m_pCAP && GetMediaState() == State_Paused) {                      m_pCAP->Paint(false);                  }              }  break;  case TIMER_FULLSCREENCONTROLBARHIDER: {              CPoint p;              GetCursorPos(&p);              CRect r;              GetWindowRect(r);  bool fCursorOutside = !r.PtInRect(p);              CWnd* pWnd = WindowFromPoint(p);  if (pWnd && (m_wndView == *pWnd || m_wndView.IsChild(pWnd) || fCursorOutside)) {  if (AfxGetAppSettings().nShowBarsWhenFullScreenTimeOut >= 0) {                      ShowControls(CS_NONE);                  }              }          }  break;  case TIMER_FULLSCREENMOUSEHIDER: {              CPoint p;              GetCursorPos(&p);              CRect r;              GetWindowRect(r);  bool fCursorOutside = !r.PtInRect(p);              CWnd* pWnd = WindowFromPoint(p);  if (IsD3DFullScreenMode()) {  if (pWnd && !m_bInOptions && *pWnd == *m_pFullscreenWnd) {                      m_pFullscreenWnd->ShowCursor(false);                  }                  KillTimer(TIMER_FULLSCREENMOUSEHIDER);              } else {  if (pWnd && !m_bInOptions && (m_wndView == *pWnd || m_wndView.IsChild(pWnd) || fCursorOutside)) {                      m_fHideCursor = true;                      SetCursor(nullptr);                  }              }          }  break;  //统计量case TIMER_STATS: {  //接收端质量信息:抖动,抖动,视音频同步情况等。。。if (m_pQP) {                  CString rate;                  rate.Format(_T("%.2f"), m_dSpeedRate);                  rate = _T("(") + rate + _T("x)");  //信息                CString info;  int val = 0;  //平均帧率                m_pQP->get_AvgFrameRate(&val); // We hang here due to a lock that never gets released.                info.Format(_T("%d.%02d %s"), val / 100, val % 100, rate);                  m_wndStatsBar.SetLine(ResStr(IDS_AG_FRAMERATE), info);  int avg, dev;  //抖动                m_pQP->get_AvgSyncOffset(&avg);                  m_pQP->get_DevSyncOffset(&dev);                  info.Format(ResStr(IDS_STATSBAR_SYNC_OFFSET_FORMAT), avg, dev);                  m_wndStatsBar.SetLine(ResStr(IDS_STATSBAR_SYNC_OFFSET), info);  //掉帧int drawn, dropped;                  m_pQP->get_FramesDrawn(&drawn);                  m_pQP->get_FramesDroppedInRenderer(&dropped);                  info.Format(IDS_MAINFRM_6, drawn, dropped);                  m_wndStatsBar.SetLine(ResStr(IDS_AG_FRAMES), info);  //抖动                m_pQP->get_Jitter(&val);                  info.Format(_T("%d ms"), val);                  m_wndStatsBar.SetLine(ResStr(IDS_STATSBAR_JITTER), info);              }  //缓存信息if (m_pBI) {                  CAtlList<CString> sl;  //获取数量for (int i = 0, j = m_pBI->GetCount(); i < j; i++) {  int samples, size;  //获取缓存状态if (S_OK == m_pBI->GetStatus(i, samples, size)) {                          CString str;                          str.Format(_T("[%d]: %03d/%d KB"), i, samples, size / 1024);                          sl.AddTail(str);                      }                  }  if (!sl.IsEmpty()) {                      CString str;                      str.Format(_T("%s (p%u)"), Implode(sl, ' '), m_pBI->GetPriority());                      m_wndStatsBar.SetLine(ResStr(IDS_AG_BUFFERS), str);                  }              }  //比特率信息            CInterfaceList<IBitRateInfo> pBRIs;              BeginEnumFilters(m_pGB, pEF, pBF) {                  BeginEnumPins(pBF, pEP, pPin) {  if (CComQIPtr<IBitRateInfo> pBRI = pPin) {                          pBRIs.AddTail(pBRI);                      }                  }                  EndEnumPins;  if (!pBRIs.IsEmpty()) {                      CAtlList<CString> sl;                      POSITION pos = pBRIs.GetHeadPosition();  for (int i = 0; pos; i++) {  //比特率接口                        IBitRateInfo* pBRI = pBRIs.GetNext(pos);  //当前比特率DWORD cur = pBRI->GetCurrentBitRate() / 1000;  //平均比特率DWORD avg = pBRI->GetAverageBitRate() / 1000;  if (avg == 0) {  continue;                          }  //添加到字符串                        CString str;  if (cur != avg) {                              str.Format(_T("[%d]: %u/%u Kb/s"), i, avg, cur);                          } else {                              str.Format(_T("[%d]: %u Kb/s"), i, avg);                          }  //加入                        sl.AddTail(str);                      }  if (!sl.IsEmpty()) {                          m_wndStatsBar.SetLine(ResStr(IDS_STATSBAR_BITRATE), Implode(sl, ' ') + ResStr(IDS_STATSBAR_BITRATE_AVG_CUR));                      }  break;                  }              }              EndEnumFilters;  if (GetPlaybackMode() == PM_DVD) { // we also use this timer to update the info panel for DVD playbackULONG ulAvailable, ulCurrent;  // Location                CString Location('-');                  DVD_PLAYBACK_LOCATION2 loc;  ULONG ulNumOfVolumes, ulVolume;                  DVD_DISC_SIDE Side;  ULONG ulNumOfTitles;  ULONG ulNumOfChapters;  if (SUCCEEDED(m_pDVDI->GetCurrentLocation(&loc))                          && SUCCEEDED(m_pDVDI->GetNumberOfChapters(loc.TitleNum, &ulNumOfChapters))                          && SUCCEEDED(m_pDVDI->GetDVDVolumeInfo(&ulNumOfVolumes, &ulVolume, &Side, &ulNumOfTitles))) {                      Location.Format(IDS_MAINFRM_9,                                      ulVolume, ulNumOfVolumes,                                      loc.TitleNum, ulNumOfTitles,                                      loc.ChapterNum, ulNumOfChapters);  ULONG tsec = (loc.TimeCode.bHours * 3600)                                   + (loc.TimeCode.bMinutes * 60)                                   + (loc.TimeCode.bSeconds);  /* This might not always work, such as on resume */if (loc.ChapterNum != m_lCurrentChapter) {                          m_lCurrentChapter = loc.ChapterNum;                          m_lChapterStartTime = tsec;                      } else {  /* If a resume point was used, and the user chapter jumps,                        then it might do some funky time jumping.  Try to 'fix' the                        chapter start time if this happens */if (m_lChapterStartTime > tsec) {                              m_lChapterStartTime = tsec;                          }                      }                  }                  m_wndInfoBar.SetLine(ResStr(IDS_INFOBAR_LOCATION), Location);  // Video                CString Video('-');                  DVD_VideoAttributes VATR;  if (SUCCEEDED(m_pDVDI->GetCurrentAngle(&ulAvailable, &ulCurrent))                          && SUCCEEDED(m_pDVDI->GetCurrentVideoAttributes(&VATR))) {                      Video.Format(IDS_MAINFRM_10,                                   ulCurrent, ulAvailable,                                   VATR.ulSourceResolutionX, VATR.ulSourceResolutionY, VATR.ulFrameRate,                                   VATR.ulAspectX, VATR.ulAspectY);                  }                  m_wndInfoBar.SetLine(ResStr(IDS_INFOBAR_VIDEO), Video);  // Audio                CString Audio('-');                  DVD_AudioAttributes AATR;  if (SUCCEEDED(m_pDVDI->GetCurrentAudio(&ulAvailable, &ulCurrent))                          && SUCCEEDED(m_pDVDI->GetAudioAttributes(ulCurrent, &AATR))) {                      CString lang;  if (AATR.Language) {  int len = GetLocaleInfo(AATR.Language, LOCALE_SENGLANGUAGE, lang.GetBuffer(64), 64);                          lang.ReleaseBufferSetLength(max(len - 1, 0));                      } else {                          lang.Format(IDS_AG_UNKNOWN, ulCurrent + 1);                      }  switch (AATR.LanguageExtension) {  case DVD_AUD_EXT_NotSpecified:  default:  break;  case DVD_AUD_EXT_Captions:                              lang += _T(" (Captions)");  break;  case DVD_AUD_EXT_VisuallyImpaired:                              lang += _T(" (Visually Impaired)");  break;  case DVD_AUD_EXT_DirectorComments1:                              lang += _T(" (Director Comments 1)");  break;  case DVD_AUD_EXT_DirectorComments2:                              lang += _T(" (Director Comments 2)");  break;                      }                      CString format = GetDVDAudioFormatName(AATR);                      Audio.Format(IDS_MAINFRM_11,                                   lang,                                   format,                                   AATR.dwFrequency,                                   AATR.bQuantization,                                   AATR.bNumberOfChannels,                                   (AATR.bNumberOfChannels > 1 ? ResStr(IDS_MAINFRM_13) : ResStr(IDS_MAINFRM_12)));                      m_wndStatusBar.SetStatusBitmap(                          AATR.bNumberOfChannels == 1 ? IDB_AUDIOTYPE_MONO                          : AATR.bNumberOfChannels >= 2 ? IDB_AUDIOTYPE_STEREO                          : IDB_AUDIOTYPE_NOAUDIO);                  }                  m_wndInfoBar.SetLine(ResStr(IDS_INFOBAR_AUDIO), Audio);  // Subtitles                CString Subtitles('-');  BOOL bIsDisabled;                  DVD_SubpictureAttributes SATR;  if (SUCCEEDED(m_pDVDI->GetCurrentSubpicture(&ulAvailable, &ulCurrent, &bIsDisabled))                          && SUCCEEDED(m_pDVDI->GetSubpictureAttributes(ulCurrent, &SATR))) {                      CString lang;  int len = GetLocaleInfo(SATR.Language, LOCALE_SENGLANGUAGE, lang.GetBuffer(64), 64);                      lang.ReleaseBufferSetLength(max(len - 1, 0));  switch (SATR.LanguageExtension) {  case DVD_SP_EXT_NotSpecified:  default:  break;  case DVD_SP_EXT_Caption_Normal:                              lang += _T("");  break;  case DVD_SP_EXT_Caption_Big:                              lang += _T(" (Big)");  break;  case DVD_SP_EXT_Caption_Children:                              lang += _T(" (Children)");  break;  case DVD_SP_EXT_CC_Normal:                              lang += _T(" (CC)");  break;  case DVD_SP_EXT_CC_Big:                              lang += _T(" (CC Big)");  break;  case DVD_SP_EXT_CC_Children:                              lang += _T(" (CC Children)");  break;  case DVD_SP_EXT_Forced:                              lang += _T(" (Forced)");  break;  case DVD_SP_EXT_DirectorComments_Normal:                              lang += _T(" (Director Comments)");  break;  case DVD_SP_EXT_DirectorComments_Big:                              lang += _T(" (Director Comments, Big)");  break;  case DVD_SP_EXT_DirectorComments_Children:                              lang += _T(" (Director Comments, Children)");  break;                      }  if (bIsDisabled) {                          lang = _T("-");                      }                      Subtitles.Format(_T("%s"),                                       lang);                  }                  m_wndInfoBar.SetLine(ResStr(IDS_INFOBAR_SUBTITLES), Subtitles);              } else if (GetPlaybackMode() == PM_CAPTURE && AfxGetAppSettings().iDefaultCaptureDevice == 1) {                  CComQIPtr<IBDATuner> pTun = m_pGB;  BOOLEAN bPresent;  BOOLEAN bLocked;  LONG lDbStrength;  LONG lPercentQuality;                  CString Signal;  if (SUCCEEDED(pTun->GetStats(bPresent, bLocked, lDbStrength, lPercentQuality)) && bPresent) {                      Signal.Format(ResStr(IDS_STATSBAR_SIGNAL_FORMAT), (int)lDbStrength, lPercentQuality);                      m_wndStatsBar.SetLine(ResStr(IDS_STATSBAR_SIGNAL), Signal);                  }              } else if (GetPlaybackMode() == PM_FILE) {                  UpdateChapterInInfoBar();              }  if (GetMediaState() == State_Running && !m_fAudioOnly) {  BOOL fActive = FALSE;  if (SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0,       &fActive, 0)) {                      SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE,   nullptr,     SPIF_SENDWININICHANGE); // this might not be needed at all...                    SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, fActive, nullptr,     SPIF_SENDWININICHANGE);                  }                  fActive = FALSE;  if (SystemParametersInfo(SPI_GETPOWEROFFACTIVE, 0,       &fActive, 0)) {                      SystemParametersInfo(SPI_SETPOWEROFFACTIVE, FALSE,   nullptr,     SPIF_SENDWININICHANGE); // this might not be needed at all...                    SystemParametersInfo(SPI_SETPOWEROFFACTIVE, fActive, nullptr,     SPIF_SENDWININICHANGE);                  }  // prevent screensaver activate, monitor sleep/turn off after playback                SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);              }          }  break;  case TIMER_STATUSERASER: {              KillTimer(TIMER_STATUSERASER);              m_playingmsg.Empty();          }  break;  case TIMER_DVBINFO_UPDATER:              KillTimer(TIMER_DVBINFO_UPDATER);              ShowCurrentChannelInfo(false, false);  break;      }      __super::OnTimer(nIDEvent);  }
复制代码

5:关于对话框 (CAboutDlg)

核心类已经分析的差不多了,现在可以看一看其他类的定义了。可是如此多的类,看看什么好呢?本着由易到难的原则,应该先看看“关于”对话框的代码。“关于”对话框作为mpc-hc系统的一部分,比较有代表性,而且代码相对来说十分简单,因而适合刚入门的人进行学习。

如图所示,“关于”对话框类的定义和实现都在最前面(因为开头是'A'......= =)。类的名字叫做CAboutDlg,定义位于AboutDlg.h,实现位于AboutDlg.cpp。

先看看“关于”对话框是什么样子的吧:

其实相比于其他的“关于”对话框来说,这个还算是一个相对比较复杂的。包含了编译器信息,版本等等信息。

CAboutDlg定义如下所示:

复制代码
/* * (C) 2012 see Authors.txt * * This file is part of MPC-HC. * * MPC-HC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * MPC-HC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.  If not, see <http://www.gnu.org/licenses/>. * */#pragma once#include <afxwin.h>#include "resource.h"class CAboutDlg : public CDialog  {      CStatic m_icon;      CString m_appname;      CString m_strBuildNumber;      CString m_MPCCompiler;  #ifndef MPCHC_LITE    CString m_FFmpegCompiler;  #endif    CString m_credits;      CString m_AuthorsPath;  public:      CAboutDlg();  virtual BOOL OnInitDialog();      afx_msg void OnHomepage(NMHDR* pNMHDR, LRESULT* pResult);      afx_msg void OnAuthors(NMHDR* pNMHDR, LRESULT* pResult);  // Dialog Data//{{AFX_DATA(CAboutDlg)enum { IDD = IDD_ABOUTBOX };  //}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:  virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected:  //{{AFX_MSG(CAboutDlg)// No message handlers//}}AFX_MSG    DECLARE_MESSAGE_MAP()  };
复制代码

从代码上来看。该对话框类和普通的MFC对话框类没有什么区别。不过这个“高端”的“关于”对话框确实包含了不少信息:mpc-hc版本,ffmpeg版本,编译器版本等等。这里就不再多说了,看看它类的实现部分的代码:

复制代码
/* * (C) 2012-2013 see Authors.txt * * This file is part of MPC-HC. * * MPC-HC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * MPC-HC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.  If not, see <http://www.gnu.org/licenses/>. * */#include "stdafx.h"#include "AboutDlg.h"#include "mpc-hc_config.h"#ifndef MPCHC_LITE#include "FGFilterLAV.h"#endif#include "mplayerc.h"#include "version.h"#include "SysVersion.h"#include "WinAPIUtils.h"/////////////////////////////////////////////////////////////////////////////// CAboutDlg dialog used for App AboutCAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)      , m_appname(_T(""))      , m_strBuildNumber(_T(""))      , m_MPCCompiler(_T(""))  #ifndef MPCHC_LITE    , m_LAVFiltersVersion(_T(""))  #endif{  //{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}  //初始化BOOL CAboutDlg::OnInitDialog()  {  // Get the default text before it is overwritten by the call to __super::OnInitDialog()    GetDlgItem(IDC_STATIC1)->GetWindowText(m_appname);      GetDlgItem(IDC_AUTHORS_LINK)->GetWindowText(m_credits);  #ifndef MPCHC_LITE    GetDlgItem(IDC_LAVFILTERS_VERSION)->GetWindowText(m_LAVFiltersVersion);  #endif    __super::OnInitDialog();  // Because we set LR_SHARED, there is no need to explicitly destroy the icon    m_icon.SetIcon((HICON)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 48, 48, LR_SHARED));  #if MPC_BETA_RELEASE || _WIN64    m_appname += _T(" (");  #endif#if MPC_BETA_RELEASE    m_appname += MPC_VERSION_BETA;  #endif#if MPC_BETA_RELEASE && _WIN64    m_appname += _T(", ");  #endif#ifdef _WIN64    m_appname += _T("64-bit");  #endif#if MPC_BETA_RELEASE || _WIN64    m_appname += _T(")");  #endif#ifdef MPCHC_LITE    m_appname += _T(" Lite");  #endif// Build the path to Authors.txt    m_AuthorsPath = GetProgramPath() + _T("Authors.txt");  // Check if the file existsif (FileExists(m_AuthorsPath)) {  // If it does, we make the filename clickable        m_credits.Replace(_T("Authors.txt"), _T("<a>Authors.txt</a>"));      }      m_homepage.Format(_T("<a>%s</a>"), WEBSITE_URL);      m_strBuildNumber = MPC_VERSION_STR_FULL;  #if defined(__INTEL_COMPILER)#if (__INTEL_COMPILER >= 1210)    m_MPCCompiler = _T("ICL ") MAKE_STR(__INTEL_COMPILER) _T(" Build ") MAKE_STR(__INTEL_COMPILER_BUILD_DATE);  #else#error Compiler is not supported!#endif#elif defined(_MSC_VER)#if (_MSC_VER == 1700) // 2012#if (_MSC_FULL_VER == 170060610)    m_MPCCompiler = _T("MSVC 2012 Update 3");  #elif (_MSC_FULL_VER == 170060315)  // MSVC 2012 Update 2#error VS2012 Update 2 is not supported because the binaries will not run on XP. Install Update 3 instead.#elif (_MSC_FULL_VER == 170051106)    m_MPCCompiler = _T("MSVC 2012 Update 1");  #elif (_MSC_FULL_VER < 170050727)   // MSVC 2012#error Please install the latest Update for VS2012.#else    m_MPCCompiler = _T("MSVC 2012");  #endif#elif (_MSC_VER == 1600) // 2010#if (_MSC_FULL_VER >= 160040219)    m_MPCCompiler = _T("MSVC 2010 SP1");  #else    m_MPCCompiler = _T("MSVC 2010");  #endif#elif (_MSC_VER < 1600)#error Compiler is not supported!#endif#else#error Please add support for your compiler#endif#if (__AVX__)    m_MPCCompiler += _T(" (AVX)");  #elif (__SSSE3__)    m_MPCCompiler += _T(" (SSSE3)");  #elif (__SSE3__)    m_MPCCompiler += _T(" (SSE3)");  #elif !defined(_M_X64) && defined(_M_IX86_FP)#if (_M_IX86_FP == 2)   // /arch:SSE2 was used    m_MPCCompiler += _T(" (SSE2)");  #elif (_M_IX86_FP == 1) // /arch:SSE was used    m_MPCCompiler += _T(" (SSE)");  #endif#endif#ifdef _DEBUG    m_MPCCompiler += _T(" Debug");  #endif#ifndef MPCHC_LITE//版本    CString LAVFiltersVersion = CFGFilterLAV::GetVersion();  if (!LAVFiltersVersion.IsEmpty()) {          m_LAVFiltersVersion = LAVFiltersVersion;      }  #endif    m_buildDate = _T(__DATE__) _T(" ") _T(__TIME__);      OSVERSIONINFOEX osVersion = SysVersion::GetFullVersion();      m_OSName.Format(_T("Windows NT %1u.%1u (build %u"),                      osVersion.dwMajorVersion, osVersion.dwMinorVersion, osVersion.dwBuildNumber);  if (osVersion.szCSDVersion[0]) {          m_OSName.AppendFormat(_T(", %s)"), osVersion.szCSDVersion);      } else {          m_OSName += _T(")");      }      m_OSVersion.Format(_T("%1u.%1u"), osVersion.dwMajorVersion, osVersion.dwMinorVersion);  if (SysVersion::Is64Bit()) {          m_OSVersion += _T(" (64-bit)");      }      UpdateData(FALSE);      GetDlgItem(IDOK)->SetFocus();  return FALSE;  }  void CAboutDlg::DoDataExchange(CDataExchange* pDX)  {      CDialog::DoDataExchange(pDX);  //{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP    DDX_Control(pDX, IDR_MAINFRAME, m_icon);      DDX_Text(pDX, IDC_STATIC1, m_appname);      DDX_Text(pDX, IDC_AUTHORS_LINK, m_credits);      DDX_Text(pDX, IDC_HOMEPAGE_LINK, m_homepage);      DDX_Text(pDX, IDC_VERSION, m_strBuildNumber);      DDX_Text(pDX, IDC_MPC_COMPILER, m_MPCCompiler);  #ifndef MPCHC_LITE    DDX_Text(pDX, IDC_LAVFILTERS_VERSION, m_LAVFiltersVersion);  #endif    DDX_Text(pDX, IDC_STATIC2, m_buildDate);      DDX_Text(pDX, IDC_STATIC3, m_OSName);      DDX_Text(pDX, IDC_STATIC4, m_OSVersion);  }  BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)  //{{AFX_MSG_MAP(CAboutDlg)// No message handlers//}}AFX_MSG_MAP    ON_NOTIFY(NM_CLICK, IDC_HOMEPAGE_LINK, OnHomepage)      ON_NOTIFY(NM_CLICK, IDC_AUTHORS_LINK, OnAuthors)      ON_BN_CLICKED(IDC_BUTTON1, OnCopyToClipboard)  END_MESSAGE_MAP()  void CAboutDlg::OnHomepage(NMHDR* pNMHDR, LRESULT* pResult)  {      ShellExecute(m_hWnd, _T("open"), WEBSITE_URL, nullptr, nullptr, SW_SHOWDEFAULT);      *pResult = 0;  }  void CAboutDlg::OnAuthors(NMHDR* pNMHDR, LRESULT* pResult)  {      ShellExecute(m_hWnd, _T("open"), m_AuthorsPath, nullptr, nullptr, SW_SHOWDEFAULT);      *pResult = 0;  }  //拷贝到剪切板void CAboutDlg::OnCopyToClipboard()  {  //把各种信息添加到一个字符串中    CStringW info = m_appname;      info += _T("\n----------------------------------\n\n");      info += _T("Build information:\n");      info += _T("    Version:            ") + m_strBuildNumber + _T("\n");      info += _T("    MPC-HC compiler:    ") + m_MPCCompiler + _T("\n");      info += _T("    Build date:         ") + m_buildDate + _T("\n\n");  #ifndef MPCHC_LITE    info += _T("LAV Filters:\n");      info += _T("    LAV Splitter:       ") + CFGFilterLAV::GetVersion(CFGFilterLAV::SPLITTER) + _T("\n");      info += _T("    LAV Video:          ") + CFGFilterLAV::GetVersion(CFGFilterLAV::VIDEO_DECODER) + _T("\n");      info += _T("    LAV Audio:          ") + CFGFilterLAV::GetVersion(CFGFilterLAV::AUDIO_DECODER) + _T("\n\n");  #endif    info += _T("Operating system:\n");      info += _T("    Name:               ") + m_OSName + _T("\n");      info += _T("    Version:            ") + m_OSVersion + _T("\n");      COleDataSource* pData = DEBUG_NEW COleDataSource();  int len = info.GetLength() + 1;  HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, len * sizeof(WCHAR));  if (pData && hGlob) {          wcscpy_s((WCHAR*)hGlob, len, (LPCWSTR)info);          pData->CacheGlobalData(CF_UNICODETEXT, hGlob);  // The system will take care of removing the allocated memory        pData->SetClipboard();      } else if (pData) {  delete pData;      } else if (hGlob) {          GlobalFree(hGlob);      }  }
复制代码

6:MediaInfo选项卡 (CPPageFileMediaInfo)

发现CAboutDlg和普通的MFC对话框类其实没有什么区别。CAboutDlg功能相对比较简单,本文将会分析一个功能相对比较复杂的类:MediaInfo选项卡。在播放视频的时候,右键点击视频->选择“属性”->MediaInfo就可以查看该选项卡。一般情况下,该选项卡给出了正在播放的视频文件的详细参数(确实是非常的详细),包括:封装格式,视频编码,音频编码等等。是获取视频详细参数的最佳途径。

该选项卡的功能实际上是调用了开源项目MediaInfo的库。MediaInfo之前已经进行过详细介绍:

C++中使用MediaInfo库获取视频信息

MediaInfo使用简介(新版本支持HEVC)

在此不再重复。先看看该选项卡长什么样子。

先来看看MediaInfo选项卡类的定义是什么样的吧。该类的定义位于PPageFileMediaInfo.h文件中。

复制代码
/* 雷霄骅  * 中国传媒大学/数字电视技术  * leixiaohua1020@126.com  *  *//* * (C) 2009-2013 see Authors.txt * * This file is part of MPC-HC. * * MPC-HC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * MPC-HC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.  If not, see <http://www.gnu.org/licenses/>. * */#pragma once// CPPageFileMediaInfo dialog// 【属性】页面里面的【MediaInfo】class CPPageFileMediaInfo : public CPropertyPage  {      DECLARE_DYNAMIC(CPPageFileMediaInfo)  private:      CComPtr<IFilterGraph> m_pFG;  public:  //构造函数都是两个参数    CPPageFileMediaInfo(CString fn, IFilterGraph* pFG);  virtual ~CPPageFileMediaInfo();  // Dialog Dataenum { IDD = IDD_FILEMEDIAINFO };  //显示信息的控件    CEdit m_mediainfo;      CString m_fn;      CFont* m_pCFont;  //信息    CString MI_Text;  #if !USE_STATIC_MEDIAINFOstatic bool HasMediaInfo();  #endifprotected:  virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support//初始化,加载MediaInfo库,读取文件信息virtual BOOL OnInitDialog();      DECLARE_MESSAGE_MAP()  public:  //显示窗口,并不做其他事情    afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);  };
复制代码

该类和普通的MFC对话框类差别也不大。需要注意的有以下几点:

1.有一个变量:CComPtr<IFilterGraph> m_pFG,这个是mpc-hc中的变量,先不分析该变量的全部代码,在这里仅说一下它的作用:获取正在播放的视频文件的路径。

2.有一个控件类:CEdit m_mediainfo,对应界面上那个大框框,用于显示信息。

3.有一个字符串变量:CString MI_Text,用于存储MediaInfo得到的媒体信息。

下面来看看具体类的实现,该类的实现位于PPageFileMediaInfo.cpp文件中。

复制代码
/* 雷霄骅  * 中国传媒大学/数字电视技术  * leixiaohua1020@126.com  *  *//* * (C) 2009-2013 see Authors.txt * * This file is part of MPC-HC. * * MPC-HC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * MPC-HC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.  If not, see <http://www.gnu.org/licenses/>. * */// PPageFileMediaInfo.cpp : implementation file#include "stdafx.h"#include "mplayerc.h"#include "PPageFileMediaInfo.h"#include "WinAPIUtils.h"#if USE_STATIC_MEDIAINFO#include "MediaInfo/MediaInfo.h"using namespace MediaInfoLib;  #else#include "MediaInfoDLL.h"using namespace MediaInfoDLL;  #endif// CPPageFileMediaInfo dialogIMPLEMENT_DYNAMIC(CPPageFileMediaInfo, CPropertyPage)  CPPageFileMediaInfo::CPPageFileMediaInfo(CString fn, IFilterGraph* pFG)      : CPropertyPage(CPPageFileMediaInfo::IDD, CPPageFileMediaInfo::IDD)      , m_fn(fn)      , m_pFG(pFG)      , m_pCFont(nullptr)  {  }  CPPageFileMediaInfo::~CPPageFileMediaInfo()  {  delete m_pCFont;      m_pCFont = nullptr;  }  void CPPageFileMediaInfo::DoDataExchange(CDataExchange* pDX)  {      __super::DoDataExchange(pDX);      DDX_Control(pDX, IDC_MIEDIT, m_mediainfo);  }  BEGIN_MESSAGE_MAP(CPPageFileMediaInfo, CPropertyPage)      ON_WM_SHOWWINDOW()  END_MESSAGE_MAP()  // CPPageFileMediaInfo message handlersstatic WNDPROC OldControlProc;  static LRESULT CALLBACK ControlProc(HWND control, UINT message, WPARAM wParam, LPARAM lParam)  {  if (message == WM_KEYDOWN) {  if ((LOWORD(wParam) == 'A' || LOWORD(wParam) == 'a')                  && (GetKeyState(VK_CONTROL) < 0)) {              CEdit* pEdit = (CEdit*)CWnd::FromHandle(control);              pEdit->SetSel(0, pEdit->GetWindowTextLength(), TRUE);  return 0;          }      }  return CallWindowProc(OldControlProc, control, message, wParam, lParam); // call edit control's own windowproc}  //初始化,加载MediaInfo库,读取文件信息BOOL CPPageFileMediaInfo::OnInitDialog()  {      __super::OnInitDialog();  if (!m_pCFont) {          m_pCFont = DEBUG_NEW CFont;      }  if (!m_pCFont) {  return TRUE;      }  if (m_fn.IsEmpty()) {          BeginEnumFilters(m_pFG, pEF, pBF) {              CComQIPtr<IFileSourceFilter> pFSF = pBF;  if (pFSF) {  //当前文件路径                LPOLESTR pFN = nullptr;  //媒体类型                AM_MEDIA_TYPE mt;  //获取当前文件的路径和媒体类型if (SUCCEEDED(pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) {                      m_fn = CStringW(pFN);                      CoTaskMemFree(pFN);                  }  break;              }          }          EndEnumFilters;      }  #if USE_STATIC_MEDIAINFO//使用静态库MediaInfo//文件路径    MediaInfoLib::String f_name = m_fn;      MediaInfoLib::MediaInfo MI;  #else    MediaInfoDLL::String f_name = m_fn;      MediaInfo MI;  #endif//设置    MI.Option(_T("ParseSpeed"), _T("0"));      MI.Open(f_name);      MI.Option(_T("Complete"));      MI.Option(_T("Language"), _T("  Config_Text_ColumnSize;30"));  //信息字符串    MI_Text = MI.Inform().c_str();      MI.Close();  if (!MI_Text.Find(_T("Unable to load"))) {          MI_Text = _T("");      }      LOGFONT lf;      ZeroMemory(&lf, sizeof(lf));      lf.lfPitchAndFamily = DEFAULT_PITCH | FF_MODERN;  // The empty string will fallback to the first font that matches the other specified attributes.LPCTSTR fonts[] = { _T("Lucida Console"), _T("Courier New"), _T("") };  // Use a negative value to match the character height instead of the cell height.int fonts_size[] = { -10, -11, -11 };  UINT i = 0;  BOOL success;  do {          _tcscpy_s(lf.lfFaceName, fonts[i]);          lf.lfHeight = fonts_size[i];          success = IsFontInstalled(fonts[i]) && m_pCFont->CreateFontIndirect(&lf);          i++;      } while (!success && i < _countof(fonts));  //控件设置字体和内容    m_mediainfo.SetFont(m_pCFont);      m_mediainfo.SetWindowText(MI_Text);  // subclass the edit control    OldControlProc = (WNDPROC)SetWindowLongPtr(m_mediainfo.m_hWnd, GWLP_WNDPROC, (LONG_PTR)ControlProc);  return TRUE;  // return TRUE unless you set the focus to a control// EXCEPTION: OCX Property Pages should return FALSE}  //显示or不显示?void CPPageFileMediaInfo::OnShowWindow(BOOL bShow, UINT nStatus)  {      __super::OnShowWindow(bShow, nStatus);  if (bShow) {          GetParent()->GetDlgItem(IDC_BUTTON_MI)->ShowWindow(SW_SHOW);      } else {          GetParent()->GetDlgItem(IDC_BUTTON_MI)->ShowWindow(SW_HIDE);      }  }  #if !USE_STATIC_MEDIAINFObool CPPageFileMediaInfo::HasMediaInfo()  {      MediaInfo MI;  return MI.IsReady();  }  #endif
复制代码

可以看出,主要的工作都是在OnInitDialog()函数中实现的。大体的步骤如下:

1.通过调用pFSF->GetCurFile(&pFN, &mt),获得当前文件的路径,存入pFN中。

2.因为字符串类型不同,几经转换把pFN转换为MediaInfo可以识别的字符串f_name

3.根据该路径,调用MediaInfo库,获得视频的详细信息存入字符串变量MI_Text。

4.将MI_Text显示到控件上。

总体说来,过程并不复杂,理解起来还是比较简单的。

7:详细信息选项卡(CPPageFileInfoDetails)

本文分析一下mpc-hc的详细信息选项卡。在播放视频的时候,右键点击视频->选择“属性”后默认打开的就是该选项卡。一般情况下,该选项卡给出了正在播放的视频文件的一些基本参数:视频大小,分辨率,时长等。注意:详细信息选项卡和MediaInfo选项卡获得视频参数的原理是不一样的。详细信息选项卡是通过调用DirectShow函数接口而获得的视频的参数。而MediaInfo选项卡则是通过调用MediaInfo类库而获得视频的参数。

先看看选项卡长什么样子:

先来看看详细信息选项卡类的定义是什么样的吧。该类的定义位于PPageFileInfoDetails.h文件中。

复制代码
/* 雷霄骅  * 中国传媒大学/数字电视技术  * leixiaohua1020@126.com  *  *//* * (C) 2003-2006 Gabest * (C) 2006-2012 see Authors.txt * * This file is part of MPC-HC. * * MPC-HC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * MPC-HC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.  If not, see <http://www.gnu.org/licenses/>. * */#pragma once#include "../SubPic/ISubPic.h"#include <afxwin.h>//取得一些基本信息// CPPageFileInfoDetails dialogclass CPPageFileInfoDetails : public CPropertyPage  {      DECLARE_DYNAMIC(CPPageFileInfoDetails)  private:      CComPtr<IFilterGraph> m_pFG;      CComPtr<ISubPicAllocatorPresenter> m_pCAP;  HICON m_hIcon;  void InitEncoding();  public:      CPPageFileInfoDetails(CString fn, IFilterGraph* pFG, ISubPicAllocatorPresenter* pCAP);  virtual ~CPPageFileInfoDetails();  // Dialog Dataenum { IDD = IDD_FILEPROPDETAILS };      CStatic m_icon;      CString m_fn;      CString m_type;      CString m_size;      CString m_time;      CString m_res;      CString m_created;      CEdit   m_encoding;  protected:  virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV supportvirtual BOOL OnInitDialog();  virtual BOOL OnSetActive();  virtual LRESULT OnSetPageFocus(WPARAM wParam, LPARAM lParam);      DECLARE_MESSAGE_MAP()  public:  };
复制代码

该类的定义和普通的MFC对话框类差不多,有以下几点是需要注意的:

1.以下两个变量是用于获得对话框上显示的相关的信息的:

CComPtr<IFilterGraph> m_pFG;   

CComPtr<ISubPicAllocatorPresenter> m_pCAP;

2.有一系列的字符串变量:m_fn, m_type, m_size, m_time等用于存储获得的信息

详细信息选项卡类的实现位于PPageFileInfoDetails.cpp文件中。

复制代码
/* 雷霄骅  * 中国传媒大学/数字电视技术  * leixiaohua1020@126.com  *  *//* * (C) 2003-2006 Gabest * (C) 2006-2013 see Authors.txt * * This file is part of MPC-HC. * * MPC-HC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * MPC-HC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program.  If not, see <http://www.gnu.org/licenses/>. * *///取得一些基本信息#include "stdafx.h"#include "mplayerc.h"#include "PPageFileInfoDetails.h"#include <atlbase.h>#include "DSUtil.h"#include "text.h"#include <d3d9.h>#include <vmr9.h>#include "moreuuids.h"// CPPageFileInfoDetails dialogIMPLEMENT_DYNAMIC(CPPageFileInfoDetails, CPropertyPage)  CPPageFileInfoDetails::CPPageFileInfoDetails(CString fn, IFilterGraph* pFG, ISubPicAllocatorPresenter* pCAP)      : CPropertyPage(CPPageFileInfoDetails::IDD, CPPageFileInfoDetails::IDD)      , m_fn(fn)      , m_pFG(pFG)      , m_pCAP(pCAP)      , m_hIcon(nullptr)      , m_type(ResStr(IDS_AG_NOT_KNOWN))      , m_size(ResStr(IDS_AG_NOT_KNOWN))      , m_time(ResStr(IDS_AG_NOT_KNOWN))      , m_res(ResStr(IDS_AG_NOT_KNOWN))      , m_created(ResStr(IDS_AG_NOT_KNOWN))  {  }  CPPageFileInfoDetails::~CPPageFileInfoDetails()  {  if (m_hIcon) {          DestroyIcon(m_hIcon);      }  }  void CPPageFileInfoDetails::DoDataExchange(CDataExchange* pDX)  {      __super::DoDataExchange(pDX);      DDX_Control(pDX, IDC_DEFAULTICON, m_icon);      DDX_Text(pDX, IDC_EDIT1, m_fn);      DDX_Text(pDX, IDC_EDIT4, m_type);      DDX_Text(pDX, IDC_EDIT3, m_size);      DDX_Text(pDX, IDC_EDIT2, m_time);      DDX_Text(pDX, IDC_EDIT5, m_res);      DDX_Text(pDX, IDC_EDIT6, m_created);      DDX_Control(pDX, IDC_EDIT7, m_encoding);  }  #define SETPAGEFOCUS (WM_APP + 252) // arbitrary number, can be changed if necessaryBEGIN_MESSAGE_MAP(CPPageFileInfoDetails, CPropertyPage)      ON_MESSAGE(SETPAGEFOCUS, OnSetPageFocus)  END_MESSAGE_MAP()  // CPPageFileInfoDetails message handlersstatic bool GetProperty(IFilterGraph* pFG, LPCOLESTR propName, VARIANT* vt)  {      BeginEnumFilters(pFG, pEF, pBF) {  if (CComQIPtr<IPropertyBag> pPB = pBF)  if (SUCCEEDED(pPB->Read(propName, vt, nullptr))) {  return true;              }      }      EndEnumFilters;  return false;  }  static CString FormatDateTime(FILETIME tm)  {      SYSTEMTIME st;      FileTimeToSystemTime(&tm, &st);  TCHAR buff[256];      GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, nullptr, buff, _countof(buff));      CString ret(buff);      ret += _T(" ");      GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, nullptr, buff, _countof(buff));      ret += buff;  return ret;  }  BOOL CPPageFileInfoDetails::OnInitDialog()  {      __super::OnInitDialog();  if (m_fn.IsEmpty()) {          BeginEnumFilters(m_pFG, pEF, pBF) {              CComQIPtr<IFileSourceFilter> pFSF = pBF;  if (pFSF) {                  LPOLESTR pFN = nullptr;                  AM_MEDIA_TYPE mt;  if (SUCCEEDED(pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) {                      m_fn = CStringW(pFN);                      CoTaskMemFree(pFN);                  }  break;              }          }          EndEnumFilters;      }      CString ext = m_fn.Left(m_fn.Find(_T("://")) + 1).TrimRight(':');  if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) {          ext = _T(".") + m_fn.Mid(m_fn.ReverseFind('.') + 1);      }      m_hIcon = LoadIcon(m_fn, false);  if (m_hIcon) {          m_icon.SetIcon(m_hIcon);      }  if (!LoadType(ext, m_type)) {          m_type.LoadString(IDS_AG_NOT_KNOWN);      }      CComVariant vt;  if (::GetProperty(m_pFG, L"CurFile.TimeCreated", &vt)) {  if (V_VT(&vt) == VT_UI8) {              ULARGE_INTEGER uli;              uli.QuadPart = V_UI8(&vt);              FILETIME ft;              ft.dwLowDateTime = uli.LowPart;              ft.dwHighDateTime = uli.HighPart;              m_created = FormatDateTime(ft);          }      }      WIN32_FIND_DATA wfd;  HANDLE hFind = FindFirstFile(m_fn, &wfd);  if (hFind != INVALID_HANDLE_VALUE) {          FindClose(hFind);  __int64 size = (__int64(wfd.nFileSizeHigh) << 32) | wfd.nFileSizeLow;  const int MAX_FILE_SIZE_BUFFER = 65;  WCHAR szFileSize[MAX_FILE_SIZE_BUFFER];          StrFormatByteSizeW(size, szFileSize, MAX_FILE_SIZE_BUFFER);          CString szByteSize;          szByteSize.Format(_T("%I64d"), size);          m_size.Format(_T("%s (%s bytes)"), szFileSize, FormatNumber(szByteSize));  if (m_created.IsEmpty()) {              m_created = FormatDateTime(wfd.ftCreationTime);          }      }  //获取时常    REFERENCE_TIME rtDur = 0;      CComQIPtr<IMediaSeeking> pMS = m_pFG;  if (pMS && SUCCEEDED(pMS->GetDuration(&rtDur)) && rtDur > 0) {          m_time = ReftimeToString2(rtDur);      }      CSize wh(0, 0), arxy(0, 0);  //获取宽和高if (m_pCAP) {          wh = m_pCAP->GetVideoSize(false);          arxy = m_pCAP->GetVideoSize(true);      } else {  if (CComQIPtr<IBasicVideo> pBV = m_pFG) {  if (SUCCEEDED(pBV->GetVideoSize(&wh.cx, &wh.cy))) {  if (CComQIPtr<IBasicVideo2> pBV2 = m_pFG) {                      pBV2->GetPreferredAspectRatio(&arxy.cx, &arxy.cy);                  }              } else {                  wh.SetSize(0, 0);              }          }  if (wh.cx == 0 && wh.cy == 0) {              BeginEnumFilters(m_pFG, pEF, pBF) {  if (CComQIPtr<IBasicVideo> pBV = pBF) {                      pBV->GetVideoSize(&wh.cx, &wh.cy);  if (CComQIPtr<IBasicVideo2> pBV2 = pBF) {                          pBV2->GetPreferredAspectRatio(&arxy.cx, &arxy.cy);                      }  break;                  } else if (CComQIPtr<IVMRWindowlessControl> pWC = pBF) {                      pWC->GetNativeVideoSize(&wh.cx, &wh.cy, &arxy.cx, &arxy.cy);  break;                  } else if (CComQIPtr<IVMRWindowlessControl9> pWC9 = pBF) {                      pWC9->GetNativeVideoSize(&wh.cx, &wh.cy, &arxy.cx, &arxy.cy);  break;                  }              }              EndEnumFilters;          }      }  if (wh.cx > 0 && wh.cy > 0) {          m_res.Format(_T("%dx%d"), wh.cx, wh.cy);  int gcd = GCD(arxy.cx, arxy.cy);  if (gcd > 1) {              arxy.cx /= gcd;              arxy.cy /= gcd;          }  if (arxy.cx > 0 && arxy.cy > 0 && arxy.cx * wh.cy != arxy.cy * wh.cx) {              CString ar;              ar.Format(_T(" (AR %d:%d)"), arxy.cx, arxy.cy);              m_res += ar;          }      }      m_fn.TrimRight('/');      m_fn.Replace('\\', '/');      m_fn = m_fn.Mid(m_fn.ReverseFind('/') + 1);      UpdateData(FALSE);      InitEncoding();      m_pFG = nullptr;      m_pCAP = nullptr;  return TRUE;  // return TRUE unless you set the focus to a control// EXCEPTION: OCX Property Pages should return FALSE}  BOOL CPPageFileInfoDetails::OnSetActive()  {  BOOL ret = __super::OnSetActive();      PostMessage(SETPAGEFOCUS, 0, 0L);  return ret;  }  LRESULT CPPageFileInfoDetails::OnSetPageFocus(WPARAM wParam, LPARAM lParam)  {      CPropertySheet* psheet = (CPropertySheet*) GetParent();      psheet->GetTabControl()->SetFocus();  return 0;  }  void CPPageFileInfoDetails::InitEncoding()  {      CAtlList<CString> sl;      BeginEnumFilters(m_pFG, pEF, pBF) {          CComPtr<IBaseFilter> pUSBF = GetUpStreamFilter(pBF);  if (GetCLSID(pBF) == CLSID_NetShowSource) {  continue;          } else if (GetCLSID(pUSBF) != CLSID_NetShowSource) {  if (IPin* pPin = GetFirstPin(pBF, PINDIR_INPUT)) {                  CMediaType mt;  if (FAILED(pPin->ConnectionMediaType(&mt)) || mt.majortype != MEDIATYPE_Stream) {  continue;                  }              }  if (IPin* pPin = GetFirstPin(pBF, PINDIR_OUTPUT)) {                  CMediaType mt;  if (SUCCEEDED(pPin->ConnectionMediaType(&mt)) && mt.majortype == MEDIATYPE_Stream) {  continue;                  }              }          }          BeginEnumPins(pBF, pEP, pPin) {              CMediaTypeEx mt;              PIN_DIRECTION dir;  if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT                      || FAILED(pPin->ConnectionMediaType(&mt))) {  continue;              }              CString str = mt.ToString();  if (!str.IsEmpty()) {  if (mt.majortype == MEDIATYPE_Video) { // Sort streams, set Video streams at headbool found_video = false;  for (POSITION pos = sl.GetTailPosition(); pos; sl.GetPrev(pos)) {                          CString Item = sl.GetAt(pos);  if (!Item.Find(_T("Video:"))) {                              sl.InsertAfter(pos, str + CString(L" [" + GetPinName(pPin) + L"]"));                              found_video = true;  break;                          }                      }  if (!found_video) {                          sl.AddHead(str + CString(L" [" + GetPinName(pPin) + L"]"));                      }                  } else {                      sl.AddTail(str + CString(L" [" + GetPinName(pPin) + L"]"));                  }              }          }          EndEnumPins;      }      EndEnumFilters;      CString text = Implode(sl, '\n');      text.Replace(_T("\n"), _T("\r\n"));      m_encoding.SetWindowText(text);  }
复制代码

从代码中可以看出,CPPageFileInfoDetails的功能是在OnInitDialog()中完成的。通过调用DirectShow相应的接口,分别获取了视频的宽高,时长等信息。

0 0
原创粉丝点击