Media Player Classic - HC 源代码分析 4:核心类 (CMainFrame)(3)
此前已经写了2篇文章介绍Media Player Classic - HC (mpc-hc)源代码中的核心类 CMainFrame:
Media Player Classic - HC 源代码分析 2:核心类 (CMainFrame)(1)
Media Player Classic - HC 源代码分析 3:核心类 (CMainFrame)(2)
此前的文章一直都是围绕着OpenMedia()以及其调用的函数进行分析的。研究的都是和文件打开有关系的功能。在这里再介绍一些其它函数。
在mpc-hc开始运行的时候,会调用OnCreate():
//定时刷新的操作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 play if ((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 playback ULONG 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);}