zoukankan      html  css  js  c++  java
  • Media Player Classic

    注:写了一系列分析Media Player Classic - HC 源代码的文章,在此列一个列表:

    Media Player Classic - HC 源代码分析 1:整体结构
    Media Player Classic - HC 源代码分析 2:核心类 (CMainFrame)(1)
    Media Player Classic - HC 源代码分析 3:核心类 (CMainFrame)(2)
    Media Player Classic - HC 源代码分析 4:核心类 (CMainFrame)(3)
    Media Player Classic - HC 源代码分析 5:关于对话框 (CAboutDlg)
    Media Player Classic - HC 源代码分析 6:MediaInfo选项卡 (CPPageFileMediaInfo)
    Media Player Classic - HC 源代码分析 7:详细信息选项卡(CPPageFileInfoDetails)


    上一篇文章概括性的介绍了Media Player Classic - Home Cinema (mpc-hc)播放器的源代码:Media Player Classic - HC 源代码分析 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)
    
        // Attributes
    public:
        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);
    	//打开DVD
        void 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);
    
        // capturing
        bool 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 enc
        bool 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 capture
        void ShowCurrentChannelInfo(bool fShowOSD = true, bool fShowInfoBar = false);
    
        // Implementation
    public:
        virtual ~CMainFrame();
    #ifdef _DEBUG
        virtual void AssertValid() const;
        virtual void Dump(CDumpContext& dc) const;
    #endif
    
    protected:  
    	// 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 functions
        void        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()//打开一个DVD
    OpenCurPlaylistItem()//打开播放列表的一条记录(比如说一个文件)

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

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

    //打开媒体(非private)
    void CMainFrame::OpenMedia(CAutoPtr<OpenMediaData> pOMD)
    {
        // shortcut
        if (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 logo
    
        const 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 fullscreen
        if (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 code
        if (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]:
    "), index);
                TRACE(_T("	%ws
    "), 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 used
                if (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 shift
            if (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 things
    
        if (!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 sense
            if (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);









  • 相关阅读:
    matlab之图像处理(2)
    FIR滤波器(1)- 基础知识
    图像融合
    IEEE Floating Point Standard (IEEE754浮点数表示法标准)
    ISE 中使用system generate
    System Generator入门
    System Generator入门笔记
    2019 Multi-University Training Contest 7 Kejin Player Final Exam
    Sequence POJ
    POJ
  • 原文地址:https://www.cnblogs.com/leixiaohua1020/p/3902008.html
Copyright © 2011-2022 走看看